架構實踐 - 3. 基於事件系統的demo

1、概述

基於上篇文章,我們設計一個具體的demo。demo在linux版本運行,gcc編譯通過

主要由如下文件構成:

main.c                  實現main_loop, 和main_handler

base_queue.c/h   實現隊列模塊

base_timer.c/h     實現timer模塊

Makefile               編譯文件,直接使用make編譯就行

其他依賴文件

lish.h common.h 

2、運行

 

3、源碼

main.c 

#include <pthread.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include "common.h"
#include "base_queue.h"
#include "base_timer.h"

extern int msgqid;
tmr_hdl_t tmr_hdl = NULL;

/**
 * func: request event handler
 * parm:
 * return:
 */
void main_request_handler(request_t *req)
{
    switch(req->type) {

    case POWER_ON:
        printf("req msg.power_on.id=%d, name=%s\n", req->msg.power_on_req.id, req->msg.power_on_req.name);
    break;

    case POWER_OFF:
        printf("req msg.power_off.id=%d, name=%s\n", req->msg.power_off_req.id, req->msg.power_off_req.name);
    break;

    default:
        printf("not support the request!\n");
        break;
    }
}

/**
 * func: pthread, trans
 * parm:
 * return:
 */
void *pthread(void *arg)
{
    int rc, timeout, ret;
    msg_t msg = {0};
    ms_t ms = 0;
    printf("start pthread %s...\n", ((data_t*)arg)->name);

    while(1) {

        /* 1. read event from queue */
        // msgrcv(msgqid, &msg, sizeof(msg)-sizeof(long), QUEUE_TYPE, 0);
        ret = msgrcv(msgqid, &msg, sizeof(msg)-sizeof(long), QUEUE_TYPE, IPC_NOWAIT);

        /* 2. trans message to msg handler */
        if (ret > 0) {
            request_t *req = (request_t *)msg.mdata;
            // printf("request->typed=%d, msg.id=%d, msg.name=%s\n",
            //             req->type, msg.mtype, msg.mdata);
            main_request_handler(req);
        }

        /* 3. get the remain time of the recent timer, not using here */
        rc = get_next_timeout(tmr_hdl, &ms);
        if (rc < 0) {
            timeout = 1000;
        } else {
            timeout = ms;
        }

        /* 4. update system timer */
        time_update(tmr_hdl);

        /* 5. execute callback, if the timer is end  */
        proc_timer(tmr_hdl);

        usleep(1*1000);  //sleep 1ms

    }
}

/**
 * func: test request function1
 * parm:
 * return:
 */
void func_demo1()
{
    power_on_req_t req = {0};
    req.id = 1;
    memcpy(req.name, "power_on", sizeof("power_on"));

    POST_REQUEST(POWER_ON, &req, sizeof(req), NULL, NULL);
}

/**
 * func: test request function2
 * parm:
 * return:
 */
void func_demo2()
{
    power_off_req_t req = {0};
    req.id = 2;
    memcpy(req.name, "power_off", sizeof("power_off"));

    POST_REQUEST(POWER_OFF, &req, sizeof(req), NULL, NULL);
}

/**
 * func: test timer
 * parm:
 * return:
 */
void timer_handler(int timer_id, void* data)
{
    printf("lyh add -> enter timer_handler\n");
}


/**
 * func:
 * parm:
 * return:
 */
int main()
{
    printf("Hello World\n");

    pthread_t p_hander = 0;
    tmr_t main1_tmr={0}, main2_tmr={0};

    /* queue init */
    queue_init();

    /* timer init */
    tmr_hdl = timer_init();

    /* create pthread */
    data_t data = {.num=1, .name="test"};
    pthread_create(&p_hander, NULL, pthread, (void*)(&data));

    /* test request event */
    func_demo1();
    func_demo2();

    /* test timer */
    start_tmr(tmr_hdl, &main1_tmr, timer_handler, 1 * 1000 / MS_PER_TICK);
    start_tmr(tmr_hdl, &main2_tmr, timer_handler, 10 * 1000 / MS_PER_TICK);

    while(1) {
        sleep(1);
    }
}

 

