notify.3   [plain text]


.\" Copyright (c) 2003 Apple Computer
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in the
.\"    documentation and/or other materials provided with the distribution.
.\" 4. Neither the name of Apple Computer nor the names of its contributors
.\"    may be used to endorse or promote products derived from this software
.\"    without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\"
.Dd September 3, 2008
.Dt notify 3
.Os "Mac OS X"
.Sh NAME
.Nm notify_post ,
.Nm notify_register_check ,
.Nm notify_register_dispatch ,
.Nm notify_register_signal ,
.Nm notify_register_mach_port ,
.Nm notify_register_file_descriptor ,
.Nm notify_check ,
.Nm notify_get_state ,
.Nm notify_set_state ,
.Nm notify_cancel
.Nd event distribution functions
.Sh SYNOPSIS
.Fd #include <notify.h>
.Ft uint32_t
.Fn notify_post "const char *name"
.Ft uint32_t
.Fn notify_register_check "const char *name, int *out_token"
.Ft uint32_t
.Fn notify_register_dispatch "const char *name, int *out_token" "dispatch_queue_t queue" "notify_handler_t handler"
.Ft uint32_t
.Fn notify_register_signal "const char *name, int sig, int *out_token"
.Ft uint32_t
.Fn notify_register_mach_port "const char *name, mach_port_t *notify_port, int flags, int *out_token"
.Ft uint32_t
.Fn notify_register_file_descriptor "const char *name, int *notify_fd, int flags, int *out_token"
.Ft uint32_t
.Fn notify_check "int token, int *check"
.Ft uint32_t
.Fn notify_set_state "int token, uint64_t state"
.Ft uint32_t
.Fn notify_get_state "int token, uint64_t *state"
.Ft uint32_t
.Fn notify_cancel "int token"
.Sh DESCRIPTION
These routines allow processes to exchange stateless notification events.
Processes post notifications to a single system-wide notification server,
which then distributes notifications to client processes that have
registered to receive those notifications, including processes run by
other users.
.Pp
Notifications are associated with names in a namespace shared by all 
clients of the system.
Clients may post notifications for names, and
may monitor names for posted notifications.
Clients may request
notification delivery by a number of different methods.
.Pp
Clients desiring to monitor names in the notification system must
register with the system, providing a name and other information
required for the desired notification delivery method.
Clients are
given an integer token representing the registration.
.Pp
The kernel provides limited queues for mach message and file descriptor messages.
It is important to make sure that clients read mach ports and file descriptors frequently
to prevent messages from being lost due to resource limitations.
Clients that use signal-based notification should be aware that signals
are not delivered to a process while it is running in a signal handler.
This may affect the delivery of signals in close succession.
.Pp
Notifications may be coalesced in some cases.
Multiple events posted
for a name in rapid succession may result in a single notification sent
to clients registered for notification for that name.
Clients checking
for changes using the notify_check() routine cannot determine if
more than one event has been posted since a previous call to 
notify_check() for that name.
.Pp
"False positives" may occur in notify_check() when used with a token
generated by notify_register_check() due to implementation constraints.
This behavior may vary in future releases.
.Ss notify_post
This routine causes the system to send a notification for the given 
name to all clients that have registered for notifications of this name.
This is the only API required for an appication that only produces
notifications. 
.Ss notify_register_check
Registers for passive notification for the given name.
The routine generates
a token that may be used with the
.Fn notify_check
routine to check if any notifications have been posted for the name.
The check is implemented using a shared memory scheme, making the check 
very fast and efficient.
The implementation has a limited amount
of shared memory, so developers are encouraged to use this mechanism
sparingly.
It is also important to release the resources consumed
by a registration with 
.Fn notify_cancel
when they are no longer required by the application.
.Ss notify_register_dispatch
registers a callback handler in the form of a block which will be
dispatched to the queue when a notification for the given name is
received.  This is a convenient way to register callbacks without any
management of file descriptors, mach ports, or signals on the part of
the application.  The given queue is retained by the system for the
lifetime of the notification.  Use
.Fn notify_cancel
to release the notification and its reference to the queue.
.Ss notify_register_signal
registers a client for notification delivery via a signal.
This fits
well with the design of many UNIX daemons that use a signal such as SIGHUP
to reinitialize of reset internal state information.
Clients may use the
registration token generated by this routine to check for notifications using
.Fn notify_check .
This allows the application to determine if a signal was received as the
result of a notification, or is the signal was generated by some other source.
It also permits the application that registers for signal notification for
multiple names to determine which name was associated with the notification.
.Ss notify_register_mach_port
registers a client for notification delivery via mach messaging.
Notifications are delivered by an empty message sent to a mach port.
By default, a new port is created by a call to this routine.
A mach port
previously created by a call to this routine may be used for notifications
if a pointer to that port is passed in to the routine and NOTIFY_REUSE is
set in the flags parameter.
The notification service must be able to extract
send rights to the port.
.Pp
Note that the kernel limits the size of the message queue for any port.
If it is important that notifications should not be lost due to queue
overflow, clients should service messages quickly, and be cautious in
using the same port for notifications for more than one name.
.Pp
A notification message has an empty message body.
The msgh_id field
in the mach message header will have the value of the notification
token.
If a port is reused for multiple notification registrations,
the msgh_id value may be used to determine which name generated
the notification.
.Ss notify_register_file_descriptor
Register for notification by a write to a file descriptor. 
.Pp
By default, a new file descriptor is created and a pointer to it
is returned as the value of the "notify_fd" parameter.
A file descriptor
created by a previous call to this routine may be used for notifications
if a pointer to that file descriptor is passed in to the routine and
NOTIFY_REUSE is set in the flags parameter. 
.Pp
Note that the kernel limits the buffer space for queued writes on a
file descriptor.
If it is important that notifications should not be
lost due to queue overflow, clients should service messages quickly,
and be cautious in using the same file descriptor for notifications
for more than one name.
.Pp
Notifications are delivered by an integer value written to the
file descriptor.
The value will match the notification token
for which the notification was generated.
.Ss notify_check
Checks if any notifications have been posted for a name.
The output
parameter "check" is set to 0 for false, 1 for true.
A true indication is
returned the first time notify_check is called for a token.
Subsequent calls
give a true indication when notifications have been posted for the name
associated with the notification token.
.Pp
.Fn notify_check
may be used with any notification token produced by any of the notification
registration routines.
A fast check based on a shared memory implementation
is used when the token was generated by
.Fn notify_register_check .
Other tokens are checked by a call to the notification server.
.Ss notify_set_state
Set a 64-bit unsigned integer variable associated with a token.
.Pp
Each registered notification key has an associated 64-bit integer variable,
which may be set using this routine and examined using the
.Fn notify_get_state
routine.
The state variable is free to be used by clients of the notification API.
It may be used to synchronize state information between cooperating processes or threads.
(Available in Mac OS X 10.5 or later.)
.Ss notify_get_state
Get the 64-bit unsigned integer value associated with a token.
The default value of a state variable is zero.
(Available in Mac OS X 10.5 or later.)
.Ss notify_cancel
Cancel notification and free resources associated with a notification
token.
Mach ports and file descriptor associated with a token are released
(deallocated or closed) when all registration tokens associated with 
the port or file descriptor have been cancelled.
.Sh NAMESPACE CONVENTIONS
Names in the namespace must be NULL-terminated.
Names should be encoded as UTF-8 strings.
.Pp
The namespace supported by the system is unstructured, but users of
this API are highly encouraged to follow the reverse-ICANN domain
name convention used for Java package names and for System Preferences
on Mac OS X.
For example, "com.mydomain.example.event".
.Pp
Apple Computer reserves the portion
of the namespace prefixed by "com.apple.".
This policy is not 
enforced in the current implementation, but may be in the future.
.Pp
Names in the space "user.uid.UID", where UID is a numeric user ID number
are reserved for processes with that UID.
Names in this protected space may only be accessed or modified by processes
with the effective UID specified as the UID in the name.
The name "user.uid.UID" is protected for the given UID, as are any
names of the form "user.uid.UID.<sub-path>". 
In the latter case, the name must have a dot character following the UID.
.Pp
Third party developers are encouraged to choose a prefix for names
that will avoid conflicts in the shared namespace.
.Pp
The portion of the namespece prefixed by the string "self." is set aside
for private use by applications.
That is, each client may use that part
of the namespace for intra-process notifications.
These notifications 
are private to each individual process and are not propagated between
processes.
.Sh USAGE EXAMPLES
A notification producer.
.Pp
    #include <notify.h>
    ...
