GSK Reference Manual | ||||
---|---|---|---|---|
Main Loop (Generic Event Management)Main Loop (Generic Event Management) — Convenient way to be notified when certain types of event occur. |
GskMainLoopChange; GskMainLoopEvent; GskMainLoopWaitInfo; GskSource; GskMainLoopContextList; enum GskMainLoopEventType; GskMainLoopClass; GskMainLoop; void (*GskMainLoopWaitPidFunc) (GskMainLoopWaitInfo *info, gpointer user_data); gboolean (*GskMainLoopIdleFunc) (gpointer user_data); gboolean (*GskMainLoopSignalFunc) (int sig_no, gpointer user_data); gboolean (*GskMainLoopTimeoutFunc) (gpointer user_data); gboolean (*GskMainLoopIOFunc) (int fd, GIOCondition condition, gpointer user_data); enum GskMainLoopCreateFlags; GskMainLoop* gsk_main_loop_new (GskMainLoopCreateFlags create_flags); GskMainLoop* gsk_main_loop_default (void); guint gsk_main_loop_run (GskMainLoop *main_loop, gint timeout, guint *t_waited_out); GskSource* gsk_main_loop_add_idle (GskMainLoop *main_loop, GskMainLoopIdleFunc source_func, gpointer user_data, GDestroyNotify destroy); GskSource* gsk_main_loop_add_signal (GskMainLoop *main_loop, int signal_number, GskMainLoopSignalFunc signal_func, gpointer user_data, GDestroyNotify destroy); GskSource* gsk_main_loop_add_waitpid (GskMainLoop *main_loop, int process_id, GskMainLoopWaitPidFunc waitpid_func, gpointer user_data, GDestroyNotify destroy); GskSource* gsk_main_loop_add_io (GskMainLoop *main_loop, int fd, guint events, GskMainLoopIOFunc io_func, gpointer user_data, GDestroyNotify destroy); void gsk_source_adjust_io (GskSource *source, guint events); void gsk_source_remove_io_events (GskSource *source, guint events); void gsk_source_add_io_events (GskSource *source, guint events); GskSource* gsk_main_loop_add_timer (GskMainLoop *main_loop, GskMainLoopTimeoutFunc timer_func, gpointer timer_data, GDestroyNotify timer_destroy, gint64 millis_expire, gint64 milli_period); GskSource* gsk_main_loop_add_timer_absolute (GskMainLoop *main_loop, GskMainLoopTimeoutFunc timer_func, gpointer timer_data, GDestroyNotify timer_destroy, int unixtime, int unixtime_micro); void gsk_source_adjust_timer (GskSource *timer_source, gint64 millis_expire, gint64 milli_period); void gsk_source_remove (GskSource *source); void gsk_main_loop_add_context (GskMainLoop *main_loop, GMainContext *context); void gsk_main_loop_quit (GskMainLoop *main_loop); gboolean gsk_main_loop_should_continue (GskMainLoop *main_loop); GskMainLoop* gsk_source_peek_main_loop (GskSource *source); void gsk_main_loop_destroy_all_sources (GskMainLoop *main_loop); gboolean gsk_main_loop_do_waitpid (int pid, GskMainLoopWaitInfo *wait_info);
A main loop is an object which can trap events and call user functions when those events happen.
The events that our main loop handles are fixed: file-descriptors being readied, signals being delivered, timeouts, idle functions and child-process termination are the currently known events.
GskMainLoop itself is abstract, you must use a system-specific derived class
to do polling. Use gsk_main_loop_default()
to get a main loop which is
appropriate to your system.
typedef struct { GskMainLoopEventType type; union { struct { guint number; gboolean add; } signal; struct { guint fd; GIOCondition old_events; GIOCondition events; } io; struct { gint pid; gboolean add; gboolean did_exit; } process; } data; } GskMainLoopChange;
This structure is passed to the system-dependent polling mechanism to indicate a change in events we want notification of.
GskMainLoopEventType type ; |
what type of change is to occur. |
typedef struct { GskMainLoopEventType type; union { guint signal; struct { guint fd; GIOCondition events; } io; GskMainLoopWaitInfo process_wait_info; } data; } GskMainLoopEvent;
An event passed back from the system-dependent polling mechanism.
GskMainLoopEventType type ; |
what type of event occurred. |
GskMainLoopWaitInfo process_wait_info ; |
typedef struct { int pid; gboolean exited; /* exit(2) or killed by signal? */ union { int signal; /* !exited */ int exit_status; /* exited */ } d; gboolean dumped_core; } GskMainLoopWaitInfo;
Information about a process's termination.
int pid ; |
the process-id which terminated. |
gboolean exited ; |
whether the process exited, versus being killed by a signal, including crashes, which exit with SIGSEGV, SIGABRT, etc. |
gboolean dumped_core ; |
whether the process dumped core. |
typedef enum { GSK_MAIN_LOOP_EVENT_IO, GSK_MAIN_LOOP_EVENT_SIGNAL, GSK_MAIN_LOOP_EVENT_PROCESS } GskMainLoopEventType;
Types of event that can be dealt with by this main-loop.
typedef struct { GObjectClass object_class; gboolean (*setup) (GskMainLoop *main_loop); void (*change) (GskMainLoop *main_loop, GskMainLoopChange *change); guint (*poll) (GskMainLoop *main_loop, guint max_events_out, GskMainLoopEvent *events, gint timeout); } GskMainLoopClass;
The virtual function which must be implemented for each type of main-loop.
GObjectClass object_class ; |
the base class from which the main-loop is derived. |
setup () |
function to call to initialize the main-loop. |
change () |
function invoked to indicate that a change in events we are interested in has occurred. |
poll () |
function invoked to check which events have occurred. |
typedef struct { gint exit_status; GskMainLoopEvent *event_array_cache; unsigned max_events; /* a list of GMainContext's */ GskMainLoopContextList *first_context; GskMainLoopContextList *last_context; } GskMainLoop;
A main-loop. This holds information about all its sources.
gint exit_status ; |
Stored exit status which the user may
return from main() .
|
GskMainLoopEvent *event_array_cache ; |
|
GskMainLoopContextList *first_context ; |
first GMainContext in the list. |
GskMainLoopContextList *last_context ; |
last GMainContext in the list. |
void (*GskMainLoopWaitPidFunc) (GskMainLoopWaitInfo *info, gpointer user_data);
A function which will be invoked when a process terminates.
info : |
information about the process and why it terminated. |
user_data : |
data registered to gsk_main_loop_add_waitpid() .
|
gboolean (*GskMainLoopIdleFunc) (gpointer user_data);
Function to be called repetitively (that is, with no blocking or waiting; however,
other events will continue to be processed). It will stop when gsk_main_loop_remove()
is run on its source, or if it returns FALSE.
user_data : |
data registered to gsk_main_loop_add_idle() .
|
Returns : | whether to continue running. |
gboolean (*GskMainLoopSignalFunc) (int sig_no, gpointer user_data);
Function to be called whenever a UNIX signal of a particular number is raised.
It will be untrapped when gsk_main_loop_remove()
is run on its source,
or if it returns FALSE.
sig_no : |
the number of the signal that was raised. |
user_data : |
data registered to gsk_main_loop_add_signal() .
|
Returns : | whether to continue trapping the unix signal. |
gboolean (*GskMainLoopTimeoutFunc) (gpointer user_data);
Function to invoke whenever a timeout expires.
It will be untrapped when gsk_main_loop_remove()
is run on its source,
or if it returns FALSE, or after it runs if it was registered as a one-shot (with
milli_period==-1).
user_data : |
data registered to gsk_main_loop_add_timer() or
gsk_main_loop_add_timer_absolute() .
|
Returns : | whether to keep running this timer. (Will be ignored if it is a one-shot timer or if the source has been destroyed) |
gboolean (*GskMainLoopIOFunc) (int fd, GIOCondition condition, gpointer user_data);
Function to run whenever some subset of a set of requested events are noticed.
fd : |
the file-descriptor that the events occured on. |
condition : |
the events that triggered the callback. |
user_data : |
data registered to gsk_main_loop_add_io() .
|
Returns : | whether to keep these source. |
typedef enum { GSK_MAIN_LOOP_NEEDS_THREADS = (1 << 0) } GskMainLoopCreateFlags;
Indicate user requirements for the main-loop being constructed.
GskMainLoop* gsk_main_loop_new (GskMainLoopCreateFlags create_flags);
Make a new main loop.
create_flags : |
Stipulations on the nature of the main-loop. |
Returns : | a new main loop. |
GskMainLoop* gsk_main_loop_default (void);
Get the main-loop which is associated with the current thread.
Returns : | a pointer to the main-loop. This function does not
increase the ref-count on the main-loop, so you do not need
to call g_object_unref() on the return value.
|
guint gsk_main_loop_run (GskMainLoop *main_loop, gint timeout, guint *t_waited_out);
Run the main loop once, for a specified number of milliseconds.
main_loop : |
the main loop to run. |
timeout : |
the maximum number of milliseconds to run, or -1 for no maximum. |
t_waited_out : |
the number of milliseconds out used, if non-NULL. |
Returns : | the number of sources processed. |
GskSource* gsk_main_loop_add_idle (GskMainLoop *main_loop, GskMainLoopIdleFunc source_func, gpointer user_data, GDestroyNotify destroy);
This adds an idle function to the main loop. An idle function is a function which gets called every time the main loop is run. Furthermore, while there are idle functions, the main loop will never block.
One popular use of idle functions is to defer an operation, usually because either something is not in a good state to call immediately, or because there may be many requests that should be handled at one time.
main_loop : |
the loop to add the idle function to. |
source_func : |
the function to call. |
user_data : |
parameter to be passed to source_func
|
destroy : |
to be called when the source is destroyed. |
Returns : | a GskSource which can be removed (or ignored). |
GskSource* gsk_main_loop_add_signal (GskMainLoop *main_loop, int signal_number, GskMainLoopSignalFunc signal_func, gpointer user_data, GDestroyNotify destroy);
Add a signal handler to the main loop.
Please note that unlike a normal unix signal handler (as provided by signal(2) or sigaction(2)), this handler will be run synchronously, so you can call non-reentrant methods.
Also, because unix signal delivery is unreliable, if the signal is raised a few times in rapid succession, you may miss some callbacks.
It is ok to connect multiple times to a single signal simulataneously.
main_loop : |
the loop to add the unix signal handler function to. |
signal_number : |
the number of the signal handler, like SIGINT. |
signal_func : |
the function to run synchronously when a unix signal is raised. |
user_data : |
data to be passed to signal_func .
|
destroy : |
to be called when the source is destroyed. |
Returns : | a GskSource which can be removed (or ignored). |
GskSource* gsk_main_loop_add_waitpid (GskMainLoop *main_loop, int process_id, GskMainLoopWaitPidFunc waitpid_func, gpointer user_data, GDestroyNotify destroy);
Add a handler to trap process termination.
Only one handler is allowed per child process.
The handler will be invoked synchronously.
main_loop : |
the loop to add the child-process termination handler function to. |
process_id : |
the child's process-id to wait for. |
waitpid_func : |
function to call when the process terminates in some way or another. |
user_data : |
data to be passed to waitpid_func
|
destroy : |
to be called when the source is destroyed. |
Returns : | GskSource which can be removed (or ignored). |
GskSource* gsk_main_loop_add_io (GskMainLoop *main_loop, int fd, guint events, GskMainLoopIOFunc io_func, gpointer user_data, GDestroyNotify destroy);
Add a handler to input or output on a file-descriptor (a socket or a pipe, usually).
Only one handler trap is allowed per file-descriptor.
The handler will be re-invoked until the event subsides.
For example, if you read only part of the data when a input event is raised,
the io_func
will be invoked again at every iteration of the main-loop
until there is no data available.
main_loop : |
the loop to add the i/o watch to. |
fd : |
the file-descriptor to watch for events. |
events : |
initial I/O events to watch for. |
io_func : |
a function to call when the currently requested events occur. |
user_data : |
data to be passed to io_func
|
destroy : |
to be called when the source is destroyed. |
Returns : | a GskSource which can be removed or altered. |
void gsk_source_adjust_io (GskSource *source, guint events);
This changes the types of events being watched by the main-loop.
Note: each new file-descriptor needs a new GskSource. You must reuse this GskSource for a new file-descriptor even if it happens to have the same numeric value as a file-descriptor you closed. (The reason why: GSK automatically coagulates multiple adjust_io calls. This is fine with all main-loops. However, kqueue(2) on BSD, and possibly others, automatically unregister all interest in an event if the file-descriptor closes. Hence, if the file-descriptor is re-opened and re-used with the same GskSource, GSK will not be able to determine that anything has changed, and will not issue a new GskMainLoopChange. This will break main-loops that are sensitive to exact which file-descriptor (not just the number) was registered.)
source : |
the I/O source which now wants to watch different events. |
events : |
the new events to watch for the I/O source. |
void gsk_source_remove_io_events (GskSource *source, guint events);
Cause this source to stop being notified if any of the events in
the events
parameter are set.
source : |
the input/output source whose events-of-interest set should be reduced. |
events : |
new events which should stop causing source to wake-up.
|
void gsk_source_add_io_events (GskSource *source, guint events);
Cause this source to be notified if any of the events in
the events
parameter are set, in addition to the events which
already caused this source to be woken up.
source : |
the input/output source whose events-of-interest set should be expanded. |
events : |
new events which should cause source to wake-up.
|
GskSource* gsk_main_loop_add_timer (GskMainLoop *main_loop, GskMainLoopTimeoutFunc timer_func, gpointer timer_data, GDestroyNotify timer_destroy, gint64 millis_expire, gint64 milli_period);
Add a timeout function to the main-loop. This is a function that will be called after a fixed amount of time passes, and then may be called at a regular interval thereafter.
main_loop : |
the main-loop which should keep track and run the timeout. |
timer_func : |
function to call when the requested amount of time elapses. |
timer_data : |
data to pass to timer_func .
|
timer_destroy : |
optional function to call to destroy the timer_data .
|
millis_expire : |
number of milliseconds to wait before running timer_func .
|
milli_period : |
period between subsequent invocation of the timeout. This may be -1 to indicate that the timeout is a one-shot. |
Returns : | GskSource which can be removed or altered. |
GskSource* gsk_main_loop_add_timer_absolute (GskMainLoop *main_loop, GskMainLoopTimeoutFunc timer_func, gpointer timer_data, GDestroyNotify timer_destroy, int unixtime, int unixtime_micro);
Add a timeout function to the main-loop.
The timer_func
will be called as soon as we detect that the specified time has passed.
The time to wait until is (unixtime
+ unixtime_micro
* 10^{-6}) seconds after
New Years, Jan 1, 1970 GMT.
main_loop : |
the main-loop which should keep track and run the timeout. |
timer_func : |
function to call when the requested amount of time elapses. |
timer_data : |
data to pass to timer_func .
|
timer_destroy : |
optional function to call to destroy the timer_data .
|
unixtime : |
number of seconds since Jan 1, 1970 GMT that will have passed when the timer should expire. |
unixtime_micro : |
fractional part of unixtime , in microseconds.
|
Returns : | a GskSource which can be removed or altered. |
void gsk_source_adjust_timer (GskSource *timer_source, gint64 millis_expire, gint64 milli_period);
Adjust the timeout and period for an already existing timer source. (You may only call this on timer sources.)
timer_source : |
the timeout source returned by gsk_main_loop_add_timer() or gsk_main_loop_add_timer_absolute() .
|
millis_expire : |
the number of milliseconds from now that the timer should run. |
milli_period : |
the period between subsequent runs of the timer, or -1 to indicate that the timer is a one-shot. |
void gsk_source_remove (GskSource *source);
Destroy a main loop's source.
If the source is currently running, it's destroy method will not be called until the source's callback returns. (This way, important data won't be deleted unexpectedly in the middle of the user's callback.)
source : |
the source to remove and destroy. |
void gsk_main_loop_add_context (GskMainLoop *main_loop, GMainContext *context);
Indicate that a particular GskMainLoop will take care of
invoking the necessary methods of context
.
main_loop : |
main-loop which will take responsibility for context .
|
context : |
a GMainContext that should be handled by gsk_main_loop_run() .
|
void gsk_main_loop_quit (GskMainLoop *main_loop);
Set the main-loop flag that indicates that it should really stop running.
If you are executing a GskMainLoop using gsk_main_loop_run()
,
then you should probably check gsk_main_loop_should_continue()
at every iteration
to ensure that you should not have quit by now.
main_loop : |
the main-loop which is being asked to quit. |
gboolean gsk_main_loop_should_continue (GskMainLoop *main_loop);
Query whether the main-loop should keep running or not.
main_loop : |
the main-loop to query. |
Returns : | whether to keep running this main-loop. |
GskMainLoop* gsk_source_peek_main_loop (GskSource *source);
Get the main-loop where the source was created.
source : |
the source to query. |
Returns : | the main-loop associated with the source. |
void gsk_main_loop_destroy_all_sources (GskMainLoop *main_loop);
main_loop : |
gboolean gsk_main_loop_do_waitpid (int pid, GskMainLoopWaitInfo *wait_info);
Do a waitpid system call on the process and munge the
data into wait_info
for the caller to use.
pid : |
the process id to wait for. |
wait_info : |
place to collect termination status of the process. |
Returns : | whether the waitpid succeeded. |