base_queue.c

#include "base_queue.h"


int msgqid = 0;  /* message queue */

/**
 * func: init queue
 * parm:
 * return:
 */
int queue_init()
{
    key_t key;
    key = ftok("./", 1024);

    /* create queue */
    msgqid = msgget(key, IPC_CREAT|0666);

    return 0;
}

/**
 * func: post message to queue
 * parm:
 * return:
 */
int post_request_async(req_type_t type, const void* req, unsigned int size, prot_rsp_cb_t routine, const void* priv)
{
    // printf("enter post_request_async\n");

    /* 1. create queue message */
    msg_t *msg = malloc(sizeof(msg_t));
    msg->mtype = QUEUE_TYPE;
    /* transform request to quue message */
    request_t *request = (request_t *)(msg->mdata);

    /* 2. fill queue message */
    request->type = type;
    memcpy(&(request->msg), req, size);
    request->cb_func = routine;
    request->priv = priv;

    /* 3. seed message */
    return msgsnd(msgqid, (void *)msg, sizeof(msg_t)-sizeof(long), 0);
}

 

base_queue.h

#ifndef _BASE_QUEUE_H_
#define _BASE_QUEUE_H_

#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include "common.h"

#define QUEUE_TYPE      10

#define POST_REQUEST(type, req, size, routine, priv) \
            post_request_async(type, req, size, routine, priv)

/* request message type */
typedef enum {
    POWER_ON,
    POWER_OFF,
} req_type_t;

/* message data1 */
typedef struct {
    int id;
    char name[20];
} power_on_req_t;

/* message data2 */
typedef struct {
    int id;
    char name[20];
    void *p;
} power_off_req_t;

/* message callback */
typedef void (*prot_rsp_cb_t)(int, const void*, void*);

/* request type */
typedef struct {
    req_type_t            type;                 /* support request message type */
    union {
        power_on_req_t    power_on_req;
        power_off_req_t   power_off_req;
    } msg;                                      /* support request message */
    prot_rsp_cb_t              cb_func;         /* callback */
    const void*                priv;            /* priv will be passed back in cb_func */
} request_t;

/* queue message */
typedef struct msg{
    long mtype;
    char mdata[sizeof(request_t)];
} msg_t;


extern int msgqid;  /* message queue */

int queue_init();
int post_request_async(req_type_t type, const void* req, unsigned int size,
                            prot_rsp_cb_t routine, const void* priv);








#endif  //_BASE_QUEUE_H_

 

base_tiemr.c

#include <time.h>
#include <stdlib.h>
#include "base_timer.h"

typedef struct tmr_cb {
    list_t         tmr_list;
    int            init;
    int            tmr_cnt;
    volatile ms_t  sys_msec;
} tmr_cb_t;

static volatile ms_t  sys_msec;

/* t1 is earlier than t2 */
#define time_before(t1, t2) ((long long)((t1)-(t2)) <= 0)
#define timer_before(tmr1, tmr2) (time_before(tmr1->expire, tmr2->expire))

/**
 * Update the current time.
 * Because all timer's expiring time is relative to current time, so we must
 * update current time after each time-consuming operations, e.g. epoll_wait.
 */
void time_update(tmr_hdl_t hdl)
{
    int rc;
    static struct timespec tp;

    /* get system time, and save to timer */
    rc = clock_gettime(CLOCK_MONOTONIC, &tp);
    if (rc < 0) abort();

    ((tmr_cb_t*)hdl)->sys_msec = (ms_t)(tp.tv_sec * 1000) + (ms_t)(tp.tv_nsec)/(1000*1000);
    return;
}

/**
 * Create a timer list
 */
