Linux用户态程序定时器——POSIX定时器
2016-05-19 18:15
471 查看
背景
客户端和服务器采用异步请求/回复模式,客户端需要为每个API设置超时回调处理。方案
采用posix定时器。posix定时器
主要接口函数:1)创建一个定时器:
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
2)启动一个定时器:
timer_create()所创建的定时器并未启动。要将它关联到一个到期时间以及启动时钟周期,可以使用timer_settime()。
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspect *ovalue);
3)获得一个活动定时器的剩余时间:
int timer_gettime(timer_t timerid,struct itimerspec *value);
4)删除一个定时器:
int timer_delete (timer_t timerid);
接口函数的参数解释,请通过man命令查看。
实例
timeout-handler.h/*********************************************************** * * File name : timeout-handler.h * Version : 1.0 * Description: posix real timer test * ************************************************************/ #ifndef _TIMEOUT_HANDLER_H_ #define _TIMEOUT_HANDLER_H_ #include <signal.h> #include <time.h> #define MAX_TIMER_NUM 32 #define SIGNUM_RT_TIMER (SIGRTMIN + 2) typedef enum { CLIENT_MIN_TIMER_ID, HEART_BEAT_TIMER_ID, REGISTER_TIMER_ID, LOGIN_TIMER_ID, BIND_TIMER_ID, UNBIND_TIMER_ID, CLIENT_MAX_TIMER_ID } CLIENT_TIMER_ID; typedef struct { char *name; /* API name */ int count; /* timeout times */ int expires; /* general 5s */ timer_t timer; /* timer id */ void (*cb)(void); /* call back */ } REQUEST_TIMEOUT_OBJECT; /* initialize request timeout times */ int initReqTimeoutCount(int idx); /* start or stop timer */ int clientTimerSwitch(int idx, int type); /* delete timer */ int clientDeleteTimer(timer_t timer_id); /* delete all timer */ int clientDeleteAllTimer(); /* init timer */ int initClientTimer(); #endif
timeout-handler.c
/*********************************************************** * * File name : timer-handler.c * Version : 1.0 * Description: timeout handler * ************************************************************/ #include <string.h> #include <errno.h> #include "client-timer.h" #include "timeout-handler.h" timer_t timers[MAX_TIMER_NUM] = {0}; static void clientHeartBeatExpired(); static void clientRegisterExpired(); static void clientLoginExpired(); static void clientBindExpired(); static void clientUnbindExpired(); REQUEST_TIMEOUT_OBJECT gReqTimeoutObj[] = { [CLIENT_MIN_TIMER_ID] = { .name = "min timer", .count = 0, .expires = 5, .cb = NULL, .timer = 0 }, [HEART_BEAT_TIMER_ID] = { .name = "heartbeat", .count = 0, .expires = 3, .cb = clientHeartBeatExpired, .timer = 0 }, [REGISTER_TIMER_ID] = { .name = "register", .count = 0, .expires = 5, .cb = clientRegisterExpired, .timer = 0 }, [LOGIN_TIMER_ID] = { .name = "login", .count = 0, .expires = 7, .cb = clientLoginExpired, .timer = 0 }, [BIND_TIMER_ID] = { .name = "bind", .count = 0, .expires = 2, .cb = clientBindExpired, .timer = 0 }, [UNBIND_TIMER_ID] = { .name = "unbind", .count = 0, .expires = 5, .cb = clientUnbindExpired, .timer = 0 }, [CLIENT_MAX_TIMER_ID] = { .name = "max timer", .count = 0, .expires = 5, .cb = NULL, .timer = 0 }, }; /****************************************************************************** * FUNCTION : recordTimeoutCount() * DESCRIPTION : record timeout times for every API * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static int recordTimeoutCount(int idx) { gReqTimeoutObj[idx].count++; MSG_LOG("API: %s, timeout %d times.\n", gReqTimeoutObj[idx].name, gReqTimeoutObj[idx].count); return CLIENT_OK; } /****************************************************************************** * FUNCTION : initReqTimeoutCount() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ int initReqTimeoutCount(int idx) { int i = 0; if (idx > CLIENT_MIN_TIMER_ID && idx < CLIENT_MAX_TIMER_ID) { gReqTimeoutObj[idx].count = 0; return 0; } MSG_LOG("initialize all count 0.\n"); for (i = CLIENT_MIN_TIMER_ID + 1; i < CLIENT_MAX_TIMER_ID; i++) { gReqTimeoutObj[i].count = 0; } return 0; } /****************************************************************************** * FUNCTION : clientHeartBeatExpired() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void clientHeartBeatExpired() { MSG_LOG("heartBeat timeout!\n"); (void)recordTimeoutCount(HEART_BEAT_TIMER_ID); return ; } /****************************************************************************** * FUNCTION : clientRegisterExpired() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void clientRegisterExpired() { MSG_LOG("register timeout!\n"); (void)recordTimeoutCount(REGISTER_TIMER_ID); return ; } /****************************************************************************** * FUNCTION : clientLoginExpired() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void clientLoginExpired() { MSG_LOG("Login timeout!\n"); (void)recordTimeoutCount(LOGIN_TIMER_ID); return ; } /****************************************************************************** * FUNCTION : clientBindExpired() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void clientBindExpired() { MSG_LOG("Bind timeout!\n"); (void)recordTimeoutCount(BIND_TIMER_ID); return ; } /****************************************************************************** * FUNCTION : clientRegisterExpired() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void clientUnbindExpired() { MSG_LOG("Unbind timeout!\n"); (void)recordTimeoutCount(UNBIND_TIMER_ID); return ; } /****************************************************************************** * FUNCTION : clientTimerHandler() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void clientTimerHandler(int signum, siginfo_t *siginfo, void *context) { int sigval = siginfo->si_value.sival_int; if (gReqTimeoutObj[sigval].cb) { gReqTimeoutObj[sigval].cb(); } } /****************************************************************************** * FUNCTION : clientCreateTimer() * DESCRIPTION : create a timer, when time's up, will send a signal "signum" to the handler_func * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static timer_t clientCreateTimer(int sigval) { static int isHanderSet = 0; struct sigevent se; struct sigaction sa; int index = sigval; if (sigval < CLIENT_MIN_TIMER_ID || sigval > CLIENT_MAX_TIMER_ID) { MSG_ERR("tpCreateTimer: signum is too small\n"); return 0; } /* signal already registered? */ if (timers[index]) { MSG_ERR("tpCreateTimer: signal %d has been used\n", sigval); return 0; } if (isHanderSet == 0) { memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = clientTimerHandler; sa.sa_flags = SA_SIGINFO; sa.sa_restorer = NULL; sigemptyset(&sa.sa_mask); if (sigaction(SIGNUM_RT_TIMER, &sa, NULL) < 0) { MSG_ERR("register timer signal cb failed. errno = %d.\n", errno); return 0; } isHanderSet = 1; } memset (&se, 0, sizeof (se)); se.sigev_notify = SIGEV_SIGNAL; se.sigev_signo = SIGNUM_RT_TIMER; se.sigev_value.sival_int = sigval; se.sigev_notify_function = NULL; if (timer_create(CLOCK_MONOTONIC, &se, &timers[index]) < 0) { timers[index] = 0; MSG_ERR("timer_creat failed\n"); return 0; } return timers[index]; } /****************************************************************************** * FUNCTION : initClientTimer() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ int initClientTimer() { int ret = CLIENT_ERR; int idx = 0; for (idx = CLIENT_MIN_TIMER_ID + 1; idx < CLIENT_MAX_TIMER_ID; idx++) { if (NULL == gReqTimeoutObj[idx].cb) { continue; } gReqTimeoutObj[idx].timer = clientCreateTimer(idx); if (0 >= gReqTimeoutObj[idx].timer) { MSG_ERR("create gReqTimeoutObj[%d] timer failed!\n", idx); return CLIENT_ERR; } } return CLIENT_OK; } /****************************************************************************** * FUNCTION : clientSetTimer() * DESCRIPTION : let the timer run * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static int clientSetTimer(timer_t timer_id, int firstRun, int interval) { struct itimerspec ts, ots; ts.it_value.tv_sec = firstRun; ts.it_value.tv_nsec = 0; ts.it_interval.tv_sec = interval; ts.it_interval.tv_nsec = 0; if (timer_settime(timer_id, 0, &ts, &ots) < 0) { MSG_ERR("setTimer failed!\n"); return (-1); } return (0); } /****************************************************************************** * FUNCTION : clientTimerSwitch() * DESCRIPTION : start or stop timer * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ int clientTimerSwitch(int idx, int type) { if (idx <= CLIENT_MIN_TIMER_ID || idx >= CLIENT_MAX_TIMER_ID) { MSG_ERR("idx of timer invalid.\n"); return CLIENT_ERR; } /* stop timer */ if (0 == type) { MSG_LOG("stop timer: %s.\n", gReqTimeoutObj[idx].name); return clientSetTimer(gReqTimeoutObj[idx].timer, 0, 0); } /* start timer */ else { MSG_LOG("start timer: %s.\n", gReqTimeoutObj[idx].name); return clientSetTimer(gReqTimeoutObj[idx].timer, gReqTimeoutObj[idx].expires, 0); } } /****************************************************************************** * FUNCTION : clientDeleteTimer() * DESCRIPTION : delete a time which has been created. * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ int clientDeleteTimer(timer_t timer_id) { int i; for (i = 0; i < MAX_TIMER_NUM; i ++) { if (timers[i] == timer_id) { timers[i] = 0; return timer_delete(timer_id); } } MSG_LOG("delete timer id %d failed: not found\n", (int)timer_id); return -1; } /****************************************************************************** * FUNCTION : clientDeleteAllTimer() * DESCRIPTION : delete all timer. * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ int clientDeleteAllTimer() { int i = 0; int ret = -1; for (i = 0; i < MAX_TIMER_NUM; i ++) { if (0 < timers[i]) { ret = timer_delete(timers[i]); if (0 != ret) { MSG_ERR("delete timer %d failed\n", (int)timers[i]); return CLIENT_ERR; } timers[i] = 0; } } MSG_LOG("delete timer successed!\n"); return CLIENT_OK; }
client-timer.h
/****************************************************************************** * * FILE NAME : client-timer.h * VERSION : 1.0 * DESCRIPTION: program for testing posix timer. * ******************************************************************************/ #ifndef _CLIENT_TIMER_H_ #define _CLIENT_TIMER_H_ #include <stdio.h> typedef struct { int opera; /* opera type */ int timer; /* timer index */ } OPEAR_ARR; #define OPERA_NUM 5 #define SLEEP_TIME (OPERA_NUM + 2) #define CLIENT_OK 0 #define CLIENT_ERR -1 #define MSG_LOG(...) do { \ printf("Function:%s, Line:%d.", __FUNCTION__, __LINE__); \ printf(__VA_ARGS__); \ printf("\n"); \ } while(0) #define MSG_ERR(...) do { \ printf("Function:%s, Line:%d.", __FUNCTION__, __LINE__); \ printf(__VA_ARGS__); \ printf("\n"); \ } while(0) #endif
client-timer.c
/****************************************************************************** * * FILE NAME : client-timer.c * VERSION : 1.0 * DESCRIPTION: program for testing posix timer... * ******************************************************************************/ #include <unistd.h> #include "client-timer.h" #include "timeout-handler.h" /****************************************************************************** * FUNCTION : clientClientInit() * DESCRIPTION : init environment for running * INPUT : * OUTPUT : * RETURN : 0:success; -1:failed ******************************************************************************/ int clientClientInit(void) { int iRet = CLIENT_ERR; /* init timer, used to handle timeout event */ iRet = initClientTimer(); if (CLIENT_OK != iRet) { MSG_ERR("init client-client's timer failed!\n"); (void)clientDeleteAllTimer(); return CLIENT_ERR; } MSG_LOG("Init client-client environment successful.\n"); return CLIENT_OK; } /****************************************************************************** * FUNCTION : clientClientExit() * DESCRIPTION : clean source befor exit client client * INPUT : * OUTPUT : * RETURN : 0:success; -1:failed ******************************************************************************/ int clientClientExit(void) { int iRet = CLIENT_ERR; iRet = clientDeleteAllTimer(); if (CLIENT_OK != iRet) { MSG_ERR("fatal error: delete timer failed.\n"); return CLIENT_ERR; } return CLIENT_OK; } /****************************************************************************** * FUNCTION : posixTimerTest() * DESCRIPTION : test posix timer * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void posixTimerTest() { int i = 0; OPEAR_ARR operas[OPERA_NUM] = {0}; MSG_LOG("please input %d operations: \n", OPERA_NUM); for (i = 0; i < OPERA_NUM; i++) { printf("No%d:\n", i); scanf("%d %d", &(operas[i].opera), &(operas[i].timer)); } for (i = 0; i < OPERA_NUM; i++) { (void)clientTimerSwitch(operas[i].timer, operas[i].opera); sleep(SLEEP_TIME); } return ; } /****************************************************************************** * FUNCTION : main() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ int main(int argc, char** argv) { int iRet = CLIENT_ERR; /* init posix timer */ iRet = clientClientInit(); if (CLIENT_OK != iRet) { MSG_ERR("init client client environment failed!\n"); return CLIENT_ERR; } /* test posix timer */ posixTimerTest(); /* release timers before exit */ iRet = clientClientExit(); if (CLIENT_OK != iRet) { MSG_ERR("clientClientExit failed!\n"); return CLIENT_ERR; } return CLIENT_OK; }
Makefile
# build client-timer executable when user executes "make" LDFLAGS += -lrt CFLAGS += -std=gnu99 APP_NAME = client-timer OBJ = client-timer.o OBJ += timeout-handler.o $(APP_NAME): $(OBJ) $(CC) $^ -o $(APP_NAME) $(LDFLAGS) %.o:%.c $(CC) $(CFLAGS) -c $^ -o $@ # remove object files and executable when user executes "make clean" clean: rm *.o $(APP_NAME)
定时器接口(timer-handler.h和timer-handler.c两个文件的函数),已在平常开发中严格验证过,请放心使用。对于本文中的测试接口写得偏简单,仅供参考。
代码也可以从github上下载,地址:https://github.com/wangfuyu/posix-timer
相关文章推荐
- win7测底删除Linux系统恢复Win7引导
- Linux查看物理CPU个数、核数、逻辑CPU个数
- Linux常用命令汇总--rename
- Centos6.5部署大众点评CAT
- linux python工具pip和 easy_install的安装
- 64位linux下inet_ntop()返回值竟然为int,printf报段错误
- Linux service 创建和注册
- Hello World_Linux篇——测试gcc和g++是否可用
- centos6.7升级svn1.6到1.8
- Centos7 PostgreSQL安装
- 《Linux驱动》分层分离
- linux内核启动第二阶段分析-setup_arch()函数
- 20160518:Linux系统搭建NFS并共享给AIX
- centos6安装elasticsearch-2.3.3
- 《Linux驱动》输入子系统
- arm-linux驱动:c文件操作控制驱动
- 迁移与裁剪linux系统
- CentOS/RHEL 7中的firewall控制
- LINUX iptables
- Linux运维人员如何学习python编程