/*
 * Copyright (c) 2003-2010 Apple Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Portions Copyright (c) 2003-2010 Apple Inc.  All Rights Reserved.
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

#ifndef __NOTIFICATION_H__
#define __NOTIFICATION_H__

#include <sys/cdefs.h>
#include <stdint.h>
#include <mach/message.h>
#include <Availability.h>
#ifdef __BLOCKS__
#include <dispatch/dispatch.h>
#endif /* __BLOCKS__ */

/*! @header
 * 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.
 *
 * 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.
 *
 * 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.
 *
 * Note that 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.
 *
 * 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 pas been posted since a previous call to 
 * notify_check() for that name.
 *
 * "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.  
 *
 * Synchronization between two processes may be achieved using the
 * notify_set_state() and notify_get_state() routines.
 */

/*! @defineblock Status Codes
 * Status codes returned by the API.
 */
#define NOTIFY_STATUS_OK 0
#define NOTIFY_STATUS_INVALID_NAME 1
#define NOTIFY_STATUS_INVALID_TOKEN 2
#define NOTIFY_STATUS_INVALID_PORT 3
#define NOTIFY_STATUS_INVALID_FILE 4
#define NOTIFY_STATUS_INVALID_SIGNAL 5
#define NOTIFY_STATUS_INVALID_REQUEST 6
#define NOTIFY_STATUS_NOT_AUTHORIZED 7
#define NOTIFY_STATUS_FAILED 1000000
/*! @/defineblock */

/*!
 * Flag bits used for registration.
 */
#define NOTIFY_REUSE 0x00000001


/*!
 * Token values are zero or positive integers.
 * NOTIFY_TOKEN_INVALID is useful as an initial value for
 * a token value passed as an in/out parameter to one of
 * the registration routines below.
 */
#define NOTIFY_TOKEN_INVALID -1

__BEGIN_DECLS

/*!
 * Post a notification for a name.
 *
 * This is the only call that is required for a notification producer.
 * Returns status.
 */
uint32_t notify_post(const char *name);


#ifdef __BLOCKS__
typedef void (^notify_handler_t)(int token);

/*!
 * @function   notify_register
 * @abstract   Request notification delivery to a dispatch queue.
 * @discussion When notifications are received by the process, the notify
 *             subsystem will deliver the registered Block to the target
 *             dispatch queue.  Notification blocks are not re-entrant,
 *             and subsequent notification Blocks will not be delivered
 *             for the same registration until the previous Block has
 *             returned.
 * @param name (input) The notification name.
 * @param out_token (output) The registration token.
 * @param queue (input) The dispatch queue to which the Block is submitted.
 *              The dispatch queue is retained by the notify subsystem while
 *              the notification is registered, and will be released when
 *              notification is canceled.
 * @param block (input) The Block to invoke on the dispatch queue in response
 *              to a notification.  The notification token is passed to the
 *              Block as an argument so that the callee can modify the state
 *              of the notification or cancel the registration.
 * @result Returns status.
 */
uint32_t notify_register_dispatch(const char *name, int *out_token, dispatch_queue_t queue, notify_handler_t handler)
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_3_2);
#endif /* __BLOCKS__ */

/*!
 * Creates a registration token be used with notify_check(),
 * but no active notifications will be delivered.
 *
 * @param name
 *    (input) notification name
 * @param out_token
 *    (output) registration token
 * @result Returns status.
 */
uint32_t notify_register_check(const char *name, int *out_token);

/*!
 * Request notification delivery by UNIX signal.
 *
 * A client may request signal notification for multiple names.  After a signal
 * is delivered, the notify_check() routine may be called with each notification 
 * token to determine which name (if any) generated the signal notification.
 *
 * @param name (input) notification name
 * @param sig (input) signal number (see signal(3))
 * @param out_token (output) notification token
 * @result Returns status.
 */
uint32_t notify_register_signal(const char *name, int sig, int *out_token);

