The gnuworld timer system allows for services clients to be notified of timed events. Timed events can be registered for any time in the future, and may optionally supply an argument to be returned to the timed event handler.
Each timed event is assigned a unique identification number. This timerID is returned to the object requesting a timed event upon registration, and is also passed to the timed event handler. Each services client may register for any number of timed events, and the expiration times of each event may overlap.
For an xClient subclass to receive timed events, each event must be scheduled (registered) in advance. This is done by calling the xServer::RegisterTimer method:
This method has the following arguments:
Returns: The unique identifier of a newly created timed event. Note that timerID's may be reused, but there will never be two timers with the same timerID simultaneously. The timerID type is a public typedef in xServer.
It is possible to supply an argument to be returned to your timer handler. There are several important considerations in choosing an argument for this purpose:
The system state may change at any time, in particular from the time your timed event is registered to the time at which it expires and is executed. For example, suppose you are creating a NickServ services client to be hosted by gnuworld. If a user does not own the nickname he/she/it is currently using, your nickserv notifies the client that it has 60 seconds to change nick or be killed.
Your nickserv client notifies the nick of the error, and registers a timer to be executed 60 seconds later. You must NOT pass the iClient pointer of the nick to the timer registration method. If the nick disconnects in the next 60 seconds, that iClient object will be deallocated by the server. When the timed event expires, a bad pointer to an invalid iClient object is passed to your timer handler. Attempting to dereference this pointer will generate a segmentation fault and crash gnuworld.
In this case, your nickserv client should instead pass a pointer to a string or small object (see below) representing the client. When the timed event expires, and your handler method is called, perform a lookup of the client in question. If the client still exists on the network, and has not changed nicknames, then you can safely kill it.
Passing a pointer to a data variable stored on the stack will eventually generate a segmentation fault, and crash gnuworld. Variables allocated on the stack are deallocated when the current set of curly braces closes (for example, at the end of the current method). If a method variable is passed by pointer as argument to a timed event, this pointer will no longer be valid once the current method ends.
Instead, the programmer should only pass pointers to variables that are allocated inside of the the services client itself, or more likely allocated on the heap.
Of course, once the timer handler method is invoked, and processing of the timed event completes, do not forget to deallocate the method argument, if applicable. Failing to deallocate memory allocated on the heap is a memory leak.
When a timed event expires, a timer handler method is invoked by the timer system. Passed to this handler are the unique timer identification and the optional argument passed to the timer registration method.
The base class xClient has a timer handler method:
Arguments:
Returns: Currently, the return type of this method is not used, but this may change in the future.
NOTE: The OnTimer() method must NOT block. This could disrupt the entire system.
Timed events may be unregistered at any time. The following xServer method provides this functionality:
Arguments:
Returns: True if the timerID was successfully located and removed, false otherwise.