PEVENT(3)                 BSD Library Functions Manual                 PEVENT(3)

     pevent — pthread event library

     PDEL Library (libpdel, -lpdel)

     #include <pthread.h>
     #include <pdel/util/pevent.h>

     struct pevent_ctx *
     pevent_ctx_create(const char *mtype, const pthread_attr_t *attr);

     pevent_ctx_destroy(struct pevent_ctx **ctxp);

     pevent_ctx_count(struct pevent_ctx *ctx);

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

     pevent_unregister(struct pevent **eventp);

     pevent_trigger(struct pevent *event);

     pevent_get_info(struct pevent *event, struct pevent_info *info);

     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

     pevent_ctx_count() returns the number of events currently registered with

     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

     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;

     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.

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

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

     The PDEL library was developed at Packet Design, LLC.

     Archie Cobbs <>

BSD                              April 22, 2002                              BSD