In order to control the execution of events, MIT provides a timing loop which it uses in both the Hub and servers. We document this loop here. As of 3.0, the functions Gal_AddTimedTask, etc. are no longer recommended; use Gal_AddTask, etc. instead.
It is now possible to use a version of the timed task API to produce threads instead.
The Gal_TaskPkg * structure argument to the task provides five things:
Gal_TaskPkg *Gal_AddTaskWithSocketIO(void
(*task)(Gal_TaskPkg *), void *refcon, long num_millisecs,
int read_blocking_available, GAL_SOCKET *read_socket, GAL_SOCKET
*write_socket, void (*cleanup_fn)(void *))
Gal_TaskPkg *Gal_AddTaskWithFileIO(void
(*task)(Gal_TaskPkg *), void *refcon, long num_millisecs,
int read_blocking_available, FILE *read_file, FILE *write_file,
void (*cleanup_fn)(void *))
Adds the task with sensitivity to I/O
on sockets and file descriptors, respectively. Otherwise, identical to
Gal_AddTask(). Note that file I/O polling is not available on Win32.
typedef int (*Gal_TaskConditionFn)(void
*caller_data);
Gal_TaskPkg *Gal_AddTaskExtended(void
(*task)(Gal_TaskPkg *), void *caller_data, long num_millisecs,
int read_blocking_available, GAL_SOCKET *read_socket, GAL_SOCKET
*write_socket, GAL_SOCKET *err_socket, FILE *read_file,
FILE *write_file, FILE*err_file, Gal_TaskConditionFn condition,
void (*cleanup_fn)(void *))
Adds the task with sensitivity to the
entire range of elements, including I/O on sockets and file descriptors,
the additional possibility of error streams and task conditions. Task conditions
are passed the caller_data, and if the task condition returns nonzero,
the task will be executed in advance of its normal time expiration. Otherwise,
identical to Gal_AddTask(). Note that file I/O polling is not available
on Win32.
void Gal_ReAddTask(Gal_TaskPkg
*p, void *refcon, long num_millisecs, int read_blocking_available,
void (*cleanup_fn)(void *))
This function is identical to Gal_AddTask(),
except it is to be used when tasks are supposed to be refired, as described
in Gal_AddTask(). In the non-threaded case,
it just adds the Gal_TaskPkg * structure back to the list of timed tasks;
in the threaded case, the thread is continued. This function is intended
to be called from inside the task which p was passed to. If the
task is not refired, the task package is freed; the programmer is responsible
for managing the memory associated with refcon.
void Gal_ReAddTaskWithSocketIO(Gal_TaskPkg
*p, void *refcon, long num_millisecs, int read_blocking_available,
GAL_SOCKET *read_socket, GAL_SOCKET *write_socket, void (*cleanup_fn)(void
*))
void Gal_ReAddTaskWithFileIO(Gal_TaskPkg
*p, void *refcon, long num_millisecs, int read_blocking_available,
FILE *read_file, FILE *write_file, void (*cleanup_fn)(void
*))
Re-adds the task with sensitivity to I/O
on sockets and file descriptors, respectively. Otherwise, identical to
Gal_ReAddTask(). Note that file I/O polling is not available on Win32.
void Gal_ReAddTaskExtended(Gal_TaskPkg
*p, void *caller_data, long num_millisecs, int read_blocking_available,
GAL_SOCKET *read_socket, GAL_SOCKET *write_socket, GAL_SOCKET
*err_socket, FILE *read_file, FILE *write_file, FILE
*err_file, Gal_TaskConditionFn condition, void (*cleanup_fn)(void
*))
Re-adds the task with sensitivity sensitivity
to the entire range of elements, including I/O on sockets and file descriptors,
the additional possibility of error streams and task conditions. Otherwise,
identical to Gal_ReAddTask(). Note that file I/O polling is not available
on Win32.
int Gal_TaskPkgRunReasons(Gal_TaskPkg
*pkg)
Returns the logical OR of the reasons
the package was run. Possible reasons are:
value | description |
GAL_SOCKET_READABLE | The task was fired because a read socket had data |
GAL_SOCKET_WRITABLE | The task was fired because a write socket had data |
GAL_SOCKET_ERR_READABLE | The task was fired because an error socket had data |
GAL_FILE_READABLE | The task was fired because a read file pointer had data |
GAL_FILE_WRITABLE | The task was fired because a write file pointer had data |
GAL_FILE_ERR_READABLE | The task was fired because an error file pointer had data |
GAL_TIMER_EXPIRED | The task was fired because it had slept for the required number of milliseconds |
GAL_CONDITION_SATISFIED | The task was fired because its task condition function returned nonzero |
GAL_THREAD_READABLE | The task was fired because a blocking read had data in the threaded case |
So you can check, for instance, to see if your task fired because of a readable file as follows:
if (Gal_TaskPkgRunReasons(pkg) & GAL_FILE_READABLE) {
...
}
voidGal_RemoveTask(Gal_TaskPkg
*task_id)
Removes the task task_id.
int Gal_TaskPkgBlocking(Gal_TaskPkg
*pkg)
If 1, the task should set its read file
descriptors to blocking mode; if 0, non-blocking.
void *Gal_TaskPkgData(Gal_TaskPkg
*pkg)
Returns the data associated with the package.
This is the same as the value of the refcon argument to Gal_AddTask
and Gal_ReAddTask.
void Gal_TimedTasksLoop(void)
This function initiates the timed task
loop. It loops until Gal_TimedTasksLoopExit is called.
void Gal_TimedTasksLoopExit(void)
This function halts the timed tasks loop.
All tasks in the queue are completed, but no other tasks are queued.
typedef void (*Gal_IdleFunction)(void
*client_data);
int Gal_AddIdleFunction(Gal_IdleFunction
func,
void *client_data)
Adds a function to the list of functions
which the timed task loop will execute when there are no tasks to fire.
The client_data argument is passed to func when it's called.
Unlike tasks, which are removed after they're fired, idle functions remain
installed until they're removed with Gal_RemoveIdleFunction().
void Gal_RemoveIdleFunction(Gal_IdleFunction
func)
Removes func from the list of functions
which the timed task loop executes when there are no tasks to fire.
void Gal_RunIdleFunctions()
Runs the idle functions. Called by the
timed task loop, but can also be called explicitly.
If you want to use the timed task loop in a threaded context, it should work (we haven't tested it extensively). In particular, you can only run the timed task loop from one thread at a time, and you can only shut down the loop from that thread. However, be warned that if you use the -thread argument, the timed task loop will not be started automatically; you will have to start it yourself.
void Gal_EnableTimedTaskThreads()
This function controls whether tasks added
via Gal_AddTask() and Gal_ReAddTask() are handled via timed tasks or via
threads. Once timed task threads are enabled, they can only disabled by
Gal_EndTasks(). Gal_EnableTimedTaskThreads() is the function which is invoked
when you provide the -thread
argument to servers when threads are enabled. If the user is writing his/her
own main() and wants to avoid
the timed task loop for server, connection and broker handling but would
like threads to handle these facilities, the user can enable this facility
with this function.
int Gal_TimedTaskThreadsEnabled()
Returns 1 if timed tasks threads have
enabled via Gal_EnableTimedTaskThreads(), 0 otherwise. The user should
never need to call this function.
void Gal_TimedTaskLoopThreadWaiter(void)
Waits until all the tasks are completed.
This function is the threaded equivalent of Gal_TimedTasksLoop.
The main server loop uses it in the threaded case to delay the actions
of the main thread so that GalSS_RunServer
only
returns when the server is finished.
void Gal_EndTasks(int
immediate)
This is a more general version of Gal_TimedTasksLoopExit.
It causes one of two types of exits: immediate and deferred. An immediate
exit will cancel tasks at the most immediate possible exit point, while
a deferred exit will cancel tasks which are already "scheduled" to happen.
If immediate is non-zero, this call causes an immediate exit,
otherwise a deferred exit. This function halts both threads (if running)
and the timed task loop (if running).
void Gal_MaybeEndTask(int
immediate,
int deferred)
This function introduces an exit point
into a long-running task. For instance, if your (threaded) task is looping
forever and doing blocking reads, you might choose to call Gal_MaybeEndTask()
to check to see if another thread has scheduled an exit via Gal_EndTasks.
If it finds an immediate scheduled exit and immediate is nonzero,
or if it finds a deferred scheduled exit and deferred is nonzero,
the thread will terminate.
int Gal_AddTimedTask(void
*task, void *refcon, long num_millisecs)
Use this function to add a timed task.
The task is a function which takes refcon as its argument
and returns void. The num_millisecs is how long in milliseconds
after the task is added (or, if the loop hasn't been started, how long
after the loop is started) the task should be executed. Once the task is
executed, it is removed from the list of timed tasks; so typically the
last thing the task will do is call Gal_AddTimedTask again. This
function is implemented in terms of the internal function Gal_AddTask.
int Gal_AddTimedTaskWithFileIO(void
*task, void *refcon, long num_millisecs, FILE *read_file,
FILE *write_file)
Use this function to add a timed task
which is sensitive to input and output on file descriptors. If any of the
elements in either of the file descriptor sets is ready for reading and
writing before num_milliseconds has elapsed, the task will nonetheless
be executed. Note that file I/O polling is not available on Win32.
int Gal_AddTimedTaskWithSocketIO(void
*task, void *refcon, long num_millisecs, GAL_SOCKET
*read_socket, GAL_SOCKET *write_socket)
Use this function to add a timed task
which is sensitive to input and output on sockets. If any of the elements
in either of the file descriptor sets is ready for reading and writing
before num_milliseconds has elapsed, the task will nonetheless be
executed.
int Gal_RemoveTimedTask(void
*task, void *refcon)
Removes the given timed task. Note that
tasks are distinguished by task and refcon, so it's not a
good idea to define multiple timed tasks with the same task and refcon.
Please send comments and suggestions
to:bugs-darpacomm@linus.mitre.org
Last updated October 30, 2000.
Copyright (c) 1998, 1999,
2000
The MITRE
Corporation
ALL RIGHTS RESERVED