/*!
 * Request notification by mach message.  
 *
 * Notifications are delivered by an empty message sent to a mach port.
 * By default, a new port is allocated and a pointer to it is returned
 * as the value of "notify_port".  A mach port previously returned 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.
 *
 * 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 careful about
 * using the same port for notifications for more than one name.
 *
 * 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.
 *
 * @param name
 *     (input) notification name
 * @param  out_token
 *     (output) notification token
 * @param  notify_port
 *     (input/output) pointer to a mach port
 * @result Returns status.
 */
uint32_t notify_register_mach_port(const char *name, mach_port_t *notify_port, int flags, int *out_token);

/*
 * Request notification by a write to a file descriptor. 
 *
 * Notifications are delivered by a write to a file descriptor.
 * By default, a new file descriptor is created and a pointer to it
 * is returned as the value of "notify_fd".  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. 
 *
 * 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 careful about using the same file descriptor for notifications
 * for more than one name.
 *
 * 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.
 *
 * @param name
 *     (input) notification name
 * @param out_token
 *     (output) notification token
 * @param notify_fd
 *     (input/output) pointer to a file descriptor
 * @result Returns status.
 */
uint32_t notify_register_file_descriptor(const char *name, int *notify_fd, int flags, int *out_token);

/*!
 * Check if any notifications have been posted.
 *
 * Output parameter check is set to 0 for false, 1 for true.  Returns status.
 * check is set to true the first time notify_check is called for a token.
 * Subsequent calls set check to true when notifications have been posted for
 * the name associated with the notification token.  This routine is independent
 * of notify_post().  That is, check will be true if an application calls
 * notify_post() for a name and then calls notify_check() for a token associated
 * with that name.
 *
 * @param token
 *     (input)notification token
 * @param check
 *     (output) true/false indication
 * @result Returns status.
 */
uint32_t notify_check(int token, int *check);

/*!
 * 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.
 *
 * @param token
 *     (input) notification token
 * @result Returns status.
 */
uint32_t notify_cancel(int token);

/*!
 * Suspend delivery of notifications for a token. Notifications for this token will be
 * pended and coalesced, then delivered following a matching call to notify_resume.
 * Calls to notify_suspend may be nested.  Notifications remain suspended until
 * an equal number of calls have been made to notify_resume.
 *
 * @param token
 *     (input) notification token
 * @result Returns status.
 */
uint32_t notify_suspend(int token)
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0);

/*!
 * Removes one level of suspension for a token previously suspended
 * by a call to notify_suspend.  Notifications will resume when a matching
 * call to notify_resume is made for each previous call to notify_suspend.
 * Notifications posted while a token is suspended are coalesced into
 * a single notification sent following a resumption.
 *
 * @param token
 *     (input) notification token
 * @result Returns status.
 */
uint32_t notify_resume(int token)
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0);

/*!
 * Set or get a state value associated with a notification token.
 * Each key in the notification namespace has an associated integer value available
 * for use by clients as for application-specific purposes.  A common usage is to 
 * allow two processes or threads to synchronize their activities.  For example, a
 * server process may need send a notification when a resource becomes available.
 * A client process can register for the notification, but when it starts up it will
 * not know whether the resource is available.  The server can set the state value,
 * and the client can check the value at startup time to synchronize with the server.
 *
 * Set the 64-bit integer state value.
 *
 * @param token
 *     (input) notification token
 * @param state64
 *     (input) 64-bit unsigned integer value
 * @result Returns status.
 */
uint32_t notify_set_state(int token, uint64_t state64)
__OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);

/*!
 * Get the 64-bit integer state value.
 *
 * @param token
 *     (input) notification token
 * @param state64
 *     (output) 64-bit unsigned integer value
 * @result Returns status.
 */
uint32_t notify_get_state(int token, uint64_t *state64)
__OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0);

/*!
 * Determine if a token is valid (currently registered).
 * Negative integer values are always invalid.  Positive or
 * zero values are valid only if they are associated with an
 * existing registratiom.
 *
 * @param val
 *     (input) integer value
 * @result Returns true if the value is a valid token, false otherwise.
 */
bool notify_is_valid_token(int val)
__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0);

__END_DECLS

#endif /* __NOTIFICATION_H__ */
