LibGG Functions
===============

Initialize and uninitialize LibGG
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. manpage:: 3 ggInit ggExit

Synopsis
--------

::

  #include <ggi/gg.h>

  int ggInit();

  int ggExit();


Description
-----------

`ggInit` initalizes LibGG for use, allocates resources, examines
the runtime environment for options, and performs initializations 
necessary to provide the LibGG API.  This function must be called 
by the application (or by proxy by another library used by the 
application) before using any other LibGG function; otherwise the 
results of invoking LibGG API functions will be undefined.


`ggInit` allows multiple invocations.  Unless `ggExit` is called 
as described below, subsequent calls to `ggInit` will do nothing 
other than increment a reference counter which LibGG uses to keep 
track of how many times it has been initialized.  This allows using
multiple libraries which call `ggInit` together without conflict.


`ggExit` decrements the reference counter which `ggInit` increments.
Until this counter indicates that `ggExit` has been called as many
times as `ggInit` it will do nothing else.


That is, to free resources used by LibGG, `ggExit` must be called as
many times as `ggInit` has been called beforehand (including any
calls made by libraries that depend on LibGG.)  After this point, 
`ggInit` may be called again to reinitialize LibGG.


When `ggExit` determines that it has been called as many times as
`ggInit` it performs the following actions (order is not guaranteed.)  
Any tasks scheduled with `ggAddTask` are canceled (no task handlers
will be called after `ggExit` returns.)  Any cleanup handlers 
registered with `ggRegisterCleanup` are invoked (no cleanup handlers
will be called after `ggExit` returns.)  If any cleanup handlers 
invoked `ggCleanupForceExit`, the current process will be terminated
before `ggExit` returns.  Otherwise, all resources used by LibGG
are released for use by the application or operating system before 
`ggExit` returns.  After `ggExit` returns, any GG functions invoked
(other than `ggInit`) will result in undefined, and probably undesirable,
behavior.


Note that, if `ggInit` is used in a library (like LibGII or LibGGI) 
and the application also calls `ggInit` itself, cleanup handlers 
installed by `ggRegisterCleanup` may not execute when expected.  See 
the `ggRegisterCleanup` manpage for more detail on this subject.
The same applies to cancelation of tasks scheduled with `ggAddTask`.  
See the `ggAddTask` manpage for more detail on that subject.



Return value
------------

`ggInit` returns `0` for OK, otherwise an error code.


ggExit returns:

`0`
    when LibGG has been completely, sucessfully, deinitialized,


`>0`
    the number of *open* `ggInit` calls, if there has been more than
    one call to `ggInit`.  As `ggInit` and `ggExit` must be used in
    properly nested pairs, for example, the first `ggExit` after two
    `giiInit`\ s will return 1.
    

`<0`
    If there was an error, including the case where `ggExit` has been 
    invoked more times than `ggInit` has.


Portable Time Routines
~~~~~~~~~~~~~~~~~~~~~~

.. manpage:: 3 ggCurTime ggUSleep ggUSlumber

Synopsis
--------

::

  #include <ggi/gg.h>

  int ggCurTime(struct timeval *tv);

  int ggUSleep(int usecs);

  void ggUSlumber(int usecs);

Description
-----------

`ggCurTime` fills the timeval structure pointed to by :p:`tv` with 
the current time to the best precision available on the executing platform.

`ggUSleep` sleeps for at least :p:`usec` microseconds, to the best 
precision available on the executing platform, but may be woken up by
a signal or other unspecified condition.

`ggUSlumber` does the same thing as `ggUSleep`, but is guaranteed not to
return until the alloted time has elapsed.

All times represent wall-clock (real, versus processor) times.

The above routines are often simple macros rather than functions, and 
as such should not be used by reference.


Return value
------------

`ggCurTime` returns `0` on success, or a non-zero value if there
was an error.

`ggUSleep` returns `0` when the alloted time interval has elapsed,
or a non-zero value if the sleep was interrupted.


Get user home directory
~~~~~~~~~~~~~~~~~~~~~~~

.. manpage:: 3 ggGetUserDir

Synopsis
--------

::

  #include <ggi/gg.h>

  const char * ggGetUserDir(void);


Description
-----------

`ggGetUserDir` returns a path to the home directory of the user executing
an application, whatever it may be on a given system.  For example, on 
unix systems it will be the contents of the `HOME` environment variable.
If no user home exists, a suitable temporary directory is found.


