diff --git a/HISTORY b/HISTORY index 6fdafd66ff67d8ca3f0659d6e1ec0ea1007e8b22..9c9f0dff37b440cd9337189f46c85ab41f8a4530 100644 --- a/HISTORY +++ b/HISTORY @@ -1,5 +1,5 @@ -Version 1.44 2020-11-26 +Version 1.44 2020-11-29 * add test file src/tests/test_pthread_lock.c * add uniq_skiplist.[hc] * add function split_string_ex diff --git a/src/locked_timer.c b/src/locked_timer.c index 22609435b96621ebbe3ae3bb6c98871d534a0642..f1a847c650e77ab09d1dd239751178f2041e7acc 100644 --- a/src/locked_timer.c +++ b/src/locked_timer.c @@ -64,8 +64,9 @@ static int locked_timer_init_slots(LockedTimer *timer) return 0; } -int locked_timer_init(LockedTimer *timer, const int slot_count, - const int64_t current_time, const int shared_lock_count) +int locked_timer_init_ex(LockedTimer *timer, const int slot_count, + const int64_t current_time, const int shared_lock_count, + const bool set_lock_index) { if (slot_count <= 0 || current_time <= 0) { return EINVAL; @@ -73,6 +74,7 @@ int locked_timer_init(LockedTimer *timer, const int slot_count, timer->slot_count = slot_count; timer->entry_shares.count = shared_lock_count; + timer->entry_shares.set_lock_index = set_lock_index; timer->base_time = current_time; //base time for slot 0 timer->current_time = current_time; return locked_timer_init_slots(timer); @@ -111,30 +113,50 @@ void locked_timer_destroy(LockedTimer *timer) #define TIMER_GET_SLOT_POINTER(timer, expires) \ (timer->slots + TIMER_GET_SLOT_INDEX(timer, expires)) -#define TIMER_ENTRY_LOCK(timer, entry) \ - PTHREAD_MUTEX_LOCK(timer->entry_shares.locks + entry->lock_index) +#define TIMER_ENTRY_LOCK(timer, lock_index) \ + PTHREAD_MUTEX_LOCK(timer->entry_shares.locks + lock_index) -#define TIMER_ENTRY_UNLOCK(timer, entry) \ - PTHREAD_MUTEX_UNLOCK(timer->entry_shares.locks + entry->lock_index) +#define TIMER_ENTRY_UNLOCK(timer, lock_index) \ + PTHREAD_MUTEX_UNLOCK(timer->entry_shares.locks + lock_index) +#define TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry) \ + (timer->entry_shares.set_lock_index ? \ + __sync_add_and_fetch(&entry->lock_index, 0) : entry->lock_index) -#define TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry) \ +#define TIMER_ENTRY_FETCH_AND_LOCK(timer, entry) \ + lock_index = TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry); \ + PTHREAD_MUTEX_LOCK(timer->entry_shares.locks + lock_index) + +#define TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry, lock_index) \ do { \ - TIMER_ENTRY_LOCK(timer, entry); \ + TIMER_ENTRY_LOCK(timer, lock_index); \ entry->status = FAST_TIMER_STATUS_NORMAL; \ entry->slot_index = slot - timer->slots; \ - TIMER_ENTRY_UNLOCK(timer, entry); \ + TIMER_ENTRY_UNLOCK(timer, lock_index); \ } while (0) static inline void add_entry(LockedTimer *timer, LockedTimerSlot *slot, LockedTimerEntry *entry, const int64_t expires, const int flags) { + int lock_index; if ((flags & FAST_TIMER_FLAGS_SET_ENTRY_LOCK) != 0) { - /* init the entry on the first call */ - entry->lock_index = ((unsigned long)entry) % - timer->entry_shares.count; + if (timer->entry_shares.set_lock_index) { + int old_index; + /* init the entry on the first call */ + lock_index = ((unsigned long)entry) % timer->entry_shares.count; + old_index = entry->lock_index; + while (!__sync_bool_compare_and_swap(&entry->lock_index, + old_index, lock_index)) + { + old_index = __sync_add_and_fetch(&entry->lock_index, 0); + } + } else { + lock_index = entry->lock_index; + } - TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry); + TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry, lock_index); + } else { + lock_index = TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry); } PTHREAD_MUTEX_LOCK(&slot->lock); @@ -146,7 +168,7 @@ static inline void add_entry(LockedTimer *timer, LockedTimerSlot *slot, if ((flags & FAST_TIMER_FLAGS_SET_ENTRY_LOCK) == 0) { /* MUST set entry status and slot index in the end when entry move */ - TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry); + TIMER_SET_ENTRY_STATUS_AND_SINDEX(timer, slot, entry, lock_index); } PTHREAD_MUTEX_UNLOCK(&slot->lock); } @@ -159,9 +181,11 @@ static inline int check_set_entry_status(LockedTimer *timer, LockedTimerEntry *entry, int *slot_index, const int new_status) { int result; + int lock_index; + lock_index = TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry); while (1) { - TIMER_ENTRY_LOCK(timer, entry); + TIMER_ENTRY_LOCK(timer, lock_index); switch (entry->status) { case FAST_TIMER_STATUS_CLEARED: result = ECANCELED; @@ -183,7 +207,7 @@ static inline int check_set_entry_status(LockedTimer *timer, break; } *slot_index = entry->slot_index; - TIMER_ENTRY_UNLOCK(timer, entry); + TIMER_ENTRY_UNLOCK(timer, lock_index); if (result != EAGAIN) { return result; @@ -266,6 +290,7 @@ int locked_timer_timeouts_get(LockedTimer *timer, const int64_t current_time, LockedTimerEntry *tmp; LockedTimerEntry *tail; bool is_valid; + int lock_index; int count; if (timer->current_time >= current_time) { @@ -283,14 +308,14 @@ int locked_timer_timeouts_get(LockedTimer *timer, const int64_t current_time, if (entry->rehash) { new_slot = TIMER_GET_SLOT_POINTER(timer, entry->expires); if (new_slot != slot) { //check to avoid deadlock - TIMER_ENTRY_LOCK(timer, entry); + TIMER_ENTRY_FETCH_AND_LOCK(timer, entry); if (entry->status == FAST_TIMER_STATUS_NORMAL) { entry->status = FAST_TIMER_STATUS_MOVING; is_valid = true; } else { is_valid = false; } - TIMER_ENTRY_UNLOCK(timer, entry); + TIMER_ENTRY_UNLOCK(timer, lock_index); if (is_valid) { fc_list_del_init(&entry->dlink); @@ -302,14 +327,14 @@ int locked_timer_timeouts_get(LockedTimer *timer, const int64_t current_time, } } } else { //expired - TIMER_ENTRY_LOCK(timer, entry); + TIMER_ENTRY_FETCH_AND_LOCK(timer, entry); if (entry->status == FAST_TIMER_STATUS_NORMAL) { entry->status = FAST_TIMER_STATUS_TIMEOUT; is_valid = true; } else { is_valid = false; } - TIMER_ENTRY_UNLOCK(timer, entry); + TIMER_ENTRY_UNLOCK(timer, lock_index); if (is_valid) { fc_list_del_init(&entry->dlink); diff --git a/src/locked_timer.h b/src/locked_timer.h index abfb400f8dfb0af9a27327dd96e717734401ad9c..8545732ebf00fc8b9352e889b36f9bbf0b34d095 100644 --- a/src/locked_timer.h +++ b/src/locked_timer.h @@ -38,7 +38,7 @@ typedef struct locked_timer_entry { struct fc_list_head dlink; //for timer slot struct locked_timer_entry *next; //for timeout chain uint32_t slot_index; //for slot lock - uint16_t lock_index; //for entry lock + volatile uint16_t lock_index; //for entry lock uint8_t status; bool rehash; } LockedTimerEntry; @@ -49,6 +49,7 @@ typedef struct locked_timer_slot { } LockedTimerSlot; typedef struct locked_timer_shared_locks { + bool set_lock_index; uint16_t count; pthread_mutex_t *locks; } LockedTimerSharedLocks; @@ -65,6 +66,10 @@ typedef struct locked_timer { extern "C" { #endif +#define locked_timer_init(timer, slot_count, current_time, shared_lock_count) \ + locked_timer_init_ex(timer, slot_count, current_time, shared_lock_count, \ + true) + #define locked_timer_add(timer, entry) \ locked_timer_add_ex(timer, entry, (entry)->expires, \ FAST_TIMER_FLAGS_SET_ENTRY_LOCK) @@ -72,8 +77,9 @@ extern "C" { #define locked_timer_remove(timer, entry) \ locked_timer_remove_ex(timer, entry, FAST_TIMER_STATUS_CLEARED) -int locked_timer_init(LockedTimer *timer, const int slot_count, - const int64_t current_time, const int shared_lock_count); +int locked_timer_init_ex(LockedTimer *timer, const int slot_count, + const int64_t current_time, const int shared_lock_count, + const bool set_lock_index); void locked_timer_destroy(LockedTimer *timer);