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_timer.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_timer.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
喜欢就支持一波哦~