Return value
------------

`ggGetUserDir` returns a NULL-terminated string holding the path the
the current user home directory.  This string may be a reference to
memory belonging to OS facilities, and **must not** be freed or altered.


Lowest common denominator locking facilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. manpage:: 3 ggLockCreate ggLockDestroy ggLock ggUnlock ggTryLock

Synopsis
--------

::

  #include <ggi/gg.h>

  void *ggLockCreate(void);

  int ggLockDestroy(void *lock);

  void ggLock(void *lock);

  void ggUnlock(void *lock);

  int ggTryLock(void *lock);


Description
-----------

These functions allow sensitive resource protection to prevent 
simultaneous or interleaved access to resources.  For developers
accustomed to POSIX-like threading environments it is important to 
differentiate a gglock from a "mutex".  A gglock fills **both** 
the role of a "mutex" and a "condition" (a.k.a. an "event" or 
"waitqueue") through a simplified API, and as such there is no
such thing as a gglock "owner".  A gglock is just locked or 
unlocked, it does not matter by who or when as long as the application 
takes care never to create a deadlock that never gets broken.


The locking mechanisms are fully functional even in single-threaded, 
uninterrupted-flow-of-control environments.   They must still be used 
as described below even in these environments; They are never reduced 
to non-operations.


Though the LibGG API does provide ample functionality for threaded
environments, do note that LibGG does not itself define any sort of 
threading support, and does not require or guarantee that threads 
are available.  As such, if the aim of an application developer
is to remain as portable as possible, they should keep in mind
that when coding for both environments, there are only two situations
where locks are appropriate to use.  These two situations are 
described in the examples below.


Cleanup handlers created with `ggRegisterCleanup` should not 
call any of these functions.


LibGG must be compiled with threading support if multiple threads 
that call any of these functions are to be used in the program.
When LibGG is compiled with threading support, the `ggLock`, `ggUnlock`, 
and `ggTryLock` functions are guaranteed memory barriers for the 
purpose of multiprocessor data access syncronization.  (When LibGG 
is not compiled with threading support, it does not matter, since 
separate threads should not be using these functions in the first 
place.)



`ggLockCreate` creates a new lock.  The new lock is initially unlocked.


`ggLockDestroy` destroys a :p:`lock`, and should only be called when
:p:`lock` is unlocked, otherwise the results are undefined and probably
undesirable.


`ggLock` will lock the :p:`lock` and return immediately, but only
if the :p:`lock` is unlocked.  If the :p:`lock` is locked, `ggLock` will
not return until the :p:`lock` gets unlocked by a later call to 
`ggUnlock`.  In either case :p:`lock` will be locked when `ggLock` returns.  
`ggLock` is "atomic," such that only one waiting call to `ggLock` will 
return (or one call to `ggTryLock` will return successfully) each 
time :p:`lock` is unlocked.  Order is **not** guaranteed by LibGG -- 
if two calls to `ggLock` are made at different times on the same 
:p:`lock`, either one may return when the :p:`lock` is unlocked 
regardless of which call was made first.  (It is even possible 
for a call to `ggTrylock` to grab the :p:`lock` right after it is 
unlocked, even though a call to `ggLock` was already waiting on the 
:p:`lock`.)


`ggTryLock` attempts to lock the :p:`lock`, but unlike `ggLock` it
always returns immediately whether or not the :p:`lock` was locked 
to begin with.  The return value indicates whether the :p:`lock` was 
locked at the time `ggTryLock` was invoked.  In either case :p:`lock` 
will be locked when `ggTryLock` returns.  


`ggUnlock` unlocks the :p:`lock`.  If any calls to `ggLock` or `ggTryLock`
are subsequently invoked, or have previously been invoked on 
the :p:`lock`, one of the calls will lock :p:`lock` and return.
As noted above, which `ggLock` call returns is not specified by LibGG
and any observed behavior should not be relied upon.  Immediacy is 
also **not** guaranteed; a waiting call to `ggLock` may take some time 
to return.  `ggUnlock` may be called, successfully, even if :p:`lock` 
is already unlocked, in which case, nothing will happen (other than
a memory barrier.)


