os: Add ospoll interface [v2]
This provides a wrapper around poll or epoll providing a callback-based interface for monitoring activity on a large set of file descriptors. v2: use xserver_poll API instead of poll. Don't use WSAPoll as that is broken. Signed-off-by: Keith Packard <keithp@keithp.com> Reviewed-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
parent
d403aca70a
commit
d6eff3c31e
|
@ -219,7 +219,7 @@ dnl Checks for library functions.
|
|||
AC_CHECK_FUNCS([backtrace ffs geteuid getuid issetugid getresuid \
|
||||
getdtablesize getifaddrs getpeereid getpeerucred getprogname getzoneid \
|
||||
mmap posix_fallocate seteuid shmctl64 strncasecmp vasprintf vsnprintf \
|
||||
walkcontext setitimer poll])
|
||||
walkcontext setitimer poll epoll_create1])
|
||||
AC_CONFIG_LIBOBJ_DIR([os])
|
||||
AC_REPLACE_FUNCS([reallocarray strcasecmp strcasestr strlcat strlcpy strndup])
|
||||
AM_CONDITIONAL(POLL, [test "x$ac_cv_func_poll" = "xyes"])
|
||||
|
|
|
@ -530,4 +530,7 @@
|
|||
/* Have poll() */
|
||||
#undef HAVE_POLL
|
||||
|
||||
/* Have epoll_create1() */
|
||||
#undef HAVE_EPOLL_CREATE1
|
||||
|
||||
#endif /* _DIX_CONFIG_H_ */
|
||||
|
|
|
@ -22,6 +22,7 @@ libos_la_SOURCES = \
|
|||
oscolor.c \
|
||||
osdep.h \
|
||||
osinit.c \
|
||||
ospoll.c \
|
||||
utils.c \
|
||||
xdmauth.c \
|
||||
xsha1.c \
|
||||
|
|
442
os/ospoll.c
Normal file
442
os/ospoll.c
Normal file
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
* Copyright © 2016 Keith Packard
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_DIX_CONFIG_H
|
||||
#include <dix-config.h>
|
||||
#endif
|
||||
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "misc.h" /* for typedef of pointer */
|
||||
#include "ospoll.h"
|
||||
#include "list.h"
|
||||
|
||||
#if !HAVE_OSPOLL && HAVE_EPOLL_CREATE1
|
||||
#include <sys/epoll.h>
|
||||
#define EPOLL 1
|
||||
#define HAVE_OSPOLL 1
|
||||
#endif
|
||||
|
||||
#if !HAVE_OSPOLL
|
||||
#include "xserver_poll.h"
|
||||
#define POLL 1
|
||||
#define HAVE_OSPOLL 1
|
||||
#endif
|
||||
|
||||
#if EPOLL
|
||||
#include <sys/epoll.h>
|
||||
|
||||
/* epoll-based implementation */
|
||||
struct ospollfd {
|
||||
int fd;
|
||||
int xevents;
|
||||
enum ospoll_trigger trigger;
|
||||
void (*callback)(int fd, int xevents, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct ospoll {
|
||||
int epoll_fd;
|
||||
struct ospollfd **fds;
|
||||
int num;
|
||||
int size;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if POLL
|
||||
|
||||
/* poll-based implementation */
|
||||
struct ospollfd {
|
||||
short revents;
|
||||
enum ospoll_trigger trigger;
|
||||
void (*callback)(int fd, int revents, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct ospoll {
|
||||
struct pollfd *fds;
|
||||
struct ospollfd *osfds;
|
||||
int num;
|
||||
int size;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* Binary search for the specified file descriptor
|
||||
*
|
||||
* Returns position if found
|
||||
* Returns -position - 1 if not found
|
||||
*/
|
||||
|
||||
static int
|
||||
ospoll_find(struct ospoll *ospoll, int fd)
|
||||
{
|
||||
int lo = 0;
|
||||
int hi = ospoll->num - 1;
|
||||
|
||||
while (lo <= hi) {
|
||||
int m = (lo + hi) >> 1;
|
||||
#if EPOLL
|
||||
int t = ospoll->fds[m]->fd;
|
||||
#endif
|
||||
#if POLL
|
||||
int t = ospoll->fds[m].fd;
|
||||
#endif
|
||||
|
||||
if (t < fd)
|
||||
lo = m + 1;
|
||||
else if (t > fd)
|
||||
hi = m - 1;
|
||||
else
|
||||
return m;
|
||||
}
|
||||
return -(lo + 1);
|
||||
}
|
||||
|
||||
/* Insert an element into an array
|
||||
*
|
||||
* base: base address of array
|
||||
* num: number of elements in the array before the insert
|
||||
* size: size of each element
|
||||
* pos: position to insert at
|
||||
*/
|
||||
static inline void
|
||||
array_insert(void *base, size_t num, size_t size, size_t pos)
|
||||
{
|
||||
char *b = base;
|
||||
|
||||
memmove(b + (pos+1) * size,
|
||||
b + pos * size,
|
||||
(num - pos) * size);
|
||||
}
|
||||
|
||||
/* Delete an element from an array
|
||||
*
|
||||
* base: base address of array
|
||||
* num: number of elements in the array before the delete
|
||||
* size: size of each element
|
||||
* pos: position to delete from
|
||||
*/
|
||||
static inline void
|
||||
array_delete(void *base, size_t num, size_t size, size_t pos)
|
||||
{
|
||||
char *b = base;
|
||||
|
||||
memmove(b + pos * size, b + (pos + 1) * size,
|
||||
(num - pos - 1) * size);
|
||||
}
|
||||
|
||||
|
||||
struct ospoll *
|
||||
ospoll_create(void)
|
||||
{
|
||||
#if EPOLL
|
||||
struct ospoll *ospoll = calloc(1, sizeof (struct ospoll));
|
||||
|
||||
ospoll->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (ospoll->epoll_fd < 0) {
|
||||
free (ospoll);
|
||||
return NULL;
|
||||
}
|
||||
return ospoll;
|
||||
#endif
|
||||
#if POLL
|
||||
return calloc(1, sizeof (struct ospoll));
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ospoll_destroy(struct ospoll *ospoll)
|
||||
{
|
||||
#if EPOLL
|
||||
if (ospoll) {
|
||||
assert (ospoll->num == 0);
|
||||
close(ospoll->epoll_fd);
|
||||
free(ospoll->fds);
|
||||
free(ospoll);
|
||||
}
|
||||
#endif
|
||||
#if POLL
|
||||
if (ospoll) {
|
||||
assert (ospoll->num == 0);
|
||||
free (ospoll->fds);
|
||||
free (ospoll->osfds);
|
||||
free (ospoll);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Bool
|
||||
ospoll_add(struct ospoll *ospoll, int fd,
|
||||
enum ospoll_trigger trigger,
|
||||
void (*callback)(int fd, int xevents, void *data),
|
||||
void *data)
|
||||
{
|
||||
int pos = ospoll_find(ospoll, fd);
|
||||
#if EPOLL
|
||||
struct ospollfd *osfd;
|
||||
|
||||
if (pos < 0) {
|
||||
|
||||
struct epoll_event ev;
|
||||
|
||||
osfd = calloc(1, sizeof (struct ospollfd));
|
||||
if (!osfd)
|
||||
return FALSE;
|
||||
|
||||
if (ospoll->num >= ospoll->size) {
|
||||
struct ospollfd **new_fds;
|
||||
int new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
|
||||
|
||||
new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
|
||||
if (!new_fds) {
|
||||
free (osfd);
|
||||
return FALSE;
|
||||
}
|
||||
ospoll->fds = new_fds;
|
||||
ospoll->size = new_size;
|
||||
}
|
||||
|
||||
ev.events = 0;
|
||||
ev.data.ptr = osfd;
|
||||
if (trigger == ospoll_trigger_edge)
|
||||
ev.events |= EPOLLET;
|
||||
if (epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
|
||||
free(osfd);
|
||||
return FALSE;
|
||||
}
|
||||
osfd->fd = fd;
|
||||
osfd->xevents = 0;
|
||||
|
||||
pos = -pos - 1;
|
||||
array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
|
||||
ospoll->fds[pos] = osfd;
|
||||
ospoll->num++;
|
||||
} else {
|
||||
osfd = ospoll->fds[pos];
|
||||
}
|
||||
osfd->data = data;
|
||||
osfd->callback = callback;
|
||||
osfd->trigger = trigger;
|
||||
#endif
|
||||
#if POLL
|
||||
if (pos < 0) {
|
||||
if (ospoll->num == ospoll->size) {
|
||||
struct pollfd *new_fds;
|
||||
struct ospollfd *new_osfds;
|
||||
int new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
|
||||
|
||||
new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
|
||||
if (!new_fds)
|
||||
return FALSE;
|
||||
ospoll->fds = new_fds;
|
||||
new_osfds = reallocarray(ospoll->osfds, new_size, sizeof (ospoll->osfds[0]));
|
||||
if (!new_osfds)
|
||||
return FALSE;
|
||||
ospoll->osfds = new_osfds;
|
||||
ospoll->size = new_size;
|
||||
}
|
||||
pos = -pos - 1;
|
||||
array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
|
||||
array_insert(ospoll->osfds, ospoll->num, sizeof (ospoll->osfds[0]), pos);
|
||||
ospoll->num++;
|
||||
|
||||
ospoll->fds[pos].fd = fd;
|
||||
ospoll->fds[pos].events = 0;
|
||||
ospoll->fds[pos].revents = 0;
|
||||
ospoll->osfds[pos].revents = 0;
|
||||
}
|
||||
ospoll->osfds[pos].trigger = trigger;
|
||||
ospoll->osfds[pos].callback = callback;
|
||||
ospoll->osfds[pos].data = data;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
ospoll_remove(struct ospoll *ospoll, int fd)
|
||||
{
|
||||
int pos = ospoll_find(ospoll, fd);
|
||||
|
||||
pos = ospoll_find(ospoll, fd);
|
||||
if (pos >= 0) {
|
||||
#if EPOLL
|
||||
struct ospollfd *osfd = ospoll->fds[pos];
|
||||
struct epoll_event ev;
|
||||
ev.events = 0;
|
||||
ev.data.ptr = osfd;
|
||||
(void) epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_DEL, fd, &ev);
|
||||
|
||||
array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
|
||||
ospoll->num--;
|
||||
free (osfd);
|
||||
#endif
|
||||
#if POLL
|
||||
array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
|
||||
array_delete(ospoll->osfds, ospoll->num, sizeof (ospoll->osfds[0]), pos);
|
||||
ospoll->num--;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if EPOLL
|
||||
static void
|
||||
epoll_mod(struct ospoll *ospoll, struct ospollfd *osfd)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
ev.events = 0;
|
||||
if (osfd->xevents & X_NOTIFY_READ)
|
||||
ev.events |= EPOLLIN;
|
||||
if (osfd->xevents & X_NOTIFY_WRITE)
|
||||
ev.events |= EPOLLOUT;
|
||||
if (osfd->trigger == ospoll_trigger_edge)
|
||||
ev.events |= EPOLLET;
|
||||
ev.data.ptr = osfd;
|
||||
(void) epoll_ctl(ospoll->epoll_fd, EPOLL_CTL_MOD, osfd->fd, &ev);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ospoll_listen(struct ospoll *ospoll, int fd, int xevents)
|
||||
{
|
||||
int pos = ospoll_find(ospoll, fd);
|
||||
|
||||
if (pos >= 0) {
|
||||
#if EPOLL
|
||||
struct ospollfd *osfd = ospoll->fds[pos];
|
||||
osfd->xevents |= xevents;
|
||||
epoll_mod(ospoll, osfd);
|
||||
#endif
|
||||
#if POLL
|
||||
if (xevents & X_NOTIFY_READ)
|
||||
ospoll->fds[pos].events |= POLLIN;
|
||||
if (xevents & X_NOTIFY_WRITE)
|
||||
ospoll->fds[pos].events |= POLLOUT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ospoll_mute(struct ospoll *ospoll, int fd, int xevents)
|
||||
{
|
||||
int pos = ospoll_find(ospoll, fd);
|
||||
|
||||
if (pos >= 0) {
|
||||
#if EPOLL
|
||||
struct ospollfd *osfd = ospoll->fds[pos];
|
||||
osfd->xevents &= ~xevents;
|
||||
epoll_mod(ospoll, osfd);
|
||||
#endif
|
||||
#if POLL
|
||||
if (xevents & X_NOTIFY_READ)
|
||||
ospoll->fds[pos].events &= ~POLLIN;
|
||||
if (xevents & X_NOTIFY_WRITE)
|
||||
ospoll->fds[pos].events &= ~POLLOUT;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ospoll_wait(struct ospoll *ospoll, int timeout)
|
||||
{
|
||||
int nready;
|
||||
#if EPOLL
|
||||
#define MAX_EVENTS 256
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
int i;
|
||||
|
||||
nready = epoll_wait(ospoll->epoll_fd, events, MAX_EVENTS, timeout);
|
||||
for (i = 0; i < nready; i++) {
|
||||
struct epoll_event *ev = &events[i];
|
||||
struct ospollfd *osfd = ev->data.ptr;
|
||||
uint32_t revents = ev->events;
|
||||
int xevents = 0;
|
||||
|
||||
if (revents & EPOLLIN)
|
||||
xevents |= X_NOTIFY_READ;
|
||||
if (revents & EPOLLOUT)
|
||||
xevents |= X_NOTIFY_WRITE;
|
||||
if (revents & (~(EPOLLIN|EPOLLOUT)))
|
||||
xevents |= X_NOTIFY_ERROR;
|
||||
|
||||
osfd->callback(osfd->fd, xevents, osfd->data);
|
||||
}
|
||||
#endif
|
||||
#if POLL
|
||||
nready = xserver_poll(ospoll->fds, ospoll->num, timeout);
|
||||
if (nready > 0) {
|
||||
int f;
|
||||
for (f = 0; f < ospoll->num; f++) {
|
||||
short revents = ospoll->fds[f].revents;
|
||||
short oldevents = ospoll->osfds[f].revents;
|
||||
|
||||
ospoll->osfds[f].revents = (revents & (POLLIN|POLLOUT));
|
||||
if (ospoll->osfds[f].trigger == ospoll_trigger_edge)
|
||||
revents &= ~oldevents;
|
||||
if (revents) {
|
||||
int xevents = 0;
|
||||
if (revents & POLLIN)
|
||||
xevents |= X_NOTIFY_READ;
|
||||
if (revents & POLLOUT)
|
||||
xevents |= X_NOTIFY_WRITE;
|
||||
if (revents & (~(POLLIN|POLLOUT)))
|
||||
xevents |= X_NOTIFY_ERROR;
|
||||
ospoll->osfds[f].callback(ospoll->fds[f].fd, xevents,
|
||||
ospoll->osfds[f].data);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return nready;
|
||||
}
|
||||
|
||||
void
|
||||
ospoll_reset_events(struct ospoll *ospoll, int fd)
|
||||
{
|
||||
#if POLL
|
||||
int pos = ospoll_find(ospoll, fd);
|
||||
|
||||
if (pos < 0)
|
||||
return;
|
||||
|
||||
ospoll->osfds[pos].revents = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *
|
||||
ospoll_data(struct ospoll *ospoll, int fd)
|
||||
{
|
||||
int pos = ospoll_find(ospoll, fd);
|
||||
|
||||
if (pos < 0)
|
||||
return NULL;
|
||||
#if EPOLL
|
||||
return ospoll->fds[pos]->data;
|
||||
#endif
|
||||
#if POLL
|
||||
return ospoll->osfds[pos].data;
|
||||
#endif
|
||||
}
|
142
os/ospoll.h
Normal file
142
os/ospoll.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright © 2016 Keith Packard
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _OSPOLL_H_
|
||||
#define _OSPOLL_H_
|
||||
|
||||
/* Forward declaration */
|
||||
struct ospoll;
|
||||
|
||||
/**
|
||||
* ospoll_wait trigger mode
|
||||
*
|
||||
* @ospoll_trigger_edge
|
||||
* Trigger only when going from no data available
|
||||
* to data available.
|
||||
*
|
||||
* @ospoll_trigger_level
|
||||
* Trigger whenever there is data available
|
||||
*/
|
||||
enum ospoll_trigger {
|
||||
ospoll_trigger_edge,
|
||||
ospoll_trigger_level
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new ospoll structure
|
||||
*/
|
||||
struct ospoll *
|
||||
ospoll_create(void);
|
||||
|
||||
/**
|
||||
* Destroy an ospoll structure
|
||||
*
|
||||
* @param ospoll ospoll to destroy
|
||||
*/
|
||||
void
|
||||
ospoll_destroy(struct ospoll *ospoll);
|
||||
|
||||
/**
|
||||
* Add a file descriptor to monitor
|
||||
*
|
||||
* @param ospoll ospoll to add to
|
||||
* @param fd File descriptor to monitor
|
||||
* @param trigger Trigger mode for ospoll_wait
|
||||
* @param callback Function to call when triggered
|
||||
* @param data Extra data to pass callback
|
||||
*/
|
||||
Bool
|
||||
ospoll_add(struct ospoll *ospoll, int fd,
|
||||
enum ospoll_trigger trigger,
|
||||
void (*callback)(int fd, int xevents, void *data),
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* Remove a monitored file descriptor
|
||||
*
|
||||
* @param ospoll ospoll to remove from
|
||||
* @param fd File descriptor to stop monitoring
|
||||
*/
|
||||
void
|
||||
ospoll_remove(struct ospoll *ospoll, int fd);
|
||||
|
||||
/**
|
||||
* Listen on additional events
|
||||
*
|
||||
* @param ospoll ospoll monitoring fd
|
||||
* @param fd File descriptor to change
|
||||
* @param events Additional events to trigger on
|
||||
*/
|
||||
void
|
||||
ospoll_listen(struct ospoll *ospoll, int fd, int xevents);
|
||||
|
||||
/**
|
||||
* Stop listening on events
|
||||
*
|
||||
* @param ospoll ospoll monitoring fd
|
||||
* @param fd File descriptor to change
|
||||
* @param events events to stop triggering on
|
||||
*/
|
||||
void
|
||||
ospoll_mute(struct ospoll *ospoll, int fd, int xevents);
|
||||
|
||||
/**
|
||||
* Wait for events
|
||||
*
|
||||
* @param ospoll ospoll to wait on
|
||||
* @param timeout < 0 wait forever
|
||||
* = 0 check and return
|
||||
* > 0 timeout in milliseconds
|
||||
* @return < 0 error
|
||||
* = 0 timeout
|
||||
* > 0 number of events delivered
|
||||
*/
|
||||
int
|
||||
ospoll_wait(struct ospoll *ospoll, int timeout);
|
||||
|
||||
/**
|
||||
* Reset edge trigger status
|
||||
*
|
||||
* @param ospoll ospoll monitoring fd
|
||||
* @param fd file descriptor
|
||||
*
|
||||
* ospoll_reset_events resets the state of an edge-triggered
|
||||
* fd so that ospoll_wait calls will report events again.
|
||||
*
|
||||
* Call this after a read/recv operation reports no more data available.
|
||||
*/
|
||||
void
|
||||
ospoll_reset_events(struct ospoll *ospoll, int fd);
|
||||
|
||||
/**
|
||||
* Fetch the data associated with an fd
|
||||
*
|
||||
* @param ospoll ospoll monitoring fd
|
||||
* @param fd file descriptor
|
||||
*
|
||||
* @return data parameter passed to ospoll_add call on
|
||||
* this file descriptor
|
||||
*/
|
||||
void *
|
||||
ospoll_data(struct ospoll *ospoll, int fd);
|
||||
|
||||
#endif /* _OSPOLL_H_ */
|
Loading…
Reference in New Issue
Block a user