PEVENT(3)

NAME
pevent - pthread event library

LIBRARY
PDEL Library (libpdel, -lpdel)

SYNOPSIS
#include <pthread.h>
#include <pdel/util/pevent.h>
struct pevent_ctx *
pevent_ctx_create(const char *mtype, const pthread_attr_t *attr);
void
pevent_ctx_destroy(struct pevent_ctx **ctxp);
u_int
pevent_ctx_count(struct pevent_ctx *ctx);
int
pevent_register(struct pevent_ctx *ctx, struct pevent **peventp, int flags, pthread_mutex_t *mutex, pevent_handler_t *handler, void *arg, enum pevent_type type, ...);
void
pevent_unregister(struct pevent **eventp);
void
pevent_trigger(struct pevent *event);
int
pevent_get_info(struct pevent *event, struct pevent_info *info);

DESCRIPTION
These functions support event-driven programming. Event-driven programming is simpler and more efficient than threaded programming because only a single thread is created to handle all blocking operations, rather than a new thread per operation. However, because the thread's stack cannot be used to store information between events, each event must be handled to completion, i.e., the event handlers must not block before returning.

Event handlers that block may also be used with these routines, but only if a separate thread is spawned for the handler (see below).

  Event contexts
pevent_ctx_create() creates a new event context, which is used to register events. All events registered with the same event context will be serviced by the single thread associated with that event context.

The scheduling attributes contained in *attr are used when creating this thread; if attr is NULL then the default thread attributes are used. Since pevent_ctx_create() makes a copy of these attributes, attr may be discarded when pevent_ctx_create() returns.

mtype is the typed_mem(3) memory type used when allocating memory for the event context.

pevent_ctx_destroy() destroys an event context. Any events still registered are automatically unregistered. Upon return, *ctxp is set to NULL. If *ctxp is already NULL when pevent_ctx_destroy() is invoked, nothing happens.

It is safe to call pevent_ctx_destroy() from within an event handler function.

pevent_ctx_count() returns the number of events currently registered with ctx.

  Events
pevent_register() creates a new event and registers it with ctx. If successful, zero is returned and a non- NULL reference to the event is stored in *peventp. When pevent_register() is invoked, *peventp must be NULL or else an error will be returned with errno set to EBUSY. If pevent_register() returns an error, *peventp will be unmodified.

handler must point to a function having this type:

    typedef void pevent_handler_t(void *arg);

When the event occurs, *peventp is set to NULL and then handler(arg) is invoked. Therefore, *peventp is not equal to NULL if and only if the event is still pending. For this to work, *peventp must remain valid and unmodified while the event is pending, and the user code must initialize peventp to NULL before the first call to pevent_register().

The type and subsequent argument(s) define the event itself; type may have be one of the following values:

PEVENT_READ
    Readable condition on a file descriptor. The next argument must have type int.

PEVENT_WRITE
    Writable condition on a file descriptor. The next argument must have type int.

PEVENT_TIME
    Time passage. The next argument must have type int, and it is the relative time delay in milliseconds. Negative delay values are silently converted to zero.

PEVENT_MESG_PORT
    Message(s) available on a message port. The next argument must have type struct mesg_port *.

PEVENT_USER
    User-triggered event. No further arguments are required.

The flags parameter may contain any of the following values OR'd together:

PEVENT_RECURRING
    The event is recurring.

PEVENT_OWN_THREAD
    Invoke handler() in a separate thread.

PEVENT_RECURRING causes the event to be automatically re-registered just before each invocation of handler(). In particular, this means that *peventp will not be NULL when handler() is invoked.

PEVENT_OWN_THREAD causes a new thread to be spawned for each invocation of handler(); this thread may block, exit, or be canceled, and is by default not joinable. If this flag is not set, handler() will execute in the event context's main thread, in which case handler() must not block or exit and the thread must not be canceled.

pevent_unregister() unregisters the event referenced by *peventp. Upon return, *peventp is set to NULL. If *peventp is already NULL when pevent_unregister() is invoked, nothing happens.

pevent_trigger() manually triggers an event, causing its handler to be invoked. Although intended for use with PEVENT_USER events, it will work with any event. The event may be NULL, in which case nothing happens.

pevent_get_info() returns the type and parameters associated with event by filling in the struct pevent_info structure pointed to by info:

    struct pevent_info {
        enum pevent_type    type;    /* event type */
        union {
            int              fd;       /* file descriptor (READ, WRITE) */
            int              millis;   /* delay in milliseconds (TIME) */
            struct mesg_port *port;    /* message port (MESG_PORT) */
        };                  u;
    };

  Synchronization
pevent_ctx_count(), pevent_register(), pevent_unregister(), pevent_trigger(), and pevent_get_info() may all safely be called from different threads simultaneously. However, there are inherent race conditions between an event's handler() being invoked and reading the value of *peventp or unregistering the event with pevent_unregister(). The mutex parameter to pevent_register() can be used to avoid these problems.

If a non- NULL mutex is provided to pevent_register(), then pevent will acquire *mutex just before setting *pevent to NULL and invoking handler(), and *mutex will be automatically released when handler() returns (or, in the case of PEVENT_OWN_THREAD, the handler thread exits by any means). If the user code acquires this mutex before any calls to pevent_register() or pevent_unregister(), or before accessing *eventp, then *eventp will always reflect the 'registered' state of the event and handler() is guaranteed to never be invoked after pevent_unregister() returns.

RETURN VALUES
pevent_ctx_create(), pevent_register(), and pevent_get_info() return NULL or -1 to indicate an error, with errno set appropriately.

SEE ALSO
libpdel(3), mesg_port(3), paction(3), pthread(3), typed_mem(3)

HISTORY
The PDEL library was developed at Packet Design, LLC. http://www.packetdesign.com/

AUTHORS
Archie Cobbs <archie@packetdesign.com>