## Main Loop (Generic Event Management)

Main Loop (Generic Event Management) — Convenient way to be notified when certain types of event occur.

## Synopsis

                        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);

## Object Hierarchy

      GObject
       +----GskMainLoop
             +----GskMainLoopPollBase
             +----GskMainLoopKqueue

## Description

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.

## Details

### GskMainLoopChange

    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.

### GskMainLoopEvent

    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`; |

### GskMainLoopWaitInfo

    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.

### GskSource

    typedef struct _GskSource GskSource;

An opaque object representing a trap of an event.

### GskMainLoopContextList

    typedef struct _GskMainLoopContextList GskMainLoopContextList;

Private.

### enum GskMainLoopEventType

    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.

`GSK_MAIN_LOOP_EVENT_IO` | An input/output event. This is really just a file-descriptor event.
`GSK_MAIN_LOOP_EVENT_SIGNAL` |
`GSK_MAIN_LOOP_EVENT_PROCESS` |

### GskMainLoopClass

    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.

### GskMainLoop

    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.

### GskMainLoopWaitPidFunc ()

    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()`.

### GskMainLoopIdleFunc ()

    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.

### GskMainLoopSignalFunc ()

    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.

### GskMainLoopTimeoutFunc ()

    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)

### GskMainLoopIOFunc ()

    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.

### enum GskMainLoopCreateFlags

    typedef enum
    {
      GSK_MAIN_LOOP_NEEDS_THREADS = (1 << 0)
    } GskMainLoopCreateFlags;

Indicate user requirements for the main-loop being constructed.

`GSK_MAIN_LOOP_NEEDS_THREADS` | Some main loops (like GskMainLoopKqueue) don't cooperate with threads at all! This flag precludes choosing main-loops which are have this property. If you don't need threads, this flag does not hurt, except that `kqueue()` is a pretty good mechanism, so you probably want to get it right for a high-volume single-threaded server.

### gsk_main_loop_new ()

    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.

### gsk_main_loop_default ()

    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.

### gsk_main_loop_run ()

    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.

### gsk_main_loop_add_idle ()

    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).

### gsk_main_loop_add_signal ()

    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).

### gsk_main_loop_add_waitpid ()

    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).

### gsk_main_loop_add_io ()

    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.

### gsk_source_adjust_io ()

    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.

### gsk_source_remove_io_events ()

    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.

### gsk_source_add_io_events ()

    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.

### gsk_main_loop_add_timer ()

    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.

### gsk_main_loop_add_timer_absolute ()

    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.

### gsk_source_adjust_timer ()

    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.

### gsk_source_remove ()

    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.

### gsk_main_loop_add_context ()

    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()`.

### gsk_main_loop_quit ()

    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.

### gsk_main_loop_should_continue ()

    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.

### gsk_source_peek_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.

### gsk_main_loop_destroy_all_sources ()

    void                gsk_main_loop_destroy_all_sources   (GskMainLoop *main_loop);

`main_loop` : |

### gsk_main_loop_do_waitpid ()

    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.