@@ -154,7 +154,6 @@ work_pool_thread(void *arg)
154
154
155
155
pthread_cond_init (& wpt -> pqcond , NULL );
156
156
pthread_mutex_lock (& pool -> pqh .qmutex );
157
- TAILQ_INSERT_TAIL (& pool -> wptqh , wpt , wptq );
158
157
159
158
wpt -> worker_index = atomic_inc_uint32_t (& pool -> worker_index );
160
159
snprintf (wpt -> worker_name , sizeof (wpt -> worker_name ), "%.5s%" PRIu32 ,
@@ -185,21 +184,21 @@ work_pool_thread(void *arg)
185
184
wpt -> work = NULL ;
186
185
pthread_mutex_lock (& pool -> pqh .qmutex );
187
186
}
188
-
189
- if (0 > pool -> pqh .qcount ++ ) {
190
- /* negative for task(s) */
191
- have = TAILQ_FIRST (& pool -> pqh .qh );
187
+ /*
188
+ * Check for any queued work to avoid scheduling.
189
+ */
190
+ have = TAILQ_FIRST (& pool -> pqh .qh );
191
+ if (have ) {
192
192
TAILQ_REMOVE (& pool -> pqh .qh , have , q );
193
-
194
193
wpt -> work = (struct work_pool_entry * )have ;
195
194
continue ;
196
195
}
197
196
198
- /* positive for waiting worker(s):
199
- * use the otherwise empty pool to hold them,
200
- * simplifying mutex and pointer setup.
197
+ /*
198
+ * Add myself to waiting queue.
201
199
*/
202
- TAILQ_INSERT_TAIL (& pool -> pqh .qh , & wpt -> pqe , q );
200
+ pool -> pqh .qcount ++ ;
201
+ TAILQ_INSERT_TAIL (& pool -> wptqh , wpt , wptq );
203
202
204
203
__warnx (TIRPC_DEBUG_FLAG_WORKER ,
205
204
"%s() %s waiting" ,
@@ -208,32 +207,46 @@ work_pool_thread(void *arg)
208
207
clock_gettime (CLOCK_REALTIME_FAST , & ts );
209
208
timespec_addms (& ts , pool -> timeout_ms );
210
209
210
+ wpt -> wakeup = false;
211
+
211
212
/* Note: the mutex is the pool _head,
212
213
* but the condition is per worker,
213
214
* making the signal efficient!
214
215
*/
215
216
rc = pthread_cond_timedwait (& wpt -> pqcond , & pool -> pqh .qmutex ,
216
217
& ts );
217
- if (!wpt -> work ) {
218
- /* Allow for possible timing race:
219
- * work entry can be submitted by another
220
- * thread during the thread task switch
221
- * after shutdown or timeout?
222
- * Then, has already been removed there.
223
- */
218
+
219
+ /*
220
+ * Wokeup after work submit.
221
+ * It could be shutdown also.
222
+ */
223
+ if (!rc ) {
224
+ if (wpt -> wakeup )
225
+ continue ;
226
+ }
227
+
228
+ /*
229
+ * It could be timeout.
230
+ * There could be race if submit got lock and
231
+ * it will try to wakeup me.
232
+ */
233
+ if (!wpt -> wakeup ) {
224
234
pool -> pqh .qcount -- ;
225
- TAILQ_REMOVE (& pool -> pqh .qh , & wpt -> pqe , q );
235
+ TAILQ_REMOVE (& pool -> wptqh , wpt , wptq );
236
+ } else {
237
+ continue ;
226
238
}
239
+
227
240
if (rc && rc != ETIMEDOUT ) {
228
241
__warnx (TIRPC_DEBUG_FLAG_ERROR ,
229
242
"%s() cond_timedwait failed (%d)\n" ,
230
243
__func__ , rc );
231
244
break ;
232
245
}
233
- } while (wpt -> work || pool -> pqh .qcount < pool -> params .thrd_min );
246
+ } while (wpt -> work || wpt -> wakeup ||
247
+ pool -> pqh .qcount < pool -> params .thrd_min );
234
248
235
249
pool -> n_threads -- ;
236
- TAILQ_REMOVE (& pool -> wptqh , wpt , wptq );
237
250
pthread_mutex_unlock (& pool -> pqh .qmutex );
238
251
239
252
__warnx (TIRPC_DEBUG_FLAG_WORKER ,
@@ -274,26 +287,23 @@ work_pool_submit(struct work_pool *pool, struct work_pool_entry *work)
274
287
/* queue is draining */
275
288
return (0 );
276
289
}
277
- pthread_mutex_lock (& pool -> pqh .qmutex );
278
-
279
- if (0 < pool -> pqh .qcount -- ) {
280
- struct work_pool_thread * wpt = (struct work_pool_thread * )
281
- TAILQ_FIRST (& pool -> pqh .qh );
282
290
283
- /* positive for waiting worker(s) */
284
- TAILQ_REMOVE (& pool -> pqh .qh , & wpt -> pqe , q );
285
- wpt -> work = work ;
286
-
287
- /* Note: the mutex is the pool _head,
288
- * but the condition is per worker,
289
- * making the signal efficient!
290
- */
291
+ pthread_mutex_lock (& pool -> pqh .qmutex );
292
+ /*
293
+ * Insert in work queue so that running thread can
294
+ * pickup without scheduling.
295
+ */
296
+ TAILQ_INSERT_TAIL (& pool -> pqh .qh , & work -> pqe , q );
297
+ struct work_pool_thread * wpt = TAILQ_LAST (& pool -> wptqh , work_pool_s );
298
+ if (wpt ) {
299
+ pool -> pqh .qcount -- ;
300
+ TAILQ_REMOVE (& pool -> wptqh , wpt , wptq );
301
+ assert (!wpt -> wakeup );
302
+ wpt -> wakeup = true;
291
303
pthread_cond_signal (& wpt -> pqcond );
292
304
} else {
293
- /* negative for task(s) */
294
- TAILQ_INSERT_TAIL (& pool -> pqh .qh , & work -> pqe , q );
305
+ assert (pool -> pqh .qcount == 0 );
295
306
}
296
-
297
307
pthread_mutex_unlock (& pool -> pqh .qmutex );
298
308
return rc ;
299
309
}
0 commit comments