GNU Info

Info Node: (xaos.info)timerlib

(xaos.info)timerlib


Prev: algorithm Up: Hacker
Enter node , (file) or (file)node

The timer library
=================

   Timer library is library I did for timming in XaoS. But I found it
usefull in many other programs (like demonstrations, games, animation
players and all other stuff that needs to be timed). So you should read
this description and possibly use it in your application and save some
coding time.

   There is many ways how to design of such timed aplicatioin (game)

  1. read user input, move badies, display and again this way has one
     disadvantage. Speed of game depends on speed of computer.  This
     was acceptable in old times where only processor was Z80 :) but now
     with wide variety of various hardwares such internal loop is
     unacceptable

  2. read user input, measure time since last loop and caluclate step
     for badies, move badies for set step, display and again.  This way
     fixes problem with speed. But moving badies just for caluclated
     step, that should differ a much is quite complex, usually
     introduces complex calculation, floating/fixedpoint math and other
     unnecesarry stuff that makes program long and introduces many bugs.

  3. Set the fixed framerate that is high enought to make game smooth
     but low enought to do whole internal loop in time. So internal
     loop should look like: read user input, move badies, display,
     meausre time spent in loop an sleep rest of time until next frame.
     This is quite popular scheme but has another disadvantage -- game
     can not be designed to use whole cpu power since on slower
     computers internal loop should take longer time that is reserved
     for one frame. Game will run slowly again.

  4. To take away disadvantage of previous methot, many games times just
     moving of badies and user input. Other stuff like displaying
     should be done in rest of time. In dos games moving and user input
     is often at asynchronous interrupt and drawing runs as main loop.
     This solves problem in case that drawing of game takes
     significantly longer time than moving of badies. This is quite
     usual so this scheme works well.

  5. previous scheme still has one problem -- since timer interrupt
     works asynchronously, there should happend many race condition, in
     case moving takes longer time than time reserved from frame,
     computer can crash. So this scheme should be enhanced into
     synchronous one with exactly same result but avoiding problem with
     race condition:

     read user input, measure time spent by loop and caluclate how many
     simulated frame interrupts activated since last activation, if
     zero sleep until simulated interrupt, move badies as many times as
     required, display

     this is an combination of 4 and 3 and seems to be most confortable
     way for writing games but since main loop is now quite complex
     many games don't do that.

  6. there is still one small problem. Method 5 expect that moving takes
     significantly lower time that displaying. This may not be truth.
     Simple work around is to write moving routine, that should move
     for x moves by faster way that calling move x times. This is often
     possible and makes easy extension to scheme 5. This scheme allows
     you to use very large maximal framerate (say 100FPS) and to have
     same results as method 2 (that is maximally exact method)

   As you can see, designing of main loop isn't so easy. This is just
very simple example. More advanced aplication for example should want
to move one set of badies at one framerate and other at different
framerate. This requires two such timmings. Another complication is
that there is many different ways to measure time exactly at different
platforms. Under linux you can measure using gettimeofday but under DOS
this is exact just to 1/18 of second and thats too low for smooth
animation and so on.

   Thats why I decided to design portable easy to use timer library,
that makes easy to implement all described method, combining of them
and much more.  During design I taken care at the following thinks:
quality of timming, how easy to use it is, speed, portability and to
minimalize inexpected situations (like race conditions in asynchronous
interrupts and so on)

What is what
------------

   Timer library operates with "timers". They should be created, you
should measuere time since last reset, pause them or set "handler" and
"interval".  But handler is not activat at gived interval yet. Since
timer library is not asynchronous, you must activate them.

   For activating is used "groups". You should provess group at some
place in your program. Then all timers in group are checked and their
handlers activated if required. When time spent since last activation
is higher than interval, handler is activated more times. Also interval
to next invocation is calculated to keep freqency.  Simple scheduling
is performed at handler -- handler is activated just once and then all
other timers are checked before it is activated again. You should also
define an multihandler -- handler that is activated just once and
receives argument how many intervals has left.

   There is two special groups -- `asyncgroup'. Timers in this group
are activated asynchornously like from interrupt. It is not recomended
to use it, since it brings many problems and usually isn't required.
Also it does not work at many platforms. `Syncgroup' is the default
group. Program is expected to process is quite often. In case you don't
need to use more groups, you should use this one.

   Time in timerlib is bit strange, since it does not flow continuously
but jumps. It is updated every time you call `tl_updatetime'. I used
this way in order to minimize context switches but later I found this
scheme very usefull, since you should lookup timer, do something and
then reset it and don't wory about time spend between lookup and reset
since it is 0 in case you did not called tl_updatetime. This helps to
keep freqency of timers exact w/o any errors caused by such situations.
At the other hand you need to call tl_updatetime at least once in your
main loop.

   Maybe you don't know why to create more groups, but I found it quite
usefull.  For example an autopilot in XaoS has such special group -- I
need to call it approx. every 1/20 of second but just at one place in
program. Invoking of autopilot when caluclation is active should
produce incorrect results, so I have special group for autopilot and
process just at one place where I am sure it is safe.

   Timers should be also emulated. You should stop them and then
control flow of time for given timer. This should be quite usefull for
example when you want precalculate animation at given framerate.

Time functions
--------------

 - Function: void tl_update_time (void)
     Update time used by timerlib. This must be called at least once in
     main loop otherwise time will not flow. See above.

 - Function: void tl_sleep (int TIME)
     Sleep given time. Similiar to usleep at POSIX.

Group functions
---------------

 - Function: tl_group *tl_create_group (void)
     Allocate and initialize group header. Returns NULL when malloc
     fails.

 - Function: void tl_free_group (tl_group *GROUP)
     Free memory storage used by group structure

 - Function: int tl_process_group (tl_group *GROUP, int *ACTIVATED)
     Process timers in group and activates their handlers. Returns time
     until next invocation. Main loop should sleep returned time then.
     An ACTIVATED parameter sould be `NULL'. If it is non `NULL',
     variable is set to number of activated handlers.

Timer functions
---------------

 - Function: tl_timer *tl_create_timer (void)
     Create timer structure.

 - Function: void tl_free_timer (tl_timer *TIMER)
     Free memory storage used by timer structure

 - Function: void tl_reset_timer (tl_timer *TIMER);
     Reset timer to current time. (time of last actication of
     `tl_update_time')

 - Function: int tl_lookup_timer (tl_timer *TIMER);
     Return time since last call of tl_reset_timer or last activation
     of handler.

 - Function: void tl_set_interval (tl_timer *TIMER, int INTERVAL);

 - Function: void tl_set_handler (tl_timer *TIMER, void (*HANDLER)
          (void *),void *userdata);

 - Function: void tl_set_multihandler (tl_timer *TIMER, void (*HANDLER)
          (void *,int),void *userdata);
     Handler, multihandler and interval control functions

 - Function: void tl_add_timer (tl_group *GROUP, tl_timer *TIMER)
     Add timer to given group. Timer should be added into just one
     group.

 - Function: void tl_stop_timer (tl_timer *TIMER)

 - Function: void tl_resume_timer (tl_timer *TIMER)
     Stop and resume timer.

 - Function: void tl_slowdown_timer (tl_timer *TIMER,int TIME)
     Time in timer is moved back for given time.

Example main loop
-----------------

     while(1)
     {
       time=tl_process_group(syncgroup,activated); /*Call game control functions*/
       update_keys();
       if(activated) /*something changed*/
         display();
       else tl_sleep(time);
     }



automatically generated by info2www version 1.2.2.9