Loading...
Searching...
No Matches
Syncronization and Threading

Syncronization and threading interface. More...

## Topics

| Example and test code for syncronization and threads
| Example programs demonstrate the su syncronization and threading primitives.

## Files

file | su_wait.h
| Syncronization and threading interface.

## Variables

int | su_root_size_hint
| Contains hint of number of sockets supported by su_root_t.

## Detailed Description

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

The process may be divided into many tasks via cloning. 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

A task is the basic execution unit for the Sofia event-driven programming model. 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

When application expects I/O events, it can create a wait object and register it, a callback function and a context pointer to the su_root_t object using the su_root_register() function. 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

Timers are used to schedule some task to be executed at given time or after a default interval. 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():

timer = su_timer_create(su_root_task(root), 200);
su_root_task
su_task_r su_root_task(su_root_t const *root)
Get task reference.
Definition su_root.c:958
su_timer_create
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:

su_timer_set_for_ever(timer, timer_wakeup, args);
su_timer_set_for_ever
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().

su_timer_set(timer, timer_wakeup, args);
su_timer_set
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:

su_timer_reset(timer);
su_timer_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:

su_timer_destroy(timer);
su_timer_destroy
void su_timer_destroy(su_timer_t *)
Destroy a timer.
Definition su_timer.c:322

### Wait objects

Wait objects are used to signal I/O events to the process. 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).

## Variable Documentation

## su_root_size_hint

int su_root_size_hint

Contains hint of number of sockets supported by su_root_t.

Hint for number of registered fds in su_root.

Sofia-SIP 1.12.11devel - Copyright (C) 2006 Nokia Corporation. All rights reserved. Licensed under the terms of the GNU Lesser General Public License.