In all the above functions, where required, the :p:`lock` parameter 
**must** be a valid lock, or the results are undefined, may contradict 
what is written here, and, in general, bad and unexpected things might
happen to you and your entire extended family.  The functions do 
**not** validate the :p:`lock`; It is the responsibility of the calling 
code to ensure it is valid before it is used.


Remember, locking is a complicated issue (at least, when coding for
multiple environments) and should be a last resort.


Return value
------------

`ggLockCreate` returns a non-NULL opaque pointer to a mutex, hiding 
its internal implementation.  On failure, ggLockCreate returns NULL.

`ggTryLock` returns `0` if the lock was unlocked, or some non-zero 
value if the lock was already locked.

ggLockDestroy returns `0` on success, or some non-zero value if
something went wrong.


Examples
--------

One use of gglocks is to protect a critical section, for example access
to a global variable, such that the critical section is never entered
by more than one thread when a function is called in a multi-threaded
environment.  It is important for developers working in a single-threaded
environment to consider the needs of multi-threaded environments when 
they provide a function for use by others.

static int foo = 0;
static gglock *l;

void increment_foo(void) {
     ggLock(l);
     foo++;
     ggUnlock(l);
}

In the above example, it is assumed that gglock is initialized using
`ggLockCreate` before any calls to increment_foo are made.  Also note that
in the above example, when writing for maximum portability, increment_foo 
should not be called directly or indirectly by a task handler which was
registered via ggAddTask because a deadlock may result (unless it is 
somehow known that increment_foo is not being executed by any code outside 
the task handler.)

Another use of gglocks is to delay or skip execution of a task handler
registered with `ggAddTask`.  It is important for developers working 
in a multi-threaded environment to consider this when they use tasks,
because in single-threaded environments tasks interrupt the flow of control
and may in fact themselves be immune to interruption.  As such they 
cannot wait for a locked lock to become unlocked -- that would create
a deadlock.

static gglock *t, *l, *s;
int misscnt = 0;

void do_foo (void) {
	ggLock(t);		/* prevent reentry            */
	ggLock(l);		/* keep task out              */
	do_something();
	ggUnlock(l);            /* task OK to run again       */
	if (!ggTryLock(s)) {    /* run task if it was missed  */
                if (misscnt) while (misscnt--) do_something_else();
		ggUnlock(s);
	}
	ggUnlock(t);            /* end of critical section    */
}

/* This is called at intervals by the LibGG scheduler */
static int task_handler(struct gg_task *task) {
       int do_one;

       /* We know the main application never locks s and l at the
        * same time.  We also know it never locks either of the 
	* two more than once (e.g. from more than one thread.)
	*/

       if (!ggTryLock(s)) {
              /* Tell the main application to run our code for us
	       * in case we get locked out and cannot run it ourselves.
	       */
              misscnt++;
	      ggUnlock(s);
	      if (ggTryLock(l)) return; /* We got locked out. */
       } else {
              /* The main application is currently running old missed
	       * tasks.  But it is using misscnt, so we can't just ask
	       * it to do one more.
	       *
	       * If this is a threaded environment, we may spin here for
               * while in the rare case that the main application unlocked
               * s and locked l between our the above ggTryLock(s) and the
	       * below ggLock(l).  However we will get control back eventually.
               *
               * In a non-threaded environment, the below ggLock cannot 
               * fail, because the main application is stuck inside the 
	       * section where s is locked, so we know l is unlocked.
	       */
              ggLock(l);
	      do_something_else();
	      ggUnlock(l);
	      return();
       }

       /* now we know it is safe to run do_something_else() as 
        * do_something() cannot be run until we unlock l.
        * However, in threaded environments, the main application may 
        * have just started running do_something_else() for us already.
        * If so, we are done, since we already incremented misscnt.
	* Otherwise we must run it ourselves, and decrement misscnt
	* so it won't get run an extra time when we unlock s.
        */
       if (ggTryLock(s)) return;
       if (misscnt) while (misscnt--) do_something_else();
       ggUnlock(s);
       ggUnlock(l);
}

In the above example, the lock t prevents reentry into the dofoo
subroutine the same as the last example.  The lock l prevents 
do_something_else() from being called while do_something() is running.  
The lock s is being used to protect the misscnt variable and also
acts as a memory barrier to guarantee that the value seen in misscnt
is up-to-date.   The code in function dofoo will run do_something_else() 
after do_something() if the task happened while do_something() was 
running.  The above code will work in multi-threaded-single-processor, 
multi-threaded-multi-processor, and single-threaded environments.