tmr_hdl_t timer_init()
{
    tmr_cb_t* thdl = (tmr_cb_t*)malloc(sizeof(tmr_cb_t));

    if (!thdl) return NULL;

    /* create timer list */
    list_init(&(thdl->tmr_list));
    /* update timer */
    time_update(thdl);
    thdl->tmr_cnt = 0;

    return (tmr_hdl_t)thdl;
}

/**
 * Delete a timer list
 */
void timer_deinit(tmr_hdl_t hdl)
{
    list_node_t *node, *tmp;
    tmr_t *tmr;
    tmr_cb_t* tmr_cb = hdl;

    list_for_del(&(tmr_cb->tmr_list), node, tmp) {
        tmr = object_of(tmr_t, self, node);
        list_del(&(tmr->self));
        tmr_cb->tmr_cnt--;
    }
    free(hdl);
}

/**
 * Place the timer into timer queue.
 */
void add_timer(tmr_hdl_t hdl, tmr_t* timer)
{
    list_node_t* node;
    tmr_t* tmr;
    tmr_cb_t* tmr_cb = hdl;

    timer->expire = tmr_cb->sys_msec + timer->val * MS_PER_TICK;

    list_for(&(tmr_cb->tmr_list), node) {
        tmr = object_of(tmr_t, self, node); //get timer addr from node
        if (timer_before(timer, tmr)) {
            break;
        }
    }
    list_node_init(&(timer->self));
    list_ins_before(node, &(timer->self));

    tmr_cb->tmr_cnt++;
}

/**
 * Delete the timer from timer queue.
 */
void del_timer(tmr_hdl_t hdl, tmr_t* timer)
{
    tmr_cb_t* tmr_cb = hdl;

    if (timer->self.next != NULL && timer->self.prev != NULL) {
        list_del(&(timer->self));
        tmr_cb->tmr_cnt--;
    }
}

int timer_is_running(tmr_t *timer)
{
    if (timer->self.next != NULL && timer->self.prev != NULL) {
        return 1;
    }
    return 0;
}

/**
 * Do callbacks for all the expired timer, restart the timer
 * if it's repeatitive.
 */
void proc_timer(tmr_hdl_t hdl)
{
    tmr_t* tmr;
    list_node_t *node;
    tmr_cb_t* tmr_cb = hdl;

    for (;;) {
        if (tmr_cb->tmr_cnt == 0) {
            break;
        }

        node = list_first(&(tmr_cb->tmr_list));
        tmr = object_of(tmr_t, self, node);

        if (time_before(tmr->expire, tmr_cb->sys_msec)) {
            del_timer(hdl, tmr);
            if (tmr->repeat) {
                add_timer(hdl, tmr);
            }
            tmr->fn(tmr->timer_id, tmr->data);
        } else {
            break;
        }
    }
}


/**
 * Find out how much time can we sleep before we need to
 * wake up to handle the timer.
 */
int get_next_timeout(tmr_hdl_t hdl, ms_t* tick)
{
    list_node_t* node;
    tmr_t* tmr;
    tmr_cb_t* tmr_cb = hdl;

    *tick = 0;

    if (tmr_cb->tmr_cnt == 0) {       /* no timer yet */
        return -1;
    }

    node = list_first(&(tmr_cb->tmr_list));

    tmr = object_of(tmr_t, self, node);

    if (time_before(tmr->expire, tmr_cb->sys_msec)) {
        *tick = 0;
    } else {
        *tick = tmr->expire - tmr_cb->sys_msec;
    }

    return 0;
}

base_tiemr.h

#ifndef TIMER_H
#define TIMER_H

#include "list.h"

#define MS_PER_TICK      5         /* milli-seconds per tick */

typedef unsigned long long ms_t;
typedef void* tmr_hdl_t;

typedef void (*timer_func_t)(int timer_id, void* data);

/**
 * timer struct data
*/
typedef struct {
    list_node_t    self;
    int            timer_id;        /* timer id */
    unsigned       val;             /* how many ticks? */
    ms_t           expire;          /* timer left */
    int            repeat;          /* timer repeat time */
    timer_func_t   fn;              /* timer end, callback */
    void           *data;
} tmr_t;

