29 /** |
36 /** |
30 * Dequeue a piece of work |
37 * Dequeue a piece of work |
31 */ |
38 */ |
32 static void pt_work_dequeue (struct pt_ctx *ctx, struct pt_work **work_ptr) |
39 static void pt_work_dequeue (struct pt_ctx *ctx, struct pt_work **work_ptr) |
33 { |
40 { |
34 // acquire |
41 // acquire, cancel-safe |
|
42 pthread_cleanup_push(pt_mutex_unlock, &ctx->work_mutex); |
35 assert(!pthread_mutex_lock(&ctx->work_mutex)); |
43 assert(!pthread_mutex_lock(&ctx->work_mutex)); |
36 |
44 |
37 // idle? |
45 // idle? |
38 if (TAILQ_EMPTY(&ctx->work)) |
46 if (TAILQ_EMPTY(&ctx->work)) |
39 assert(!pthread_cond_signal(&ctx->idle_cond)); |
47 assert(!pthread_cond_signal(&ctx->idle_cond)); |
40 |
48 |
41 // wait for work |
49 // wait for work |
42 while (TAILQ_EMPTY(&ctx->work)) |
50 while (TAILQ_EMPTY(&ctx->work)) |
|
51 // we can expect to get pthread_cancel'd here |
43 assert(!pthread_cond_wait(&ctx->work_cond, &ctx->work_mutex)); |
52 assert(!pthread_cond_wait(&ctx->work_cond, &ctx->work_mutex)); |
44 |
53 |
45 // pop work |
54 // pop work |
46 *work_ptr = TAILQ_FIRST(&ctx->work); |
55 *work_ptr = TAILQ_FIRST(&ctx->work); |
47 TAILQ_REMOVE(&ctx->work, *work_ptr, ctx_work); |
56 TAILQ_REMOVE(&ctx->work, *work_ptr, ctx_work); |
48 |
57 |
49 // release |
58 // release |
50 assert(!pthread_mutex_unlock(&ctx->work_mutex)); |
59 pthread_cleanup_pop(true); |
51 } |
60 } |
52 |
61 |
53 /** |
62 /** |
54 * Wait for work queue to become empty |
63 * Wait for work queue to become empty |
55 */ |
64 */ |