AG_Timer structure describes a unique timer, which may or may not be associated with
AG_Object(3). If a timer has a parent object, Agar will guarantee cancellation of any
callbacks if the parent object is destroyed or detached.
When a timer expires, its callback routine is executed.
Timer callback routines should be defined as:
The timer argument, and the list of arguments under event are those previously specified in AG_AddTimer(). The current timer interval (in ticks) can be retrieved from the ival member of the AG_Timer structure. The callback should return a new timer interval (if the timer is to be restarted), or 0 if the timer is to be cancelled.
The timer's parent object is guaranteed to remain locked during the execution of the callback. The context of execution of the callback is platform-dependent. On platforms where kqueue(2) is available, the routine is executed in the event loop. On platforms where only POSIX timers are available, the routine is executed in a separate thread. On platforms which don't provide any timer interface at all, the event loop repeatedly calls AG_ProcessTimeouts() routine to process expired timers. Different objects may also manage timers differently (see SPECIALIZED TIMERS below).
The AG_InitTimer() routine initializes a AG_Timer structure. name is an optional string identifier, useful for debugging purposes. Acceptable flags options include:
The AG_AddTimer() function starts the timer. The optional obj argument specifies a parent AG_Object(3) which will manage the timer. The callback routine is specified as the fn() argument. Arguments to pass to the callback may be specified under fmt (using the AG_Event(3) style of argument passing). The AG_AddTimer() function returns 0 on success or -1 if the timer could not be created.
Timers created with AG_AddTimer() are set to expire in t ticks from now. On expiration, the timer's callback is invoked. If it returns a non-zero number of ticks, the timer is restarted, otherwise it is cancelled.
The AG_AddTimerAuto() variant of AG_AddTimer() allocates an anonymous AG_Timer structure which will be freed upon cancellation. On success, a pointer to the new timer structure is returned (it is not safe to dereference this pointer unless AG_LockTimers() is in effect). On failure, AG_AddTimerAuto() returns NULL.
The AG_DelTimer() function cancels the execution of a timer and frees all resources allocated by it. If the given timer is not active, AG_DelTimer() does nothing. The optional obj argument specifies the timer's parent object. The timer argument does not need to point to an initialized structure. If the timer is not running, AG_DelTimer() is a safe no-op.
The AG_ResetTimer() function changes the interval of a running timer, such that it will expire in t ticks from now. It is illegal to invoke AG_ResetTimer() on a timer that is not currently running, and the call must be protected by AG_LockTimers().
In the timer callback routine, it is safe to make AG_AddTimer() or AG_DelTimer() calls. It is not safe to try and detach or destroy the timer's parent object from the callback routine.
The AG_TimerIsRunning() function returns 1 if the timer is active. For thread safety, the call should be protected by AG_LockTimers():
AG_ExecTimer() runs the timer's callback routine artificially and returns its return value. The caller is normally expected to use AG_DelTimer() on a return value of 0 and AG_ResetTimer() if the returned interval differs from current to->ival.
The AG_ProcessTimeouts() function advances the timing wheel and executes the callbacks of expired timers. Normally, this function is not used directly, but it can be useful on platforms without timer interfaces (i.e., AG_ProcessTimeouts() may be called repeatedly from a delay loop). The ticks argument is the monotonic time in ticks (usually obtained from AG_GetTicks(3)). For AG_ProcessTimeouts() to work as expected, the AG_SOFT_TIMERS flag must be passed to AG_InitCore(3).
AG_Timer interface is not tied to any specific time source.
A timer's parent object may influence the way timers are processed.
By default, the execution of timers is based on the progress of a monotonic system clock and one "tick" is roughly equivalent to one millisecond. However, it is possible for different parent objects to process time differently. For example, an object in a simulation application might manage its timers using use some software-defined time, or an offline renderer might require that logic time be stopped during rendering (see AG_Time(3)).
AG_Event(3), AG_GetTicks(3), AG_Intro(3), AG_Object(3), AG_SchedEvent(3), AG_Time(3) |
|The AG_Timer facility first appeared in Agar 1.0 as AG_Timeout, and was modeled after the OpenBSD timeout(9) API by Artur Grabowski and Thomas Nordin. In Agar 1.5.0, callback routines were allowed to accept multiple arguments, and support for kqueue(2) was added.|