178 lines
5.7 KiB
C
178 lines
5.7 KiB
C
/*
|
|
* This software is licensed under the terms of the MIT License.
|
|
* See COPYING for further information.
|
|
* ---
|
|
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
|
|
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
|
|
*/
|
|
|
|
#pragma once
|
|
#include "taisei.h"
|
|
|
|
#include "thread.h"
|
|
|
|
typedef struct TaskManager TaskManager;
|
|
typedef struct Task Task;
|
|
|
|
typedef enum TaskStatus {
|
|
TASK_INVALID, /** Indicates an error */
|
|
TASK_PENDING, /** Task is still in queue and can be cancelled */
|
|
TASK_RUNNING, /** Task is currently executing and can not be cancelled */
|
|
TASK_CANCELLED, /** Task has been cancelled and will not run */
|
|
TASK_FINISHED, /** Task has finished executing and has been removed from the queue */
|
|
} TaskStatus;
|
|
|
|
typedef void *(*task_func_t)(void *userdata);
|
|
typedef void (*task_free_func_t)(void *userdata);
|
|
|
|
/**
|
|
* Parameters for `taskmgr_submit`. See its documentation below.
|
|
*/
|
|
typedef struct TaskParams {
|
|
/**
|
|
* The function implementing the task. Must not be NULL.
|
|
* The return value may be anything. It can be obtained with `task_wait` or `task_finish`.
|
|
*/
|
|
task_func_t callback;
|
|
|
|
/**
|
|
* Value passed as argument to callback.
|
|
*/
|
|
void *userdata;
|
|
|
|
/**
|
|
* Unless NULL, this function will be called when userdata should be freed.
|
|
* You should use it instead of releasing resources in the task function. It's guaranteed to
|
|
* be called even if the task has been cancelled.
|
|
*
|
|
* This function may be called from any thread, so be careful what you do with it.
|
|
*/
|
|
task_free_func_t userdata_free_callback;
|
|
|
|
/**
|
|
* Priority of the task. Lower values mean higher priority. Higher priority tasks are added
|
|
* to the queue ahead of the lower priority ones, and thus will start executing sooner. Note
|
|
* that this affects only the pending tasks. A task that already began executing cannot be
|
|
* interrupted, regardless of its priority.
|
|
*/
|
|
int prio;
|
|
|
|
/**
|
|
* If true, this task will be inserted ahead of the others with the same priority, if any.
|
|
* Otherwise, it'll be put behind them instead.
|
|
*/
|
|
bool topmost;
|
|
} TaskParams;
|
|
|
|
/**
|
|
* Create a new TaskManager with [numthreads] worker threads, and set their priority to [prio].
|
|
* If [numthreads] is 0, a default based on the amount of system's CPU cores will be used.
|
|
* The actual amount of threads spawned may be lower than requested.
|
|
*
|
|
* [name] is used to form names of the worker threads. Keep it short.
|
|
*
|
|
* On success, returns a pointer to the created TaskManager.
|
|
* On failure, returns NULL.
|
|
*/
|
|
TaskManager *taskmgr_create(uint numthreads, ThreadPriority prio, const char *name)
|
|
attr_nodiscard attr_returns_max_aligned attr_nonnull(3);
|
|
|
|
/**
|
|
* Submit a new task to [mgr] described by [params]. It is generally placed at the end of the
|
|
* task manager's queue, but that can be influenced with [params.prio] and [params.topmost].
|
|
*
|
|
* See documentation for TaskParams above.
|
|
*
|
|
* However, you should not rely on the tasks being actually executed in any specific order, in
|
|
* particular if the task manager is multi-threaded.
|
|
*
|
|
* On success, returns a pointer to a Task structure, which must be eventually passed to one of
|
|
* `task_detach`, `task_finish`, or `task_abort`. Not doing so is a resource leak.
|
|
*
|
|
* On failure, returns NULL.
|
|
*/
|
|
Task *taskmgr_submit(TaskManager *mgr, TaskParams params)
|
|
attr_nonnull(1) attr_nodiscard attr_returns_max_aligned;
|
|
|
|
/**
|
|
* Returns the number of remaining tasks in [mgr]'s queue.
|
|
*/
|
|
uint taskmgr_remaining(TaskManager *mgr)
|
|
attr_nonnull(1);
|
|
|
|
/**
|
|
* Wait for all remaining tasks to complete, then destroy [mgr], freeing associated resources.
|
|
* [mgr] must be treated as an invalid pointer as soon as this function is called.
|
|
*/
|
|
void taskmgr_finish(TaskManager *mgr)
|
|
attr_nonnull(1);
|
|
|
|
/**
|
|
* Cancel all pending tasks, wait for all running tasks to complete, then destroy [mgr], freeing
|
|
* associated resources. [mgr] must be treated as an invalid pointer as soon as this function
|
|
* is called.
|
|
*/
|
|
void taskmgr_abort(TaskManager *mgr)
|
|
attr_nonnull(1);
|
|
|
|
/**
|
|
* Returns the current status of [task]. See TaskStatus documentation above.
|
|
* Returns TASK_INVALID on failure.
|
|
*/
|
|
TaskStatus task_status(Task *task);
|
|
|
|
/**
|
|
* Wait for [task] to complete. If the task is not running yet, it will be removed from the queue and
|
|
* executed on the current thread instead.
|
|
*
|
|
* On success, returns true and stores the task's return value in [result] (unless [result] is NULL).
|
|
* On failure, returns false; [result] is left untouched.
|
|
*/
|
|
bool task_wait(Task *task, void **result);
|
|
|
|
/**
|
|
* Cancel a pending [task].
|
|
* This does not stop an already running task.
|
|
*
|
|
* Returns true on success, false on failure.
|
|
*/
|
|
bool task_cancel(Task *task);
|
|
|
|
/**
|
|
* Disown the [task]. Resources associated with this task will be eventually freed by its TaskManager,
|
|
* or immediately after this call if the task is no longer in the queue. Use this when you are done
|
|
* with the task.
|
|
*
|
|
* [task] must be treated as an invalid pointer as soon as this function is called.
|
|
*
|
|
* Returns true on success, false on failure.
|
|
*/
|
|
bool task_detach(Task *task);
|
|
|
|
/**
|
|
* Wait for [task] to complete, then disown it.
|
|
* Functionally equivalent to `task_wait` followed by `task_detach`.
|
|
*/
|
|
bool task_finish(Task *task, void **result);
|
|
|
|
/**
|
|
* Attempt to cancel the [task], then disown it.
|
|
* Functionally equivalent to `task_cancel` followed by `task_detach`.
|
|
*/
|
|
bool task_abort(Task *task);
|
|
|
|
/**
|
|
* Initialize the global task manager with default parameters.
|
|
*/
|
|
void taskmgr_global_init(void);
|
|
|
|
/**
|
|
* Wait for tasks submitted to the global task manager to finish, then destroy
|
|
* it, freeing all associated resources.
|
|
*/
|
|
void taskmgr_global_shutdown(void);
|
|
|
|
/**
|
|
* Submit a task to the global task manager. See `taskmgr_submit`.
|
|
*/
|
|
Task *taskmgr_global_submit(TaskParams params);
|