eventlink_private.h   [plain text]


#ifndef __OS_EVENTLINK__
#define __OS_EVENTLINK__

#include <os/object.h>
#include <mach/mach.h>
#include <os/clock.h>

__BEGIN_DECLS

OS_OBJECT_ASSUME_NONNULL_BEGIN

/*!
 * @typedef os_eventlink_t
 *
 * @abstract
 * A reference counted os_object representing a directed paired link of "wake" events
 * between two designated threads, the link `source` and the link `target`.
 * The target thread may optionally inherit properties of the source thread upon
 * return from wait (such as membership in a workgroup).
 *
 * @discussion
 * Threads explicitly associate themselves with an an eventlink, only one source
 * and one target may exist per eventlink.
 */
#if defined(__DISPATCH_BUILDING_DISPATCH__) && !defined(__OBJC__)
typedef struct os_eventlink_s *os_eventlink_t;
#else
API_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0))
OS_OBJECT_DECL_CLASS(os_eventlink);
#endif

/*!
 * @function os_eventlink_create
 *
 * @abstract
 * Creates an inactive refcounted os_object representing an os_eventlink_t.
 *
 * This function creates only 1 endpoint of an eventlink object.  The other
 * endpoint of the eventlink needs to be created from this eventlink object
 * using one of the other creator functions -
 * os_eventlink_create_remote_with_eventlink() or
 * os_eventlink_create_with_port()
 */
OS_EXPORT OS_OBJECT_RETURNS_RETAINED
os_eventlink_t _Nullable
os_eventlink_create(const char *name);

#if defined(__DISPATCH_BUILDING_DISPATCH__) && !defined(__OBJC__)

/* TODO: API for the future when we make a variant of eventlink that does
 * copyin */

/*!
 * @typedef os_eventlink_shared_data_t
 *
 * @abstract
 * Pointer to an opaque structure identifying the data that is used to
 * synchronize between the two endpoints of an eventlink.
 *
 * It is the client's responsibility to allocate this structure such that both
 * threads on the two endpoints of the eventlink can synchronize with it ie. If
 * the eventlink is between 2 threads in 2 processes, os_eventlink_shared_data_t
 * should be allocated in shared memory between the two processes.
 */
typedef struct os_eventlink_shared_data_s {
	uint64_t local_count;
	uint64_t remote_count;
} os_eventlink_shared_data_s, *os_eventlink_shared_data_t;
#define OS_EVENTLINK_SHARED_DATA_INITIALIZER { 0 }

/*!
 * @function os_eventlink_set_shared_data
 *
 * @abstract
 * Associates a shared data structure with the os_eventlink.
 *
 * As a performance enhancement, clients may choose to provide an opaque shared
 * data structure in memory visible to both ends of the eventlink based on the
 * usage pattern of the os eventlink.
 *
 * Passing in NULL for shared data is recommended if the eventlink is to be used
 * for the typical RPC ping-pong case whereby one side of the eventlink is
 * always blocked waiting on a signal from the other side. In this case, each
 * signal causes a single wakeup.
 *
 * Passing in shared data is recommended when one side of the eventlink is not
 * necessarily always waiting for the other's signal in order to work. Passing
 * in the shared data allows for more efficient signalling - potentially without
 * any system calls.
 */
int
os_eventlink_set_shared_data(os_eventlink_t eventlink,
		os_eventlink_shared_data_t data);

#endif

/*!
 * @function os_eventlink_activate
 *
 * @abstract
 * Activates the os_eventlink object for use. No further configuration can be
 * done on the eventlink object after it has been activated. This API is not
 * real-time safe.
 *
 * If an error is encountered, errno is set and returned.
 */
OS_EXPORT OS_OBJECT_WARN_UNUSED_RESULT
int
os_eventlink_activate(os_eventlink_t eventlink);

/*!
 * @function os_eventlink_extract_remote_port
 *
 * @abstract
 * Returns a reference to a send right representing the remote endpoint of the
 * eventlink. This port is to be passed to os_eventlink_create_with_port() to
 * create an eventlink object.
 *
 * Calling this function multiple times on an eventlink object will result in an
 * error.
 *
 * @param eventlink
 * An eventlink returns from a previous call to os_eventlink_create(). This
 * evenlink must have been activated.
 */
OS_EXPORT OS_OBJECT_WARN_UNUSED_RESULT
int
os_eventlink_extract_remote_port(os_eventlink_t eventlink, mach_port_t *port_out);

/*!
 * @function os_eventlink_create_with_port
 *
 * @abstract
 * Creates an inactive eventlink from a port returned from a previous call to
 * os_eventlink_extract_remote_port. This function does not consume a reference
 * on the specified send right.
 */
OS_EXPORT OS_OBJECT_RETURNS_RETAINED
os_eventlink_t _Nullable
os_eventlink_create_with_port(const char *name, mach_port_t mach_port);

