Compare commits

...

22 Commits
V0.1 ... master

Author SHA1 Message Date
AaronKonishi 1e7ef0dd95 add igeore rules for mutl_timer
Signed-off-by: AaronKonishi <konishi5202@163.com>

 Changes to be committed:

	new file:   .gitignore
2019-10-16 17:50:31 +08:00
AaronKonishi 01fe162ecf optimize deal speed
Signed-off-by: AaronKonishi <konishi5202@163.com>

 Changes to be committed:

	modified:   source/mt_timer.c
	modified:   source/mt_timer.h
2019-10-16 17:49:38 +08:00
AaronKonishi 6c8d47b9bb close epoll_fd in timer_deinit() function
Signed-off-by: AaronKonishi <konishi5202@163.com>

 Changes to be committed:

	modified:   source/mt_timer.c
2019-10-16 15:00:19 +08:00
极简美 f6286f4885 更新 README.md 2019-06-01 10:38:37 +08:00
AaronKonishi a9ac521d91 change line end CR/LF(Windows) to LF(Unix)
Signed-off-by: AaronKonishi <konishi5202@163.com>
2019-05-31 17:43:25 +08:00
AaronKonishi da4e0bf67e add release callback for userdata
Signed-off-by: AaronKonishi <konishi5202@163.com>
2019-05-31 17:41:28 +08:00
极简美 07764643ac 更新 README.md 2019-05-12 09:42:35 +08:00
极简美 78d1ac1ea6 更新 README.md 2019-05-10 14:48:39 +08:00
极简美 27d2717eab 更新 README.md 2019-05-10 14:48:02 +08:00
极简美 f34faaf2de 更新 README.md
添加作者说明
2019-05-10 14:41:28 +08:00
AaronKonishi 0492ef5479 add cmake support for timer
Signed-off-by: AaronKonishi <konishi5202@163.com>
2019-05-07 10:11:12 +08:00
AaronKonishi 8db67f4ce4 Merge branch 'master' of https://gitee.com/simpost/timer 2019-05-07 09:31:59 +08:00
AaronKonishi 0627f2b504 delete timed-task from timer, when it lose efficacy.
Signed-off-by: AaronKonishi <konishi5202@163.com>
2019-05-07 09:30:28 +08:00
极简美 7844081690 更新 README.md 2019-05-06 22:53:48 +08:00
极简美 9d94fca3d2 更新 README.md 2019-05-06 22:48:10 +08:00
极简美 787745bc1e 更新 README.md 2019-05-06 22:47:34 +08:00
极简美 8a5640fb1c 更新 README.md
添加介绍和使用说明
2019-05-06 22:45:42 +08:00
极简美 3f7f62a2d5 更新 LICENSE 2019-05-06 19:04:02 +08:00
AaronKonishi fcdcd2b4fe optimize source directory
Signed-off-by: AaronKonishi <konishi5202@163.com>
2019-05-06 18:54:46 +08:00
AaronKonishi 73630bfb8e add license for source file
Signed-off-by: AaronKonishi <konishi5202@163.com>
2019-05-06 18:52:30 +08:00
qiyin.zhang 431359a96f add rdlock for find
Signed-off-by: qiyin.zhang <qiyin.zhang@ihuisen.com>
2019-05-06 10:57:32 +08:00
qiyin.zhang 2b11efe1f9 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 <qiyin.zhang@ihuisen.com>
2019-05-06 10:45:22 +08:00
16 changed files with 652 additions and 304 deletions

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
build

26
CMakeLists.txt Normal file
View File

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.0)
project(timer)
set(CMAKE_BUILD_TYPE Release)
#set(CMAKE_C_FLAGS_RELEASE "$ENV${CFLAGS} -O3 -Wall")
include_directories(source)
add_subdirectory(source)
add_subdirectory(examples)
# uninstall target
if(NOT TARGET uninstall)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()
include (CTest)
add_test(example examples/example)

View File

@ -18,4 +18,4 @@ 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.
SOFTWARE.

View File

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

120
README.md
View File

