Timers
For the
The
The
The
As it notes in the comments in
The
Example Timer Callback
The return value of the timer callback function is critical: if 0 is returned,
the timer is done, and will not fire again. If non-zero, the timer is
restarted, and will again be invoked once the configured length of time has
passed.
The
Ostensibly,
Another thing of which to be aware is the use of the
This use of
When adding a timer, watch out for these predefined timer number/IDs:
How Timers Work
One caveat to keep in mind is that timers do not provide fine-grained
time resolution, and are not meant for precise work. They do well for
approximate timing-based sorts of activities.
When
At present, the callback function is invoked thus, from src/timers.c:86:
Be aware that the pending signal set for a process is reset when
The core code provides a mechanism for setting timers, which can be used
to set time limits on actions, or to perform actions on a recurring basis.
timers.h
:
int add_timer(int seconds, int timerno, module *mod, callback_t cb);
int remove_timer(int timerno, module *mod);
int reset_timer(int timerno, module *mod);
void pr_alarms_block(void);
void pr_alarms_unblock(void);
add_timer()
function, seconds is the length of the
timer, timerno is an arbitrary timer ID, mod is a pointer to the
module registering the timer, and cb is the function to be invoked once
the timer has expired. If timerno is -1, the timer will be assigned a
"dynamic" timer number greater than 1024. This "dynamic"
number is not random; rather, it starts at 1024, as is incremented for every
timer created with a timerno of -1. This function returns the
given timerno, and has no error return value.
remove_timer()
function does just that, removing every timer
with the given ID timerno registered by module mod. Note that
for this function, and for reset_timer
, the macro
ANY_MODULE
may be given for mod, in which case every timer
with the given timerno will be removed. If a matching timer is found,
it's timerno is returned, otherwise 0 is returned.
reset_timer()
function is also pretty self-explanatory,
resetting the timer with the given timerno from module mod.
If a matching timer is found, that timer's timerno is returned,
otherwise 0 is returned.
pr_alarms_block()
function is used to prevent timers from
firing. Timers that would have fired while blocked are noted, and will be
fired once alarms are unblocked. This is to be used in critical sections of
code which cannot stand interruption.
timers.c
, the blocking of
alarms is done manually, rather than via system calls, to allow for easier
signal handling, portability, detection of the number of blocked alarms, and
to allow for nested block
/unblock
calls.
pr_alarms_unblock()
function allows alarms to once again be
delivered. Any pending alarms that should have been delivered while alarms
were blocked are handled.
This excerpt from
mod_auth.c
shows
the TimeoutLogin
timer implementation:
int login_timeout_cb(CALLBACK_FRAME) {
/* Is this the proper behavior when timing out? */
pr_response_send_async(R_421,
"Login Timeout (%d seconds): "
"closing control connection.",
TimeoutLogin);
session_exit(PR_LOG_NOTICE, "FTP login timed out, disconnected.", 0, NULL);
/* Don't restart the timer */
return 0;
}
CALLBACK_FRAME
macro is #define
d to be:
#define CALLBACK_FRAME LPARAM p1,LPARAM p2,LPARAM p3,void *data
where LPARAM
is typedef
d to be:
typedef unsigned long LPARAM;
LPARAM
is the way it is because it is the "
longest bitsize compatible with a scalar and largest pointer". However,
it does evoke compiler warnings if pointers and data are passed this way.
CALLBACK_FRAME
macro: it defines your function argument variable names a priori, which
can be easy to overlook when you're trying to figure out the name of the
variables to use in your timer callback function. Unfortunately, most
of the current timer callback functions in the core code ignore the callback
variables. When used, p1 will always be zero (with the current code),
p2 will be the timerno of the timer, p3 will be time
elapsed on the timer (which should be less than or equal to zero), and
data will be NULL
.
static int auth_init_child(void) {
/* Start the login timer */
if (TimeoutLogin)
add_timer(TimeoutLogin, TIMER_LOGIN, &auth_module, login_timer_cb);
if (get_param_ptr(main_server->conf, "DisplayConnect", FALSE) != NULL)
_do_user_counts();
return 0;
}
add_timer()
illustrate how one registers one's timer
callback function, and starts the timer running. Once the child process has
forked and mod_auth
's child initialization function called, the
client has until the timer expires to successfully authenticate.
#define TIMER_LOGIN 1
#define TIMER_IDLE 2
#define TIMER_NOXFER 3
#define TIMER_STALLED 4
Note that there is no requirement that your timer number be a preprocessor
macro. The author has successfully used randomly generated numbers as
unique timer identifiers, so that each timer could have custom actions and
values.
The timer mechanism is based on SIGALRM
and a single signal
handler for that signal. How then can multiple timers all use one signal
handler? A linked list of timers is maintained, and that list is checked
every time SIGARLM
is received. For each timer, the amount
of time that has expired is calculated, and if the specifier timer length
has been reached, that timer's callback is invoked.
add_timer()
is called, a list of old, recyclable timers
is checked, to see if any are available. If none are avaiable, a new timer
is allocated. The timer is given the caller's parameters, then inserted
into the active timer list.
t->callback(t->interval, t->timerno, t->interval - t->count, t->mod) == 0 {
This shows what is actually passed as the arguments in the callback_t.
fork()
is called. This is why modules should and do register
timers for the child process in their respective child initialization
functions.
Author: $Author: castaglia $
Last Updated: $Date: 2003/01/02 18:36:35 $
© Copyright 2000-2003 TJ Saunders
All Rights Reserved