您的位置:首页 > 运维架构 > Linux

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: