/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* bos72X src/bos/kernel/sys/pollset.h 1.4.1.4                            */
/*                                                                        */
/* Licensed Materials - Property of IBM                                   */
/*                                                                        */
/* Restricted Materials of IBM                                            */
/*                                                                        */
/* COPYRIGHT International Business Machines Corp. 2005,2020              */
/* All Rights Reserved                                                    */
/*                                                                        */
/* US Government Users Restricted Rights - Use, duplication or            */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.      */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/* @(#)70       1.4.1.4  src/bos/kernel/sys/pollset.h, sysios, bos72X, x2020_44A6 10/21/20 12:24:40 */

#ifndef _H_POLLSET
#define _H_POLLSET

#ifndef _H_POLL
#include <sys/poll.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef int pollset_t;

typedef struct pollingset {
	struct pollfd	*ps_fds;
	int		 array_length;
	int		 timeout;
} pollingset_t;

/*
 * Pollset Control Structures, Commands, Macros, and Prototypes
 *
 * The original pollset control structure was retrofitted with a 'version'
 * field by segmenting the previous 'command' field, truncating it from a
 * 2-byte field (short) to a single byte (char). This effectively makes the
 * original structure definition version 0. As only three commands were ever
 * supported, existing applications will continue to run without the need
 * for a recompile nor will they require any updates should they need to be
 * recompiled. New applications must initialize the new 'version' field,
 * preferably using the macros defined below. The ENOTSUP errno is returned
 * when an unknown pollset control structure version is encountered.
 *
 * Beginning with version 1, an extended control structure is supported,
 * effectively extending the pollset_ctl API. This allows additional data to
 * be provided to the kernel by the user. While not common, the kernel does
 * support heterogeneous pollsets. These are pollsets that are comprised of
 * file descriptors added with different functional versions. Applications
 * are encouraged to use homogeneous pollsets as it provides a consistent
 * programming model that avoids needing to handle multiple formats at the
 * same time. For example, consider an application using pollsets that are
 * all using the version 1 format versus an application with a mixture of
 * versions 1 and 0. The former application can safely conclude that only
 * the extended pollfd format will be used to communicate polled data as
 * opposed to the latter which is unable to make this conclusion and must
 * resort to evaluating the POLLEXT flag.
 *
 * Version | Functional Description
 * --------------------------------------------------------------------------
 *    0:     Original version, only the command, events, and file descriptor
 *           fields are valid. Poll data returned uses the pollfd structure.
 *
 *    1:     Initial extended version, supports same fields are version 0 and
 *           the addr/data field. Poll data returned uses the extended pollfd
 *           structure as indicated by POLLEXT event flag.
 */
#define PS_ADD		0x0
#define PS_MOD		0x1
#define PS_DELETE	0x2
#define PS_REPLACE 	0x3

typedef struct poll_ctl {
	short	cmd;
	short	events;		/* Events to monitor, POLLIN, POLLOUT, etc. */
	int	fd;		/* File descriptor to add/modify/remove     */
} poll_ctl_t;

extern pollset_t pollset_create(int maxfd);
extern int pollset_destroy(pollset_t ps);
extern int pollset_query(pollset_t ps, struct pollfd *pollfd_query);
extern int pollset_ctl(pollset_t ps, struct poll_ctl *pollctl_array,
		       int array_length);
extern int pollset_poll(pollset_t ps, struct pollfd *polldata_array,
			int array_length, int timeout);
extern int pollset_getcache(void *obuf, int *len);
extern int pollset_putcache(void *obuf, int len);

typedef struct poll_ctl_ext {
	uint8_t	version;	/* Control descriptor version */
	uint8_t	command;	/* PS_ADD, PS_MOD, etc.       */
	short	events;		/* Events to monitor, POLLIN, POLLOUT, etc. */
	int	fd;		/* File descriptor to add/modify/remove     */

	union {
		void	*addr;	/* User-defined pointer */
		uint32_t data32;/* User-defined data    */
		uint64_t data;	/* User-defined data    */
#if __C99_PRAGMA_OPERATOR && !defined(__C99_REQUIRE_FUNC_DECL) && !__cplusplus
	};
#else
	} u;
#endif

	uint64_t reserved64[6];	/* Reserved for future expansion */
} poll_ctl_ext_t;

#define POLL_CTL_HDR_INIT(_pce, _v, _cm, _ev, _fd)	\
do {							\
	((poll_ctl_ext_t *)(_pce))->version = (_v);	\
	((poll_ctl_ext_t *)(_pce))->command = (_cm);	\
	((poll_ctl_ext_t *)(_pce))->events = (_ev);	\
	((poll_ctl_ext_t *)(_pce))->fd = (_fd);		\
} while(0)

#define POLL_CTL_INIT(_pce, _cm, _ev, _fd)		\
	POLL_CTL_HDR_INIT(_pce, 0, _cm, _ev, _fd)	\

#if __C99_PRAGMA_OPERATOR && !defined(__C99_REQUIRE_FUNC_DECL) && !__cplusplus
#define POLL_CTL_EXT_INIT_V1(_pce, _cm, _ev, _fd, _dt)	\
do {							\
	POLL_CTL_HDR_INIT(_pce, 1, _cm, _ev, _fd);	\
							\
	if (sizeof((_dt)) <= sizeof((_pce)->data32))	\
		(_pce)->data32 = (uint32_t)(_dt);	\
	else						\
		(_pce)->data = (uint64_t)(_dt);		\
} while(0)
#endif

/*
 * Extended Pollset Cast-avoidance Wrappers and Runtime Checkers
 *
 * The *_ext wrappers allow an application to avoid casting extended poll
 * control structures when invoking the pollset control, poll, or query
 * services. Additionally, the poll wrapper performs the conversion that
 * is necessary to properly indicate the 'length' of the return poll data
 * array.
 *
 * The pollset_ext() service allows an application to detect the presence
 * of extended pollset support at runtime. Applications can use this to
 * support execution in legacy and extended environments using the same
 * binary.
 */
static __inline int
pollset_query_ext(pollset_t ps, struct pollfd_ext *pq)
{
	return pollset_query(ps, (struct pollfd *)pq);
}

static __inline int
pollset_ctl_ext(pollset_t ps, struct poll_ctl_ext *pa, int alen)
{
	return pollset_ctl(ps, (struct poll_ctl *)pa, alen);
}

static __inline int
pollset_poll_ext(pollset_t ps, struct pollfd_ext *pa, int alen, int timeout)
{
	int	pfdm = sizeof(struct pollfd_ext) / sizeof(struct pollfd);

	return pollset_poll(ps, (struct pollfd *)pa, pfdm * alen, timeout);
}

static __inline int
pollset_ext(void)
{
	return !pollset_create(-2);
}

#ifdef __cplusplus
}
#endif

#ifdef _KERNSYS

typedef struct pollingset64 {
	int		ps_fds_hi;
	int		ps_fds_lo;
	int		array_length;
	int		timeout;
} pollingset64_t;

#endif
#endif	/* _H_POLLSET */
