Linuxユーザー状態プログラムタイマー——POSIXタイマー

16176 ワード

バックグラウンドクライアントとサーバは非同期要求/返信モードを採用しており、クライアントは各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コマンドで表示してください.
≪インスタンス|Instance|emdw≫
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 
#include 

#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 
#include 

#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.
", 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.
"); 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!
"); (void)recordTimeoutCount(HEART_BEAT_TIMER_ID); return ; } /****************************************************************************** * FUNCTION : clientRegisterExpired() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void clientRegisterExpired() { MSG_LOG("register timeout!
"); (void)recordTimeoutCount(REGISTER_TIMER_ID); return ; } /****************************************************************************** * FUNCTION : clientLoginExpired() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void clientLoginExpired() { MSG_LOG("Login timeout!
"); (void)recordTimeoutCount(LOGIN_TIMER_ID); return ; } /****************************************************************************** * FUNCTION : clientBindExpired() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void clientBindExpired() { MSG_LOG("Bind timeout!
"); (void)recordTimeoutCount(BIND_TIMER_ID); return ; } /****************************************************************************** * FUNCTION : clientRegisterExpired() * DESCRIPTION : * INPUT : * OUTPUT : * RETURN : ******************************************************************************/ static void clientUnbindExpired() { MSG_LOG("Unbind timeout!
"); (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
"); return 0; } /* signal already registered? */ if (timers[index]) { MSG_ERR("tpCreateTimer: signal %d has been used
", 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.
", 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
"); 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!
", 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!
"); 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.
"); return CLIENT_ERR; } /* stop timer */ if (0 == type) { MSG_LOG("stop timer: %s.
", gReqTimeoutObj[idx].name); return clientSetTimer(gReqTimeoutObj[idx].timer, 0, 0); } /* start timer */ else { MSG_LOG("start timer: %s.
", 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
", (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
", (int)timers[i]); return CLIENT_ERR; } timers[i] = 0; } } MSG_LOG("delete timer successed!
"); 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 

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("
"); \ } while(0) #define MSG_ERR(...) do { \ printf("Function:%s, Line:%d.", __FUNCTION__, __LINE__); \ printf(__VA_ARGS__); \ printf("
"); \ } while(0) #endif

client-timer.c
/******************************************************************************
*
* FILE NAME  :	client-timer.c
* VERSION    :	1.0
* DESCRIPTION:	program for testing posix timer...
*
******************************************************************************/

#include 
#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!
"); (void)clientDeleteAllTimer(); return CLIENT_ERR; } MSG_LOG("Init client-client environment successful.
"); 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.
"); 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:
", OPERA_NUM); for (i = 0; i < OPERA_NUM; i++) { printf("No%d:
", 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!
"); return CLIENT_ERR; } /* test posix timer */ posixTimerTest(); /* release timers before exit */ iRet = clientClientExit(); if (CLIENT_OK != iRet) { MSG_ERR("clientClientExit failed!
"); 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の2つのファイルの関数)は、通常の開発で厳格に検証されていますので、安心して使用してください.本明細書のテストインタフェースは、参考までに簡単に書かれています.
コードはgithubからダウンロードすることもできます.アドレス:https://github.com/wangfuyu/posix-timer