Timer routines

Allegro can set up several virtual timer functions, all going at different speeds.

Under DOS it will constantly reprogram the clock to make sure they are all called at the correct times. Because they alter the low level timer chip settings, these routines should not be used together with other DOS timer functions like the DJGPP uclock() routine. Moreover, the FPU state is not preserved across Allegro interrupts so you ought not to use floating point or MMX code inside timer interrupt handlers.

Under other platforms, they are usually implemented using threads, which run parallel to the main thread. Therefore timer callbacks on such platforms will not block the main thread when called, so you may need to use appropriate synchronisation devices (eg. mutexes, semaphores, etc.) when accessing data that is shared by a callback and the main thread. (Currently Allegro does not provide such devices.)


int install_timer();

Installs the Allegro timer interrupt handler. You must do this before installing any user timer routines, and also before displaying a mouse pointer, playing FLI animations or MIDI music, and using any of the GUI routines.

Return value: Returns zero on success, or a negative number on failure (but you may decide not to check the return value as this function is very unlikely to fail).

See also: remove_timer, install_int.
Examples using this: Available Allegro examples.
void remove_timer();

Removes the Allegro timer handler (and, under DOS, passes control of the clock back to the operating system). You don't normally need to bother calling this, because allegro_exit() will do it for you.
See also: install_timer, allegro_exit.
int install_int(void (*proc)(), int speed);

Installs a user timer handler, with the speed given as the number of milliseconds between ticks. This is the same thing as install_int_ex(proc, MSEC_TO_TIMER(speed)). If you call this routine without having first installed the timer module, install_timer() will be called automatically. Calling again this routine with the same timer handler as parameter allows you to adjust its speed.

Return value: Returns zero on success, or a negative number if there is no room to add a new user timer.

See also: install_timer, remove_int, install_int_ex, install_param_int.
Examples using this: exscn3d, exswitch, extimer, exzbuf.
int install_int_ex(void (*proc)(), int speed);

Adds a function to the list of user timer handlers or, if it is already installed, retroactively adjusts its speed (i.e makes as though the speed change occurred precisely at the last tick). The speed is given in hardware clock ticks, of which there are 1193181 a second. You can convert from other time formats to hardware clock ticks with the macros:
      SECS_TO_TIMER(secs)  - give the number of seconds between
                             each tick
      MSEC_TO_TIMER(msec)  - give the number of milliseconds
                             between ticks
      BPS_TO_TIMER(bps)    - give the number of ticks each second
      BPM_TO_TIMER(bpm)    - give the number of ticks per minute
There can only be sixteen timers in use at a time, and some other parts of Allegro (the GUI code, the mouse pointer display routines, rest(), the FLI player, and the MIDI player) need to install handlers of their own, so you should avoid using too many at the same time. If you call this routine without having first installed the timer module, install_timer() will be called automatically.

Your function will be called by the Allegro interrupt handler and not directly by the processor, so it can be a normal C function and does not need a special wrapper. You should be aware, however, that it will be called in an interrupt context, which imposes a lot of restrictions on what you can do in it. It should not use large amounts of stack, it must not make any calls to the operating system, use C library functions, or contain any floating point code, and it must execute very quickly. Don't try to do lots of complicated code in a timer handler: as a general rule you should just set some flags and respond to these later in your main control loop.

In a DOS protected mode environment like DJGPP, memory is virtualised and can be swapped to disk. Due to the non-reentrancy of DOS, if a disk swap occurs inside an interrupt handler the system will die a painful death, so you need to make sure you lock all the memory (both code and data) that is touched inside timer routines. Allegro will lock everything it uses, but you are responsible for locking your handler functions. The macros LOCK_VARIABLE (variable), END_OF_FUNCTION (function_name), END_OF_STATIC_FUNCTION (function_name), and LOCK_FUNCTION (function_name) can be used to simplify this task. For example, if you want an interrupt handler that increments a counter variable, you should write:

      volatile int counter;

      void my_timer_handler()
      {
         counter++;
      }

      END_OF_FUNCTION(my_timer_handler)