@ -1,25 +1,115 @@
# timer
# MT_TimerMT译为Multiple或Multi
#### 介绍
一个超级简介的Linux下的定时器
#### 一、介绍
#### 软件架构
软件架构说明
一个Linux下的超级简洁的定时器*利用epoll机制和timerfd新特性实现的多重、多用、多个定时任务实现*。只需要使用TIMER_CREATE()接口创建一个定时器实体,即**可向其添加成千上万个定时任务,定时任务可达到纳秒级别的精度,且可在同一时间点添加不同的定时任务!**。
#### 二、软件接口
#### 安装教程
整个定时器包含如下几类接口。
1. xxxx
2. xxxx
3. xxxx
1. **创建和声明定时器实例**使用定时器的第一步就是使用TIMER_CREATE()创建一个定时器实例在其它文件使用到该定时器时使用TIMER_DECLEAR()进行声明:
```
TIMER_CREATE(name);
TIMER_DECLEAR(name);
```
#### 使用说明
2. **初始化和反初始化定时器**在正式使用定时器之前首先使用TIMER_INIT()初始化前面创建的定时器实例name是实例名称max是创建定时器要检测的定时任务数量当不再使用定时器时可使用TIMER_DEINIT()反初始化定时器(退出定时器,并释放所有资源):
```
TIMER_INIT(name, max);
TIMER_DEINIT(name);
```
1. xxxx
2. xxxx
3. xxxx
3. **添加和删除定时任务**
```
TIMER_ADD(name, itimespec, repeat, cb, data, rb);
TIMER_DEL(name, timerfd);
```
#### 参与贡献
TIMER_ADD()用于向定时器实例name中添加一个定时任务其参数描述如下
- ittimespec是定时任务的定时时间和循环时间其结构体类型如下
```
struct timespec {
time_t tv_sec; // seconds
long tv_nsec; // nanoseconds
};
struct itimerspec {
struct timespec it_value;
struct timespec it_interval;
};
```
其中it_value即是超时时间相对时间若想定义周期定时任务则设置it_interval成员若不想定义周期定时任务则需设置it_interval成员都为0。因此第一次超时和后面周期定时任务是可以使用不同时间的。
- repeat是周期定时任务的重复次数若设置为**-1代表永远重复0代表一次都不执行**因此repeat应至少为1或者使用-1
- cb为定时任务超时回调函数其类型为void (*timer_callback_t)(void *data)
- data为定时任务回调函数的参数为void *类型,用户可指定为自己定义的结构体;
TIMER_ADD()添加定时任务成功返回新定时任务的文件描述符,失败返回 < 0TIMER_DEL()
4. **查询和清空定时任务**
```
TIMER_COUNT(name);
TIMER_CLEAR(name);
```
TIMER_COUNT(name)用于查询定时器实例name中现存的定时任务个数TIMER_CLEAR(name)用于清空定时器实例name中的所有定时任务。
#### 三、使用实例
下面是一个非常简单的使用示例共创建了两个定时任务每个第一次超时都是3S后面每隔1S超时一次但第一个定时任务频次为8第二个定时任务频次为3当所有定时任务都超时后输入回车即可退出
```
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "mt_timer.h"
void timeout_handle(void *arg)
{
printf("[%ld]:timeout1\n", time(NULL));
}
void timeout_handler(void *arg)
{
printf("[%ld]:timeout2\n", time(NULL));
}
TIMER_CREATE(test);
int main(void)
{
int timer;
struct itimerspec itimespec;
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;
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(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(test);
return 0;
}
```
#### 四、赞赏作者
![image](https://images.gitee.com/uploads/images/2019/0510/144101_bc93efba_3026819.jpeg)
#### 五、参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
@ -27,7 +117,7 @@
4. 新建 Pull Request
#### 码云特技
#### 六、码云特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)

22
cmake_uninstall.cmake.in Normal file
View File

@ -0,0 +1,22 @@
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif(NOT "${rm_retval}" STREQUAL 0)
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)

10
examples/CMakeLists.txt Normal file
View File

@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.0)
project(examples)
link_libraries(pthread)
aux_source_directory(. SRCS)
add_executable(example ${SRCS})
target_link_libraries(example mttimer)

6
examples/Makefile Normal file
View File

@ -0,0 +1,6 @@
all:
gcc example.c ../source/mt_timer.c -I../source -pthread -o timer -Wall
clean:
rm timer

69
examples/example.c Normal file
View File

