@@ -157,6 +157,12 @@ sentry__task_decref(sentry_bgworker_task_t *task)
157157 }
158158}
159159
160+ enum {
161+ SENTRY_BGW_STOPPED = 0 ,
162+ SENTRY_BGW_RUNNING = 1 ,
163+ SENTRY_BGW_STOPPING = 2 ,
164+ };
165+
160166struct sentry_bgworker_s {
161167 sentry_threadid_t thread_id ;
162168 char * thread_name ;
@@ -169,7 +175,7 @@ struct sentry_bgworker_s {
169175 void * state ;
170176 void (* free_state )(void * state );
171177 long refcount ;
172- long running ;
178+ long status ; // SENTRY_BGW_*
173179};
174180
175181sentry_bgworker_t *
@@ -236,9 +242,14 @@ sentry__bgworker_get_state(sentry_bgworker_t *bgw)
236242static bool
237243sentry__bgworker_is_done (sentry_bgworker_t * bgw )
238244{
239- return (!bgw -> first_task
240- || sentry__monotonic_time () < bgw -> first_task -> execute_after )
241- && !sentry__atomic_fetch (& bgw -> running );
245+ long status = sentry__atomic_fetch (& bgw -> status );
246+ if (status == SENTRY_BGW_STOPPING ) {
247+ // stop immediately to leave remaining tasks in the queue
248+ return true;
249+ }
250+ return status != SENTRY_BGW_RUNNING
251+ && (!bgw -> first_task
252+ || sentry__monotonic_time () < bgw -> first_task -> execute_after );
242253}
243254
244255SENTRY_THREAD_FN
@@ -317,11 +328,11 @@ int
317328sentry__bgworker_start (sentry_bgworker_t * bgw )
318329{
319330 SENTRY_DEBUG ("starting background worker thread" );
320- sentry__atomic_store (& bgw -> running , 1 );
331+ sentry__atomic_store (& bgw -> status , SENTRY_BGW_RUNNING );
321332 // this incref moves the reference into the background thread
322333 sentry__bgworker_incref (bgw );
323334 if (sentry__thread_spawn (& bgw -> thread_id , & worker_thread , bgw ) != 0 ) {
324- sentry__atomic_store (& bgw -> running , 0 );
335+ sentry__atomic_store (& bgw -> status , SENTRY_BGW_STOPPED );
325336 sentry__bgworker_decref (bgw );
326337 return 1 ;
327338 }
@@ -358,7 +369,7 @@ sentry__flush_task_decref(sentry_flush_task_t *task)
358369int
359370sentry__bgworker_flush (sentry_bgworker_t * bgw , uint64_t timeout )
360371{
361- if (! sentry__atomic_fetch (& bgw -> running ) ) {
372+ if (sentry__atomic_fetch (& bgw -> status ) != SENTRY_BGW_RUNNING ) {
362373 SENTRY_WARN ("trying to flush non-running thread" );
363374 return 0 ;
364375 }
@@ -421,14 +432,14 @@ static void
421432shutdown_task (void * task_data , void * UNUSED (state ))
422433{
423434 sentry_bgworker_t * bgw = task_data ;
424- sentry__atomic_store (& bgw -> running , 0 );
435+ sentry__atomic_store (& bgw -> status , SENTRY_BGW_STOPPED );
425436}
426437
427438int
428439sentry__bgworker_shutdown_cb (sentry_bgworker_t * bgw , uint64_t timeout ,
429440 void (* on_timeout )(void * ), void * on_timeout_data )
430441{
431- if (! sentry__atomic_fetch (& bgw -> running ) ) {
442+ if (sentry__atomic_fetch (& bgw -> status ) != SENTRY_BGW_RUNNING ) {
432443 SENTRY_WARN ("trying to shut down non-running thread" );
433444 return 0 ;
434445 }
@@ -443,16 +454,18 @@ sentry__bgworker_shutdown_cb(sentry_bgworker_t *bgw, uint64_t timeout,
443454 uint64_t now = sentry__monotonic_time ();
444455 if (now > started && now - started > timeout ) {
445456 if (on_timeout ) {
446- // fire on_timeout to cancel the ongoing task, and give the
447- // worker an extra loop cycle up to 250ms to handle the
448- // cancellation
457+ // fire on_timeout to cancel the ongoing task, and tell
458+ // the worker to stop so remaining tasks stay in the
459+ // queue for dumping. the worker gets up to 250ms for
460+ // graceful cancellation before the thread is detached.
449461 sentry__mutex_unlock (& bgw -> task_lock );
450462 on_timeout (on_timeout_data );
463+ sentry__atomic_store (& bgw -> status , SENTRY_BGW_STOPPING );
451464 on_timeout = NULL ;
452465 sentry__mutex_lock (& bgw -> task_lock );
453- // fall through to !running check below
466+ // fall through to detach on next timeout
454467 } else {
455- sentry__atomic_store (& bgw -> running , 0 );
468+ sentry__atomic_store (& bgw -> status , SENTRY_BGW_STOPPING );
456469 sentry__thread_detach (bgw -> thread_id );
457470 sentry__mutex_unlock (& bgw -> task_lock );
458471 SENTRY_WARN ("background thread failed to shut down cleanly "
@@ -461,7 +474,7 @@ sentry__bgworker_shutdown_cb(sentry_bgworker_t *bgw, uint64_t timeout,
461474 }
462475 }
463476
464- if (! sentry__atomic_fetch (& bgw -> running ) ) {
477+ if (sentry__atomic_fetch (& bgw -> status ) == SENTRY_BGW_STOPPED ) {
465478 sentry__mutex_unlock (& bgw -> task_lock );
466479 sentry__thread_join (bgw -> thread_id );
467480 return 0 ;
0 commit comments