(Note the above code assumes do_something_else() is reentrant)


See Also
--------

:man:`pthread_mutex_init(3)`



Cleanup callback facilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. manpage:: 3 ggRegisterCleanup ggUnregisterCleanup ggCleanupForceExit

Synopsis
--------

::

  #include <ggi/gg.h>

  typedef void (ggcleanup_func)(void *);

  int ggRegisterCleanup(ggcleanup_func *func, void *arg);

  int ggUnregisterCleanup(ggcleanup_func *func, void *arg);

  void ggCleanupForceExit(void);


Description
-----------

`ggRegisterCleanup` registers a callback to be executed when an
abnormal and unexpected program termination is imminant. The
:p:`func`\ tion will be called with its :p:`arg`\ ument.


`ggUnregisterCleanup` cancels a callback installed with
`ggRegisterCleanup`.


Once `ggCleanupForceExit` is called, :man:`_exit(2)` will be
explicitly called after all registered cleanup callbacks.  It
is not possible to cancel such a request once it is made.


These functions are for emergency use only, and should not be
used as a substitute to proper memory deallocation routines.
They should only be used to restore system state that would 
otherwise be left corrupted after an abnormal program 
termination, for example, a video-card timing mode.  When normal 
termination occurs, `ggUnregisterCleanup` should be called to 
systematically remove the emergency callbacks.



Callback functions registered with `ggRegisterCleanup` should not 
itself invoke (or invoke any subroutines that may in turn invoke) 
any of the LibGG locking functions `ggLockCreate`, `ggLockDestroy`, 
`ggLock`, `ggUnlock`, or `ggTryLock`.  Since they are only invoked
during emergencies, they should be ignoring locks in general.


The callback functions may be called by a normal call to ggExit().
As such, it is considered best practice to use ggUnRegisterCleanup()
to remove cleanups when gracefully deinitializing LibGG or a library 
that uses LibGG.


Return value
------------

`ggRegisterCleanup` and `ggUnregisterCleanup` return `0` on success, a
negative error code otherwise.


Portable code module loading facilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. manpage:: 3 ggLoadModule ggFreeModule ggGetSymbolAddress

Synopsis
--------

::

   #include <ggi/gg.h>

   gg_module ggLoadModule(const char *name, int flags);

   void ggFreeModule(gg_module module);

   void *ggGetSymbolAddress(gg_module module, const char *symbol);

Description
-----------


LibGG abstracts dynamic code loading (and emulates dynamic code loading
for statically linked embedded binaries) through a simple API which
represents the very lowest level required of any loadable module system.  
The actual underlying mechanisms used in various operating systems
to load additional code into an application on demand vary drastically, 
however, minus OS-specific frills, they can all be mapped to the above 
three LibGG API functions.


A more sophisticated module system (a layer above these functions)
is also provided as part of the LibGG configuration abstraction system 
(see `ggInstantModule`.)


`ggLoadModule` finds a loadable collection of code symbols known by
the name :p:`name` through whatever system is available on the operating
system.  The symbols are loaded into the address space of the caller.
If the :p:`flags` parameter contains the bitflag GG_MODULE_GLOBAL, then
certain symbols in the collection are also made accessible to any modules
also loaded through `ggLoadModule`.  This may happen even if the bitflag
is not supplied, depending on the underlying system, but to guarantee
it you must use the bitflag.


`ggFreeModule` unloads the symbol collection represented by the 
handle :p:`module`, which must have been previously loaded with 
`ggLoadModule`  (:p:`module` should be a return value from a previous 
call to `ggLoadModule`.)  Reference counts are kept to ensure that 
redundantly loaded symbol collections are not discarded until their 
last owner releases them.  Calling `ggFreeModule` on a handle too
many times, or on an invalid handle, may produce undefined results.
Accessing symbols after the collections they were contained in are 
unloaded will produce undesirable and undefined results.


`ggGetSymbolAddress` searches the symbol collection represented by the 
handle :p:`module`, which has been loaded with `ggLoadModule` (and
not yet unloaded with `ggFreeModule`, of course) for a symbol named
:p:`symbol`, so that the application may use the item associated with the
symbol.  The parameter :p:`module` should be a return value from 
a previous call to `ggLoadModule`.   As `ggGetSymbolAddress` may 
have no way of knowing what the symbol represents, the application 
must take the responsibility for assigning the item a correct C type.


