Linuxユーザー状態プログラムタイマー——POSIXタイマー
バックグラウンドクライアントとサーバは非同期要求/返信モードを採用しており、クライアントは各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
timeout-handler.c
client-timer.h
client-timer.c
Makefile
タイマインタフェース(timer-handler.hとtimer-handler.cの2つのファイルの関数)は、通常の開発で厳格に検証されていますので、安心して使用してください.本明細書のテストインタフェースは、参考までに簡単に書かれています.
コードはgithubからダウンロードすることもできます.アドレス:https://github.com/wangfuyu/posix-timer
シナリオは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