/*! Handle sandbox stop event. It will call the corresponding task stop callback, and remove the task from task_map. @param id Task ID. */ static void sandbox_stop_callback(uint64_t id) { auto task_it = task_map.find(id); assert(task_it != task_map.end()); Task task = task_it->second; assert(task.callback != NULL); task.callback(id, task.sdbx->stat, task.data); task_map.erase(task_it); INFO("Task %lu finished.\n", id); }
static int taskmgr_thread(void *arg) { TaskManager *mgr = arg; attr_unused SDL_threadID tid = SDL_ThreadID(); if(SDL_SetThreadPriority(mgr->thread_prio) < 0) { log_sdl_error(LOG_WARN, "SDL_SetThreadPriority"); } bool running; bool aborted; do { SDL_LockMutex(mgr->mutex); running = mgr->running; aborted = mgr->aborted; if(!running && !aborted) { SDL_CondWait(mgr->cond, mgr->mutex); } SDL_UnlockMutex(mgr->mutex); } while(!running && !aborted); while(running && !aborted) { SDL_LockMutex(mgr->mutex); Task *task = alist_pop(&mgr->queue); running = mgr->running; aborted = mgr->aborted; if(running && task == NULL && !aborted) { SDL_CondWait(mgr->cond, mgr->mutex); } SDL_UnlockMutex(mgr->mutex); if(task != NULL) { SDL_LockMutex(task->mutex); bool task_disowned = task->disowned; if(aborted && task->status == TASK_PENDING) { task->status = TASK_CANCELLED; } if(task->status == TASK_PENDING) { task->status = TASK_RUNNING; SDL_UnlockMutex(task->mutex); task->result = task->callback(task->userdata); SDL_LockMutex(task->mutex); assert(task->in_queue); task->in_queue = false; (void)SDL_AtomicDecRef(&mgr->numtasks); if((task_disowned = task->disowned)) { SDL_UnlockMutex(task->mutex); task_free(task); } else { task->status = TASK_FINISHED; SDL_CondBroadcast(task->cond); SDL_UnlockMutex(task->mutex); } } else if(task->status == TASK_CANCELLED) { assert(task->in_queue); task->in_queue = false; (void)SDL_AtomicDecRef(&mgr->numtasks); SDL_UnlockMutex(task->mutex); if(task_disowned) { task_free(task); } } else { UNREACHABLE; } } } return 0; }