fastdfs/common/ioevent.c

180 lines
4.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "ioevent.h"
#if IOEVENT_USE_KQUEUE
/* we define these here as numbers, because for kqueue mapping them to a combination of
* filters / flags is hard to do. */
int kqueue_ev_convert(int16_t event, uint16_t flags)
{
int r;
if (event == EVFILT_READ) {
r = KPOLLIN;
}
else if (event == EVFILT_WRITE) {
r = KPOLLOUT;
}
else {
r = 0;
}
if (flags & EV_EOF) {
r |= KPOLLHUP;
}
return r;
}
#endif
int ioevent_init(IOEventPoller *ioevent, const int size,
const int timeout, const int extra_events)
{
int bytes;
ioevent->size = size;
ioevent->extra_events = extra_events;
#if IOEVENT_USE_EPOLL
ioevent->timeout = timeout;
ioevent->poll_fd = epoll_create(ioevent->size);
bytes = sizeof(struct epoll_event) * size;
ioevent->events = (struct epoll_event *)malloc(bytes);
#elif IOEVENT_USE_KQUEUE
ioevent->timeout.tv_sec = timeout / 1000;
ioevent->timeout.tv_nsec = 1000000 * (timeout % 1000);
ioevent->poll_fd = kqueue();
bytes = sizeof(struct kevent) * size;
ioevent->events = (struct kevent *)malloc(bytes);
#elif IOEVENT_USE_PORT
ioevent->timeout.tv_sec = timeout / 1000;
ioevent->timeout.tv_nsec = 1000000 * (timeout % 1000);
ioevent->poll_fd = port_create();
bytes = sizeof(port_event_t) * size;
ioevent->events = (port_event_t *)malloc(bytes);
#endif
if (ioevent->events == NULL) {
return errno != 0 ? errno : ENOMEM;
}
return 0;
}
void ioevent_destroy(IOEventPoller *ioevent)
{
if (ioevent->events != NULL) {
free(ioevent->events);
ioevent->events = NULL;
}
if (ioevent->poll_fd >=0) {
close(ioevent->poll_fd);
ioevent->poll_fd = -1;
}
}
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
void *data)
{
#if IOEVENT_USE_EPOLL
struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
ev.events = e | ioevent->extra_events;
ev.data.ptr = data;
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_ADD, fd, &ev);
#elif IOEVENT_USE_KQUEUE
struct kevent ev[2];
int n = 0;
if (e & IOEVENT_READ) {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | ioevent->extra_events, 0, 0, data);
}
if (e & IOEVENT_WRITE) {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | ioevent->extra_events, 0, 0, data);
}
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
#elif IOEVENT_USE_PORT
return port_associate(ioevent->poll_fd, PORT_SOURCE_FD, fd, e, data);
#endif
}
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
void *data)
{
#if IOEVENT_USE_EPOLL
struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
ev.events = e | ioevent->extra_events;
ev.data.ptr = data;
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_MOD, fd, &ev);
#elif IOEVENT_USE_KQUEUE
struct kevent ev[2];
int n = 0;
if (e & IOEVENT_READ) {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | ioevent->extra_events, 0, 0, data);
}
else {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_DELETE, 0, 0, data);
}
if (e & IOEVENT_WRITE) {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | ioevent->extra_events, 0, 0, data);
}
else {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, data);
}
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
#elif IOEVENT_USE_PORT
return port_associate(ioevent->poll_fd, PORT_SOURCE_FD, fd, e, data);
#endif
}
int ioevent_detach(IOEventPoller *ioevent, const int fd)
{
#if IOEVENT_USE_EPOLL
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_DEL, fd, NULL);
#elif IOEVENT_USE_PORT
return port_dissociate(ioevent->poll_fd, PORT_SOURCE_FD, fd);
#else
return 0;
#endif
}
int ioevent_poll(IOEventPoller *ioevent)
{
#if IOEVENT_USE_EPOLL
return epoll_wait(ioevent->poll_fd, ioevent->events, ioevent->size, ioevent->timeout);
#elif IOEVENT_USE_KQUEUE
return kevent(ioevent->poll_fd, NULL, 0, ioevent->events, ioevent->size, &ioevent->timeout);
#elif IOEVENT_USE_PORT
int result;
int retval;
unsigned int nget = 1;
if((retval = port_getn(ioevent->poll_fd, ioevent->events,
ioevent->size, &nget, &ioevent->timeout)) == 0)
{
result = (int)nget;
} else {
switch(errno) {
case EINTR:
case EAGAIN:
case ETIME:
if (nget > 0) {
result = (int)nget;
}
else {
result = 0;
}
break;
default:
result = -1;
break;
}
}
return result;
#else
#error port me
#endif
}