Return value
------------

On success, `ggLoadModule` returns an opaque pointer to a handle 
representing a newly loaded symbol collection (which must be retained 
in order to use or free the collection.)  These pointers are not 
guaranteed to be unique.  On failure, `ggLoadModule` returns the 
special value GG_MODULE_NULL, which is guaranteed never to be used
as a valid handle.

`ggGetSymbolAddress` returns the address of the item that the named 
symbol represents, if it has been loaded into the caller's address 
space.  Otherwise it returns NULL.



Generic configuration file/registry extraction routines
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. manpage:: 3 ggParseOptions ggSystemOptions

Synopsis
--------

::

   #include <ggi/gg.h>

   int ggSystemOpts(char **rls, gg_option *optlist, int count);

   char *ggParseOpts(const char *str, gg_option *optlist, int count, int flag);


Description
-----------

`ggSystemOpts` is a front-end for various utilities to retrieve
configuration information from configuration files/registries/etc
present in the operating system environment.  What utility is used
is determined by the first part of each of the strings in :p:'rls',
which use a URL-like syntax.  Currently the only supported utility
"basicfile://" is one that extracts an option value from some of 
the more basic UNIX configuration file formats.  Each string in 
:p:'rls' corresponds to the respective name/result pair in
the aray :p:'optlist' (:p:`count` indicates how many options are 
being looked for.)  The general form of the strings in :p:`rls`
is "method://[rname]/[section]/[subsection]/config_optname",
which looks for a variable named :p:`config_optname` in the subsection
named :p:`subsection` of the section named :p:`section` of the
resource (usually a file name) named :p:`rname` using the utility
that corresponds to the :p:`method`.

In the above any character (other than '\0') may be substituted 
for the slashes, to avoid conflict with resource, section, or 
variable names The section/subsection parts may be omitted or more 
subsections added as needed.  If a blank section is given before 
the :p:`config_optname` then all sections on the most specific 
level will be searched (For example, to search for an option named 
"useaccel" without respect to section globally in a file, one 
would specify "basicfile:||/path/to/file||useaccel" in the :p:'rls' 
string.)

`ggParseOpts` parses a string :p:`str` of options in LibGG's option 
format and places the results in the ".name" members of the :p:`optlist`.  
The parameter :p:`count` specifies the length of optlist.  The parameter
:p:`flags` is a bitwise or of values that alter behavior, the only
one defined at this time being GG_PARSEOPTS_ALLOW_UNKNOWN, which, if
present, will cause ggParseOpts to ignore options found in the string
for which there are no matching entries in optlist (normally this 
generates a failure and a warning message).

The normal LibGG option format is defined as follows:

A colon or whitespace is the separator between options.  

Option names consist of any character except parenthesis, colons, 
whitespace characters, the equals sign ('=') and the NULL ('\0') 
character.