and in your initialisation code you should lock the memory:
      LOCK_VARIABLE(counter);
      LOCK_FUNCTION(my_timer_handler);
Obviously this can get awkward if you use complicated data structures and call other functions from within your handler, so you should try to keep your interrupt routines as simple as possible.

Return value: Returns zero on success, or a negative number if there is no room to add a new user timer.

See also: install_timer, remove_int, install_int, install_param_int_ex.
Examples using this: excamera, exsprite, extimer, exunicod, exupdate.
Macro LOCK_VARIABLE(variable_name);

Due to interrupts, you are required to lock all the memory used by your timer routines. See the description of install_int_ex() for a more detailed explanation and usage example.
See also: install_int, install_int_ex.
Examples using this: exscn3d, exsprite, exswitch, extimer, exupdate, exzbuf.
Macro LOCK_FUNCTION(function_name);

Due to interrupts, you are required to lock all the memory used by your timer routines. See the description of install_int_ex() for a more detailed explanation and usage example.
See also: install_int, install_int_ex.
Examples using this: exkeys, exscn3d, exsprite, exswitch, extimer, exupdate, exzbuf.
Macro END_OF_FUNCTION(function_name);

Due to interrupts, you are required to lock all the code used by your timer routines. See the description of install_int_ex() for a more detailed explanation and usage example.
See also: install_int, install_int_ex.
Examples using this: exkeys, exscn3d, exsprite, exswitch, extimer, exupdate, exzbuf.
void remove_int(void (*proc)());

Removes a function from the list of user interrupt routines. At program termination, allegro_exit() does this automatically.
See also: install_int, install_int_ex, remove_param_int.
int install_param_int(void (*proc)(void *), void *param, int speed);

Like install_int(), but the callback routine will be passed a copy of the specified void pointer parameter. To disable the handler, use remove_param_int() instead of remove_int().
See also: install_timer, remove_param_int, install_param_int_ex, install_int.
int install_param_int_ex(void (*proc)(void *), void *param, int speed);

Like install_int_ex(), but the callback routine will be passed a copy of the specified void pointer parameter. To disable the handler, use remove_param_int() instead of remove_int().
See also: install_timer, remove_param_int, install_param_int, install_int_ex.
void remove_param_int(void (*proc)(void *), void *param);

Like remove_int(), but for use with timer callbacks that have parameter values. If there is more than one copy of the same callback active at a time, it identifies which one to remove by checking the parameter value (so you can't have more than one copy of a handler using an identical parameter).
See also: install_param_int, install_param_int_ex, remove_int.
extern volatile int retrace_count;

If the retrace simulator is installed, this count is incremented on each vertical retrace; otherwise, if the refresh rate is known, the count is incremented at the same rate (ignoring retraces); otherwise, it is incremented 70 times a second. This provides a way of controlling the speed of your program without installing user timer functions.
Examples using this: ex3d, exblend, exdbuf, exflip, exlights.
void rest(unsigned int time);

This function waits for the specified number of milliseconds.

Passing 0 as parameter will not wait, but just yield. This can be useful in order to "play nice" with other processes. Other values will cause CPU time to be dropped on most platforms. This will look better to users, and also does things like saving battery power and making fans less noisy.

Note that calling this inside your active game loop is a bad idea, as you never know when the OS will give you the CPU back, so you could end up missing the vertical retrace and skipping frames. On the other hand, on multitasking operating systems it is good form to give up the CPU for a while if you will not be using it.

See also: install_timer, rest_callback, vsync, d_yield_proc.
Examples using this: Available Allegro examples.
void rest_callback(long time, void (*callback)())

Like rest(), but for non-zero values continually calls the specified function while it is waiting for the required time to elapse. If the provided `callback' parameter is NULL, this function does exactly the same thing as calling rest().
See also: install_timer, rest.

Back to contents