fast_timer.[hc]: support lock for option
parent
58e1aea32b
commit
f5028fcbe0
3
HISTORY
3
HISTORY
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
Version 1.44 2020-11-03
|
||||
Version 1.44 2020-11-23
|
||||
* add test file src/tests/test_pthread_lock.c
|
||||
* add uniq_skiplist.[hc]
|
||||
* add function split_string_ex
|
||||
|
|
@ -37,6 +37,7 @@ Version 1.44 2020-11-03
|
|||
* shared_func.[hc]: add function fc_path_contains
|
||||
* fast_mblock.[hc]: support alloc elements limit
|
||||
* sockopt.[hc]: add function asyncconnectserverbyip
|
||||
* fast_timer.[hc]: support lock for option
|
||||
|
||||
Version 1.43 2019-12-25
|
||||
* replace function call system to getExecResult,
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ struct fast_task_info;
|
|||
|
||||
typedef struct ioevent_entry
|
||||
{
|
||||
FastTimerEntry timer; //must first
|
||||
int fd;
|
||||
FastTimerEntry timer;
|
||||
IOEventCallback callback;
|
||||
} IOEventEntry;
|
||||
|
||||
|
|
@ -70,6 +70,12 @@ struct nio_thread_data
|
|||
} notify; //for thread notify
|
||||
};
|
||||
|
||||
struct ioevent_notify_entry
|
||||
{
|
||||
IOEventEntry event; //must first
|
||||
struct nio_thread_data *thread_data;
|
||||
};
|
||||
|
||||
struct fast_task_info
|
||||
{
|
||||
IOEventEntry event; //must first
|
||||
|
|
|
|||
191
src/fast_timer.c
191
src/fast_timer.c
|
|
@ -20,16 +20,36 @@
|
|||
#include <errno.h>
|
||||
#include "logger.h"
|
||||
#include "fc_memory.h"
|
||||
#include "pthread_func.h"
|
||||
#include "fast_timer.h"
|
||||
|
||||
int fast_timer_init(FastTimer *timer, const int slot_count,
|
||||
const int64_t current_time)
|
||||
static int fast_timer_init_locks(FastTimer *timer)
|
||||
{
|
||||
int result;
|
||||
FastTimerSlot *slot;
|
||||
FastTimerSlot *end;
|
||||
|
||||
end = timer->slots + timer->slot_count;
|
||||
for (slot=timer->slots; slot<end; slot++) {
|
||||
if ((result=init_pthread_lock(&slot->lock)) != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fast_timer_init_ex(FastTimer *timer, const int slot_count,
|
||||
const int64_t current_time, const bool need_lock)
|
||||
{
|
||||
int result;
|
||||
int bytes;
|
||||
|
||||
if (slot_count <= 0 || current_time <= 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
timer->need_lock = need_lock;
|
||||
timer->slot_count = slot_count;
|
||||
timer->base_time = current_time; //base time for slot 0
|
||||
timer->current_time = current_time;
|
||||
|
|
@ -39,29 +59,98 @@ int fast_timer_init(FastTimer *timer, const int slot_count,
|
|||
return ENOMEM;
|
||||
}
|
||||
memset(timer->slots, 0, bytes);
|
||||
|
||||
if (need_lock) {
|
||||
if ((result=fast_timer_init_locks(timer)) != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fast_timer_destroy(FastTimer *timer)
|
||||
{
|
||||
if (timer->slots != NULL) {
|
||||
if (timer->need_lock) {
|
||||
FastTimerSlot *slot;
|
||||
FastTimerSlot *end;
|
||||
end = timer->slots + timer->slot_count;
|
||||
for (slot=timer->slots; slot<end; slot++) {
|
||||
pthread_mutex_destroy(&slot->lock);
|
||||
}
|
||||
}
|
||||
|
||||
free(timer->slots);
|
||||
timer->slots = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define TIMER_CHECK_LOCK(timer, slot) \
|
||||
do { \
|
||||
if (timer->need_lock) { \
|
||||
PTHREAD_MUTEX_LOCK(&(slot)->lock); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TIMER_CHECK_UNLOCK(timer, slot) \
|
||||
do { \
|
||||
if (timer->need_lock) { \
|
||||
PTHREAD_MUTEX_UNLOCK(&(slot)->lock); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TIMER_CHECK_LOCK_AND_SET_SLOT(timer, slot, entry) \
|
||||
do { \
|
||||
if (timer->need_lock) { \
|
||||
PTHREAD_MUTEX_LOCK(&(slot)->lock); \
|
||||
entry->slot_index = slot - timer->slots; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TIMER_CHECK_LOCK_BY_ENTRY(timer, entry) \
|
||||
do { \
|
||||
if (timer->need_lock && entry->slot_index >= 0) { \
|
||||
PTHREAD_MUTEX_LOCK(&(timer->slots + entry->slot_index)->lock); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define TIMER_CHECK_UNLOCK_AND_REMOVE_BY_ENTRY(timer, entry) \
|
||||
do { \
|
||||
if (timer->need_lock && entry->slot_index >= 0) { \
|
||||
PTHREAD_MUTEX_UNLOCK(&(timer->slots + entry->slot_index)->lock); \
|
||||
entry->slot_index = -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TIMER_CHECK_LOCK_BY_SINDEX(timer, slot_index) \
|
||||
do { \
|
||||
if (timer->need_lock) { \
|
||||
PTHREAD_MUTEX_LOCK(&(timer->slots + slot_index)->lock); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TIMER_CHECK_UNLOCK_BY_SINDEX(timer, slot_index) \
|
||||
do { \
|
||||
if (timer->need_lock) { \
|
||||
PTHREAD_MUTEX_UNLOCK(&(timer->slots + slot_index)->lock); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define TIMER_GET_SLOT_INDEX(timer, expires) \
|
||||
(((expires) - timer->base_time) % timer->slot_count)
|
||||
|
||||
#define TIMER_GET_SLOT_POINTER(timer, expires) \
|
||||
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
|
||||
|
||||
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry)
|
||||
static inline void add_entry(FastTimer *timer, FastTimerSlot *slot,
|
||||
FastTimerEntry *entry, const int64_t expires, const bool set_expires)
|
||||
{
|
||||
FastTimerSlot *slot;
|
||||
|
||||
slot = TIMER_GET_SLOT_POINTER(timer, entry->expires >
|
||||
timer->current_time ? entry->expires : timer->current_time);
|
||||
TIMER_CHECK_LOCK_AND_SET_SLOT(timer, slot, entry);
|
||||
if (set_expires) {
|
||||
entry->expires = expires;
|
||||
}
|
||||
entry->next = slot->head.next;
|
||||
if (slot->head.next != NULL) {
|
||||
slot->head.next->prev = entry;
|
||||
|
|
@ -69,34 +158,54 @@ int fast_timer_add(FastTimer *timer, FastTimerEntry *entry)
|
|||
entry->prev = &slot->head;
|
||||
slot->head.next = entry;
|
||||
entry->rehash = false;
|
||||
return 0;
|
||||
TIMER_CHECK_UNLOCK(timer, slot);
|
||||
}
|
||||
|
||||
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
||||
void fast_timer_add_ex(FastTimer *timer, FastTimerEntry *entry,
|
||||
const int64_t expires, const bool set_expires)
|
||||
{
|
||||
FastTimerSlot *slot;
|
||||
int64_t new_expires;
|
||||
bool new_set_expires;
|
||||
|
||||
if (expires > timer->current_time) {
|
||||
new_expires = expires;
|
||||
new_set_expires = set_expires;
|
||||
} else {
|
||||
new_expires = timer->current_time;
|
||||
new_set_expires = true;
|
||||
}
|
||||
slot = TIMER_GET_SLOT_POINTER(timer, new_expires);
|
||||
add_entry(timer, slot, entry, new_expires, new_set_expires);
|
||||
}
|
||||
|
||||
void fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
||||
const int64_t new_expires)
|
||||
{
|
||||
if (new_expires == entry->expires) {
|
||||
return 0;
|
||||
int slot_index;
|
||||
|
||||
if (new_expires > entry->expires) {
|
||||
if (timer->need_lock && entry->slot_index >= 0) {
|
||||
slot_index = entry->slot_index;
|
||||
if (slot_index < 0) {
|
||||
slot_index = TIMER_GET_SLOT_INDEX(timer, entry->expires);
|
||||
}
|
||||
} else {
|
||||
slot_index = TIMER_GET_SLOT_INDEX(timer, entry->expires);
|
||||
}
|
||||
|
||||
if (new_expires < entry->expires) {
|
||||
fast_timer_remove(timer, entry);
|
||||
entry->expires = new_expires;
|
||||
return fast_timer_add(timer, entry);
|
||||
}
|
||||
|
||||
entry->rehash = TIMER_GET_SLOT_INDEX(timer, new_expires) !=
|
||||
TIMER_GET_SLOT_INDEX(timer, entry->expires);
|
||||
TIMER_CHECK_LOCK_BY_SINDEX(timer, slot_index);
|
||||
entry->rehash = TIMER_GET_SLOT_INDEX(timer, new_expires) != slot_index;
|
||||
entry->expires = new_expires; //lazy move
|
||||
return 0;
|
||||
TIMER_CHECK_UNLOCK_BY_SINDEX(timer, slot_index);
|
||||
} else if (new_expires < entry->expires) {
|
||||
fast_timer_remove(timer, entry);
|
||||
fast_timer_add_ex(timer, entry, new_expires, true);
|
||||
}
|
||||
}
|
||||
|
||||
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry)
|
||||
static inline void remove_entry(FastTimerEntry *entry)
|
||||
{
|
||||
if (entry->prev == NULL) {
|
||||
return ENOENT; //already removed
|
||||
}
|
||||
|
||||
if (entry->next != NULL) {
|
||||
entry->next->prev = entry->prev;
|
||||
entry->prev->next = entry->next;
|
||||
|
|
@ -107,7 +216,21 @@ int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry)
|
|||
}
|
||||
|
||||
entry->prev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry)
|
||||
{
|
||||
int result;
|
||||
|
||||
TIMER_CHECK_LOCK_BY_ENTRY(timer, entry);
|
||||
if (entry->prev == NULL) {
|
||||
result = ENOENT; //already removed
|
||||
} else {
|
||||
remove_entry(entry);
|
||||
result = 0;
|
||||
}
|
||||
TIMER_CHECK_UNLOCK_AND_REMOVE_BY_ENTRY(timer, entry);
|
||||
return result;
|
||||
}
|
||||
|
||||
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time)
|
||||
|
|
@ -123,6 +246,7 @@ int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
|||
FastTimerEntry *head)
|
||||
{
|
||||
FastTimerSlot *slot;
|
||||
FastTimerSlot *new_slot;
|
||||
FastTimerEntry *entry;
|
||||
FastTimerEntry *first;
|
||||
FastTimerEntry *last;
|
||||
|
|
@ -141,6 +265,7 @@ int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
|||
count = 0;
|
||||
while (timer->current_time < current_time) {
|
||||
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
||||
TIMER_CHECK_LOCK(timer, slot);
|
||||
entry = slot->head.next;
|
||||
while (entry != NULL) {
|
||||
if (entry->expires >= current_time) { //not expired
|
||||
|
|
@ -157,13 +282,17 @@ int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
|||
last = entry;
|
||||
entry = entry->next;
|
||||
|
||||
new_slot = TIMER_GET_SLOT_POINTER(timer, last->expires);
|
||||
if (new_slot != slot) { //check to avoid deadlock
|
||||
remove_entry(last);
|
||||
add_entry(timer, new_slot, last,
|
||||
last->expires, false);
|
||||
} else {
|
||||
last->rehash = false;
|
||||
fast_timer_remove(timer, last);
|
||||
fast_timer_add(timer, last);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else { //expired
|
||||
} else { //expired
|
||||
count++;
|
||||
if (first == NULL) {
|
||||
first = entry;
|
||||
|
|
@ -182,6 +311,7 @@ int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
|||
tail = last;
|
||||
first = NULL;
|
||||
}
|
||||
TIMER_CHECK_UNLOCK(timer, slot);
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
|
|
@ -190,4 +320,3 @@ int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,21 +17,25 @@
|
|||
#define __FAST_TIMER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include "common_define.h"
|
||||
|
||||
struct fast_timer_slot;
|
||||
typedef struct fast_timer_entry {
|
||||
int64_t expires;
|
||||
void *data;
|
||||
struct fast_timer_entry *prev;
|
||||
struct fast_timer_entry *next;
|
||||
int slot_index;
|
||||
bool rehash;
|
||||
} FastTimerEntry;
|
||||
|
||||
typedef struct fast_timer_slot {
|
||||
struct fast_timer_entry head;
|
||||
pthread_mutex_t lock;
|
||||
} FastTimerSlot;
|
||||
|
||||
typedef struct fast_timer {
|
||||
bool need_lock;
|
||||
int slot_count; //time wheel slot count
|
||||
int64_t base_time; //base time for slot 0
|
||||
int64_t current_time;
|
||||
|
|
@ -42,13 +46,20 @@ typedef struct fast_timer {
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
int fast_timer_init(FastTimer *timer, const int slot_count,
|
||||
const int64_t current_time);
|
||||
#define fast_timer_init(timer, slot_count, current_time) \
|
||||
fast_timer_init_ex(timer, slot_count, current_time, false)
|
||||
|
||||
#define fast_timer_add(timer, entry) \
|
||||
fast_timer_add_ex(timer, entry, (entry)->expires, false)
|
||||
|
||||
int fast_timer_init_ex(FastTimer *timer, const int slot_count,
|
||||
const int64_t current_time, const bool need_lock);
|
||||
void fast_timer_destroy(FastTimer *timer);
|
||||
|
||||
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry);
|
||||
void fast_timer_add_ex(FastTimer *timer, FastTimerEntry *entry,
|
||||
const int64_t expires, const bool set_expires);
|
||||
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry);
|
||||
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
||||
void fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
||||
const int64_t new_expires);
|
||||
|
||||
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ static void deal_ioevents(IOEventPoller *ioevent)
|
|||
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent,
|
||||
ioevent->iterator.index);
|
||||
if (pEntry != NULL) {
|
||||
pEntry->callback(pEntry->fd, event, pEntry->timer.data);
|
||||
pEntry->callback(pEntry->fd, event, pEntry);
|
||||
}
|
||||
else {
|
||||
logDebug("file: "__FILE__", line: %d, "
|
||||
|
|
@ -51,7 +51,7 @@ int ioevent_remove(IOEventPoller *ioevent, void *data)
|
|||
|
||||
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent,
|
||||
ioevent->iterator.index);
|
||||
if (pEntry != NULL && pEntry->timer.data == data) {
|
||||
if (pEntry != NULL && (void *)pEntry == data) {
|
||||
return 0; //do NOT clear current entry
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ int ioevent_remove(IOEventPoller *ioevent, void *data)
|
|||
index++)
|
||||
{
|
||||
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent, index);
|
||||
if (pEntry != NULL && pEntry->timer.data == data) {
|
||||
if (pEntry != NULL && (void *)pEntry == data) {
|
||||
logDebug("file: "__FILE__", line: %d, "
|
||||
"clear ioevent data: %p", __LINE__, data);
|
||||
IOEVENT_CLEAR_DATA(ioevent, index);
|
||||
|
|
@ -83,11 +83,10 @@ static void deal_timeouts(FastTimerEntry *head)
|
|||
entry = entry->next;
|
||||
|
||||
current->prev = current->next = NULL; //must set NULL because NOT in time wheel
|
||||
pEventEntry = (IOEventEntry *)current->data;
|
||||
pEventEntry = (IOEventEntry *)current;
|
||||
if (pEventEntry != NULL)
|
||||
{
|
||||
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT,
|
||||
current->data);
|
||||
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT, current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,16 +96,16 @@ int ioevent_loop(struct nio_thread_data *pThreadData,
|
|||
clean_up_callback, volatile bool *continue_flag)
|
||||
{
|
||||
int result;
|
||||
IOEventEntry ev_notify;
|
||||
struct ioevent_notify_entry ev_notify;
|
||||
FastTimerEntry head;
|
||||
struct fast_task_info *task;
|
||||
time_t last_check_time;
|
||||
int count;
|
||||
|
||||
memset(&ev_notify, 0, sizeof(ev_notify));
|
||||
ev_notify.fd = FC_NOTIFY_READ_FD(pThreadData);
|
||||
ev_notify.callback = recv_notify_callback;
|
||||
ev_notify.timer.data = pThreadData;
|
||||
ev_notify.event.fd = FC_NOTIFY_READ_FD(pThreadData);
|
||||
ev_notify.event.callback = recv_notify_callback;
|
||||
ev_notify.thread_data = pThreadData;
|
||||
if (ioevent_attach(&pThreadData->ev_puller,
|
||||
pThreadData->pipe_fds[0], IOEVENT_READ,
|
||||
&ev_notify) != 0)
|
||||
|
|
@ -210,18 +209,7 @@ int ioevent_set(struct fast_task_info *task, struct nio_thread_data *pThread,
|
|||
return result;
|
||||
}
|
||||
|
||||
task->event.timer.data = task;
|
||||
task->event.timer.expires = g_current_time + timeout;
|
||||
result = fast_timer_add(&pThread->timer, &task->event.timer);
|
||||
if (result != 0)
|
||||
{
|
||||
logError("file: "__FILE__", line: %d, " \
|
||||
"fast_timer_add fail, " \
|
||||
"errno: %d, error info: %s", \
|
||||
__LINE__, result, STRERROR(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
fast_timer_add(&pThread->timer, &task->event.timer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue