Skip to content

Commit 0a24d76

Browse files
Merge pull request #312 from shintaro-iwasaki/pr/poolquickcheck
pool: check the pool's emptiness before taking a lock
2 parents 6fbeec1 + 3028387 commit 0a24d76

File tree

2 files changed

+167
-112
lines changed

2 files changed

+167
-112
lines changed

src/pool/fifo.c

Lines changed: 127 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ struct data {
3232
size_t num_threads;
3333
ABTI_thread *p_head;
3434
ABTI_thread *p_tail;
35+
/* If the pool is empty, pop() accesses only is_empty so that pop() does not
36+
* slow down a push operation. */
37+
ABTD_atomic_int is_empty; /* Whether the pool is empty or not. */
3538
};
3639
typedef struct data data_t;
3740

@@ -40,6 +43,28 @@ static inline data_t *pool_get_data_ptr(void *p_data)
4043
return (data_t *)p_data;
4144
}
4245

46+
ABTU_ret_err static inline int spinlock_acquire_if_not_empty(data_t *p_data)
47+
{
48+
if (ABTD_atomic_acquire_load_int(&p_data->is_empty)) {
49+
/* The pool is empty. Lock is not taken. */
50+
return 1;
51+
}
52+
while (ABTD_spinlock_try_acquire(&p_data->mutex)) {
53+
/* Lock acquisition failed. Check the size. */
54+
while (1) {
55+
if (ABTD_atomic_acquire_load_int(&p_data->is_empty)) {
56+
/* The pool becomes empty. Lock is not taken. */
57+
return 1;
58+
} else if (!ABTD_spinlock_is_locked(&p_data->mutex)) {
59+
/* Lock seems released. Let's try to take a lock again. */
60+
break;
61+
}
62+
}
63+
}
64+
/* Lock is acquired. */
65+
return 0;
66+
}
67+
4368
/* Obtain the FIFO pool definition according to the access type */
4469
ABTU_ret_err int ABTI_pool_get_fifo_def(ABT_pool_access access,
4570
ABTI_pool_def *p_def)
@@ -105,6 +130,7 @@ static int pool_init(ABT_pool pool, ABT_pool_config config)
105130
p_data->num_threads = 0;
106131
p_data->p_head = NULL;
107132
p_data->p_tail = NULL;
133+
ABTD_atomic_relaxed_store_int(&p_data->is_empty, 1);
108134

109135
p_pool->data = p_data;
110136

@@ -141,6 +167,8 @@ static void pool_push_shared(ABT_pool pool, ABT_unit unit)
141167
p_thread->p_next = p_thread;
142168
p_data->p_head = p_thread;
143169
p_data->p_tail = p_thread;
170+
p_data->num_threads = 1;
171+
ABTD_atomic_release_store_int(&p_data->is_empty, 0);
144172
} else {
145173
ABTI_thread *p_head = p_data->p_head;
146174
ABTI_thread *p_tail = p_data->p_tail;
@@ -149,8 +177,8 @@ static void pool_push_shared(ABT_pool pool, ABT_unit unit)
149177
p_thread->p_prev = p_tail;
150178
p_thread->p_next = p_head;
151179
p_data->p_tail = p_thread;
180+
p_data->num_threads++;
152181
}
153-
p_data->num_threads++;
154182

155183
ABTD_atomic_release_store_int(&p_thread->is_in_pool, 1);
156184
ABTD_spinlock_release(&p_data->mutex);
@@ -167,6 +195,8 @@ static void pool_push_private(ABT_pool pool, ABT_unit unit)
167195
p_thread->p_next = p_thread;
168196
p_data->p_head = p_thread;
169197
p_data->p_tail = p_thread;
198+
p_data->num_threads = 1;
199+
ABTD_atomic_release_store_int(&p_data->is_empty, 0);
170200
} else {
171201
ABTI_thread *p_head = p_data->p_head;
172202
ABTI_thread *p_tail = p_data->p_tail;
@@ -175,8 +205,8 @@ static void pool_push_private(ABT_pool pool, ABT_unit unit)
175205
p_thread->p_prev = p_tail;
176206
p_thread->p_next = p_head;
177207
p_data->p_tail = p_thread;
208+
p_data->num_threads++;
178209
}
179-
p_data->num_threads++;
180210

