Test queued cancellation against running work and reserved cleanup
This commit is contained in:
1 parent
1a7f877f32
commit
ae26d626c8
1 file changed
+58
-1
@@ -519,6 +519,63 @@ static void worker_completion_test(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
struct cancel_case {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t condition;
|
||||
int started, released, worked, done, cancelled;
|
||||
};
|
||||
|
||||
static void cancel_block(void* arg) {
|
||||
struct cancel_case* t = arg;
|
||||
pthread_mutex_lock(&t->mutex); t->started = 1; pthread_cond_signal(&t->condition);
|
||||
while (!t->released) pthread_cond_wait(&t->condition, &t->mutex);
|
||||
pthread_mutex_unlock(&t->mutex); t->worked++;
|
||||
}
|
||||
static void cancel_work(void* arg) { ((struct cancel_case*)arg)->worked++; }
|
||||
static void cancel_done(void* arg, int error) {
|
||||
struct cancel_case* t = arg;
|
||||
EXPECT(!error || error == MF_WORK_CANCELLED, "cancel completion status");
|
||||
t->done++; t->cancelled += error == MF_WORK_CANCELLED;
|
||||
}
|
||||
|
||||
/* Диск стоит на барьере: отмена головы/хвоста не выполняет work и сохраняет обязательную cleanup. */
|
||||
static void worker_cancel_test(void) {
|
||||
size_t before = u_get_allocated_count();
|
||||
struct cancel_case running = { .mutex = PTHREAD_MUTEX_INITIALIZER, .condition = PTHREAD_COND_INITIALIZER };
|
||||
struct cancel_case head = {0}, tail = {0};
|
||||
struct UASYNC* ua = uasync_create();
|
||||
struct mf_worker* worker = ua ? mf_worker_create(ua) : NULL;
|
||||
struct mf_work* cleanup = mf_worker_reserve();
|
||||
EXPECT(worker && cleanup, "cancel worker fixture");
|
||||
if (worker && cleanup) {
|
||||
mf_worker_submit(worker, cancel_block, &running, cancel_done, &running);
|
||||
pthread_mutex_lock(&running.mutex);
|
||||
while (!running.started) pthread_cond_wait(&running.condition, &running.mutex);
|
||||
pthread_mutex_unlock(&running.mutex);
|
||||
mf_worker_submit(worker, cancel_work, &head, cancel_done, &head);
|
||||
mf_worker_submit_reserved(worker, cleanup, cancel_work, &head, cancel_done, &head); cleanup = NULL;
|
||||
mf_worker_submit(worker, cancel_work, &tail, cancel_done, &tail);
|
||||
EXPECT(mf_worker_cancel(worker, &running) == 0, "running work cannot be cancelled");
|
||||
EXPECT(mf_worker_cancel(worker, &head) == 1, "cancel head preserves reserved cleanup with same data");
|
||||
EXPECT(mf_worker_cancel(worker, &tail) == 1, "cancel tail");
|
||||
EXPECT(mf_worker_cancel(worker, &head) == 0, "cancel is idempotent");
|
||||
uasync_poll(ua, 0);
|
||||
EXPECT(head.done == 1 && head.cancelled == 1 && tail.done == 1 && tail.cancelled == 1,
|
||||
"cancel completion delivered while disk remains blocked");
|
||||
EXPECT(!head.worked && !tail.worked && !running.done, "cancelled work has no side effects");
|
||||
pthread_mutex_lock(&running.mutex); running.released = 1; pthread_cond_signal(&running.condition);
|
||||
pthread_mutex_unlock(&running.mutex);
|
||||
}
|
||||
mf_worker_destroy(worker); mf_worker_unreserve(cleanup);
|
||||
if (ua) { uasync_poll(ua, 0); uasync_destroy(ua, 1); }
|
||||
EXPECT(running.worked == 1 && running.done == 1 && !running.cancelled, "running command finishes once");
|
||||
EXPECT(head.worked == 1 && head.done == 2 && head.cancelled == 1, "reserved cleanup finishes once");
|
||||
EXPECT(!tail.worked && tail.done == 1 && tail.cancelled == 1, "cancelled tail never executes");
|
||||
pthread_cond_destroy(&running.condition); pthread_mutex_destroy(&running.mutex);
|
||||
EXPECT(u_get_allocated_count() == before, "cancelled jobs/completions freed");
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "worker cancellation: queued jobs skipped, running command and reserved cleanup completed");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_MEDIA, DEBUG_LEVEL_DEBUG);
|
||||
char directory[1024] = "/tmp/utun_member_files_XXXXXX";
|
||||
@@ -528,7 +585,7 @@ int main(void) {
|
||||
#ifndef _WIN32
|
||||
local_fifo_test(directory); large_offset_test(directory);
|
||||
#endif
|
||||
worker_test();
|
||||
worker_test(); worker_cancel_test();
|
||||
#ifdef __linux__
|
||||
worker_completion_test();
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user