@ -0,0 +1,69 @@
/*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "mt_timer.h"
void timeout_handle(void *arg)
{
printf("[%ld]:timeout1\n", time(NULL));
}
void timeout_handler(void *arg)
{
printf("[%ld]:timeout2\n", time(NULL));
}
TIMER_CREATE(test);
int main(void)
{
int timer;
struct itimerspec itimespec;
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;
timer = TIMER_ADD(test, &itimespec, 8, timeout_handle, NULL, NULL);
TIMER_ADD(test, &itimespec, 3, timeout_handler, NULL, NULL);
printf("[%ld]:timer_add : %d\n", time(NULL), TIMER_COUNT(test));
sleep(4);//getchar();
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(test);
return 0;
}

9
source/CMakeLists.txt Normal file
View File

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.0)
project(mttimer)
add_library(mttimer SHARED mt_timer.c)
set_target_properties(mttimer PROPERTIES VERSION 0.4 SOVERSION 1)
install (TARGETS mttimer DESTINATION lib)
install (FILES mt_timer.h DESTINATION include)
install (FILES uthash.h DESTINATION include)

211
source/mt_timer.c Normal file
View File

@ -0,0 +1,211 @@
/*
* 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.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/eventfd.h>
#include "mt_timer.h"
int timer_init(MT_TIMER_OBJECT *object, void *(*thread_handler)(void *arg), int max_num)
{
struct epoll_event event;
assert(NULL != object);
if(true == object->timer_active_flag)
return 0;
object->timer_event_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
if(-1 == object->timer_event_fd)
{
MT_TIMER_PRINT_INL("MT-Timer error: eventfd() failed, %s!\n", strerror(errno));
return -1;
}
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));
close(object->timer_event_fd);
object->timer_event_fd = -1;
return -1;
}
event.data.ptr = NULL;
event.events = EPOLLIN | EPOLLET;
if(epoll_ctl(object->timer_epoll_fd, EPOLL_CTL_ADD, object->timer_event_fd, &event) < 0)
{
fprintf(stderr, "epoll: epoll_ctl ADD failed, %s\n", strerror(errno));
close(object->timer_epoll_fd);
close(object->timer_event_fd);
object->timer_epoll_fd = -1;
object->timer_event_fd = -1;
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));
close(object->timer_epoll_fd);
close(object->timer_event_fd);
object->timer_epoll_fd = -1;
object->timer_event_fd = -1;
return -1;
}
return 0;
}
void timer_deinit(MT_TIMER_OBJECT *object)
{
uint64_t quit = 0x51;
assert(NULL != object);
if(false == object->timer_active_flag)
return ;
object->timer_active_flag = false;
usleep(100);
write(object->timer_event_fd, &quit, sizeof(uint64_t)); /* wakeup thread */
pthread_join(object->timer_thread_id, NULL);
timer_clear(object);
close(object->timer_epoll_fd);
close(object->timer_event_fd);
object->timer_epoll_fd = -1;
object->timer_event_fd = -1;
}
int timer_add(MT_TIMER_OBJECT *object, struct itimerspec *itimespec,
int repeat, timer_callback_t cb, void *data, timer_release_t rb)
{
uint64_t quit = 0x51;
struct epoll_event event;
MT_TIMER_NODE *handler = NULL;
assert(NULL != object);
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->release_cb = rb;
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;
}
write(object->timer_event_fd, &quit, sizeof(uint64_t)); /* wakeup thread */
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;
assert(NULL != object);
pthread_rwlock_rdlock(&object->timer_rwlock);
HASH_FIND_INT(object->timer_head, &timerfd, handler);
pthread_rwlock_unlock(&object->timer_rwlock);
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);
if(handler->release_cb)
handler->release_cb(handler->timer_data);
free(handler);
return 0;
}
int timer_count(MT_TIMER_OBJECT *object)
{
assert(NULL != object);
return HASH_COUNT(object->timer_head);
}
int timer_clear(MT_TIMER_OBJECT *object)
{
struct epoll_event event;
MT_TIMER_NODE *handler = NULL;
assert(NULL != object);
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);
if(handler->release_cb)
handler->release_cb(handler->timer_data);
free(handler);
}
return 0;
}

181
source/mt_timer.h Normal file
View File

@ -0,0 +1,181 @@
/*
* 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 <pthread.h>
#include <sys/epoll.h>
#include <sys/timerfd.h>
#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_release_t)(void *data);
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;
timer_release_t release_cb;
}MT_TIMER_NODE; /* MT mean multiple */
typedef struct {
int timer_max;
int timer_epoll_fd;
int timer_event_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; \
uint64_t u64; \
char buf[128]; \
struct epoll_event event; \
MT_TIMER_NODE *timer_node = NULL; \
struct epoll_event events[mt_timer_##name.timer_max]; \
/*pthread_detach(pthread_self());*/ \
event.events = EPOLLIN | EPOLLET; \
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) \
{ \
read(mt_timer_##name.timer_event_fd, &u64, sizeof(uint64_t)); \
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--; \
} \
else \
{ \
event.data.ptr = (void *)timer_node; \
epoll_ctl(mt_timer_##name.timer_epoll_fd, EPOLL_CTL_DEL, timer_node->timer_fd, &event); \
pthread_rwlock_wrlock(&mt_timer_##name.timer_rwlock); \
HASH_DEL(mt_timer_##name.timer_head, timer_node); \
pthread_rwlock_unlock(&mt_timer_##name.timer_rwlock); \
close(timer_node->timer_fd); \
if(timer_node->release_cb) \
timer_node->release_cb(timer_node->timer_data); \
free(timer_node); \
} \
} \
} \
} \
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, timer_release_t rb);
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, -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, rb) \
timer_add(&mt_timer_##name, itimespec, repeat, cb, data, rb)
#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__

43
test.c
View File

@ -1,43 +0,0 @@
#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;
}

216
timer.c
View File

@ -1,216 +0,0 @@
#include <stdio.h>
#include <errno.h>
#include <string.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_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;
}

23
timer.h
View File

@ -1,23 +0,0 @@
#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__