locked_timer: atomic opt for lock_index
parent
b236808a69
commit
93e6cec05d
2
HISTORY
2
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 test file src/tests/test_pthread_lock.c
|
||||||
* add uniq_skiplist.[hc]
|
* add uniq_skiplist.[hc]
|
||||||
* add function split_string_ex
|
* add function split_string_ex
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,9 @@ static int locked_timer_init_slots(LockedTimer *timer)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int locked_timer_init(LockedTimer *timer, const int slot_count,
|
int locked_timer_init_ex(LockedTimer *timer, const int slot_count,
|
||||||
const int64_t current_time, const int shared_lock_count)
|
const int64_t current_time, const int shared_lock_count,
|
||||||
|
const bool set_lock_index)
|
||||||
{
|
{
|
||||||
if (slot_count <= 0 || current_time <= 0) {
|
if (slot_count <= 0 || current_time <= 0) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
@ -73,6 +74,7 @@ int locked_timer_init(LockedTimer *timer, const int slot_count,
|
||||||
|
|
||||||
timer->slot_count = slot_count;
|
timer->slot_count = slot_count;
|
||||||
timer->entry_shares.count = shared_lock_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->base_time = current_time; //base time for slot 0
|
||||||
timer->current_time = current_time;
|
timer->current_time = current_time;
|
||||||
return locked_timer_init_slots(timer);
|
return locked_timer_init_slots(timer);
|
||||||
|
|
@ -111,30 +113,50 @@ void locked_timer_destroy(LockedTimer *timer)
|
||||||
#define TIMER_GET_SLOT_POINTER(timer, expires) \
|
#define TIMER_GET_SLOT_POINTER(timer, expires) \
|
||||||
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
|
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
|
||||||
|
|
||||||
#define TIMER_ENTRY_LOCK(timer, entry) \
|
#define TIMER_ENTRY_LOCK(timer, lock_index) \
|
||||||
PTHREAD_MUTEX_LOCK(timer->entry_shares.locks + entry->lock_index)
|
PTHREAD_MUTEX_LOCK(timer->entry_shares.locks + lock_index)
|
||||||
|
|
||||||
#define TIMER_ENTRY_UNLOCK(timer, entry) \
|
#define TIMER_ENTRY_UNLOCK(timer, lock_index) \
|
||||||
PTHREAD_MUTEX_UNLOCK(timer->entry_shares.locks + entry->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 { \
|
do { \
|
||||||
TIMER_ENTRY_LOCK(timer, entry); \
|
TIMER_ENTRY_LOCK(timer, lock_index); \
|
||||||
entry->status = FAST_TIMER_STATUS_NORMAL; \
|
entry->status = FAST_TIMER_STATUS_NORMAL; \
|
||||||
entry->slot_index = slot - timer->slots; \
|
entry->slot_index = slot - timer->slots; \
|
||||||
TIMER_ENTRY_UNLOCK(timer, entry); \
|
TIMER_ENTRY_UNLOCK(timer, lock_index); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static inline void add_entry(LockedTimer *timer, LockedTimerSlot *slot,
|
static inline void add_entry(LockedTimer *timer, LockedTimerSlot *slot,
|
||||||
LockedTimerEntry *entry, const int64_t expires, const int flags)
|
LockedTimerEntry *entry, const int64_t expires, const int flags)
|
||||||
{
|
{
|
||||||
|
int lock_index;
|
||||||
if ((flags & FAST_TIMER_FLAGS_SET_ENTRY_LOCK) != 0) {
|
if ((flags & FAST_TIMER_FLAGS_SET_ENTRY_LOCK) != 0) {
|
||||||
|
if (timer->entry_shares.set_lock_index) {
|
||||||
|
int old_index;
|
||||||
/* init the entry on the first call */
|
/* init the entry on the first call */
|
||||||
entry->lock_index = ((unsigned long)entry) %
|
lock_index = ((unsigned long)entry) % timer->entry_shares.count;
|
||||||
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);
|
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) {
|
if ((flags & FAST_TIMER_FLAGS_SET_ENTRY_LOCK) == 0) {
|
||||||
/* MUST set entry status and slot index in the end when entry move */
|
/* 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);
|
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)
|
LockedTimerEntry *entry, int *slot_index, const int new_status)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
int lock_index;
|
||||||
|
|
||||||
|
lock_index = TIMER_ENTRY_FETCH_LOCK_INDEX(timer, entry);
|
||||||
while (1) {
|
while (1) {
|
||||||
TIMER_ENTRY_LOCK(timer, entry);
|
TIMER_ENTRY_LOCK(timer, lock_index);
|
||||||
switch (entry->status) {
|
switch (entry->status) {
|
||||||
case FAST_TIMER_STATUS_CLEARED:
|
case FAST_TIMER_STATUS_CLEARED:
|
||||||
result = ECANCELED;
|
result = ECANCELED;
|
||||||
|
|
@ -183,7 +207,7 @@ static inline int check_set_entry_status(LockedTimer *timer,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*slot_index = entry->slot_index;
|
*slot_index = entry->slot_index;
|
||||||
TIMER_ENTRY_UNLOCK(timer, entry);
|
TIMER_ENTRY_UNLOCK(timer, lock_index);
|
||||||
|
|
||||||
if (result != EAGAIN) {
|
if (result != EAGAIN) {
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -266,6 +290,7 @@ int locked_timer_timeouts_get(LockedTimer *timer, const int64_t current_time,
|
||||||
LockedTimerEntry *tmp;
|
LockedTimerEntry *tmp;
|
||||||
LockedTimerEntry *tail;
|
LockedTimerEntry *tail;
|
||||||
bool is_valid;
|
bool is_valid;
|
||||||
|
int lock_index;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
if (timer->current_time >= current_time) {
|
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) {
|
if (entry->rehash) {
|
||||||
new_slot = TIMER_GET_SLOT_POINTER(timer, entry->expires);
|
new_slot = TIMER_GET_SLOT_POINTER(timer, entry->expires);
|
||||||
if (new_slot != slot) { //check to avoid deadlock
|
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) {
|
if (entry->status == FAST_TIMER_STATUS_NORMAL) {
|
||||||
entry->status = FAST_TIMER_STATUS_MOVING;
|
entry->status = FAST_TIMER_STATUS_MOVING;
|
||||||
is_valid = true;
|
is_valid = true;
|
||||||
} else {
|
} else {
|
||||||
is_valid = false;
|
is_valid = false;
|
||||||
}
|
}
|
||||||
TIMER_ENTRY_UNLOCK(timer, entry);
|
TIMER_ENTRY_UNLOCK(timer, lock_index);
|
||||||
|
|
||||||
if (is_valid) {
|
if (is_valid) {
|
||||||
fc_list_del_init(&entry->dlink);
|
fc_list_del_init(&entry->dlink);
|
||||||
|
|
@ -302,14 +327,14 @@ int locked_timer_timeouts_get(LockedTimer *timer, const int64_t current_time,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { //expired
|
} else { //expired
|
||||||
TIMER_ENTRY_LOCK(timer, entry);
|
TIMER_ENTRY_FETCH_AND_LOCK(timer, entry);
|
||||||
if (entry->status == FAST_TIMER_STATUS_NORMAL) {
|
if (entry->status == FAST_TIMER_STATUS_NORMAL) {
|
||||||
entry->status = FAST_TIMER_STATUS_TIMEOUT;
|
entry->status = FAST_TIMER_STATUS_TIMEOUT;
|
||||||
is_valid = true;
|
is_valid = true;
|
||||||
} else {
|
} else {
|
||||||
is_valid = false;
|
is_valid = false;
|
||||||
}
|
}
|
||||||
TIMER_ENTRY_UNLOCK(timer, entry);
|
TIMER_ENTRY_UNLOCK(timer, lock_index);
|
||||||
|
|
||||||
if (is_valid) {
|
if (is_valid) {
|
||||||
fc_list_del_init(&entry->dlink);
|
fc_list_del_init(&entry->dlink);
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ typedef struct locked_timer_entry {
|
||||||
struct fc_list_head dlink; //for timer slot
|
struct fc_list_head dlink; //for timer slot
|
||||||
struct locked_timer_entry *next; //for timeout chain
|
struct locked_timer_entry *next; //for timeout chain
|
||||||
uint32_t slot_index; //for slot lock
|
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;
|
uint8_t status;
|
||||||
bool rehash;
|
bool rehash;
|
||||||
} LockedTimerEntry;
|
} LockedTimerEntry;
|
||||||
|
|
@ -49,6 +49,7 @@ typedef struct locked_timer_slot {
|
||||||
} LockedTimerSlot;
|
} LockedTimerSlot;
|
||||||
|
|
||||||
typedef struct locked_timer_shared_locks {
|
typedef struct locked_timer_shared_locks {
|
||||||
|
bool set_lock_index;
|
||||||
uint16_t count;
|
uint16_t count;
|
||||||
pthread_mutex_t *locks;
|
pthread_mutex_t *locks;
|
||||||
} LockedTimerSharedLocks;
|
} LockedTimerSharedLocks;
|
||||||
|
|
@ -65,6 +66,10 @@ typedef struct locked_timer {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#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) \
|
#define locked_timer_add(timer, entry) \
|
||||||
locked_timer_add_ex(timer, entry, (entry)->expires, \
|
locked_timer_add_ex(timer, entry, (entry)->expires, \
|
||||||
FAST_TIMER_FLAGS_SET_ENTRY_LOCK)
|
FAST_TIMER_FLAGS_SET_ENTRY_LOCK)
|
||||||
|
|
@ -72,8 +77,9 @@ extern "C" {
|
||||||
#define locked_timer_remove(timer, entry) \
|
#define locked_timer_remove(timer, entry) \
|
||||||
locked_timer_remove_ex(timer, entry, FAST_TIMER_STATUS_CLEARED)
|
locked_timer_remove_ex(timer, entry, FAST_TIMER_STATUS_CLEARED)
|
||||||
|
|
||||||
int locked_timer_init(LockedTimer *timer, const int slot_count,
|
int locked_timer_init_ex(LockedTimer *timer, const int slot_count,
|
||||||
const int64_t current_time, const int shared_lock_count);
|
const int64_t current_time, const int shared_lock_count,
|
||||||
|
const bool set_lock_index);
|
||||||
|
|
||||||
void locked_timer_destroy(LockedTimer *timer);
|
void locked_timer_destroy(LockedTimer *timer);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue