Lightweight Hookable Events

Lightweight Hookable Events — a blockable, optionally shutdown-able, trap-able structure inside a GObject.

Synopsis




            GskHook;
gboolean    (*GskHookFunc)                  (GObject *object,
                                             gpointer data);
void        (*GskHookSetPollFunc)           (GObject *object,
                                             gboolean do_polling);
void        (*GskHookShutdownFunc)          (GObject *object);
gboolean    (*GskHookShutdownErrorFunc)     (GObject *object,
                                             GError **error);
enum        GskHookFlags;
#define     GSK_HOOK_GET_OBJECT             (hook)
#define     GSK_HOOK_TEST_FLAG              (hook, flag_shortname)
#define     GSK_HOOK_SET_FLAG
#define     GSK_HOOK_CLEAR_FLAG             (hook, flag_shortname)
#define     GSK_HOOK_TEST_USER_FLAG         (hook, bit)
#define     GSK_HOOK_MARK_USER_FLAG         (hook, bit)
#define     GSK_HOOK_CLEAR_USER_FLAG        (hook, bit)
#define     GSK_HOOK_TEST_SHUTTING_DOWN     (hook)
#define     GSK_HOOK_TEST_NEVER_BLOCKS      (hook)
#define     GSK_HOOK_TEST_IS_AVAILABLE      (hook)
#define     GSK_HOOK_TEST_IDLE_NOTIFY       (hook)
void        gsk_hook_trap                   (GskHook *hook,
                                             GskHookFunc func,
                                             GskHookFunc shutdown,
                                             gpointer data,
                                             GDestroyNotify destroy);
void        gsk_hook_untrap                 (GskHook *hook);
#define     gsk_hook_is_trapped             (hook)
void        gsk_hook_block                  (GskHook *hook);
void        gsk_hook_unblock                (GskHook *hook);
gboolean    gsk_hook_shutdown               (GskHook *hook,
                                             GError **error);
void        gsk_hook_init                   (GskHook *hook,
                                             GskHookFlags flags,
                                             guint inset,
                                             guint class_set_poll_offset,
                                             guint class_shutdown_offset);
void        gsk_hook_class_init             (GObjectClass *object_class,
                                             const char *name,
                                             guint hook_offset);
void        gsk_hook_notify                 (GskHook *hook);
void        gsk_hook_notify_shutdown        (GskHook *hook);
void        gsk_hook_destruct               (GskHook *hook);
void        gsk_hook_set_idle_notify        (GskHook *hook,
                                             gboolean should_idle_notify);
void        gsk_hook_mark_idle_notify       (GskHook *hook);
void        gsk_hook_clear_idle_notify      (GskHook *hook);
void        gsk_hook_mark_never_blocks      (GskHook *hook);
gboolean    gsk_hook_get_last_poll_state    (GskHook *hook);
#define     GSK_HOOK_INIT                   (object, struct, member, flags, set_poll, shutdown)
#define     GSK_HOOK_INIT_NO_SHUTDOWN       (object, struct, member, flags, set_poll)
#define     GSK_HOOK_CLASS_INIT             (object_class, hook_name, Type, member)

Description

GskHook is to be used as a member of a GObject. Its class must have at least a GskHookSetPollFunc member, and for hooks which have a corresponding shutdown method, that should be in the class as well.

The point of this class is to encapsulate i/o event handling. This means that it must be possible to trap the event, and it also must not waste cpu notifying us if the event is not trapped.

Therefore, GskHook has two components: (1) methods to make it easy to write classes which have GskHooks in them. (2) methods to be exposed to an end user of such a class: meaning, ways to trap, untrap, block, unblock the events.

To implement a class which contains a GskHook, traditionally, you should have a set_poll method of the class which should just turn on or off whether the class tries to call gsk_hook_notify(). Furthermore, you might want a shutdown method. It's optional.

Sometimes a hook is always ready to trigger. You can call gsk_hook_mark_idle_notify() to cause the hook to trigger constantly, if it's trapped and unblocked. Also, gsk_hook_clear_idle_notify() stops that. In this case, you may not need a set_poll function even.

When a hook is shut down, it is marked as unavailable. When you wish to shut down a hook, you should call gsk_hook_shutdown(). Typically, the shutdown happens immediately. However, the implementation of a class that contains a hook may need to leave the object in a transitional state, SHUTTING_DOWN. Even if this happens, the hook is still marked as unavailable. The implementation should eventually call gsk_hook_notify_shutdown() to indicate that the shutdown finally finished. The shutdown hook registered with gsk_hook_trap() will only be run after gsk_hook_notify_shutdown() is called in that case.

Details

GskHook

typedef struct {
} GskHook;

A structure which you can embed in a GObject. All of its members are private.


GskHookFunc ()

gboolean    (*GskHookFunc)                  (GObject *object,
                                             gpointer data);

To be called when the hook is triggered.

object : the object which contains this hook.
data : user-data passed in to gsk_hook_trap
Returns : whether the hook should stay trapped.

GskHookSetPollFunc ()

void        (*GskHookSetPollFunc)           (GObject *object,
                                             gboolean do_polling);

To be called when the class should start or stop calling gsk_hook_notify.

object : the object which contains this hook.
do_polling : whether to trigger the hook.

GskHookShutdownFunc ()

void        (*GskHookShutdownFunc)          (GObject *object);

This function is how the "shutdown" method in a class will be invoked (if the hook WAS NOT created with GSK_HOOK_CAN_HAVE_SHUTDOWN_ERROR; see GskHookShutdownErrorFunc).

GSK automatically untraps after this is over, since there is no more potential for this hook to trigger.

object : the object whose hook should shut down.

GskHookShutdownErrorFunc ()

gboolean    (*GskHookShutdownErrorFunc)     (GObject *object,
                                             GError **error);

This function is how the "shutdown" method in a class will be invoked (if the hook WAS NOT created without GSK_HOOK_CAN_HAVE_SHUTDOWN_ERROR; see GskHookShutdownErrorFunc).

This function returns with whether the shutdown completed successfully.

If this function return FALSE but sets no error, then this hook is not shutdown, but it is working on shutting down. (The shutdown notify hook should be called by the object itself later.)

object : the object whose hook should shut down.
error : place for an error to be placed if shutdown fails.
Returns : whether shutdown succeeds.

enum GskHookFlags

typedef enum
{
  GSK_HOOK_IS_AVAILABLE            	= (1 << 0),
  GSK_HOOK_NEVER_AUTO_SHUTS_DOWN   	= (1 << 1),
  GSK_HOOK_CAN_HAVE_SHUTDOWN_ERROR 	= (1 << 2),
  GSK_HOOK_private_IDLE_NOTIFY     	= (1 << 3), /*< private >*/
  GSK_HOOK_private_JUST_NEVER_BLOCKS    = (1 << 4), /*< private >*/
  GSK_HOOK_private_NEVER_BLOCKS		= (GSK_HOOK_private_IDLE_NOTIFY | GSK_HOOK_private_JUST_NEVER_BLOCKS), /*< private >*/
  GSK_HOOK_private_CAN_DEFER_SHUTDOWN   = (1 << 5), /*< private >*/
  GSK_HOOK_private_SHUTTING_DOWN        = (1 << 6), /*< private >*/
  _GSK_HOOK_FLAGS_RESERVED	   	= (0xff << 8), /*< private >*/
} GskHookFlags;

Flags which can be read about any hook. See GSK_HOOK_TEST_FLAG(), GSK_HOOK_SET_FLAG() and GSK_HOOK_CLEAR_FLAG().

GSK_HOOK_IS_AVAILABLE whether the hook is available to be trapped. (It is not available either because it was never available, or because it was shut down.)
GSK_HOOK_NEVER_AUTO_SHUTS_DOWN whether the hook will auto-shutdown in some circumstances, ie due to end-of-file or error.
GSK_HOOK_CAN_HAVE_SHUTDOWN_ERROR whether this hook can have an error on shutdown.
GSK_HOOK_private_IDLE_NOTIFY private. (used by macros so it has to be exposed)
GSK_HOOK_private_JUST_NEVER_BLOCKS private. (used by macros so it has to be exposed)
GSK_HOOK_private_NEVER_BLOCKS private. (used by macros so it has to be exposed)
GSK_HOOK_private_CAN_DEFER_SHUTDOWN
GSK_HOOK_private_SHUTTING_DOWN private. (used by macros so it has to be exposed)
_GSK_HOOK_FLAGS_RESERVED bits used internally. private.

GSK_HOOK_GET_OBJECT()

#define GSK_HOOK_GET_OBJECT(hook)	(G_OBJECT ((char *) (hook) - (hook)->inset))

Get a pointer to the GObject which owns this hook.

hook : the hook whose GObject should be found.

GSK_HOOK_TEST_FLAG()

#define     GSK_HOOK_TEST_FLAG(hook, flag_shortname)

Test if a particular flag in the GskHook is set.

hook : the hook to test.
flag_shortname : the name of the flag, without its GSK_HOOK prefix.

GSK_HOOK_SET_FLAG

#define GSK_HOOK_SET_FLAG GSK_HOOK_MARK_FLAG

Set the bit of the hook to TRUE. This should only be used by implementors of GskHook-containing objects.


GSK_HOOK_CLEAR_FLAG()

#define     GSK_HOOK_CLEAR_FLAG(hook, flag_shortname)

Set the bit of the hook to FALSE. This should only be used by implementors of GskHook-containing objects.

hook : the hook to affect.
flag_shortname : the name of the flag, without its GSK_HOOK prefix.

GSK_HOOK_TEST_USER_FLAG()

#define     GSK_HOOK_TEST_USER_FLAG(hook, bit)

Test if a class-usable bit of the hook is TRUE.

hook : the hook whose class-usable bit should be tested.
bit : the bit. (a guint16)

GSK_HOOK_MARK_USER_FLAG()

#define     GSK_HOOK_MARK_USER_FLAG(hook, bit)

Set a class-usable bit of the hook to TRUE.

hook : the hook whose class-usable bit should be marked (set to 1).
bit : the bit. (a guint16)

GSK_HOOK_CLEAR_USER_FLAG()

#define     GSK_HOOK_CLEAR_USER_FLAG(hook, bit)

Set a class-usable bit of the hook to FALSE.

hook : the hook whose class-usable bit should be cleared (set to 0).
bit : the bit. (a guint16)

GSK_HOOK_TEST_SHUTTING_DOWN()

#define GSK_HOOK_TEST_SHUTTING_DOWN(hook) GSK_HOOK_TEST_FLAG(hook, private_SHUTTING_DOWN)

Test if a hook is in the process of shutting down.

hook : the hook to query.

GSK_HOOK_TEST_NEVER_BLOCKS()

#define GSK_HOOK_TEST_NEVER_BLOCKS(hook) GSK_HOOK_TEST_FLAG(hook, private_NEVER_BLOCKS)

Test if a hook is permanently non-blocking.

hook : the hook to query.

GSK_HOOK_TEST_IS_AVAILABLE()

#define GSK_HOOK_TEST_IS_AVAILABLE(hook) GSK_HOOK_TEST_FLAG(hook, IS_AVAILABLE)

Test if a hook is available for trapping.

hook : the hook to query.

GSK_HOOK_TEST_IDLE_NOTIFY()

#define GSK_HOOK_TEST_IDLE_NOTIFY(hook)  GSK_HOOK_TEST_FLAG(hook, private_IDLE_NOTIFY)

Test whether this hook is in the idle-notify state, meaning that it will trigger an active trap constantly.

hook : the hook to query.

gsk_hook_trap ()

void        gsk_hook_trap                   (GskHook *hook,
                                             GskHookFunc func,
                                             GskHookFunc shutdown,
                                             gpointer data,
                                             GDestroyNotify destroy);

Traps hook triggers and shutdowns. The caller's functions will be run in response to gsk_hook_notify.

hook : the hook to trap
func : function to call with the hook is triggered.
shutdown : function to be called if the hook is shutting down and will never trigger again.
data : user-data to pass to func and shutdown.
destroy : function to call on user-data when the hook is untrapped.

gsk_hook_untrap ()

void        gsk_hook_untrap                 (GskHook *hook);

Stops trapping the hook. The user's function will no longer be run, and invoke the user's destroy method, if it was supplied to gsk_hook_trap.

If you untrap the hook while it is executing, the destroy handler will be deferred until after the hook is done notifying and/or shutdown-notifying.

hook : the hook to untrap

gsk_hook_is_trapped()

#define gsk_hook_is_trapped(hook) (((hook)->func) != NULL)

Return whether the hook is trapped (has a callback).

Note that the hook may be blocked.

hook : the hook to test.

gsk_hook_block ()

void        gsk_hook_block                  (GskHook *hook);

Temporarily block the hook from triggerring the callback. This may cause the set_poll method to be run.

This increases a block_count, so you may call gsk_hook_block as many times as you like, but you must call gsk_hook_unblock an equal number of times.

hook : the hook to block.

gsk_hook_unblock ()

void        gsk_hook_unblock                (GskHook *hook);

Undoes a gsk_hook_block(). The block count is decreased, and if it gets to 0, the hook may be eligible to start triggering again.

hook : the hook to unblock.

gsk_hook_shutdown ()

gboolean    gsk_hook_shutdown               (GskHook *hook,
                                             GError **error);

Shutdown a hook. You may call gsk_hook_shutdown on a hook more than once, but it will be ignored after the first time.

Note that when gsk_hook_shutdown succeeds, the hook is not necessarily completely shut down. Some hooks (for example, for a socket waiting for a reply from a remote server) may remain in the SHUTTING_DOWN state for some time before the shutdown completes and the user's shutdown callback is invoked. You may test whether the shutdown has completed using GSK_HOOK_TEST_SHUTTING_DOWN (hook): if true, the shutdown is still in progress.

Regardless of whether the shutdown succeeds, or whether the shutdown completes immediately, the hook will be marked unavailable after calling gsk_hook_shutdown. (That is, GSK_HOOK_TEST_IS_AVAILABLE (hook) will be false.)

hook : the hook to shut down.
error : optional error return.
Returns : true if successful, or false if an error occurred.

gsk_hook_init ()

void        gsk_hook_init                   (GskHook *hook,
                                             GskHookFlags flags,
                                             guint inset,
                                             guint class_set_poll_offset,
                                             guint class_shutdown_offset);

Prepare a GskHook to be used. This should almost always be done in the instance-init function of the class which contains the hook.

hook : The hook to initialize.
flags : Special details about the hook.
inset : Offset in bytes of this hook inside the containing object.
class_set_poll_offset : Offset in bytes of the set_poll method in the containing object's class.
class_shutdown_offset : Offset in bytes of the shutdown method in the containing object's class, or 0 if there is no shutdown method.

gsk_hook_class_init ()

void        gsk_hook_class_init             (GObjectClass *object_class,
                                             const char *name,
                                             guint hook_offset);

This is used to register a hook. This is mostly used to make debugging printouts easier to read.

object_class : the class of the object which contains this hook.
name : an identifying name for this type of hook.
hook_offset : the offset of the hook in the structure.

gsk_hook_notify ()

void        gsk_hook_notify                 (GskHook *hook);

This is called by the implementation of a class which contains a hook to trigger it, i.e. call the user's callback.

Generally, you should only call this if the user is ready for data (so that set_poll has been called with TRUE); however, if you call it, it will be remembered, and immediately triggered once it is allowed to: for example, when the block count gets to 0.

Some gory details come up now and then:

- there are reentrance guards which prevent recursive calls to do anything. Also, notify within shutdown is not allowed.

hook : the hook which is triggering.

gsk_hook_notify_shutdown ()

void        gsk_hook_notify_shutdown        (GskHook *hook);

Notify the user that a shutdown event has occurred. This may happen because you called gsk_hook_shutdown() or because the hook was shut down by the object: for example, the remote side of a connection may have shutdown.

This does nothing if the hook is not presently available or in the middle of shutting down (i.e., IS_AVAILABLE || SHUTTING_DOWN); after this call the hook will be marked both unavailable and completely shut down (i.e., !IS_AVAILABLE && !SHUTTING_DOWN).

A shutdown hook will no longer be idle-notified.

hook : the hook which has shut down.

gsk_hook_destruct ()

void        gsk_hook_destruct               (GskHook *hook);

This should be called only by the class which contains the hook, from the instance's finalize method.

hook : the hook to destroy.

gsk_hook_set_idle_notify ()

void        gsk_hook_set_idle_notify        (GskHook *hook,
                                             gboolean should_idle_notify);

When idle_notify is set, the hook will run every cycle of the main-loop. Nothing will happen unless the user has trapped the event, and it's not blocked.

Opposite of gsk_hook_clear_idle_notify().

hook : the hook to run constantly.
should_idle_notify : whether to run the user's callback continually.

gsk_hook_mark_idle_notify ()

void        gsk_hook_mark_idle_notify       (GskHook *hook);

When idle_notify is set, the hook will run every cycle of the main-loop. Of course, nothing will happen unless the user has trapped the event, and it's not blocked.

Opposite of gsk_hook_clear_idle_notify().

hook : the hook to run constantly.

gsk_hook_clear_idle_notify ()

void        gsk_hook_clear_idle_notify      (GskHook *hook);

Stop running the hook at every cycle of the main-loop.

Opposite of gsk_hook_set_idle_notify().

hook : the hook to stop running constantly.

gsk_hook_mark_never_blocks ()

void        gsk_hook_mark_never_blocks      (GskHook *hook);

Indicate that you will never block, ever.

hook : the hook which will never block.

gsk_hook_get_last_poll_state ()

gboolean    gsk_hook_get_last_poll_state    (GskHook *hook);

Get whether this hook is supposed to be polling or not.

hook : test whether the last invocation of the set-poll function was called with TRUE or FALSE.
Returns : whether the hook is being polled.

GSK_HOOK_INIT()

#define     GSK_HOOK_INIT(object, struct, member, flags, set_poll, shutdown)

Initialize a hook which is contained in a GObject. This should only be used for GObject instance init functions.

object : a pointer to an instance of a GObject.
struct : name of type for this init function.
member : member name of hook inside of type struct.
flags : GskHookFlags which apply to this hook.
set_poll : member function of type gboolean(*)(GObject*, gpointer) in the class whose name is struct with Class appended. to call to specify whether or not the hook should be triggered.
shutdown : member function to perform shutdown in the class whose name is struct with Class appended.

GSK_HOOK_INIT_NO_SHUTDOWN()

#define     GSK_HOOK_INIT_NO_SHUTDOWN(object, struct, member, flags, set_poll)

Initialize a hook which is contained in a GObject. This should only be used for GObject instance init functions. This hook is for when have no shutdown virtual is wanted in the base class.

object : a pointer to an instance of a GObject.
struct : name of type for this init function.
member : member name of hook inside of type struct.
flags : GskHookFlags which apply to this hook.
set_poll : member function of type gboolean(*)(GObject*, gpointer) in the class whose name is struct with Class appended. to call to specify whether or not the hook should be triggered.

GSK_HOOK_CLASS_INIT()

#define     GSK_HOOK_CLASS_INIT(object_class, hook_name, Type, member)

For assigning a hook a name. This is mostly used by debugging printout code.

object_class : a class whose instances will always have hooks.
hook_name : name of the hook.
Type : type name of the instance.
member : member name of this hook in Type.

See Also

GskIO, GskStream