181211
ABTD_atomic_release_store_int(&p_thread->is_in_pool, 1);
182212
}
@@ -186,148 +216,154 @@ static ABT_unit pool_pop_wait(ABT_pool pool, double time_secs)
186216
ABTI_pool *p_pool = ABTI_pool_get_ptr(pool);
187217
data_t *p_data = pool_get_data_ptr(p_pool->data);
188218
ABTI_thread *p_thread = NULL;
189-
ABT_unit h_unit = ABT_UNIT_NULL;
190219

191220
double time_start = 0.0;
192221

193-
do {
194-
ABTD_spinlock_acquire(&p_data->mutex);
195-
if (p_data->num_threads > 0) {
196-
p_thread = p_data->p_head;
197-
if (p_data->num_threads == 1) {
198-
p_data->p_head = NULL;
199-
p_data->p_tail = NULL;
200-
} else {
201-
p_thread->p_prev->p_next = p_thread->p_next;
202-
p_thread->p_next->p_prev = p_thread->p_prev;
203-
p_data->p_head = p_thread->p_next;
222+
while (1) {
223+
if (spinlock_acquire_if_not_empty(p_data) == 0) {
224+
ABT_unit h_unit = ABT_UNIT_NULL;
225+
if (p_data->num_threads > 0) {
226+
p_thread = p_data->p_head;
227+
if (p_data->num_threads == 1) {
228+
p_data->p_head = NULL;
229+
p_data->p_tail = NULL;
230+
p_data->num_threads = 0;
231+
ABTD_atomic_release_store_int(&p_data->is_empty, 1);
232+
} else {
233+
p_thread->p_prev->p_next = p_thread->p_next;
234+
p_thread->p_next->p_prev = p_thread->p_prev;
235+
p_data->p_head = p_thread->p_next;
236+
p_data->num_threads--;
237+
}
238+
239+
p_thread->p_prev = NULL;
240+
p_thread->p_next = NULL;
241+
ABTD_atomic_release_store_int(&p_thread->is_in_pool, 0);
242+
243+
h_unit = (ABT_unit)p_thread;
204244
}
205-
p_data->num_threads--;
206-
207-
p_thread->p_prev = NULL;
208-
p_thread->p_next = NULL;
209-
ABTD_atomic_release_store_int(&p_thread->is_in_pool, 0);
210-
211-
h_unit = (ABT_unit)p_thread;
212245
ABTD_spinlock_release(&p_data->mutex);
246+
if (h_unit != ABT_UNIT_NULL)
247+
return h_unit;
248+
}
249+
if (time_start == 0.0) {
250+
time_start = ABTI_get_wtime();
213251
} else {
214-
ABTD_spinlock_release(&p_data->mutex);
215-
if (time_start == 0.0) {
216-
time_start = ABTI_get_wtime();
217-
} else {
218-
double elapsed = ABTI_get_wtime() - time_start;
219-
if (elapsed > time_secs)
220-
break;
252+
double elapsed = ABTI_get_wtime() - time_start;
253+
if (elapsed > time_secs)
254+
return ABT_UNIT_NULL;
255+
}
256+
/* Sleep. */
257+
const int sleep_nsecs = 100;
258+
struct timespec ts = { 0, sleep_nsecs };
259+
nanosleep(&ts, NULL);
260+
}
261+
}
262+
263+
static ABT_unit pool_pop_timedwait(ABT_pool pool, double abstime_secs)
264+
{
265+
ABTI_pool *p_pool = ABTI_pool_get_ptr(pool);
266+
data_t *p_data = pool_get_data_ptr(p_pool->data);
267+
ABTI_thread *p_thread = NULL;
268+
269+
while (1) {
270+
if (spinlock_acquire_if_not_empty(p_data) == 0) {
271+
ABT_unit h_unit = ABT_UNIT_NULL;
272+
if (p_data->num_threads > 0) {
273+
p_thread = p_data->p_head;
274+
if (p_data->num_threads == 1) {
275+
p_data->p_head = NULL;
276+
p_data->p_tail = NULL;
277+
p_data->num_threads = 0;
278+
ABTD_atomic_release_store_int(&p_data->is_empty, 1);
279+
} else {
280+
p_thread->p_prev->p_next = p_thread->p_next;
281+
p_thread->p_next->p_prev = p_thread->p_prev;
282+
p_data->p_head = p_thread->p_next;
283+
p_data->num_threads--;
284+
}
285+
286+
p_thread->p_prev = NULL;
287+
p_thread->p_next = NULL;
288+
ABTD_atomic_release_store_int(&p_thread->is_in_pool, 0);
289+
290+
h_unit = (ABT_unit)p_thread;
221291
}
222-
/* Sleep. */
223-
const int sleep_nsecs = 100;
224-
struct timespec ts = { 0, sleep_nsecs };
225-
nanosleep(&ts, NULL);
292+
ABTD_spinlock_release(&p_data->mutex);
293+
if (h_unit != ABT_UNIT_NULL)
294+
return h_unit;
226295
}
227-
} while (h_unit == ABT_UNIT_NULL);
296+
const int sleep_nsecs = 100;
297+
struct timespec ts = { 0, sleep_nsecs };
298+
nanosleep(&ts, NULL);
228299

229-
return h_unit;
300+
if (ABTI_get_wtime() > abstime_secs)
301+
return ABT_UNIT_NULL;
302+
}
230303
}
231304

232-
static ABT_unit pool_pop_timedwait(ABT_pool pool, double abstime_secs)
305+
static ABT_unit pool_pop_shared(ABT_pool pool)
233306
{
234307
ABTI_pool *p_pool = ABTI_pool_get_ptr(pool);
235308
data_t *p_data = pool_get_data_ptr(p_pool->data);
236309
ABTI_thread *p_thread = NULL;
237-
ABT_unit h_unit = ABT_UNIT_NULL;
238310

239-
do {
240-
ABTD_spinlock_acquire(&p_data->mutex);
311+
if (spinlock_acquire_if_not_empty(p_data) == 0) {
312+
ABT_unit h_unit = ABT_UNIT_NULL;
241313
if (p_data->num_threads > 0) {
242314
p_thread = p_data->p_head;
243315
if (p_data->num_threads == 1) {
244316
p_data->p_head = NULL;
245317
p_data->p_tail = NULL;
318+
p_data->num_threads = 0;
319+
ABTD_atomic_release_store_int(&p_data->is_empty, 1);
246320
} else {
247321
p_thread->p_prev->p_next = p_thread->p_next;
248322
p_thread->p_next->p_prev = p_thread->p_prev;
249323
p_data->p_head = p_thread->p_next;
324+
p_data->num_threads--;
250325
}
251-
p_data->num_threads--;
252326

253327
p_thread->p_prev = NULL;
254328
p_thread->p_next = NULL;
255329
ABTD_atomic_release_store_int(&p_thread->is_in_pool, 0);
256330

257331
h_unit = (ABT_unit)p_thread;
258-
ABTD_spinlock_release(&p_data->mutex);
259-
} else {
260-
ABTD_spinlock_release(&p_data->mutex);
261-
/* Sleep. */
262-
const int sleep_nsecs = 100;
263-
struct timespec ts = { 0, sleep_nsecs };
264-
nanosleep(&ts, NULL);
265-
266-
if (ABTI_get_wtime() > abstime_secs)
267-
break;
268-
}
269-
} while (h_unit == ABT_UNIT_NULL);
270-
271-
return h_unit;
272-
}
273-
274-
static ABT_unit pool_pop_shared(ABT_pool pool)
275-
{
276-
ABTI_pool *p_pool = ABTI_pool_get_ptr(pool);
277-
data_t *p_data = pool_get_data_ptr(p_pool->data);
278-
ABTI_thread *p_thread = NULL;
279-
ABT_unit h_unit = ABT_UNIT_NULL;
280-
281-
ABTD_spinlock_acquire(&p_data->mutex);
282-
if (p_data->num_threads > 0) {
283-
p_thread = p_data->p_head;
284-
if (p_data->num_threads == 1) {
285-
p_data->p_head = NULL;
286-
p_data->p_tail = NULL;
287-
} else {
288-
p_thread->p_prev->p_next = p_thread->p_next;
289-
p_thread->p_next->p_prev = p_thread->p_prev;
290-
p_data->p_head = p_thread->p_next;
291332
}
292-
p_data->num_threads--;
293-
294-
p_thread->p_prev = NULL;
295-
p_thread->p_next = NULL;
296-
ABTD_atomic_release_store_int(&p_thread->is_in_pool, 0);
297-
298-
h_unit = (ABT_unit)p_thread;
333+
ABTD_spinlock_release(&p_data->mutex);
334+
return h_unit;
335+
} else {
336+
return ABT_UNIT_NULL;
299337
}
300-
ABTD_spinlock_release(&p_data->mutex);
301-
302-
return h_unit;
303338
}
304339

305340
static ABT_unit pool_pop_private(ABT_pool pool)
306341
{
307342
ABTI_pool *p_pool = ABTI_pool_get_ptr(pool);
308343
data_t *p_data = pool_get_data_ptr(p_pool->data);
309344
ABTI_thread *p_thread = NULL;
310-
ABT_unit h_unit = ABT_UNIT_NULL;
311345

346+
ABT_unit h_unit = ABT_UNIT_NULL;
312347
if (p_data->num_threads > 0) {
313348
p_thread = p_data->p_head;
314349
if (p_data->num_threads == 1) {
315350
p_data->p_head = NULL;
316351
p_data->p_tail = NULL;
352+
p_data->num_threads = 0;
353+
ABTD_atomic_relaxed_store_int(&p_data->is_empty, 1);
317354
} else {
318355
p_thread->p_prev->p_next = p_thread->p_next;
319356
p_thread->p_next->p_prev = p_thread->p_prev;
320357
p_data->p_head = p_thread->p_next;
358+
p_data->num_threads--;
321359
}
322-
p_data->num_threads--;
323360

324361
p_thread->p_prev = NULL;
325362
p_thread->p_next = NULL;
326363
ABTD_atomic_release_store_int(&p_thread->is_in_pool, 0);
327364

328365
h_unit = (ABT_unit)p_thread;
329366
}
330-
331367
return h_unit;
332368
}
333369

@@ -345,6 +381,8 @@ static int pool_remove_shared(ABT_pool pool, ABT_unit unit)
345381
if (p_data->num_threads == 1) {
346382
p_data->p_head = NULL;
347383
p_data->p_tail = NULL;
384+
p_data->num_threads = 0;
385+
ABTD_atomic_release_store_int(&p_data->is_empty, 1);
348386
} else {
349387
p_thread->p_prev->p_next = p_thread->p_next;
350388
p_thread->p_next->p_prev = p_thread->p_prev;
@@ -353,8 +391,8 @@ static int pool_remove_shared(ABT_pool pool, ABT_unit unit)
353391
} else if (p_thread == p_data->p_tail) {
354392
p_data->p_tail = p_thread->p_prev;
355393
}
394+
p_data->num_threads--;
356395
}
357-
p_data->num_threads--;
358396

359397
ABTD_atomic_release_store_int(&p_thread->is_in_pool, 0);
360398
ABTD_spinlock_release(&p_data->mutex);
@@ -378,6 +416,8 @@ static int pool_remove_private(ABT_pool pool, ABT_unit unit)
378416
if (p_data->num_threads == 1) {
379417
p_data->p_head = NULL;
380418
p_data->p_tail = NULL;
419+
p_data->num_threads = 0;
420+
ABTD_atomic_relaxed_store_int(&p_data->is_empty, 1);
381421
} else {
382422
p_thread->p_prev->p_next = p_thread->p_next;
383423
p_thread->p_next->p_prev = p_thread->p_prev;
@@ -386,8 +426,8 @@ static int pool_remove_private(ABT_pool pool, ABT_unit unit)
386426
} else if (p_thread == p_data->p_tail) {
387427
p_data->p_tail = p_thread->p_prev;
388428
}
429+
p_data->num_threads--;
389430
}
390-
p_data->num_threads--;
391431

392432
ABTD_atomic_release_store_int(&p_thread->is_in_pool, 0);
393433
p_thread->p_prev = NULL;

0 commit comments

Comments
 (0)