.Pp
    notify_post("com.eg.random.event");
.Pp
A client using notify_check() to determine when to invalidate a cache.
.Pp
    #include <stdio.h>
    #include <stdlib.h>
    #include <notify.h>
.Pp
    int
    main(int argc, char *argv[])
    {
        int status, token, check;
.Pp
        status = notify_register_check("com.eg.update", &token);
        if (status != NOTIFY_STATUS_OK)
        {
           fprintf(stderr, "registration failed (%u)\\n", status);
           exit(status);
        }
.Pp
        build_my_cache();
.Pp
        ...
.Pp
        status = notify_check(token, &check);
        if ((status == NOTIFY_STATUS_OK) && (check != 0))
        {
           /* An update has occurred - invalidate the cache */
           reset_my_cache();
        }
.Pp
        ...
.Pp
A client using file descriptor notifications.
.Pp
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <unistd.h>
    #include <notify.h>
.Pp
    int
    main(int argc, char *argv[])
    {
        int nf, status, rtoken, qtoken, t;
        fd_set readfds;
.Pp
        status = notify_register_file_descriptor("com.eg.random.event",
           &nf, 0, &rtoken);
        if (status != NOTIFY_STATUS_OK)
        {
           fprintf(stderr, "registration failed (%u)\\n", status);
           exit(status);
        }
.Pp
        status = notify_register_file_descriptor("com.eg.random.quit",
            &nf, NOTIFY_REUSE, &qtoken);
        if (status != NOTIFY_STATUS_OK)
        {
           fprintf(stderr, "registration failed (%u)\\n", status);
           exit(status);
        }
.Pp
        FD_ZERO(&readfds);
        FD_SET(nf, &readfds);
.Pp
        for (;;)
        {
           status = select(nf+1, &readfds, NULL, NULL, NULL);
           if (status <= 0) continue;
           if (!FD_ISSET(nf, &readfds)) continue;
.Pp
           status = read(nf, &t, sizeof(int));
           if (status < 0)
           {
               perror("read");
               break;
           }
.Pp
           if (t == rtoken) printf("random event\\n");
           else if (t == qtoken) break;
        }
.Pp
        printf("shutting down\\n");
        notify_cancel(rtoken);
        notify_cancel(qtoken);
        exit(0);
    }
.Pp
A client using file dispatch notifications.
.Pp
    #include <stdio.h>
    #include <stdlib.h>
    #include <notify.h>
    #include <dispatch/dispatch.h>
.Pp
    int
    main(void)
    {
        int token, status;
.Pp
        status = notify_register_dispatch("com.eg.random.event", &token,
            dispatch_get_main_queue(), ^(int t) { 
                printf("com.eg.random.event received!\n"); });
.Pp
        dispatch_main();
        exit(0);
    }
.Sh HISTORY
These functions first appeared in
Mac OS X 10.3.
.Sh SEE ALSO
.Xr read 2 ,
.Xr select 2 ,
.Xr signal 3