#include #include "libnul.h" typedef struct FdInfo FdInfo; struct FdInfo { gpointer data; unsigned int mask : 16; unsigned int valid : 1; unsigned int enabled : 1; }; struct nul_poll_t { int n_fds; FdInfo * fd_info; }; nul_poll_t * nul_poll_new (void) { nul_poll_t *nul_poll = g_new0 (nul_poll_t, 1); nul_poll->n_fds = 0; nul_poll->fd_info = nul_array_new (FdInfo); return nul_poll; } void nul_poll_add_fd (nul_poll_t *nul_poll, int fd, nul_poll_event_type_t mask, gpointer data) { g_return_if_fail (!nul_poll_has_fd (nul_poll, fd)); mask &= (NUL_POLL_RESERVED - 1); while (fd >= nul_array_len (nul_poll->fd_info)) nul_poll->fd_info = nul_array_set_size (nul_poll->fd_info, fd + 1); nul_poll->n_fds++; nul_poll->fd_info[fd].mask = mask; nul_poll->fd_info[fd].data = data; nul_poll->fd_info[fd].valid = TRUE; nul_poll->fd_info[fd].enabled = TRUE; } gboolean nul_poll_has_fd (nul_poll_t *nul_poll, int fd) { g_return_val_if_fail (nul_poll != NULL, FALSE); return fd < nul_array_len (nul_poll->fd_info) && nul_poll->fd_info[fd].valid; } gint nul_poll_get_n_fds (nul_poll_t *nul_poll) { return nul_poll->n_fds; } void nul_poll_remove_fd (nul_poll_t *nul_poll, int fd) { g_return_if_fail (nul_poll_has_fd (nul_poll, fd)); nul_poll->fd_info[fd].valid = FALSE; } gpointer nul_poll_get_fd_data (nul_poll_t *nul_poll, int fd) { g_return_val_if_fail (nul_poll != NULL, NULL); g_return_val_if_fail (nul_poll_has_fd (nul_poll, fd), NULL); return nul_poll->fd_info[fd].data; } /* nul_poll_wait() is a one-shot polling mechanism, so this function * must be called to reenable fd's after they have been returned * by nul_poll_wait(). */ void nul_poll_reenable_fd (nul_poll_t *nul_poll, int fd) { g_return_if_fail (nul_poll_has_fd (nul_poll, fd)); nul_poll->fd_info[fd].enabled = TRUE; } nul_poll_event_t * nul_poll_wait (nul_poll_t *nul_poll, int *n_events, int timeout) { struct pollfd *fds; int i, j; int n_poll_fds; int n_ready; nul_poll_event_t *events; fds = g_new (struct pollfd, nul_poll->n_fds); j = 0; for (i = 0; i < nul_array_len (nul_poll->fd_info); ++i) { if (nul_poll->fd_info[i].valid && nul_poll->fd_info[i].enabled && nul_poll->fd_info[i].mask != 0) { fds[j].events = 0; if (nul_poll->fd_info[i].mask & NUL_POLL_READ) fds[j].events |= POLLIN; if (nul_poll->fd_info[i].mask & NUL_POLL_WRITE) fds[j].events |= POLLOUT; if (nul_poll->fd_info[i].mask & NUL_POLL_HANGUP) fds[j].events |= POLLHUP; if (nul_poll->fd_info[i].mask & NUL_POLL_PRIORITY) fds[j].events |= POLLPRI; if (nul_poll->fd_info[i].mask & NUL_POLL_ERROR) fds[j].events |= POLLERR; fds[j].fd = i; j++; } } n_poll_fds = j; events = NULL; n_ready = poll (fds, n_poll_fds, timeout); if (n_ready) { events = g_new0 (nul_poll_event_t, n_ready); j = 0; for (i = 0; i < n_poll_fds; ++i) { if (fds[i].revents) { events[j].events = 0; if (fds[i].revents & POLLIN) events[j].events |= NUL_POLL_READ; if (fds[i].revents & POLLOUT) events[j].events |= NUL_POLL_WRITE; if (fds[i].revents & POLLHUP) events[j].events |= NUL_POLL_HANGUP; if (fds[i].revents & POLLERR) events[j].events |= NUL_POLL_ERROR; if (fds[i].revents & POLLPRI) events[j].events |= NUL_POLL_PRIORITY; events[j].fd = fds[i].fd; nul_poll->fd_info[fds[i].fd].enabled = FALSE; } } } g_free (fds); if (n_events) *n_events = n_ready; return events; }