From 2b11efe1f93c17d192d262d142d6046890474ad1 Mon Sep 17 00:00:00 2001 From: "qiyin.zhang" Date: Mon, 6 May 2019 10:45:22 +0800 Subject: [PATCH] implementation multiple timer 1.change name from timer.c/h to mt_timer.c/h 2.move thread and variable to mt_timer.h Signed-off-by: qiyin.zhang --- Makefile | 4 +- mt_timer.c | 146 ++++++++++++++++++++++++++++++++++++ mt_timer.h | 160 +++++++++++++++++++++++++++++++++++++++ test.c | 24 +++--- timer.c | 216 ----------------------------------------------------- timer.h | 23 ------ 6 files changed, 321 insertions(+), 252 deletions(-) create mode 100644 mt_timer.c create mode 100644 mt_timer.h delete mode 100644 timer.c delete mode 100644 timer.h diff --git a/Makefile b/Makefile index b235b68..6d8b4af 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -all: timer.c test.c - gcc test.c timer.c -pthread -o timer -Wall +all: mt_timer.c test.c + gcc test.c mt_timer.c -pthread -o timer -Wall clean: rm timer diff --git a/mt_timer.c b/mt_timer.c new file mode 100644 index 0000000..0c65c55 --- /dev/null +++ b/mt_timer.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include + +#include "mt_timer.h" + +int timer_init(MT_TIMER_OBJECT *object, void *(*thread_handler)(void *arg), int max_num) +{ + object->timer_max = max_num; + object->timer_active_flag = true; + object->timer_epoll_fd = epoll_create(max_num); + if(object->timer_epoll_fd < 0) + { + MT_TIMER_PRINT_INL("MT-Timer error: epoll_create failed %s.\n", strerror(errno)); + return -1; + } + + if(pthread_create(&object->timer_thread_id, NULL, thread_handler, NULL) != 0) + { + MT_TIMER_PRINT_INL("MT-Timer error: pthread_create failed %s.\n", strerror(errno)); + return -1; + } + + return 0; +} + +void timer_deinit(MT_TIMER_OBJECT *object) +{ + struct itimerspec itimespec; + + object->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(object, &itimespec, 0, NULL, NULL); + pthread_join(object->timer_thread_id, NULL); + timer_clear(object); +} + +int timer_add(MT_TIMER_OBJECT *object, 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) + { + MT_TIMER_PRINT_INL("MT-Timer error: malloc failed %s.\n", strerror(errno)); + 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) + { + MT_TIMER_PRINT_INL("MT-Timer error: timerfd_create failed %s.\n", strerror(errno)); + free(handler); + return -2; + } + if(timerfd_settime(handler->timer_fd, 0, itimespec, NULL) == -1) + { + MT_TIMER_PRINT_INL("MT-Timer error: timerfd_settime failed %s.\n", strerror(errno)); + close(handler->timer_fd); + free(handler); + return -3; + } + + event.events = EPOLLIN | EPOLLET; + event.data.ptr = handler; + if(epoll_ctl(object->timer_epoll_fd, EPOLL_CTL_ADD, handler->timer_fd, &event) < 0) + { + MT_TIMER_PRINT_INL("MT-Timer error: epoll_ctl ADD failed %s.\n", strerror(errno)); + close(handler->timer_fd); + free(handler); + return -4; + } + + pthread_rwlock_wrlock(&object->timer_rwlock); + HASH_ADD_INT(object->timer_head, timer_fd, handler); + pthread_rwlock_unlock(&object->timer_rwlock); + + return handler->timer_fd; +} + +int timer_del(MT_TIMER_OBJECT *object, int timerfd) +{ + struct epoll_event event; + MT_TIMER_NODE *handler = NULL; + + HASH_FIND_INT(object->timer_head, &timerfd, handler); + if(NULL == handler) + return 0; + + event.data.ptr = (void *)handler; + event.events = EPOLLIN | EPOLLET; + if(epoll_ctl(object->timer_epoll_fd, EPOLL_CTL_DEL, handler->timer_fd, &event) < 0) + { + MT_TIMER_PRINT_INL("MT-Timer error: epoll_ctl DEL failed %s.\n", strerror(errno)); + return -1; + } + + pthread_rwlock_wrlock(&object->timer_rwlock); + HASH_DEL(object->timer_head, handler); + pthread_rwlock_unlock(&object->timer_rwlock); + close(handler->timer_fd); + free(handler); + + return 0; +} + +int timer_count(MT_TIMER_OBJECT *object) +{ + return HASH_COUNT(object->timer_head); +} + +int timer_clear(MT_TIMER_OBJECT *object) +{ + struct epoll_event event; + MT_TIMER_NODE *handler = NULL; + + event.events = EPOLLIN | EPOLLET; + for(handler = object->timer_head; handler != NULL; handler = handler->hh.next) + { + event.data.ptr = (void *)handler; + if(epoll_ctl(object->timer_epoll_fd, EPOLL_CTL_DEL, handler->timer_fd, &event) < 0) + { + MT_TIMER_PRINT_INL("MT-Timer error: epoll_ctl CLEAR failed %s.\n", strerror(errno)); + return -1; + } + pthread_rwlock_wrlock(&object->timer_rwlock); + HASH_DEL(object->timer_head, handler); + pthread_rwlock_unlock(&object->timer_rwlock); + close(handler->timer_fd); + free(handler); + } + return 0; +} + diff --git a/mt_timer.h b/mt_timer.h new file mode 100644 index 0000000..f7fb0b3 --- /dev/null +++ b/mt_timer.h @@ -0,0 +1,160 @@ +/* + * MIT License + * + * Copyright (c) 2019 极简美 @ konishi5202@163.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _MT_TIMER_H__ +#define _MT_TIMER_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#include +#include "uthash.h" + +#define DEBUG_ENABLE +/************************** Debug Config Start **************************/ +#ifdef DEBUG_ENABLE + + #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L + + #ifdef EFSM_PRINT + #define MT_TIMER_PRINT_INL(...) EFSM_PRINT(__VA_ARGS__) + #else + #define MT_TIMER_PRINT_INL(...) printf(__VA_ARGS__) + #endif + + #else + + #ifdef EFSM_PRINT + #define MT_TIMER_PRINT_INL(format, args...) EFSM_PRINT(format, ##args) + #else + #define MT_TIMER_PRINT_INL(format, args...) printf(format, ##args) + #endif + #endif + +#else + + #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L + #define MT_TIMER_PRINT_INL(...) + #else + #define MT_TIMER_PRINT_INL(format, args...) + #endif + +#endif +/************************** Debug Config End **************************/ + +#ifndef bool +typedef enum{false, true} bool; +#define bool bool +#endif + +typedef void (*timer_callback_t)(void *data); + +typedef struct { + int timer_fd; + int timer_cnt; + void *timer_data; + UT_hash_handle hh; + timer_callback_t timer_cb; +}MT_TIMER_NODE; /* MT mean multiple */ + +typedef struct { + int timer_max; + int timer_epoll_fd; + bool timer_active_flag; + MT_TIMER_NODE *timer_head; + pthread_t timer_thread_id; + pthread_rwlock_t timer_rwlock; +}MT_TIMER_OBJECT; + +#define TIMER_THREAD_CREATE(name) \ + static void *mt_timer_thread_##name(void *arg) \ + { \ + int nfds, i; \ + char buf[128]; \ + MT_TIMER_NODE *timer_node = NULL; \ + struct epoll_event events[mt_timer_##name.timer_max]; \ + /*pthread_detach(pthread_self());*/ \ + MT_TIMER_PRINT_INL("MT-Timer Info: %s thread is running.\n", #name); \ + while(mt_timer_##name.timer_active_flag) \ + { \ + nfds = epoll_wait(mt_timer_##name.timer_epoll_fd, events, mt_timer_##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--; \ + } \ + } \ + } \ + } \ + MT_TIMER_PRINT_INL("MT-Timer Info: %s thread is exit.\n", #name); \ + pthread_exit(NULL); \ + } + +extern int timer_init(MT_TIMER_OBJECT *object, void *(*thread_handler)(void *arg), int max_num); +extern void timer_deinit(MT_TIMER_OBJECT *object); +extern int timer_add(MT_TIMER_OBJECT *object, struct itimerspec *itimespec, + int repeat, timer_callback_t cb, void *data); +extern int timer_del(MT_TIMER_OBJECT *object, int timerfd); +extern int timer_count(MT_TIMER_OBJECT *object); +extern int timer_clear(MT_TIMER_OBJECT *object); + +/************************** API Interface **************************/ +#define TIMER_CREATE(name) \ + MT_TIMER_OBJECT mt_timer_##name = {0, -1, false, NULL, 0, PTHREAD_RWLOCK_INITIALIZER}; \ + TIMER_THREAD_CREATE(name) +#define TIMER_DECLEAR(name) \ + extern MT_TIMER_OBJECT mt_timer_##name +#define TIMER_INIT(name, max) \ + timer_init(&mt_timer_##name, mt_timer_thread_##name, max) +#define TIMER_DEINIT(name) \ + timer_deinit(&mt_timer_##name) +#define TIMER_ADD(name, itimespec, repeat, cb, data) \ + timer_add(&mt_timer_##name, itimespec, repeat, cb, data) +#define TIMER_DEL(name, timerfd) \ + timer_del(&mt_timer_##name, timerfd) +#define TIMER_COUNT(name) timer_count(&mt_timer_##name) +#define TIMER_CLEAR(name) timer_clear(&mt_timer_##name) + +#ifdef __cplusplus +} +#endif + +#endif // _MT_TIMER_H__ + diff --git a/test.c b/test.c index 79738fe..0921001 100644 --- a/test.c +++ b/test.c @@ -2,7 +2,7 @@ #include #include -#include "timer.h" +#include "mt_timer.h" void timeout_handle(void *arg) { @@ -14,29 +14,31 @@ void timeout_handler(void *arg) printf("[%ld]:timeout2\n", time(NULL)); } +TIMER_CREATE(test); + int main(void) { - int timer1; + int timer; struct itimerspec itimespec; - timer_init(10); + TIMER_INIT(test, 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()); + timer = TIMER_ADD(test, &itimespec, 8, timeout_handle, NULL); + TIMER_ADD(test, &itimespec, 3, timeout_handler, NULL); + printf("[%ld]:timer_add : %d\n", time(NULL), TIMER_COUNT(test)); 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()); + TIMER_DEL(test, timer); + printf("[%ld]:timer_del : %d\n", time(NULL), TIMER_COUNT(test)); + TIMER_CLEAR(test); + printf("[%ld]:timer_clear : %d\n", time(NULL), TIMER_COUNT(test)); getchar(); - timer_deinit(); + TIMER_DEINIT(test); return 0; } diff --git a/timer.c b/timer.c deleted file mode 100644 index 6b761a2..0000000 --- a/timer.c +++ /dev/null @@ -1,216 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#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_rwlock_t timer_rwlock; -}MT_TIMER_OBJECT; - -MT_TIMER_OBJECT timer_object_name = {0, -1, false, NULL, 0, PTHREAD_RWLOCK_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());*/ - printf("MT-Timer Info: timer thread is running.\n"); - 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--; - } - } - } - } - printf("MT-Timer Info: timer thread is exit.\n"); - 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) - { - printf("MT-Timer error: epoll_create failed %s.\n", strerror(errno)); - return -1; - } - - if(pthread_create(&timer_object_name.timer_thread_id, NULL, mt_timer_thread_name, NULL) != 0) - { - printf("MT-Timer error: pthread_create failed %s.\n", strerror(errno)); - 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); - timer_clear(); -} - -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) - { - printf("MT-Timer error: malloc failed %s.\n", strerror(errno)); - 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) - { - printf("MT-Timer error: timerfd_create failed %s.\n", strerror(errno)); - free(handler); - return -2; - } - if(timerfd_settime(handler->timer_fd, 0, itimespec, NULL) == -1) - { - printf("MT-Timer error: timerfd_settime failed %s.\n", strerror(errno)); - close(handler->timer_fd); - 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) - { - printf("MT-Timer error: epoll_ctl ADD failed %s.\n", strerror(errno)); - close(handler->timer_fd); - free(handler); - return -4; - } - - pthread_rwlock_wrlock(&timer_object_name.timer_rwlock); - HASH_ADD_INT(timer_object_name.timer_head, timer_fd, handler); - pthread_rwlock_unlock(&timer_object_name.timer_rwlock); - - 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; - - 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) - { - printf("MT-Timer error: epoll_ctl DEL failed %s.\n", strerror(errno)); - return -1; - } - - pthread_rwlock_wrlock(&timer_object_name.timer_rwlock); - HASH_DEL(timer_object_name.timer_head, handler); - pthread_rwlock_unlock(&timer_object_name.timer_rwlock); - close(handler->timer_fd); - free(handler); - - return 0; -} - -int timer_count(void) -{ - int count = 0; - pthread_rwlock_rdlock(&timer_object_name.timer_rwlock); - count = (int) HASH_COUNT(timer_object_name.timer_head); - pthread_rwlock_unlock(&timer_object_name.timer_rwlock); - return count; -} - -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) - { - event.data.ptr = (void *)handler; - if(epoll_ctl(timer_object_name.timer_epoll_fd, EPOLL_CTL_DEL, handler->timer_fd, &event) < 0) - { - printf("MT-Timer error: epoll_ctl CLEAR failed %s.\n", strerror(errno)); - return -1; - } - pthread_rwlock_wrlock(&timer_object_name.timer_rwlock); - HASH_DEL(timer_object_name.timer_head, handler); - pthread_rwlock_unlock(&timer_object_name.timer_rwlock); - close(handler->timer_fd); - free(handler); - } - return 0; -} - diff --git a/timer.h b/timer.h deleted file mode 100644 index 3c143aa..0000000 --- a/timer.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _TIMER_H__ -#define _TIMER_H__ - -#ifdef __cplusplus -extern "C" { -#endif -#include - -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__ -