Skip to content

Commit a4428e0

Browse files
jpnurmiclaude
andcommitted
Add sentry__bgworker_submit_at for absolute timestamps
Extract the core submission logic into submit_at which takes an absolute execute_after time. submit and submit_delayed become thin wrappers. Use submit_at in bgworker_delayed_tasks to pin all tasks to a single base timestamp, making the test ordering deterministic regardless of OS preemption between submissions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2985913 commit a4428e0

File tree

3 files changed

+45
-34
lines changed

3 files changed

+45
-34
lines changed

src/sentry_sync.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -470,14 +470,27 @@ sentry__bgworker_submit(sentry_bgworker_t *bgw,
470470
sentry_task_exec_func_t exec_func, void (*cleanup_func)(void *task_data),
471471
void *task_data)
472472
{
473-
return sentry__bgworker_submit_delayed(
474-
bgw, exec_func, cleanup_func, task_data, 0);
473+
SENTRY_DEBUG("submitting task to background worker thread");
474+
return sentry__bgworker_submit_at(
475+
bgw, exec_func, cleanup_func, task_data, sentry__monotonic_time());
475476
}
476477

477478
int
478479
sentry__bgworker_submit_delayed(sentry_bgworker_t *bgw,
479480
sentry_task_exec_func_t exec_func, void (*cleanup_func)(void *task_data),
480481
void *task_data, uint64_t delay_ms)
482+
{
483+
SENTRY_DEBUGF("submitting %" PRIu64
484+
" ms delayed task to background worker thread",
485+
delay_ms);
486+
return sentry__bgworker_submit_at(bgw, exec_func, cleanup_func, task_data,
487+
sentry__monotonic_time() + delay_ms);
488+
}
489+
490+
int
491+
sentry__bgworker_submit_at(sentry_bgworker_t *bgw,
492+
sentry_task_exec_func_t exec_func, void (*cleanup_func)(void *task_data),
493+
void *task_data, uint64_t execute_after)
481494
{
482495
sentry_bgworker_task_t *task = SENTRY_MAKE(sentry_bgworker_task_t);
483496
if (!task) {
@@ -488,18 +501,11 @@ sentry__bgworker_submit_delayed(sentry_bgworker_t *bgw,
488501
}
489502
task->next_task = NULL;
490503
task->refcount = 1;
491-
task->execute_after = sentry__monotonic_time() + delay_ms;
504+
task->execute_after = execute_after;
492505
task->exec_func = exec_func;
493506
task->cleanup_func = cleanup_func;
494507
task->task_data = task_data;
495508

496-
if (delay_ms > 0) {
497-
SENTRY_DEBUGF("submitting %" PRIu64
498-
" ms delayed task to background worker thread",
499-
delay_ms);
500-
} else {
501-
SENTRY_DEBUG("submitting task to background worker thread");
502-
}
503509
sentry__mutex_lock(&bgw->task_lock);
504510

505511
if (!bgw->first_task) {

src/sentry_sync.h

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -471,24 +471,23 @@ const char *sentry__bgworker_get_thread_name(sentry_bgworker_t *bgw);
471471
/**
472472
* This will submit a new task to the background thread.
473473
*
474+
* The `_delayed` variant delays execution by the specified delay in
475+
* milliseconds, and the `_at` variant executes after the specified monotonic
476+
* timestamp. The latter is mostly useful for testing to ensure deterministic
477+
* ordering of tasks regardless of OS preemption between submissions.
478+
*
474479
* Takes ownership of `data`, freeing it using the provided `cleanup_func`.
475480
* Returns 0 on success.
476481
*/
477482
int sentry__bgworker_submit(sentry_bgworker_t *bgw,
478483
sentry_task_exec_func_t exec_func, void (*cleanup_func)(void *task_data),
479484
void *task_data);
480-
481-
/**
482-
* This will submit a new delayed task to the background thread.
483-
*
484-
* Execution is deferred by `delay_ms` milliseconds.
485-
*
486-
* Takes ownership of `data`, freeing it using the provided `cleanup_func`.
487-
* Returns 0 on success.
488-
*/
489485
int sentry__bgworker_submit_delayed(sentry_bgworker_t *bgw,
490486
sentry_task_exec_func_t exec_func, void (*cleanup_func)(void *task_data),
491487
void *task_data, uint64_t delay_ms);
488+
int sentry__bgworker_submit_at(sentry_bgworker_t *bgw,
489+
sentry_task_exec_func_t exec_func, void (*cleanup_func)(void *task_data),
490+
void *task_data, uint64_t execute_after);
492491

493492
/**
494493
* This function will iterate through all the current tasks of the worker

tests/unit/test_sync.c

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,12 @@ SENTRY_TEST(bgworker_delayed_tasks)
234234
sentry_bgworker_t *bgw = sentry__bgworker_new(&os, NULL);
235235
TEST_ASSERT(!!bgw);
236236

237+
// submit_at with a fixed base so ordering is deterministic regardless
238+
// of OS preemption between submissions (submit_delayed reads the clock
239+
// per call, so a pause between calls could shift execute_after values
240+
// and change the expected sort order)
241+
uint64_t base = sentry__monotonic_time();
242+
237243
// all tasks sorted by execute_after: immediate (0) first, then delayed
238244
// by deadline
239245
//
@@ -248,21 +254,21 @@ SENTRY_TEST(bgworker_delayed_tasks)
248254
// i(1) i(6) i(7) i(8) d50(2) d100(3) d150(4) d200(5)
249255
// i(1) i(6) i(7) i(8) d50(2) d75(9) d100(3) d150(4) d200(5)
250256
// i(1) i(6) i(7) i(8) i(10) d50(2) d75(9) d100(3) d150(4) d200(5)
251-
sentry__bgworker_submit(bgw, record_order_task, NULL, (void *)1);
252-
sentry__bgworker_submit_delayed(
253-
bgw, record_order_task, NULL, (void *)3, 100);
254-
sentry__bgworker_submit(bgw, record_order_task, NULL, (void *)6);
255-
sentry__bgworker_submit_delayed(
256-
bgw, record_order_task, NULL, (void *)2, 50);
257-
sentry__bgworker_submit(bgw, record_order_task, NULL, (void *)7);
258-
sentry__bgworker_submit_delayed(
259-
bgw, record_order_task, NULL, (void *)5, 200);
260-
sentry__bgworker_submit_delayed(
261-
bgw, record_order_task, NULL, (void *)4, 150);
262-
sentry__bgworker_submit(bgw, record_order_task, NULL, (void *)8);
263-
sentry__bgworker_submit_delayed(
264-
bgw, record_order_task, NULL, (void *)9, 75);
265-
sentry__bgworker_submit(bgw, record_order_task, NULL, (void *)10);
257+
sentry__bgworker_submit_at(bgw, record_order_task, NULL, (void *)1, base);
258+
sentry__bgworker_submit_at(
259+
bgw, record_order_task, NULL, (void *)3, base + 100);
260+
sentry__bgworker_submit_at(bgw, record_order_task, NULL, (void *)6, base);
261+
sentry__bgworker_submit_at(
262+
bgw, record_order_task, NULL, (void *)2, base + 50);
263+
sentry__bgworker_submit_at(bgw, record_order_task, NULL, (void *)7, base);
264+
sentry__bgworker_submit_at(
265+
bgw, record_order_task, NULL, (void *)5, base + 200);
266+
sentry__bgworker_submit_at(
267+
bgw, record_order_task, NULL, (void *)4, base + 150);
268+
sentry__bgworker_submit_at(bgw, record_order_task, NULL, (void *)8, base);
269+
sentry__bgworker_submit_at(
270+
bgw, record_order_task, NULL, (void *)9, base + 75);
271+
sentry__bgworker_submit_at(bgw, record_order_task, NULL, (void *)10, base);
266272

267273
sentry__bgworker_start(bgw);
268274
TEST_CHECK_INT_EQUAL(sentry__bgworker_flush(bgw, 5000), 0);

0 commit comments

Comments
 (0)