|
|
|
|
@ -27,12 +27,11 @@ struct ma_thread_ctx {
|
|
|
|
|
struct ma_thread_ctx* next; |
|
|
|
|
struct UASYNC* ua; |
|
|
|
|
pthread_t thread; |
|
|
|
|
void* timer; |
|
|
|
|
struct posted_task* completion; |
|
|
|
|
ma_work_fn work; |
|
|
|
|
void* data; |
|
|
|
|
ma_done_fn done; |
|
|
|
|
void* arg; |
|
|
|
|
int finished; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static void ma_finish(struct ma_thread_ctx* job, int error) { |
|
|
|
|
@ -44,21 +43,17 @@ static void ma_finish(struct ma_thread_ctx* job, int error) {
|
|
|
|
|
u_free(job); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void ma_poll(void* arg) { |
|
|
|
|
struct ma_thread_ctx* job = arg; job->timer = NULL; |
|
|
|
|
if (__atomic_load_n(&job->finished, __ATOMIC_ACQUIRE)) { ma_finish(job, 0); return; } |
|
|
|
|
job->timer = uasync_set_timeout(job->ua, 100, job, ma_poll, "media_worker"); |
|
|
|
|
if (!job->timer) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media worker completion timer failed"); |
|
|
|
|
ma_finish(job, -1); |
|
|
|
|
} |
|
|
|
|
/* Completion приходит только после работы; ожидать незавершённый worker здесь нельзя. */ |
|
|
|
|
static void ma_completed(void* arg) { |
|
|
|
|
struct ma_thread_ctx* job = arg; |
|
|
|
|
job->completion = NULL; |
|
|
|
|
ma_finish(job, 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void* ma_thread_entry(void* arg) { |
|
|
|
|
struct ma_thread_ctx* job = arg; |
|
|
|
|
job->work(job->data); |
|
|
|
|
__atomic_store_n(&job->finished, 1, __ATOMIC_RELEASE); |
|
|
|
|
uasync_wakeup(job->ua); |
|
|
|
|
uasync_post_reserved(job->ua, job->completion); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -75,8 +70,11 @@ void media_async_destroy(struct media_async* ma) {
|
|
|
|
|
unsigned cancelled = 0; |
|
|
|
|
while (ma->jobs) { |
|
|
|
|
struct ma_thread_ctx* job = ma->jobs; |
|
|
|
|
if (job->timer) uasync_cancel_timeout(job->ua, job->timer); |
|
|
|
|
ma_finish(job, MEDIA_ASYNC_CANCELLED); cancelled++; |
|
|
|
|
pthread_join(job->thread, NULL); |
|
|
|
|
uasync_cancel_post(job->ua, job->completion); |
|
|
|
|
ma->jobs = job->next; |
|
|
|
|
job->done(job->arg, MEDIA_ASYNC_CANCELLED); |
|
|
|
|
u_free(job); cancelled++; |
|
|
|
|
} |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "media_async: destroyed cancelled=%u", cancelled); |
|
|
|
|
u_free(ma); |
|
|
|
|
@ -92,12 +90,14 @@ void media_async_submit(struct media_async* ma, struct UASYNC* ua,
|
|
|
|
|
struct ma_thread_ctx* job = u_calloc(1, sizeof(*job)); |
|
|
|
|
if (!job) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media task allocation failed"); done(arg, -1); return; } |
|
|
|
|
job->owner = ma; job->ua = ua; job->work = work; job->data = data; job->done = done; job->arg = arg; |
|
|
|
|
job->timer = uasync_set_timeout(ua, 1, job, ma_poll, "media_worker"); |
|
|
|
|
if (!job->timer) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media task timer failed"); u_free(job); done(arg, -1); return; } |
|
|
|
|
job->completion = u_calloc(1, sizeof(*job->completion)); |
|
|
|
|
if (!job->completion) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media completion allocation failed"); u_free(job); done(arg, -1); return; } |
|
|
|
|
job->completion->callback = ma_completed; |
|
|
|
|
job->completion->arg = job; |
|
|
|
|
int rc = pthread_create(&job->thread, NULL, ma_thread_entry, job); |
|
|
|
|
if (rc) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "media task thread failed rc=%d", rc); |
|
|
|
|
uasync_cancel_timeout(ua, job->timer); u_free(job); done(arg, -1); return; |
|
|
|
|
u_free(job->completion); u_free(job); done(arg, -1); return; |
|
|
|
|
} |
|
|
|
|
job->next = ma->jobs; ma->jobs = job; |
|
|
|
|
} |
|
|
|
|
|