text: #include "uwsgi.h"
  
  extern struct uwsgi_server uwsgi;
  
  #ifdef UWSGI_EVENT_USE_POLL
  #define UWSGI_EVENT_IN POLLIN
  #define UWSGI_EVENT_OUT POLLOUT
  
  int uwsgi_poll_event_queue_max = 0;
  struct uwsgi_poll_event {
  	int nevents;
  	int max_events;
  	pthread_mutex_t lock;
  	struct pollfd *poll;
  };
  
  struct uwsgi_poll_event **uwsgi_poll_event_queue;
  
  // all of the public functions must be heavy locked
  
  static int uwsgi_poll_fd_is_registered(struct uwsgi_poll_event *upe, int fd) {
  	int i;
  	for(i=0;i<upe->nevents;i++) {
  		if (upe->poll[i].fd == fd) {
  			return 1;
  		}
  	}
  	return 0;
  }
  
  static int uwsgi_poll_fd_add(struct uwsgi_poll_event *upe, int fd, int event) {
  	int pos = upe->nevents;
  	if (pos > upe->max_events) return -1;
  	upe->poll[pos].fd = fd;
  	upe->poll[pos].events = event;
  	upe->nevents++;
  	return 0;
  }
  
  static int uwsgi_poll_fd_del(struct uwsgi_poll_event *upe, int fd) {
  	int i;
  	for(i=0;i<upe->nevents;i++) {
  		if (upe->poll[i].fd == fd) {
  			if (i < upe->nevents-1) {
  				memcpy(&upe->poll[i], &upe->poll[i+1], sizeof(struct uwsgi_poll_event) * (upe->nevents - (i+1))); 
  			}
  			upe->nevents--;
  			return 0;
  		}
  	}
  	return -1;
  }
  
  static void uwsgi_poll_queue_rebuild(struct uwsgi_poll_event *upe) {
  	// we need to check if some file descriptor is no more valid
  	int i;
  	for(i=0;i<upe->nevents;i++) {
  		if (!uwsgi_valid_fd(upe->poll[i].fd)) {
  			uwsgi_poll_fd_del(upe, upe->poll[i].fd);
  		}
  	}
  }
  
  int event_queue_wait(int eq, int timeout, int *interesting_fd) {
  	struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
  	pthread_mutex_lock(&upe->lock);
  	uwsgi_poll_queue_rebuild(upe);
  	int ret = poll(upe->poll, upe->nevents, timeout * 1000);
  	if (ret > 0) {
  		int i;
  		for(i=0;i<upe->nevents;i++) {
  			if (upe->poll[i].revents) {
  				*interesting_fd = upe->poll[i].fd;
  				pthread_mutex_unlock(&upe->lock);
  				return 1;
  			}
  		}
  	}
  	pthread_mutex_unlock(&upe->lock);
  	return ret;
  }
  
  int event_queue_init() {
  	if (!uwsgi_poll_event_queue) {
  		uwsgi_poll_event_queue = uwsgi_calloc(sizeof(struct uwsgi_poll_event *) * uwsgi.max_fd);
  	}
  	int eq = uwsgi_poll_event_queue_max;
  	uwsgi_poll_event_queue[eq] = uwsgi_calloc(sizeof(struct uwsgi_poll_event));
  	uwsgi_poll_event_queue_max++;
  	uwsgi_poll_event_queue[eq]->poll = uwsgi_malloc(sizeof(struct pollfd) * uwsgi.max_fd);
  	uwsgi_poll_event_queue[eq]->max_events = uwsgi.max_fd;
  	pthread_mutex_init(&uwsgi_poll_event_queue[eq]->lock, NULL);
  	return eq;
  }
  
  void *event_queue_alloc(int nevents) {
  	return uwsgi_calloc(sizeof(struct pollfd) * nevents);
  }
  
  int event_queue_interesting_fd_is_read(void *events, int id) {
  	struct pollfd *pevents = (struct pollfd *)events;
          struct pollfd *upoll = &pevents[id];
          if (upoll->revents & POLLIN) {
  		return 1;
  	}	
  	return 0;
  }
  
  int event_queue_fd_write_to_readwrite(int eq, int fd) {
  	struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
  	pthread_mutex_lock(&upe->lock);
  	int i;
  	for(i=0;i<upe->nevents;i++) {
  		if (upe->poll[i].fd == fd) {
  			upe->poll[i].events = POLLIN|POLLOUT;
  			pthread_mutex_unlock(&upe->lock);
  			return 0;
  		}
  	}	
  	pthread_mutex_unlock(&upe->lock);
  	return -1;
  }
  
  int event_queue_fd_read_to_readwrite(int eq, int fd) {
  	return event_queue_fd_write_to_readwrite(eq, fd);
  }
  
  int event_queue_interesting_fd_is_write(void *events, int id) {
  	struct pollfd *pevents = (struct pollfd *)events;
          struct pollfd *upoll = &pevents[id];
          if (upoll->revents & POLLOUT) {
                  return 1;
          }
          return 0;
  }
  
  int event_queue_add_fd_read(int eq, int fd) {
  	struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
  	pthread_mutex_lock(&upe->lock);
  	if (uwsgi_poll_fd_is_registered(upe, fd)) {
  		pthread_mutex_unlock(&upe->lock);
  		return 0;	
  	}
  	int ret = uwsgi_poll_fd_add(upe, fd, POLLIN);
  	pthread_mutex_unlock(&upe->lock);
  	return ret;
  }
  int event_queue_add_fd_write(int eq, int fd) {
          struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
  	pthread_mutex_lock(&upe->lock);
          if (uwsgi_poll_fd_is_registered(upe, fd)) {
  		pthread_mutex_unlock(&upe->lock);
  		return 0;
  	}
          int ret = uwsgi_poll_fd_add(upe, fd, POLLOUT);
  	pthread_mutex_unlock(&upe->lock);
  	return ret;
  }
  int event_queue_del_fd(int eq, int fd, int event) {
  	struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
  	pthread_mutex_lock(&upe->lock);
  	int ret = uwsgi_poll_fd_del(upe, fd);
  	pthread_mutex_unlock(&upe->lock);
  	return ret;
  }
  int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
  	struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
  	pthread_mutex_lock(&upe->lock);
          uwsgi_poll_queue_rebuild(upe);
          int ret = poll(upe->poll, upe->nevents, timeout * 1000);
  	int cnt = 0;
          if (ret > 0) {
                  int i;
                  for(i=0;i<upe->nevents;i++) {
                          if (upe->poll[i].revents) {
  				if (cnt >= nevents)
  					break;
  
  				struct pollfd *pevents = (struct pollfd *)events;	
  				struct pollfd *upoll = &pevents[cnt];
  				upoll->fd = upe->poll[i].fd;
  				upoll->revents = upe->poll[i].revents;
  				upoll->events = upe->poll[i].events;
  				cnt++;
                          }
                  }
          }
  	pthread_mutex_unlock(&upe->lock);
  	if (ret <= 0) return ret;
          return cnt;
  }
  int event_queue_interesting_fd_has_error(void *events, int id) {
  	struct pollfd *pevents = (struct pollfd *)events;
  	struct pollfd *upoll = &pevents[id];
  	if (upoll->revents & POLLERR || upoll->revents & POLLHUP || upoll->revents & POLLNVAL) {
  		return 1;
  	}
  	return 0;
  }
  int event_queue_interesting_fd(void *events, int id) {
  	struct pollfd *pevents = (struct pollfd *)events;
          struct pollfd *upoll = &pevents[id];
  	return upoll->fd;
  }
  int event_queue_fd_write_to_read(int eq, int fd) {
  	struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
  	pthread_mutex_lock(&upe->lock);
  	int i;
  	for(i=0;i<upe->nevents;i++) {
  		if (upe->poll[i].fd == fd) {
  			upe->poll[i].events = POLLIN;
  			pthread_mutex_unlock(&upe->lock);
  			return 0;
  		}
  	}	
  	pthread_mutex_unlock(&upe->lock);
  	return -1;
  }
  int event_queue_fd_read_to_write(int eq, int fd) {
  	struct uwsgi_poll_event *upe = uwsgi_poll_event_queue[eq];
  	pthread_mutex_lock(&upe->lock);
  	int i;
  	for(i=0;i<upe->nevents;i++) {
  		if (upe->poll[i].fd == fd) {
  			upe->poll[i].events = POLLOUT;
  			pthread_mutex_unlock(&upe->lock);
  			return 0;
  		}
  	}	
  	pthread_mutex_unlock(&upe->lock);
  	return -1;
  }
  #endif
  
  #ifdef UWSGI_EVENT_USE_PORT
  
  #include <port.h>
  
  #define UWSGI_EVENT_IN POLLIN
  #define UWSGI_EVENT_OUT POLLOUT
  
  int event_queue_init() {
  
  	int port = port_create();
  
  	if (port < 0) {
  		uwsgi_error("port_create()");
  		return -1;
  	}
  
  	return port;
  }
  
  int event_queue_del_fd(int eq, int fd, int event) {
  
  	if (port_dissociate(eq, PORT_SOURCE_FD, fd)) {
  		uwsgi_error("port_disassociate");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_fd_write_to_read(int eq, int fd) {
  
  	if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *)((long) eq))) {
  		uwsgi_error("port_associate");
  		return -1;
  	}
  
  	return 0;
  
  }
  
  int event_queue_fd_read_to_write(int eq, int fd) {
  
  	if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, (void *)((long) eq))) {
  		uwsgi_error("port_associate");
  		return -1;
  	}
  
  	return 0;
  
  }
  
  int event_queue_fd_readwrite_to_read(int eq, int fd) {
  
  	if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *)((long) eq))) {
  		uwsgi_error("port_associate");
  		return -1;
  	}
  
  	return 0;
  
  }
  
  int event_queue_fd_readwrite_to_write(int eq, int fd) {
  
  	if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, (void *)((long) eq))) {
  		uwsgi_error("port_associate");
  		return -1;
  	}
  
  	return 0;
  
  }
  
  int event_queue_fd_write_to_readwrite(int eq, int fd) {
  
  	if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN | POLLOUT, (void *)((long) eq))) {
  		uwsgi_error("port_associate");
  		return -1;
  	}
  
  	return 0;
  
  }
  
  int event_queue_fd_read_to_readwrite(int eq, int fd) {
  
  	if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN | POLLOUT, (void *)((long) eq))) {
  		uwsgi_error("port_associate");
  		return -1;
  	}
  
  	return 0;
  
  }
  
  
  int event_queue_interesting_fd_has_error(void *events, int id) {
  	port_event_t *pe = (port_event_t *) events;
  	if (pe[id].portev_events == POLLHUP || pe[id].portev_events == POLLERR) {
  		return 1;
  	}
  	return 0;
  }
  
  int event_queue_interesting_fd_is_read(void *events, int id) {
  	port_event_t *pe = (port_event_t *) events;
  	if (pe[id].portev_events == POLLIN) {
  		return 1;
  	}
  	return 0;
  }
  
  int event_queue_interesting_fd_is_write(void *events, int id) {
  	port_event_t *pe = (port_event_t *) events;
  	if (pe[id].portev_events == POLLOUT) {
  		return 1;
  	}
  	return 0;
  }
  
  int event_queue_add_fd_read(int eq, int fd) {
  
  	if (port_associate(eq, PORT_SOURCE_FD, fd, POLLIN, (void *)((long) eq))) {
  		uwsgi_error("port_associate");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_add_fd_write(int eq, int fd) {
  
  	if (port_associate(eq, PORT_SOURCE_FD, fd, POLLOUT, (void *)((long) eq))) {
  		uwsgi_error("port_associate");
  		return -1;
  	}
  
  	return 0;
  }
  
  void *event_queue_alloc(int nevents) {
  
  	return uwsgi_malloc(sizeof(port_event_t) * nevents);
  }
  
  int event_queue_interesting_fd(void *events, int id) {
  	port_event_t *pe = (port_event_t *) events;
  #ifdef PORT_SOURCE_FILE
  	if (pe[id].portev_source == PORT_SOURCE_FILE || pe[id].portev_source == PORT_SOURCE_TIMER) {
  #else
  	if (pe[id].portev_source == PORT_SOURCE_TIMER) {
  #endif
  		return (long) pe[id].portev_user;
  	}
  
  	int fd = (int) pe[id].portev_object;
  	int eq = (long) pe[id].portev_user;
  
  	if (pe[id].portev_events == POLLOUT) {
  		event_queue_add_fd_write(eq, fd);
  	}
  	if (pe[id].portev_events == POLLIN) {
  		event_queue_add_fd_read(eq, fd);
  	}
  
  	return fd;
  }
  
  int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
  
  	int ret;
  	uint_t nget = 1;
  	timespec_t ts;
  	
  
  	if (timeout >= 0) {
  		ts.tv_sec = timeout;
  		ts.tv_nsec = 0;
  		ret = port_getn(eq, events, nevents, &nget, &ts);
  	}
  	else {
  		ret = port_getn(eq, events, nevents, &nget, NULL);
  	}
  
  	if (ret < 0) {
  		if (errno == ETIME) return 0;
                  if (errno != EINTR) {
                          uwsgi_error("port_getn()");
                  }
                  return -1;
  	}
  
  	uint_t i;
  	port_event_t *pe = (port_event_t *) events;
  	for(i=0;i<nget;i++) {
  		port_event_t *pe_i = &pe[i];
  		if (pe_i->portev_source == PORT_SOURCE_FD) {
                  	// event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???)
                  	if (port_associate(eq, pe_i->portev_source, pe_i->portev_object, pe_i->portev_events, (void *)((long) eq))) {
                          	uwsgi_error("port_associate");
                  	}
          	}
  	}
  
  	return nget;
  }
  
  
  
  int event_queue_wait(int eq, int timeout, int *interesting_fd) {
  
  	int ret;
  	port_event_t pe;
  	timespec_t ts;
  
  	if (timeout > 0) {
  		ts.tv_sec = timeout;
  		ts.tv_nsec = 0;
  		ret = port_get(eq, &pe, &ts);
  	}
  	else {
  		ret = port_get(eq, &pe, NULL);
  	}
  
  	if (ret < 0) {
  		if (errno == ETIME) return 0;
  		if (errno != EINTR) {
  			uwsgi_error("port_get()");
  		}
  		return -1;
  	}
  
  	if (pe.portev_source == PORT_SOURCE_FD) {
  		// event must be readded (damn Oracle/Sun why the fu*k you made such a horrible choice ???? why not adding a ONESHOT flag ???)
  		if (port_associate(eq, pe.portev_source, pe.portev_object, pe.portev_events, (void *)((long) eq))) {
  			uwsgi_error("port_associate");
  		}
  	}
  
  
  #ifdef PORT_SOURCE_FILE
  	if (pe.portev_source == PORT_SOURCE_FILE || pe.portev_source == PORT_SOURCE_TIMER) {
  #else
  	if (pe.portev_source == PORT_SOURCE_TIMER) {
  #endif
  		*interesting_fd = (long) pe.portev_user;
  	}
  	else {
  		*interesting_fd = (int) pe.portev_object;
  	}
  
  	return 1;
  }
  
  #endif
  
  
  #ifdef UWSGI_EVENT_USE_EPOLL
  
  #include <sys/epoll.h>
  
  #define UWSGI_EVENT_IN EPOLLIN
  #define UWSGI_EVENT_OUT EPOLLOUT
  
  int event_queue_init() {
  
  	int epfd;
  
  
  	epfd = epoll_create(256);
  
  	if (epfd < 0) {
  		uwsgi_error("epoll_create()");
  		return -1;
  	}
  
  	return epfd;
  }
  
  
  int event_queue_add_fd_read(int eq, int fd) {
  
  	struct epoll_event ee;
  
  	memset(&ee, 0, sizeof(struct epoll_event));
  	ee.events = EPOLLIN;
  	ee.data.fd = fd;
  
  	if (epoll_ctl(eq, EPOLL_CTL_ADD, fd, &ee)) {
  		uwsgi_error("epoll_ctl()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_fd_write_to_read(int eq, int fd) {
  
  	struct epoll_event ee;
  
  	memset(&ee, 0, sizeof(struct epoll_event));
  	ee.events = EPOLLIN;
  	ee.data.fd = fd;
  
  	if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
  		uwsgi_error("epoll_ctl()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_fd_read_to_write(int eq, int fd) {
  
  	struct epoll_event ee;
  
  	memset(&ee, 0, sizeof(struct epoll_event));
  	ee.events = EPOLLOUT;
  	ee.data.fd = fd;
  
  	if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
  		uwsgi_error("epoll_ctl()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_fd_readwrite_to_read(int eq, int fd) {
  
  	struct epoll_event ee;
  
  	memset(&ee, 0, sizeof(struct epoll_event));
  	ee.events = EPOLLIN;
  	ee.data.fd = fd;
  
  	if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
  		uwsgi_error("epoll_ctl()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_fd_readwrite_to_write(int eq, int fd) {
  
  	struct epoll_event ee;
  
  	memset(&ee, 0, sizeof(struct epoll_event));
  	ee.events = EPOLLOUT;
  	ee.data.fd = fd;
  
  	if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
  		uwsgi_error("epoll_ctl()");
  		return -1;
  	}
  
  	return 0;
  }
  
  
  int event_queue_fd_read_to_readwrite(int eq, int fd) {
  
  	struct epoll_event ee;
  
  	memset(&ee, 0, sizeof(struct epoll_event));
  	ee.events = EPOLLIN | EPOLLOUT;
  	ee.data.fd = fd;
  
  	if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
  		uwsgi_error("epoll_ctl()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_fd_write_to_readwrite(int eq, int fd) {
  
  	struct epoll_event ee;
  
  	memset(&ee, 0, sizeof(struct epoll_event));
  	ee.events = EPOLLIN | EPOLLOUT;
  	ee.data.fd = fd;
  
  	if (epoll_ctl(eq, EPOLL_CTL_MOD, fd, &ee)) {
  		uwsgi_error("epoll_ctl()");
  		return -1;
  	}
  
  	return 0;
  }
  
  
  
  int event_queue_del_fd(int eq, int fd, int event) {
  
  	struct epoll_event ee;
  
  	memset(&ee, 0, sizeof(struct epoll_event));
  	ee.data.fd = fd;
  	ee.events = event;
  
  	if (epoll_ctl(eq, EPOLL_CTL_DEL, fd, &ee)) {
  		uwsgi_error("epoll_ctl()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_add_fd_write(int eq, int fd) {
  
  	struct epoll_event ee;
  
  	memset(&ee, 0, sizeof(struct epoll_event));
  	ee.events = EPOLLOUT;
  	ee.data.fd = fd;
  
  	if (epoll_ctl(eq, EPOLL_CTL_ADD, fd, &ee)) {
  		uwsgi_error("epoll_ctl()");
  		return -1;
  	}
  
  	return 0;
  }
  
  void *event_queue_alloc(int nevents) {
  
  	return uwsgi_malloc(sizeof(struct epoll_event) * nevents);
  }
  
  int event_queue_interesting_fd(void *events, int id) {
  	struct epoll_event *ee = (struct epoll_event *) events;
  	return ee[id].data.fd;
  }
  
  int event_queue_interesting_fd_has_error(void *events, int id) {
  	struct epoll_event *ee = (struct epoll_event *) events;
  	if (ee[id].events == EPOLLHUP || ee[id].events == EPOLLERR || (ee[id].events == (EPOLLERR | EPOLLHUP))) {
  		return 1;
  	}
  	return 0;
  }
  
  int event_queue_interesting_fd_is_read(void *events, int id) {
  	struct epoll_event *ee = (struct epoll_event *) events;
  	if (ee[id].events & EPOLLIN) {
  		return 1;
  	}
  	return 0;
  }
  
  int event_queue_interesting_fd_is_write(void *events, int id) {
  	struct epoll_event *ee = (struct epoll_event *) events;
  	if (ee[id].events & EPOLLOUT) {
  		return 1;
  	}
  	return 0;
  }
  
  
  int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
  
  	int ret;
  
  	if (timeout > 0) {
  		timeout = timeout * 1000;
  	}
  
  	ret = epoll_wait(eq, (struct epoll_event *) events, nevents, timeout);
  	if (ret < 0) {
  		if (errno != EINTR)
  			uwsgi_error("epoll_wait()");
  	}
  
  	return ret;
  }
  
  int event_queue_wait(int eq, int timeout, int *interesting_fd) {
  
  	int ret;
  	struct epoll_event ee;
  
  	if (timeout > 0) {
  		timeout = timeout * 1000;
  	}
  
  	ret = epoll_wait(eq, &ee, 1, timeout);
  	if (ret < 0) {
  		if (errno != EINTR)
  			uwsgi_error("epoll_wait()");
  	}
  
  	if (ret > 0) {
  		*interesting_fd = ee.data.fd;
  	}
  
  	return ret;
  }
  
  #endif
  
  #ifdef UWSGI_EVENT_USE_KQUEUE
  
  #define UWSGI_EVENT_IN EVFILT_READ
  #define UWSGI_EVENT_OUT EVFILT_WRITE
  
  int event_queue_init() {
  
  	int kfd = kqueue();
  
  	if (kfd < 0) {
  		uwsgi_error("kqueue()");
  		return -1;
  	}
  
  	return kfd;
  }
  
  int event_queue_fd_write_to_read(int eq, int fd) {
  
  	struct kevent kev;
  
  	EV_SET(&kev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_fd_read_to_write(int eq, int fd) {
  
  	struct kevent kev;
  
  	EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_fd_readwrite_to_read(int eq, int fd) {
  
  	struct kevent kev;
  
  	EV_SET(&kev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_fd_readwrite_to_write(int eq, int fd) {
  
  	struct kevent kev;
  
  	EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_fd_read_to_readwrite(int eq, int fd) {
  
  	struct kevent kev;
  
  	EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	return 0;
  }
  
  
  int event_queue_fd_write_to_readwrite(int eq, int fd) {
  
  	struct kevent kev;
  
  	EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	return 0;
  }
  
  
  
  int event_queue_del_fd(int eq, int fd, int event) {
  
  	struct kevent kev;
  
  	EV_SET(&kev, fd, event, EV_DELETE, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_add_fd_read(int eq, int fd) {
  
  	struct kevent kev;
  
  	EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	return 0;
  }
  
  int event_queue_add_fd_write(int eq, int fd) {
  
  	struct kevent kev;
  
  	EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	return 0;
  }
  
  void *event_queue_alloc(int nevents) {
  
  	return uwsgi_malloc(sizeof(struct kevent) * nevents);
  }
  
  int event_queue_wait_multi(int eq, int timeout, void *events, int nevents) {
  
  	int ret;
  	struct timespec ts;
  
  	if (timeout < 0) {
  		ret = kevent(eq, NULL, 0, events, nevents, NULL);
  	}
  	else {
  		memset(&ts, 0, sizeof(struct timespec));
  		ts.tv_sec = timeout;
  		ret = kevent(eq, NULL, 0, (struct kevent *) events, nevents, &ts);
  	}
  
  	if (ret < 0) {
  		if (errno != EINTR)
  			uwsgi_error("kevent()");
  	}
  
  	return ret;
  
  }
  
  int event_queue_interesting_fd(void *events, int id) {
  
  	struct kevent *ev = (struct kevent *) events;
  	return ev[id].ident;
  }
  
  int event_queue_interesting_fd_has_error(void *events, int id) {
  	struct kevent *ev = (struct kevent *) events;
  
  	// DO NOT CHECK FOR EOF !!!
  	if (ev[id].flags & EV_ERROR) {
  		return 1;
  	}
  	return 0;
  }
  
  int event_queue_interesting_fd_is_read(void *events, int id) {
  	struct kevent *ev = (struct kevent *) events;
  	if (ev[id].filter == EVFILT_READ) {
  		return 1;
  	}
  	return 0;
  }
  
  
  int event_queue_interesting_fd_is_write(void *events, int id) {
  	struct kevent *ev = (struct kevent *) events;
  	if (ev[id].filter == EVFILT_WRITE) {
  		return 1;
  	}
  	return 0;
  }
  
  int event_queue_wait(int eq, int timeout, int *interesting_fd) {
  
  	int ret;
  	struct timespec ts;
  	struct kevent ev;
  
  	if (timeout < 0) {
  		ret = kevent(eq, NULL, 0, &ev, 1, NULL);
  	}
  	else {
  		memset(&ts, 0, sizeof(struct timespec));
  		ts.tv_sec = timeout;
  		ret = kevent(eq, NULL, 0, &ev, 1, &ts);
  	}
  
  	if (ret < 0) {
  		if (errno != EINTR)
  			uwsgi_error("kevent()");
  	}
  
  	if (ret > 0) {
  		*interesting_fd = ev.ident;
  	}
  
  	return ret;
  
  }
  #endif
  
  #ifdef UWSGI_EVENT_FILEMONITOR_USE_NONE
  int event_queue_add_file_monitor(int eq, char *filename, int *id) {
  	return -1;
  }
  struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
  	return NULL;
  }
  #endif
  
  #ifdef UWSGI_EVENT_FILEMONITOR_USE_PORT
  #ifdef PORT_SOURCE_FILE
  int event_queue_add_file_monitor(int eq, char *filename, int *id) {
  
  	struct file_obj fo;
  	struct stat st;
  	static int fmon_id = 0xffffee00;
  
  	if (stat(filename, &st)) {
  		uwsgi_error("stat()");
  		return -1;
  	}
  
  	fo.fo_name = filename;
  	fo.fo_atime = st.st_atim;
  	fo.fo_mtime = st.st_mtim;
  	fo.fo_ctime = st.st_ctim;
  
  	fmon_id++;
  	if (port_associate(eq, PORT_SOURCE_FILE, (uintptr_t) & fo, FILE_MODIFIED | FILE_ATTRIB, (void *) (long) fmon_id)) {
  		uwsgi_error("port_associate()");
  		return -1;
  	}
  
  
  	*id = fmon_id;
  
  	uwsgi_log("added new file to monitor %s [%d]\n", filename, *id);
  
  	return *id;
  }
  
  struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
  
  	int i;
  	struct file_obj fo;
  	struct stat st;
  
  	for (i = 0; i < ushared->files_monitored_cnt; i++) {
  		if (ushared->files_monitored[i].registered) {
  			if (ushared->files_monitored[i].fd == id) {
  				if (stat(ushared->files_monitored[i].filename, &st)) {
  					uwsgi_error("stat()");
  					return NULL;
  				}
  				fo.fo_name = ushared->files_monitored[i].filename;
  				fo.fo_atime = st.st_atim;
  				fo.fo_mtime = st.st_mtim;
  				fo.fo_ctime = st.st_ctim;
  				if (port_associate(eq, PORT_SOURCE_FILE, (uintptr_t) & fo, FILE_MODIFIED | FILE_ATTRIB, (void *) (long) id)) {
  					uwsgi_error("port_associate()");
  					return NULL;
  				}
  				return &ushared->files_monitored[i];
  			}
  		}
  	}
  
  	return NULL;
  
  }
  
  #else
  int event_queue_add_file_monitor(int eq, char *filename, int *id) {
  	return -1;
  }
  struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
  	return NULL;
  }
  #endif
  #endif
  
  
  #ifdef UWSGI_EVENT_FILEMONITOR_USE_KQUEUE
  int event_queue_add_file_monitor(int eq, char *filename, int *id) {
  
  	struct kevent kev;
  
  	int fd = open(filename, O_RDONLY);
  	if (fd < 0) {
  		uwsgi_error_open(filename);
  		return -1;
  	}
  
  	EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_WRITE | NOTE_DELETE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE, 0, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	*id = fd;
  
  	uwsgi_log("added new file to monitor %s\n", filename);
  
  	return fd;
  }
  
  struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
  
  	int i;
  
  	for (i = 0; i < ushared->files_monitored_cnt; i++) {
  		if (ushared->files_monitored[i].registered) {
  			if (ushared->files_monitored[i].fd == id) {
  				return &ushared->files_monitored[i];
  			}
  		}
  	}
  
  	return NULL;
  
  }
  
  #endif
  
  #ifdef UWSGI_EVENT_FILEMONITOR_USE_INOTIFY
  
  
  #ifdef OBSOLETE_LINUX_KERNEL
  int event_queue_add_file_monitor(int eq, char *filename, int *id) {
  	return -1;
  }
  struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
  	return NULL;
  }
  #else
  #include <sys/inotify.h>
  
  int event_queue_add_file_monitor(int eq, char *filename, int *id) {
  
  	int ifd = -1;
  	int i;
  	int add_to_queue = 0;
  
  	for (i = 0; i < ushared->files_monitored_cnt; i++) {
  		if (ushared->files_monitored[i].registered) {
  			ifd = ushared->files_monitored[0].fd;
  			break;
  		}
  	}
  
  	if (ifd == -1) {
  		ifd = inotify_init();
  		if (ifd < 0) {
  			uwsgi_error("inotify_init()");
  			return -1;
  		}
  		add_to_queue = 1;
  	}
  
  	*id = inotify_add_watch(ifd, filename, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO);
  
  #ifdef UWSGI_DEBUG
  	uwsgi_log("added watch %d for filename %s\n", *id, filename);
  #endif
  
  	if (add_to_queue) {
  		if (event_queue_add_fd_read(eq, ifd)) {
  			return -1;
  		}
  	}
  	return ifd;
  }
  
  struct uwsgi_fmon *event_queue_ack_file_monitor(int eq, int id) {
  
  	ssize_t rlen = 0;
  	struct inotify_event ie, *bie, *iie;
  	int i, j;
  	int items = 0;
  
  	unsigned int isize = sizeof(struct inotify_event);
  	struct uwsgi_fmon *uf = NULL;
  
  	if (ioctl(id, FIONREAD, &isize) < 0) {
  		uwsgi_error("ioctl()");
  		return NULL;
  	}
  
  	if (isize > sizeof(struct inotify_event)) {
  		bie = uwsgi_malloc(isize);
  		rlen = read(id, bie, isize);
  	}
  	else {
  		rlen = read(id, &ie, sizeof(struct inotify_event));
  		bie = &ie;
  	}
  
  	if (rlen < 0) {
  		uwsgi_error("read()");
  	}
  	else {
  		items = isize / (sizeof(struct inotify_event));
  #ifdef UWSGI_DEBUG
  		uwsgi_log("inotify returned %d items\n", items);
  #endif
  		for (j = 0; j < items; j++) {
  			iie = &bie[j];
  			for (i = 0; i < ushared->files_monitored_cnt; i++) {
  				if (ushared->files_monitored[i].registered) {
  					if (ushared->files_monitored[i].fd == id && ushared->files_monitored[i].id == iie->wd) {
  						uf = &ushared->files_monitored[i];
  					}
  				}
  			}
  
  		}
  
  		if (items > 1) {
  			free(bie);
  		}
  
  		return uf;
  	}
  
  	return NULL;
  
  }
  
  #endif
  #endif
  
  #ifdef UWSGI_EVENT_TIMER_USE_TIMERFD
  
  #ifndef UWSGI_EVENT_TIMER_USE_TIMERFD_NOINC
  #include <sys/timerfd.h>
  #endif
  
  #ifndef TFD_CLOEXEC
  
  // timerfd support
  
  enum {
  	TFD_CLOEXEC = 02000000,
  #define TFD_CLOEXEC TFD_CLOEXEC
  	TFD_NONBLOCK = 04000
  #define TFD_NONBLOCK TFD_NONBLOCK
  };
  
  
  /* Bits to be set in the FLAGS parameter of `timerfd_settime'.  */
  enum {
  	TFD_TIMER_ABSTIME = 1 << 0
  #define TFD_TIMER_ABSTIME TFD_TIMER_ABSTIME
  };
  
  
  static int timerfd_create(clockid_t __clock_id, int __flags) {
  #ifdef __amd64__
  	return syscall(283, __clock_id, __flags);
  #elif defined(__i386__)
  	return syscall(322, __clock_id, __flags);
  #elif defined(__arm__)
  	return syscall(350, __clock_id, __flags);
  #else
  	return -1;
  #endif
  }
  
  static int timerfd_settime(int __ufd, int __flags, __const struct itimerspec *__utmr, struct itimerspec *__otmr) {
  #ifdef __amd64__
  	return syscall(286, __ufd, __flags, __utmr, __otmr);
  #elif defined(__i386__)
  	return syscall(325, __ufd, __flags, __utmr, __otmr);
  #elif defined(__arm__)
  	return syscall(353, __ufd, __flags, __utmr, __otmr);
  #else
  	return -1;
  #endif
  }
  #endif
  
  int event_queue_add_timer(int eq, int *id, int sec) {
  
  	struct itimerspec it;
  	int tfd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC);
  
  	if (tfd < 0) {
  		uwsgi_error("timerfd_create()");
  		return -1;
  	}
  
  	it.it_value.tv_sec = sec;
  	it.it_value.tv_nsec = 0;
  
  	it.it_interval.tv_sec = sec;
  	it.it_interval.tv_nsec = 0;
  
  	if (timerfd_settime(tfd, 0, &it, NULL)) {
  		uwsgi_error("timerfd_settime()");
  		close(tfd);
  		return -1;
  	}
  
  	*id = tfd;
  	if (event_queue_add_fd_read(eq, tfd)) {
  		return -1;
  	}
  	return tfd;
  }
  
  struct uwsgi_timer *event_queue_ack_timer(int id) {
  
  	int i;
  	ssize_t rlen;
  	uint64_t counter;
  	struct uwsgi_timer *ut = NULL;
  
  	for (i = 0; i < ushared->timers_cnt; i++) {
  		if (ushared->timers[i].registered) {
  			if (ushared->timers[i].id == id) {
  				ut = &ushared->timers[i];
  			}
  		}
  	}
  
  	rlen = read(id, &counter, sizeof(uint64_t));
  
  	if (rlen < 0) {
  		uwsgi_error("read()");
  	}
  
  	return ut;
  }
  #endif
  
  #ifdef UWSGI_EVENT_TIMER_USE_NONE
  int event_queue_add_timer(int eq, int *id, int sec) {
  	return -1;
  }
  struct uwsgi_timer *event_queue_ack_timer(int id) {
  	return NULL;
  }
  #endif
  
  #ifdef UWSGI_EVENT_TIMER_USE_PORT
  int event_queue_add_timer(int eq, int *id, int sec) {
  
  	static int timer_id = 0xffffff00;
  	port_notify_t pnotif;
  	struct sigevent sigev;
  	itimerspec_t it;
  	timer_t tid;
  
  	timer_id++;
  
  	pnotif.portnfy_port = eq;
  	pnotif.portnfy_user = (void *) (long) timer_id;
  
  	sigev.sigev_notify = SIGEV_PORT;
  	sigev.sigev_value.sival_ptr = &pnotif;
  
  	if (timer_create(CLOCK_REALTIME, &sigev, &tid) < 0) {
  		uwsgi_error("timer_create()");
  		return -1;
  	}
  
  
  	it.it_value.tv_sec = sec;
  	it.it_value.tv_nsec = 0;
  
  	it.it_interval.tv_sec = sec;
  	it.it_interval.tv_nsec = 0;
  
  	if (timer_settime(tid, 0, &it, NULL) < 0) {
  		uwsgi_error("timer_settime()");
  		return -1;
  	}
  
  	*id = timer_id;
  
  	return *id;
  
  }
  
  struct uwsgi_timer *event_queue_ack_timer(int id) {
  
  	int i;
  	struct uwsgi_timer *ut = NULL;
  
  	for (i = 0; i < uwsgi.shared->timers_cnt; i++) {
  		if (uwsgi.shared->timers[i].registered) {
  			if (uwsgi.shared->timers[i].id == id) {
  				ut = &uwsgi.shared->timers[i];
  			}
  		}
  	}
  
  	return ut;
  }
  #endif
  
  
  #ifdef UWSGI_EVENT_TIMER_USE_KQUEUE
  int event_queue_add_timer(int eq, int *id, int sec) {
  
  	static int timer_id = 0xffffff00;
  	struct kevent kev;
  
  	*id = timer_id;
  	timer_id++;
  
  	EV_SET(&kev, *id, EVFILT_TIMER, EV_ADD, 0, sec * 1000, 0);
  	if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) {
  		uwsgi_error("kevent()");
  		return -1;
  	}
  
  	return *id;
  }
  
  struct uwsgi_timer *event_queue_ack_timer(int id) {
  
  	int i;
  	struct uwsgi_timer *ut = NULL;
  
  	for (i = 0; i < uwsgi.shared->timers_cnt; i++) {
  		if (uwsgi.shared->timers[i].registered) {
  			if (uwsgi.shared->timers[i].id == id) {
  				ut = &uwsgi.shared->timers[i];
  			}
  		}
  	}
  
  	return ut;
  
  }
  #endif
  
  int event_queue_read() {
  	return UWSGI_EVENT_IN;
  }
  
  int event_queue_write() {
  	return UWSGI_EVENT_OUT;
  }
  