Syncronization and threading interface.
More...
|
file | su_wait.h |
| Syncronization and threading interface.
|
|
Syncronization and threading interface.
The Sofia utility library provides simple OS-independent synchronization interface. The synchronization interface contains primitives for managing events, messages, timers and threads.
Clone Objects
Several tasks may run in context of one thread, or each task may be run by its own thread. However, only a single thread can execute code within a task. There can be a 1-to-N mapping from thread to tasks. Thus, software using tasks can be executed by multiple threads in a multithreaded environment and by a single thread in a singlethreaded environment.The clones are useful for handling tasks that can be executed by a separate threads, but which do not block excessively. When threads are not available or they are not needed, clones can also be run in a single-threaded mode. Running in single-threaded mode is especially useful while debugging.A clone task is created with function su_clone_start(). Each clone has its own root object (su_root_t), which holds a context pointer (su_root_magic_t *). The context object can be different from that of parent task.When a clone is started, the clone initialization function is called. The initialization function should do whatever initialization there is to be performed, register I/O events and timers, and then return. If the initialization is successful, the clone task reverts to run the event loop and invoking the event callbacks until its parent stops it by calling su_clone_wait() which invokes the deinit function. The clone task is destroyed when the deinit function returns.The public API consists of following functions:
- su_clone_start()
- su_clone_task()
- su_clone_wait()
- su_clone_forget()
- Note
- There is only one event loop for each thread which can be shared by multiple clone tasks. Therefore, the clone tasks can not explicitly run or step the event loop, but they are limited to event callbacks. A clone task may not call su_root_break(), su_root_run() or su_root_step().
Tasks and root objects
According to the model, the program can ask that the event loop invokes a callback function when a certain event occurs. Such events include
I/O activity,
timers or a
message from other task. The event loop is run with function su_root_run() or su_root_step().Root object gives access to the task control. The root object represents the task to the code running within task. Through the root, the task code can access its context object (magic) and thread-synchronization features like wait objects, timers, and messages.When a message is sent between tasks, a task reference
su_task_r is used to reprent the task address. Reference counting is used to make sure that the task references stay valid.The public API contains following functions:
- su_root_create() [Do not call from cloned task]
- su_root_destroy() [Do not call from cloned task]
- su_root_magic()
- su_root_register()
- su_root_deregister()
- su_root_unregister()
- su_root_threading()
- su_root_run() [Do not call from cloned task]
- su_root_break() [Do not call from cloned task]
- su_root_step() [Do not call from cloned task]
- su_root_get_max_defer()
- su_root_set_max_defer()
- su_root_task()
New tasks can be created via
su_clone_start() function.
Registering Wait Objects
Whenever the wait object receives an event, the registered
callback function is invoked.When successful, the su_root_register() returns an small non-negative integer representing the registration. The registration can be manipulated with su_root_eventmask() function, for instance, when sending through a socket block, the application can add SU_WAIT_OUT event to the mask.The registration can be removed using su_root_deregister() function.
Timer Objects
The default interval is specified when the timer is created. We call timer activation "setting the timer", and deactivation "resetting the timer" (as in SDL). When the given time has arrived or the default interval has elapsed, the timer expires and it is ready for execution.The functions used to create, destroy, activate, and manage timers are as follows:
- su_timer_create(),
- su_timer_destroy(),
- su_timer_set_interval(),
- su_timer_set_at(),
- su_timer_set(),
- su_timer_set_for_ever(),
- su_timer_run(),
- su_timer_reset(), and
- su_timer_root().
- Note
- Timers use poll() to wake up waiting thread. On Linux, the timer granularity is determined by HZ kernel parameter, which decided when the kernel was compiled. With kernel 2.4 the default granularity is 10 milliseconds, and minimum duration of a timer is approximately 20 milliseconds. Naturally, using RTC would give better timing results, but RTC usage above 64 Hz is privileged operation.
- On Windows, the granularity is determined by the real-time clock timer. By default, it uses the 18.78 Hz granularity. That timer can be adjusted up to 1000 Hz using Windows multimedia library.
Using Timers
A timer is created by calling su_timer_create():
su_task_r su_root_task(su_root_t const *root)
Get task reference.
Definition su_root.c:958
su_timer_t * su_timer_create(su_task_r const, su_duration_t msec))
Create a timer.
Definition su_timer.c:297
The default duration is given in milliseconds.
Usually, timer wakeup function should be called at regular intervals. In such case, the timer is activated using function su_timer_set_for_ever(). When the timer is activated it is given the wakeup function and pointer to context data:
int su_timer_set_for_ever(su_timer_t *, su_timer_f, su_timer_arg_t *)
Set the timer for regular intervals.
Definition su_timer.c:475
When the interval has passed, the root event loop calls the wakeup function:
timer_wakeup(root, timer, args);
If the number of calls to callback function is important, use su_timer_run() instead. The run timer tries to compensate for missed time and invokes the callback function several times if needed. (Because the real-time clock can be adjusted or the program suspended, e.g., while debugged, the callback function can be called thousends of times in a row.) Note that while the timer tries to compensate for delays occurred before and during the callback, it cannot be used as an exact source of timing information.
Timer ceases running when su_timer_reset() is called.
Alternatively, the timer can be set for one-time event invocation. When the timer is set, it is given the wakeup function and pointer to context data. The actual duration can also be specified using su_timer_set_at().
int su_timer_set(su_timer_t *, su_timer_f, su_timer_arg_t *)
Set the timer for the default interval.
Definition su_timer.c:396
When the timer expires, the root event loop calls the wakeup function:
timer_wakeup(root, timer, args);
If the timed event is not needed anymore, the timer can be reset:
int su_timer_reset(su_timer_t *)
Reset the timer.
Definition su_timer.c:498
If the timer is expected to be called at regular intervals, it is possible to set ro run continously with su_timer_run(). While such a continously running timer is active it must not be set using su_timer_set() or su_timer_set_at().
When the timer is not needed anymore, the timer object itself should be destroyed:
void su_timer_destroy(su_timer_t *)
Destroy a timer.
Definition su_timer.c:322
Wait objects
The events are as follows:
- SU_WAIT_IN - incoming data is available on socket
- SU_WAIT_OUT - data can be sent on socket
- SU_WAIT_ERR - an error occurred on socket
- SU_WAIT_HUP - the socket connection was closed
- SU_WAIT_ACCEPT - a listening socket accepted a new connection attempt
It is possible to combine several events with |, binary or operator.The wait objects can be managed with functions as follows:
- su_wait_create()
- su_wait_destroy()
- su_wait()
- su_wait_events()
- su_wait_mask()
- Note
- In Unix, the wait object is
struct
poll
. The structure contains a file descriptor, a mask describing expected events, and a mask containing the occurred events after calling su_wait()
, ie. poll().
-
In Windows, the wait object is a
HANDLE
(a descriptor of a Windows kernel entity).
◆ su_root_size_hint
Contains hint of number of sockets supported by su_root_t.
Hint for number of registered fds in su_root.