本文共 16538 字,大约阅读时间需要 55 分钟。
基于上篇文章,我们设计一个具体的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
main.c
#include#include #include #include #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#include #include #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#include #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#includestruct 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 voidlist_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 voidlist_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 voidlist_init(list_t* l){ l->next = l; l->prev = l;}static inline voidlist_node_init(list_node_t* nd){ nd->next = nd; nd->prev = nd;}static inline intlist_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 voidlist_ins_front(list_t* l, list_node_t* nd){ list_ins_after(l, nd);}static inline voidlist_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 voidlist_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 voidlist_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 voidlist_transfer(list_t *src, list_t *dst){ list_node_t *nd; while ((nd = list_dequeue(src)) != NULL) { list_enqueue(dst, nd); }}/* * */static inline unsigned intlist_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 voidlist_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#include 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
喜欢就支持一波哦~
转载地址:http://moldi.baihongyu.com/