add timer implementation

Signed-off-by: qiyin.zhang <qiyin.zhang@ihuisen.com>
master
qiyin.zhang 2019-05-06 10:08:44 +08:00
parent 47f04bff16
commit 2ffae434ef
4 changed files with 259 additions and 0 deletions

6
Makefile Normal file
View File

@ -0,0 +1,6 @@
all: timer.c test.c
gcc test.c timer.c -pthread -o timer -Wall
clean:
rm timer

43
test.c Normal file
View File

@ -0,0 +1,43 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "timer.h"
void timeout_handle(void *arg)
{
printf("[%ld]:timeout1\n", time(NULL));
}
void timeout_handler(void *arg)
{
printf("[%ld]:timeout2\n", time(NULL));
}
int main(void)
{
int timer1;
struct itimerspec itimespec;
timer_init(10);
itimespec.it_value.tv_sec = 3;
itimespec.it_value.tv_nsec = 0;
itimespec.it_interval.tv_sec = 1;
itimespec.it_interval.tv_nsec = 0;
timer1 = timer_add(&itimespec, 8, timeout_handle, NULL);
timer_add(&itimespec, 3, timeout_handler, NULL);
printf("[%ld]:timer_add : %d\n", time(NULL), timer_count());
sleep(4);//getchar();
timer_del(timer1);
printf("[%ld]:timer_del : %d\n", time(NULL), timer_count());
timer_clear();
printf("[%ld]:timer_clear : %d\n", time(NULL), timer_count());
getchar();
timer_deinit();
return 0;
}

187
timer.c Normal file
View File

@ -0,0 +1,187 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/epoll.h>
#include "uthash.h"
#include "timer.h"
#ifndef bool
typedef enum{false, true} bool;
#define bool bool
#endif
typedef struct {
int timer_fd;
int timer_cnt;
void *timer_data;
UT_hash_handle hh;
timer_callback_t timer_cb;
}MT_TIMER_NODE;
typedef struct {
int timer_max;
int timer_epoll_fd;
bool timer_active_flag;
MT_TIMER_NODE *timer_head;
pthread_t timer_thread_id;
pthread_mutex_t timer_mutex;
}MT_TIMER_OBJECT;
MT_TIMER_OBJECT timer_object_name = {0, -1, false, NULL, 0, PTHREAD_MUTEX_INITIALIZER};
static void *mt_timer_thread_name(void *arg)
{
int nfds, i;
char buf[128];
MT_TIMER_NODE *timer_node = NULL;
struct epoll_event events[timer_object_name.timer_max];
/*pthread_detach(pthread_self());*/
while(timer_object_name.timer_active_flag)
{
nfds = epoll_wait(timer_object_name.timer_epoll_fd, events, timer_object_name.timer_max, -1);
if(nfds <= 0)
continue;
for(i = 0; i < nfds; i++)
{
timer_node = (MT_TIMER_NODE *)events[i].data.ptr;
if(NULL == timer_node)
continue;
while(read(timer_node->timer_fd, buf, sizeof(buf)) > 0);
if(NULL == timer_node->timer_cb)
continue;
if(-1 == timer_node->timer_cnt)
timer_node->timer_cb(timer_node->timer_data);
else
{
if(timer_node->timer_cnt)
{
timer_node->timer_cb(timer_node->timer_data);
timer_node->timer_cnt--;
}
}
}
}
pthread_exit(NULL);
}
int timer_init(int max_num)
{
timer_object_name.timer_max = max_num;
timer_object_name.timer_active_flag = true;
timer_object_name.timer_epoll_fd = epoll_create(max_num);
if(timer_object_name.timer_epoll_fd < 0)
return -1;
if(pthread_create(&timer_object_name.timer_thread_id, NULL, mt_timer_thread_name, NULL) != 0)
return -1;
return 0;
}
void timer_deinit(void)
{
struct itimerspec itimespec;
timer_object_name.timer_active_flag = false;
itimespec.it_value.tv_sec = 0;
itimespec.it_value.tv_nsec = 50;
itimespec.it_interval.tv_sec = 0;
itimespec.it_interval.tv_nsec = 0;
timer_add(&itimespec, 0, NULL, NULL);
pthread_join(timer_object_name.timer_thread_id, NULL);
}
int timer_add(struct itimerspec *itimespec, int repeat, timer_callback_t cb, void *data)
{
struct epoll_event event;
MT_TIMER_NODE *handler = NULL;
handler = (MT_TIMER_NODE *)malloc(sizeof(MT_TIMER_NODE));
if(NULL == handler)
return -1;
handler->timer_cb = cb;
handler->timer_cnt = repeat;
handler->timer_data = data;
handler->timer_fd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC|TFD_NONBLOCK);
if(handler->timer_fd < 0)
{
free(handler);
return -2;
}
if(timerfd_settime(handler->timer_fd, 0, itimespec, NULL) == -1)
{
free(handler);
return -3;
}
event.events = EPOLLIN | EPOLLET;
event.data.ptr = handler;
if(epoll_ctl(timer_object_name.timer_epoll_fd, EPOLL_CTL_ADD, handler->timer_fd, &event) < 0)
{
free(handler);
return -4;
}
pthread_mutex_lock(&timer_object_name.timer_mutex);
HASH_ADD_INT(timer_object_name.timer_head, timer_fd, handler);
pthread_mutex_unlock(&timer_object_name.timer_mutex);
return handler->timer_fd;
}
int timer_del(int timerfd)
{
struct epoll_event event;
MT_TIMER_NODE *handler = NULL;
HASH_FIND_INT(timer_object_name.timer_head, &timerfd, handler);
if(NULL == handler)
return 0;
pthread_mutex_lock(&timer_object_name.timer_mutex);
HASH_DEL(timer_object_name.timer_head, handler);
pthread_mutex_unlock(&timer_object_name.timer_mutex);
event.data.ptr = (void *)handler;
event.events = EPOLLIN | EPOLLET;
if(epoll_ctl(timer_object_name.timer_epoll_fd, EPOLL_CTL_DEL, handler->timer_fd, &event) < 0)
return -1;
close(handler->timer_fd);
free(handler);
return 0;
}
int timer_count(void)
{
return HASH_COUNT(timer_object_name.timer_head);
}
int timer_clear(void)
{
struct epoll_event event;
MT_TIMER_NODE *handler = NULL;
event.events = EPOLLIN | EPOLLET;
for(handler = timer_object_name.timer_head; handler != NULL; handler = handler->hh.next)
{
pthread_mutex_lock(&timer_object_name.timer_mutex);
HASH_DEL(timer_object_name.timer_head, handler);
pthread_mutex_unlock(&timer_object_name.timer_mutex);
event.data.ptr = (void *)handler;
if(epoll_ctl(timer_object_name.timer_epoll_fd, EPOLL_CTL_DEL, handler->timer_fd, &event) < 0)
return -1;
close(handler->timer_fd);
free(handler);
}
return 0;
}

23
timer.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef _TIMER_H__
#define _TIMER_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/timerfd.h>
typedef void (*timer_callback_t)(void *data);
extern int timer_init(int max_num);
extern void timer_deinit(void);
extern int timer_add(struct itimerspec *itimespec, int repeat, timer_callback_t cb, void *data);
extern int timer_del(int timerfd);
extern int timer_count(void);
extern int timer_clear(void);
#ifdef __cplusplus
}
#endif
#endif // _TIMER_H__