/**
 * start timer without data
 *
*/
#define start_tmr(hdl, tmr, func, to)           \
    do {                                        \
        (tmr)->val = to;                        \
        (tmr)->timer_id = 0;                    \
        (tmr)->data = NULL;                     \
        (tmr)->fn = func;                       \
        (tmr)->repeat = 0;                      \
        del_timer(hdl, (tmr));                  \
        add_timer(hdl, (tmr));                  \
    } while (0)


/**
 * start timer without data & timer id
 *
*/
#define start_tmr_with_data_id(hdl, tmr, func, to, d, id)       \
    do {                                                        \
        (tmr)->val = to;                                        \
        (tmr)->timer_id = id;                                   \
        (tmr)->data = d;                                        \
        (tmr)->fn = func;                                       \
        (tmr)->repeat = 0;                                      \
        del_timer(hdl, (tmr));                                  \
        add_timer(hdl, (tmr));                                  \
    } while (0)


/**
 * start timer without data
 *
*/
#define start_tmr_with_data(hdl, tmr, func, to, d)      \
    do {                                                \
        (tmr)->val = to;                                \
        (tmr)->timer_id = 0;                            \
        (tmr)->data = d;                                \
        (tmr)->fn = func;                               \
        (tmr)->repeat = 0;                              \
        del_timer(hdl, (tmr));                          \
        add_timer(hdl, (tmr));                          \
    } while (0)

/**
 * start timer, and repeat
 *
*/
#define start_rpt_tmr_with_data(hdl, tmr, func, to, d)  \
    do {                                                \
        (tmr)->val = to;                                \
        (tmr)->timer_id = 0;                            \
        (tmr)->data = d;                                \
        (tmr)->fn = func;                               \
        (tmr)->repeat = 1;                              \
        del_timer(hdl, (tmr));                          \
        add_timer(hdl, (tmr));                          \
    } while (0)


extern tmr_hdl_t timer_init(void);
extern void timer_deinit(tmr_hdl_t);
extern void add_timer(tmr_hdl_t, tmr_t*);
extern void del_timer(tmr_hdl_t, tmr_t*);
extern void proc_timer(tmr_hdl_t);
extern int get_next_timeout(tmr_hdl_t, ms_t*);
extern void time_update(tmr_hdl_t);
extern int timer_is_running(tmr_t *);

#endif

 

list.h

#ifndef LIST_H
#define LIST_H

#include <stddef.h>

struct list_node;
typedef struct list_node list_node_t;
typedef struct list_node list_t;

struct list_node {
    list_node_t*     next;
    list_node_t*     prev;
};

/*
 * For macros.
 */
#define list_for(l, nd_var) for (nd_var = (void*)((l)->next); \
                                    (nd_var != (void*)(l)) && (nd_var != NULL); \
                                    nd_var = (void*)((list_node_t*)nd_var)->next)

#define list_for_del(l, nd_var, tmp_var) for (nd_var = (void*)((l)->next); \
                                                 tmp_var = (void*)((list_node_t*)nd_var)->next, \
                                                     nd_var != (void*)(l) || (nd_var = NULL); \
                                                 nd_var = tmp_var)


/*
 * Basic node level operations.
 */
static inline void
list_ins_after(list_node_t* nd, list_node_t* new_nd)
{
    // printf("list_ins_after %p %p\n", nd, new_nd);
    // list_print(nd, "ins_after in");
    new_nd->next = nd->next;
    new_nd->prev = nd;
    nd->next->prev = new_nd;
    nd->next = new_nd;
    // list_print(nd, "ins_after out");
}

static inline void
list_ins_before(list_node_t* nd, list_node_t* new_nd)
{
    // list_print(nd, "ins_before in");
    new_nd->prev = nd->prev;
    new_nd->next = nd;
    nd->prev->next = new_nd;
    nd->prev = new_nd;
    // list_print(nd, "ins_before out");
}