/*!
 * @function os_eventlink_create_remote_with_eventlink
 *
 * @abstract
 * Creates an inactive refcounted os_object representing an os_eventlink_t
 * remote endpoint. Each eventlink has exactly one remote endpoint that can be
 * created from it. Calling this function on an eventlink object returned from
 * os_eventlink_create(), more than once will return in an error.
 *
 * @param eventlink
 * An eventlink returned from a previous call to os_eventlink_create(). This
 * eventlink must have been activated.
 */
OS_EXPORT OS_OBJECT_RETURNS_RETAINED
os_eventlink_t _Nullable
os_eventlink_create_remote_with_eventlink(const char *name, os_eventlink_t eventlink);

/*!
 * @function os_eventlink_associate
 *
 * @abstract
 * Associate a thread with the eventlink endpoint provided. The eventlink
 * provided should be activated before this call. This API is not real
 * time safe.
 *
 * If a thread is already associated with the eventlink, errno is set and
 * returned.
 */

OS_ENUM(os_eventlink_associate_options, uint64_t,
	OE_ASSOCIATE_CURRENT_THREAD = 0,
	OE_ASSOCIATE_ON_WAIT = 0x1,
);

OS_EXPORT OS_OBJECT_WARN_UNUSED_RESULT
int
os_eventlink_associate(os_eventlink_t eventlink,
		os_eventlink_associate_options_t options);

/*!
 * @function os_eventlink_disassociate
 *
 * @abstract
 * Disassociate the current thread with the eventlink endpoint provided. This
 * API is not real time safe.
 *
 * If the current thread is not associated with the eventlink via a previous
 * call to os_eventlink_associate, errno is set and returned.
 */
OS_EXPORT
int
os_eventlink_disassociate(os_eventlink_t eventlink);

/*!
 * @function os_eventlink_wait
 *
 * @abstract
 * Wait on the eventlink endpoint for a signal from the other endpoint. If there
 * are outstanding signals, this function will consume them and return
 * immediately.
 *
 * Upon receiving a signal, the function returns the number of signals that have
 * been consumed by the waiter in the out parameter if specified.
 *
 * If the eventlink has not been previously associated via a call to
 * os_eventlink_associate or if there is a mismatch between the associated
 * thread and the current thread, the process will abort. This API call is
 * real-time safe.
 */
OS_EXPORT
int
os_eventlink_wait(os_eventlink_t eventlink, uint64_t * _Nullable signals_consumed_out);

/*!
 * @function os_eventlink_wait_until
 *
 * @abstract
 * Wait on the eventlink endpoint for a signal or until the timeout specified is
 * hit. If there are outstanding signals, this function will consume them and
 * return immediately.
 *
 * Upon success, the function returns the number of signals that have been
 * consumed by the waiter in the out parameter, if provided. If the timeout is
 * hit, then 0 signals are said to have been consumed by the waiter. This API
 * call is real time safe.
 */
OS_EXPORT
int
os_eventlink_wait_until(os_eventlink_t eventlink, os_clockid_t clock,
		uint64_t timeout, uint64_t * _Nullable signals_consumed_out);

/*!
 * @function os_eventlink_signal
 *
 * @abstract
 * Signal the other endpoint of an eventlink. This API call is real time safe.
 *
 * If an error is encountered, errno will be set and returned.
 */
OS_EXPORT
int
os_eventlink_signal(os_eventlink_t eventlink);

/*!
 * @function os_eventlink_signal_and_wait
 *
 * @abstract
 * Signals on an eventlink endpoint and then proceeds to wait on it until the
 * eventlink is signalled. Returns the number of signals consumed by the waiter
 * through the out parameter if provided. This API call is real time safe.
 */
OS_EXPORT
int
os_eventlink_signal_and_wait(os_eventlink_t eventlink, uint64_t * _Nullable signals_consumed_out);

/*!
 * @function os_eventlink_signal_and_wait_until
 *
 * @abstract
 * Signals on an eventlink endpoint and then proceeds to wait on it until the
 * evenlink is signalled or the timeout is hit.  Returns the number of signals
 * consumed by the waiter through the out parameter if provided, with 0
 * indicating that a timeout has been hit. This API call is real time safe.
 */
OS_EXPORT
int
os_eventlink_signal_and_wait_until(os_eventlink_t eventlink, os_clockid_t clock,
		uint64_t timeout, uint64_t * _Nullable signals_consumed_out);

/*
 * @function os_eventlink_cancel
 *
 * @abstract
 * Invalidates an eventlink. The only follow up actions possible on the eventlink
 * after it has been invalidated, are to disassociate from the eventlink and
 * dispose of it.
 *
 * If the eventlink had a remote endpoint created, the remote side will get an
 * ECANCELED when it tries to wait or signal on it. Existing waiters on the
 * eventlink will get the same result as well. The only valid follow up
 * actions possible on a remote endpoint are to disassociate from the eventlink
 * and dispose of it.
 *
 * This API is idempotent. It is not required to call this API before dropping
 * the last reference count of an eventlink.
 */
OS_EXPORT
void
os_eventlink_cancel(os_eventlink_t eventlink);

OS_OBJECT_ASSUME_NONNULL_END

__END_DECLS

#endif /* __OS_EVENTLINK__ */