|
|
* Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings | * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings |
* AB. All Rights Reserved.'' | * AB. All Rights Reserved.'' |
* | * |
* $Id$ |
* 2005-08-31 |
|
* This has been modified by Matthew Reilly of SIPphone Inc. to |
|
* enable kernel poll (+K true) support via the epoll mechanism in Linux 2.6 |
|
* Portions created by SIPphone Inc. are Copyright 2005, SIPphone Inc. |
|
* These modifications are released under the Erlang Public License. |
|
* |
|
* $Id: otp_src_R10B-6_epoll.patch,v 1.1 2005/09/02 00:18:04 mreilly Exp $ |
*/ | */ |
| |
#ifdef HAVE_CONFIG_H | #ifdef HAVE_CONFIG_H |
|
|
# define USE_DEVPOLL | # define USE_DEVPOLL |
# include <sys/devpoll.h> | # include <sys/devpoll.h> |
# endif | # endif |
|
# ifdef HAVE_LINUX_EPOLL_H /* Too minimize code changes, we pretend we have HAVE_LINUX_KPOLL_H as well */ |
|
# define HAVE_LINUX_KPOLL_H 1 |
|
# endif |
# ifdef HAVE_LINUX_KPOLL_H | # ifdef HAVE_LINUX_KPOLL_H |
# define USE_DEVPOLL | # define USE_DEVPOLL |
# include <asm/page.h> | # include <asm/page.h> |
|
|
# ifndef POLLREMOVE | # ifndef POLLREMOVE |
# define POLLREMOVE 0x1000 /* some day it will make it to bits/poll.h ;-) */ | # define POLLREMOVE 0x1000 /* some day it will make it to bits/poll.h ;-) */ |
# endif | # endif |
# include <linux/kpoll.h> |
# ifdef HAVE_LINUX_EPOLL_H |
|
# include <sys/epoll.h> |
|
# else |
|
# include <linux/kpoll.h> |
|
# endif |
# endif | # endif |
# ifdef USE_DEVPOLL /* can only use one of them ... */ | # ifdef USE_DEVPOLL /* can only use one of them ... */ |
# ifdef USE_KQUEUE | # ifdef USE_KQUEUE |
|
|
| |
static int dev_poll_fd; /* fd for /dev/poll */ | static int dev_poll_fd; /* fd for /dev/poll */ |
#ifdef HAVE_LINUX_KPOLL_H | #ifdef HAVE_LINUX_KPOLL_H |
|
|
|
#ifdef HAVE_LINUX_EPOLL_H |
|
static struct epoll_event* dev_epoll_map; |
|
/* XXX Implement correct mapping from POLLIN/POLLOUT to/from EPOLLIN/EPOLLOUT */ |
|
/* Currenltly POLLIN/POLLOUT == EPOLLIN/EPOLLOUT. So these macros will work */ |
|
#define EPOLL_TO_POLL(bit_map) (bit_map) |
|
#define POLL_TO_EPOLL(bit_map) (bit_map & (EPOLLIN|EPOLLOUT)) |
|
#else |
static char * dev_poll_map; /* mmap'ed area from kernel /dev/kpoll */ | static char * dev_poll_map; /* mmap'ed area from kernel /dev/kpoll */ |
static struct k_poll dev_poll; /* control block for /dev/kpoll */ | static struct k_poll dev_poll; /* control block for /dev/kpoll */ |
|
#endif /* HAVE_LINUX_KPOLL_H */ |
static int max_poll_idx; /* highest non /dev/kpoll fd */ | static int max_poll_idx; /* highest non /dev/kpoll fd */ |
| |
static void kpoll_enable(); | static void kpoll_enable(); |
|
|
static struct pollfd* dev_poll_rfds = NULL; /* Allocated at startup */ | static struct pollfd* dev_poll_rfds = NULL; /* Allocated at startup */ |
| |
static void devpoll_init(void); | static void devpoll_init(void); |
static void devpoll_update_pix(int pix); |
static void devpoll_update_pix(int pix, int old_events); |
#ifdef HAVE_SYS_DEVPOLL_H | #ifdef HAVE_SYS_DEVPOLL_H |
static void devpoll_clear_pix(int pix); | static void devpoll_clear_pix(int pix); |
#endif /* HAVE_SYS_DEVPOLL_H */ | #endif /* HAVE_SYS_DEVPOLL_H */ |
|
|
| |
#ifdef USE_DEVPOLL | #ifdef USE_DEVPOLL |
if (poll_fds[pix].events != old_events) | if (poll_fds[pix].events != old_events) |
devpoll_update_pix(pix); |
devpoll_update_pix(pix, old_events); |
#endif | #endif |
#ifdef USE_KQUEUE | #ifdef USE_KQUEUE |
if (poll_fds[pix].events != old_events) | if (poll_fds[pix].events != old_events) |
|
|
if ( old_events && (dev_poll_fd != -1) ) { | if ( old_events && (dev_poll_fd != -1) ) { |
/* Tell /dev/[k]poll that we are not interested any more ... */ | /* Tell /dev/[k]poll that we are not interested any more ... */ |
poll_fds[pix].events = POLLREMOVE; | poll_fds[pix].events = POLLREMOVE; |
devpoll_update_pix(pix); |
devpoll_update_pix(pix, old_events); |
/* devpoll_update_pix may change the pix */ | /* devpoll_update_pix may change the pix */ |
pix = fd_data[fd].pix; | pix = fd_data[fd].pix; |
poll_fds[pix].events = 0; | poll_fds[pix].events = 0; |
|
|
#ifdef HAVE_SYS_DEVPOLL_H | #ifdef HAVE_SYS_DEVPOLL_H |
devpoll_clear_pix(pix); | devpoll_clear_pix(pix); |
#endif /* HAVE_SYS_DEVPOLL_H */ | #endif /* HAVE_SYS_DEVPOLL_H */ |
devpoll_update_pix(pix); |
devpoll_update_pix(pix, old_events); |
} | } |
#endif | #endif |
#ifdef USE_KQUEUE | #ifdef USE_KQUEUE |
|
|
nof_ready_fds = vr; | nof_ready_fds = vr; |
| |
#if HAVE_LINUX_KPOLL_H | #if HAVE_LINUX_KPOLL_H |
|
#ifdef HAVE_LINUX_EPOLL_H |
|
if ( do_event_poll ) { |
|
if ((r = epoll_wait(dev_poll_fd,dev_epoll_map,max_fd_plus_one,0)) > 0) { |
|
for (i = 0; (i < r); i++) { |
|
short revents = dev_epoll_map[i].events; |
|
|
|
if (revents != 0) { |
|
int fd = dev_epoll_map[i].data.fd; |
|
rp->pfd.fd = fd; |
|
rp->pfd.events = poll_fds[fd_data[fd].pix].events; |
|
rp->pfd.revents = EPOLL_TO_POLL(revents); |
|
rp->iport = fd_data[fd].inport; |
|
rp->oport = fd_data[fd].outport; |
|
rp++; |
|
nof_ready_fds ++; |
|
} |
|
} |
|
} |
|
} |
|
|
|
#else |
if ( do_event_poll ) { | if ( do_event_poll ) { |
/* Now do the fast poll */ | /* Now do the fast poll */ |
dev_poll.kp_timeout = 0; | dev_poll.kp_timeout = 0; |
|
|
nof_ready_fds += r; | nof_ready_fds += r; |
} | } |
} | } |
|
#endif /*HAVE_LINUX_EPOLL_H */ |
#endif | #endif |
| |
} else { | } else { |
|
|
poll_fds[pix].revents = 0; | poll_fds[pix].revents = 0; |
} | } |
| |
|
#ifdef HAVE_LINUX_EPOLL_H |
|
static void epoll_init() |
|
{ |
|
/* max_files is just a hint to the kernel */ |
|
if ( (dev_poll_fd=epoll_create(max_files)) < 0 ) { |
|
DEBUGF(("Will use poll()\n")); |
|
dev_poll_fd = -1; /* We will not use ekpoll */ |
|
} else { |
|
DEBUGF(("Will use epoll\n")); |
|
dev_epoll_map = (struct epoll_event *) erts_alloc(ERTS_ALC_T_POLL_FDS, (sizeof(struct epoll_event) * max_files)); |
|
erts_sys_misc_mem_sz += sizeof(struct epoll_event) * max_files; |
|
} |
|
} |
|
#else |
static void kpoll_init() | static void kpoll_init() |
{ | { |
if ( (dev_poll_fd=open("/dev/kpoll",O_RDWR)) < 0 ) { | if ( (dev_poll_fd=open("/dev/kpoll",O_RDWR)) < 0 ) { |
|
|
dev_poll_rfds = NULL; | dev_poll_rfds = NULL; |
} | } |
} | } |
|
#endif /* HAVE_LINUX_EPOLL_H */ |
| |
#endif /* HAVE_LINUX_KPOLL_H */ | #endif /* HAVE_LINUX_KPOLL_H */ |
| |
|
|
} else { | } else { |
/* Determine use of poll vs. /dev/poll at runtime */ | /* Determine use of poll vs. /dev/poll at runtime */ |
#ifdef HAVE_LINUX_KPOLL_H | #ifdef HAVE_LINUX_KPOLL_H |
|
#ifdef HAVE_LINUX_EPOLL_H |
|
epoll_init(); |
|
#else |
kpoll_init(); | kpoll_init(); |
|
#endif |
#else | #else |
#ifdef HAVE_SYS_DEVPOLL_H | #ifdef HAVE_SYS_DEVPOLL_H |
solaris_devpoll_init(); | solaris_devpoll_init(); |
|
|
return count; | return count; |
} | } |
| |
static void devpoll_update_pix(int pix) |
static void devpoll_update_pix(int pix, int old_events) |
{ | { |
int res; | int res; |
| |
|
|
| |
#endif | #endif |
if ( dev_poll_fd != -1 ) { | if ( dev_poll_fd != -1 ) { |
|
#ifdef HAVE_LINUX_EPOLL_H |
|
int events = poll_fds[pix].events; |
|
int fd = poll_fds[pix].fd; |
|
if (old_events && events & POLLREMOVE) { |
|
/* Delete file descriptor from epoll list */ |
|
res = epoll_ctl(dev_poll_fd,EPOLL_CTL_DEL,fd,NULL); |
|
/* XXX check return code */ |
|
} else { |
|
struct epoll_event epoll_ctl_event; |
|
epoll_ctl_event.data.fd = fd; |
|
epoll_ctl_event.events = POLL_TO_EPOLL(events); |
|
if (old_events) { |
|
/* Modify exiting fd */ |
|
res = epoll_ctl(dev_poll_fd,EPOLL_CTL_MOD,fd,&epoll_ctl_event); |
|
/* XXX check return code */ |
|
} else { |
|
/* Add fd to epoll list */ |
|
res = epoll_ctl(dev_poll_fd,EPOLL_CTL_ADD,fd,&epoll_ctl_event); |
|
/* XXX check return code */ |
|
} |
|
} |
|
#else |
if ( (res=devpoll_write(dev_poll_fd,&poll_fds[pix],sizeof(struct pollfd))) != | if ( (res=devpoll_write(dev_poll_fd,&poll_fds[pix],sizeof(struct pollfd))) != |
(sizeof(struct pollfd)) ) { | (sizeof(struct pollfd)) ) { |
erl_exit(1,"Can't write to /dev/poll\n"); | erl_exit(1,"Can't write to /dev/poll\n"); |
} | } |
|
#endif /* HAVE_LINUX_EPOLL_H */ |
} | } |
#if HAVE_LINUX_KPOLL_H | #if HAVE_LINUX_KPOLL_H |
} else { | } else { |