Option values may consist of any character except the NULL character,
however in order to include colons, whitespace characters, 
or parenthesis, the option must be quoted.  Option values that begin 
with a single or double quote are considered to be quoted, and must
end with the same quote character with which they began.  The quotes are 
not considered to be part of the option value.  In order to include the
quote character in use in  a quoted option value it must be escaped by 
a backslash ('\') character.  Backslashes always escape, even in 
unquoted values, and so must always be escaped with a backslash in
order to be included.

Named options begin with a dash (`-`) character followed by an option
name and may be boolean (present or not) or may contain an equal sign 
to assign the option a string value (everything following the equal sign
up to the next forbidden character as described above.)  Matching is 
case sensitive, but options can be abbreviated right down to a single 
letter as long as the name remains unique among the entries in 
:p:`optlist` and the GG_PARSEOPTS_ALLOW_UNKNOWN flag is not used.

Unnamed options do not (duh) have a name field and are positionally
mapped to entries in :p:`optlist`.  Unnamed options are processed after 
the first option field not starting with a dash is encountered, and 
occupy the rest of the option string.  They are assigned to any 
unnamed-eligible options (see below) in the order they appear in 
optlist, but if any were previously discovered in named form they 
forfeit their position in that order.

Options that are eligible to be used in an unnamed fashion must have a 
colon or dash prefixed to their optname in the :p:`optlist` when 
`ggParseOptions` is invoked.  Unnamed options may appear as named 
options as well.  `ggParseOptions` will alter the first character in 
the corresponding optname entry in :p:`optlist` to a colon or to a 
dash depending on whether the option was present in unnamed or named 
form, respectively.  Thus the caller can determine whether the option
was presented in named or unnamed form.  

Options that appear in boolen form will have the first character
in their result changed to "y".  This can be distinguished from
an explicit value of "y" because no NULL terminator is appended to
the "y".

Options that are not found are left unaltered in :p:`optlist`.

Option names and values in :p:`str` are limited in length to 
GG_MAX_OPTION_NAME and GG_MAX_OPTION_RESULT bytes, respectively, including 
one byte for a terminating NULL character.

Return value
------------

`ggSystemOpts` returns `0` on success and a negative error code on
failure.

`ggParseOpts` returns the position in :p:`str` after the last character
of a valid option string, or NULL if :p:`str` was determined not to be
a valid option string.  Even on failure, the contents of :p:`optlist` 
may have been altered.


LibGG simple task scheduler routines
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. manpage:: 3 ggAddTask ggDelTask ggTimeBase

Synopsis
--------

::

  #include <ggi/gg.h>

  struct gg_task {
        gg_task_callback_fn     *cb;    /* Function to call to run task      */
        void                    *hook;  /* Task data can be hung here        */
        int                     pticks; /* Run once every pticks ticks.      */
        int                     ncalls; /* Run ncalls times (0 = infinite)   */
        int                     lasttick; /* last tick run (read-only)       */

	/* Other members present but are for internal use only. */
  }

  typedef int (gg_task_callback_fn)(struct gg_task *task);

  int ggTimeBase(void);

  int ggAddTask(struct gg_task *task);

  int ggDelTask(struct gg_task *task);



Description
-----------


LibGG implements a task scheduler in both threaded and non-threaded 
environments.  Tasks can be registered with the scheduler to run short,
asyncronous routines called "handlers" which may interrupt or run in 
parallel with the normal flow-of-control.  It is recommended to use 
LibGG tasks in leiue of threads when writing for maximum portability, if 
they can meet the demands of the application, since not all environments 
support threads.


The LibGG task scheduler uses a unit of time called a "tick", which may
vary between architectures.  The tick is guaranteed to be no more than
one second, however, most environments will support at least 60 ticks 
per second.  By default LibGG will select 60 ticks per second if it is
supported, see below for instructions on modifying this behavior.  The
function `ggTimeBase` is used to find out the size of a tick. 


The maximum rate at which a periodic task may run is once per tick.  
The maximum period (minimum rate) of a LibGG task is the value of the macro 
GG_SCHED_TICK_WRAP minus one, and is also measured in ticks.


`ggAddTask` will examine the values in the offered task control structure
:p:`task`.  Before calling `ggAddTask` the task control structure must
be initialized by filling it with zeros, including the internal-use-only area.
The task control structure should be further initialized by providing at 
least a pointer to a callback handler function in the member :p:`cb`, and 
initializing the :p:`pticks` member to contain the number of ticks between
each call to the handler function.  The :p: `ncalls` member may be left 
at zero, in which case the task remains scheduled to run once every pticks
until explicitly deleted, or it may be set to a positive integer to indicate
that the task should be automatically deleted after the handler has been
called :p:`ncalls` times.  


The task control structure must only be used for one task, however a task 
handler may be called by multiple tasks.  The member :p:`hook` is provided 
for the application's use in the task control structure as a means to 
easily transport task-local data to the handler.  If a tick arrives during 
a call to `ggAddTask`, the handler may be invoked before `ggAddTask` 
returns; A memory barrier is included in `ggAddTask` which ensures that 
all values in the task control structure are up to date on multiprocessor
systems even in this case.  The task control structure should not be altered,
except by a task handler as noted below, while the task is scheduled.


`ggDelTask` will remove a task from the scheduler.  The task may be called
after `ggDelTask` is called, but is guaranteed not to be called after 
`ggDelTask` has returned, until such a point as it is added again with
`ggAddTask`.


Each scheduled task is guaranteed never to be reentered by the scheduler.  
That is, only one call to a task handler for a given task control structure
will be run at a time, though a single handler function that handles more 
than one task control structure may be entered simultaneuosly once per 
structure.


When a task executes, the handler is invoked and the parameter :p:`task`
given to the handler contains the same pointer value as was given to
`ggAddTask`.  The :p:`ncalls` member will be updated to contain the 
number of calls, including the current call, which remain before the 
task is automatically deleted (or zero if the task will never be 
automatically deleted.)  Thus it is safe to call `ggAddTask` again 
to reuse the task control structure once the handler has returned 
with :p:`nticks` equal to 1.  The :p:`lasttick` member will contain 
the number of the LibGG scheduler tick being executed, which should 
increase monotonically unless a problem occurs as noted below, 
wrapping around modulus the value GG_SCHED_TICK_WRAP.


`ggAddTask` and `ggDelTask` may not be called from within a task 
handler, however, the task handler is free to alter the :p:`pticks` 
and :p:`ncalls` members in the task control structure :p:`task` in order
to change its period, or increase or decrease the number of calls
before auto-deletion.  For example, to cancel itself, a task need
only set `nticks` to 1 before returning.  The task handler may also 
change it's callback function or data hook members.  A write memory
barrier is included in the scheduler to prevent old values from 
being seen by other processors on SMP systems.


LibGG ticks are measured in real (wall clock) time and LibGG
makes every effort to ensure that drift due to runtime factors is kept 
at a minimum.  When a process is suspended, however, LibGG ticks stop 
and resume where they left off.  Likewise, when system utilization is 
very high or tasks are misused the LibGG scheduler may fail to count 
ticks.  However the `ggCurTime` function will still be accurate in 
these cases and can be used to detect such situations. 


All scheduled LibGG tasks may in the worst case have to be run 
serialized, and may be postponed slightly while a call to ggAddTask
or ggDelTask is in progress, so there may be some delay between the 
start of a LibGG tick and the actual execution of the task.  This 
can be minimized by limiting the duties of task handlers to very 
short, quick operations.


When utilization is high or tasks misbehave, the scheduler may elect 
simply not to call a task handler even though it is scheduled to be 
called on a given tick.  This may happen either to all tasks or to 
select individual tasks.   The "lasttick" member of the task control
structure can be safely read from within a task handler in order
to detect such a circumstance (it will always contain the current
tick, but can be compared to a previously stored value.)


Since LibGG tasks may be called in a signal handler or other 
non-interruptable context, they should not call `ggLock` on any
locks that may already be locked.  In addition, there may be limits 
imposed on the functions which are safe to use inside task handlers
(that is, only reentrant functions may be safe.)  More detailed
information on using locks inside LibGG task handlers is contained
in the manpage for `ggLock`.


Scheduled tasks will be cancelled, in a somewhat precarious fashion, by 
a normal call to ggExit().  As such, it is considered best practice to 
use ggDelTask() to cancel tasks when gracefully deinitializing LibGG or 
a library that uses LibGG.


Return value
------------

`ggAddTask` and `ggDelTask` return `0` on success, a negative error 
code otherwise.

`ggTimeBase` returns an integer between 1 and 100000, inclusive, which
represents the number on microseconds between each tick of the LibGG
scheduler.


Environment Variables
---------------------


If the "-schedhz=speed" option is present in the $GG_OPTS 
environment variable when ggInit is first called, the scheduler
time base will be set such that the scheduler executes :p:`speed`
ticks per second.  If this is not possible, ggInit() will fail.
The default speed is 60HZ, or the maximum that the environment
can support, whichever is less.


If the "-schedsig=signum" option is present in the $GG_OPTS 
environment variable when ggInit is first called, and LibGG is
not compiled with threads support, the UNIX signal used by the
scheduler may be selected.  If :p:`signum` is not a valid signal
for this purpose, the results are undefined, but should not be 
unsafe for SUID processes.  The default signal used is usually 
SIGPROF, but may be chosen diferently based on the needs of the 
package maintainer for any particular LibGG distribution.


If the "-schedthreads=numthreads" option is present in the $GG_OPTS 
environment variable when ggInit is first called, and LibGG is
compiled with threading support, the scheduler will create 
:p:`numthreads` additional threads to call task handlers.  The default 
is one additional thread.  If :p:`numthreads` is not valid or causes
resource allocation problems, the results are undefined, but should
not be unsafe for SUID (or other elevated privilage) processes.



Get CPU features
~~~~~~~~~~~~~~~~

.. manpage:: 3 ggGetSwarType

Synopsis
--------

::

  #include <ggi/gg.h>

  #if defined GG_HAVE_INT64
  #endif

  #if defined GG_LITTLE_ENDIAN
  #endif

  #if defined GG_BIG_ENDIAN
  #endif

  enum gg_swartype ggGetSwarType(void);


Description
-----------

The GG_HAVE_INT64 macro is defined on 64-bit architectures where 
64-bit integer values function as normal integer values with respect to
C operations.  Otherwise it is not defined.

The GG_LITTLE_ENDIAN or GG_BIG_ENDIAN are defined, respectively, when
the architecture stores values in little or big endian order.  One
of the two will be defined, the other undefined, accordingly.

SWAR stands for SIMD Within A Register.  The most well known
example of SWAR is Intel MMX technology.

`ggGetSwarType` tells which specific SWAR instruction sets the CPU
implements.  This is useful to choose at runtime a machine-specific 
implementation of a very calculation-intensive routine.  SWAR detection 
is done once during ggInit() and the value is cached for future use,
thus it should be fast enough to choose implementations on the fly.
However, due to this, SMP machines must have identical feature sets
in all processors in order to ensure accurate results (see the
GG_OPTS option description below.)


Return value
------------

`ggGetSwarType` returns an integer in which each bit set means that 
a specific SWAR instruction set is available.  The integer value may 
be 32 bits long or 64 bits long, depending on whether LibGG was compiled
for a 32-bit or 64-bit machine, as per the GG_HAVE_INT64 macro.



Recognized SWARs
----------------


The following flags are defined for all architectures.  All of these
flags can be OR'ed and are exclusive even between architectures.  Note
at this stage of development some of these SIMD sets are not yet detected
correctly.

`GG_SWAR_NONE`
    The CPU can run a vanilla C program. (hopefully! :-)
    
`GG_SWAR_32BITC`
    The CPU can perform 32-bit math fast enough to give an advantage over 
    16-bit math for software SWAR implementations.  Almost all computers
    will have this capability today.

`GG_SWAR_ALTIVEC`
    The CPU has an AltiVec matrix coprocessor (Motorolla G4.)

`GG_SWAR_SSE`
    The CPU supports Intel Streaming SIMD Extensions.

`GG_SWAR_SSE2`
    The CPU supports Intel Streaming SIMD Extensions Version 2.

`GG_SWAR_MMX`
    The CPU supports Intel Multimedia Extensions.

`GG_SWAR_MMXPLUS`
    The CPU supports Cyrix enhancements to Intel Multimedia Extensions.

`GG_SWAR_3DNOW`
    The CPU supports AMD 3DNOW! instructions.

`GG_SWAR_ADV3DNOW`
    The CPU supports AMD Advanced 3DNOW! instructions.

`GG_SWAR_MAX`
    The CPU supports PA-RISC MAX Instructions.

`GG_SWAR_SIGD`
    The CPU supports Microunity Mediaprocessor SIGD instructions.


Additionnaly, 64 bits architectures define the following flags:

`GG_SWAR_64BITC`
    The CPU can perform 64-bit math fast enough to give an advantage over 
    32-bit and 16-bit math for software SWAR implementations.

`GG_SWAR_MVI`
    The CPU supports DEC (Compaq) Alpha Motion Video Instructions.

`GG_SWAR_MAX2`
    The CPU supports PA-RISC MAX2 Instructions.

`GG_SWAR_MDMX`
    The CPU supports MIPS Digital Media Extension (MaDMaX) Instructions.

`GG_SWAR_MAJC`
    The CPU supports SUN Microprocessor Architecture for Java Computing.

`GG_SWAR_VIS`
    The CPU supports the SUN Visual Instruction Set


Environment Variable
--------------------

If the "-banswar=0xhexnumber" option is present in the $GG_OPTS 
environment variable when ggInit is first called, bits set in the
:p:`0xhexnumber` field will not be presented to the application 
in the return value of `ggGetSwarType`.  This feature can be used
for performance benchmarking, to disable the use of certain SWAR
implementations.  It may also be used if a multiproccesor machine 
mis-detects the usable SWAR instruction set because the processors 
are not identical.  


BUGS
----

No support is currently implemented for PDP endian machines.

SWAR detection code is incomplete for many architectures, and as such
LibGG may may fail to detect SWAR in the CPU.

