Tasks¶
The tasks system provides “green threads” (also known as lightweight cooperative threads, or coroutines).
Additionally, the following utilities are provided to be used along with the tasks system:
- Functions to suspend a coroutine and wait for I/O to be completed:
w_task_yield_io_read()
,w_task_yield_io_write()
. - The
w_io_task_open()
andw_io_task_init()
functions can be used to create aw_io_task_t
wrapper to ease using asynchronous I/O with tasks.
Types¶
-
w_task_t
¶ Type of a task.
Tasks are created by
w_task_prepare()
, and the resources used by a task (including the stack space used by the task and thew_task_t
value itself) will be automatically freed when the tasks is exited. Never deallocate a task manually, or use it after it has been exited.
-
w_task_func_t
¶ Type of task functions.
-
w_io_task_t
¶ Stream wrapper for asynchronous input/output.
This is a subclass of :type:w_io_t; all the stream functions can be used on objects of this type. Reading and writing data uses
w_task_yield_io_read()
andw_task_yield_io_write()
, so instead of blocking until completion the current task will be suspended automatically.
Functions¶
-
w_task_t*
w_task_prepare
(w_task_func_t function, void *data, size_t stack_size)¶ Creates a task with a given stack_size and prepares it for running a function, passing a data pointer to the function. The task will be in paused state upon creation.
To get tasks running, the scheduler must be running, see
w_task_run_scheduler()
.The stack_size is always rounded up to the size of a memory page. It is possible to pass zero to get the smallest possible stack size (usually 4 kB).
-
w_task_t*
w_task_current
()¶ Obtains the task currently running.
Warning
This function must be called from inside a task, once the task scheduler has been started. Otherwise, calling this function is an error and the execution of the program will be aborted.
-
void
w_task_set_is_system
(w_task_t *task, bool is_system)¶ Set whether a task is a system task. System tasks are those which are always running.
System tasks do not prevent
w_task_run_scheduler()
from returning.
-
bool
w_task_get_is_system
(w_task_t *task)¶ Checks whether a task is a system task.
See also
w_task_set_is_system()
.
-
void
w_task_set_name
(w_task_t *task, const char *name)¶ Sets the name of a task. The name of the tast is copied as-is, and it is not interpreted in any way. The ability of naming tasks is mainly provided as an aid for debugging client code.
It is possible to pass
NULL
as the name, which will clear any custom name previously set.
-
const char*
w_task_get_name
(w_task_t *task)¶ Obtains the name of a task.
If a name has not been set using
w_task_set_name()
, an autogenerated one of the formTask<ID>
will be returned.
-
void
w_task_run_scheduler
()¶ Runs the task scheduler.
The scheduler will choose tasks in a round-robin fashion, and let each task run until it gives up the CPU explicitly using
w_task_yield()
or implicitly when waiting for input/output on a stream be means ofw_task_yield_io_read()
andw_task_yield_io_write()
.The scheduler will keep scheduling tasks until all non-system tasks have been exited.
This function must be called in the main function of a program. Typically:
extern void process_argument (void*); int main (int argc, char **argv) { while (argc--) w_task_prepare (process_argument, *argv++, 0); w_task_run_scheduler (); return 0; }
-
void
w_task_yield
()¶ Make the current task give up the CPU, giving control back to the task scheduler, which will give other other tasks the chance to run.
-
void
w_task_exit
()¶ Exits the current task. This can be used to exit from a task at any point, without needing to return from the task function.
-
w_io_result_t
w_task_yield_io_read
(w_io_t *stream, void *buffer, size_t count)¶ Reads count bytes into the memory block at buffer from an input stream, suspending the current task as needed.
If the stream has been set as non-blocking and reading from it results in an
EAGAIN
orEWOULDBLOCK
error, the current task will give up the CPU and wait until the data is available for reading as many times as needed, until count bytes are read, the end-of-file marker is reached, or an error is found.
-
w_io_result_t
w_task_yield_io_write
(w_io_t *stream, const void *buffer, size_t count)¶ Writes count bytes from the memory block at buffer to an output stream, suspending the current task as needed.
If the stream has been set as non-blocking and writing to it results in an
EAGAIN
orEWOULDBLOCK
error, the current task will give up the CPU and wait until the stream accepts writing data as many times as needed, until count bytes are written, or an error is found.
-
bool
w_io_task_init
(w_io_task_t *wrapper, w_io_t *stream)¶ Initializes a stream wrapper object (possibly allocated in the stack) which wraps a stream. The wrapper behaves like the wrapped stream, suspending the current task when needed to ensure that I/O is performed asynchronously.
The return value indicates whether the stream can be wrapped. Most of the streams for which
w_io_get_fd()
returns a valid file descriptor can be wrapped.
-
w_io_t*
w_io_task_open
(w_io_t *stream)¶ Wraps a stream and returns an object that behaves like the wrapped stream, suspending the current task when needed to ensure that I/O is performed asynchronously.
Returns
NULL
when the stream cannot be wrapped. Most of the streams for whichw_io_get_fd()
returns a valid file descriptor can be wrapped.
-
void
w_task_system
()¶ Mark the current task as a system task.
See also
w_task_set_system()
.
-
const char*
w_task_name
()¶ Obtain the name of the current task.
See also
w_task_get_name()
.