static inline void*
list_del(list_node_t* nd)
{
    // list_print(nd, "del in");
    nd->prev->next = nd->next;
    nd->next->prev = nd->prev;
    // list_print(nd->next, "del out");
    nd->next = NULL;    // just to be safe
    nd->prev = NULL;    // just to be safe

    return nd;
}

/*
 * High-level operations.
 */
static inline void
list_init(list_t* l)
{
    l->next = l;
    l->prev = l;
}

static inline void
list_node_init(list_node_t* nd)
{
    nd->next = nd;
    nd->prev = nd;
}

static inline int
list_is_empty(list_t* l)
{
    return (l == l->next);
}

static inline void*
list_next(list_t* l)
{
    return (list_is_empty(l) ? NULL : l->next);
}

static inline void*
list_prev(list_t* l)
{
    return (list_is_empty(l) ? NULL : l->prev);
}

static inline void*
list_first(list_t* l)
{
    return list_next(l);
}

static inline void*
list_last(list_t* l)
{
    return list_prev(l);
}

static inline void
list_ins_front(list_t* l, list_node_t* nd)
{
    list_ins_after(l, nd);
}

static inline void
list_ins_back(list_t* l, list_node_t* nd)
{
    list_ins_before(l, nd);
}

static inline void*
list_del_front(list_t* l)
{
    return (list_is_empty(l) ? NULL : list_del(l->next));
}

static inline void*
list_del_back(list_t* l)
{
    return (list_is_empty(l) ? NULL : list_del(l->prev));
}

/*
 *
 */
static inline void
list_enqueue(list_t* l, list_node_t* nd)
{
    list_ins_back(l, nd);
}

static inline void*
list_dequeue(list_t* l)
{
    return list_del_front(l);
}

/*
 *
 */
static inline void
list_push(list_t* l, list_node_t* nd)
{
    list_ins_front(l, nd);
}

static inline void*
list_pop(list_t* l)
{
    return list_del_front(l);
}


/*
 *
 */
static inline void
list_transfer(list_t *src, list_t *dst)
{
    list_node_t *nd;

    while ((nd = list_dequeue(src)) != NULL) {
        list_enqueue(dst, nd);
    }
}

/*
 *
 */
static inline unsigned int
list_count_slowly(list_t *l)
{
    list_node_t  *nd;
    unsigned int    cnt = 0;

    list_for(l, nd) {
        cnt++;
    }

    return cnt;
}


/**
 * list_splice - join two lists. result list would be (src + dst) and
 * src list head will be re-initialized.
 * @src:  the new list to add.
 * @dest: the place to add it in the first list.
 */
static inline void
list_splice(list_t *src, list_t *dst)
{
    if (!list_is_empty(src)) {
        list_t *first = src->next;
        list_t *last = src->prev;
        list_t *at = dst->next;

        first->prev = dst;
        dst->next = first;

        last->next = at;
        at->prev = last;

        list_init(src);
    }
}

/**
 * get type struct addr from ptr
 *
*/
#define object_of(type, member, ptr) ({                                 \
            const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
            (type *)( (char *)__mptr - offsetof(type,member) );})

#endif

common.h

#ifndef _COMMON_H_
#define _COMMON_H_

#include <stdio.h>
#include <stdlib.h>

typedef struct data
{
    int num;
    char *name;
} data_t;


#endif

 

Makefile

#表示用的編譯器
CC = gcc

#表示編譯時的動作,-Wall 小心的, -g可調試的。
CC_FLAGS = -Wall -g

# 加載動態庫
SO = -lpthread

#目標文件
all:demo

#加載編譯文件
SRCS = $(wildcard ./*.c)


#執行動作
demo:$(SRCS)
	$(CC) $(CC_FLAGS) $^ -o $@ $(SO)

clean:
	rm -f demo *.o *.exe

 

 

 

喜歡就支持一波哦~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章