--- otp_src_R8B-1/erts/acconfig.h Wed Apr 10 15:42:54 2002 +++ otp_src_R8B-1.kpoll/erts/acconfig.h Thu Jul 11 07:53:37 2002 @@ -157,6 +157,14 @@ /* Define if you have the ieee_handler() function. */ #undef HAVE_IEEE_HANDLER +/* Define if you have the header file. */ +#undef HAVE_SYS_DEVPOLL_H + +/* Define if you have the header file. */ +#undef HAVE_LINUX_KPOLL_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_EVENT_H /* * The lines below this marker is copied into the bottom of config.h.in @@ -190,6 +198,18 @@ #if !defined(HAVE_POLL) || !defined(HAVE_POLL_H) #define USE_SELECT +#endif + +#if !defined(USE_SELECT) +# if defined(HAVE_SYS_DEVPOLL_H) || defined(HAVE_LINUX_KPOLL_H) +# define USE_DEVPOLL +# endif +#endif + +#if !defined(USE_SELECT) +# if defined(HAVE_SYS_EVENT_H) +# define USE_KQUEUE +# endif #endif #ifdef HAVE_GETHRVTIME_PROCFS_IOCTL --- otp_src_R8B-1/erts/configure.in Wed Apr 10 15:42:07 2002 +++ otp_src_R8B-1.kpoll/erts/configure.in Fri Jul 12 22:54:15 2002 @@ -393,6 +393,11 @@ dnl Some Linuxes have instead of AC_CHECK_HEADER(pthread/mit/pthread.h, AC_DEFINE(HAVE_MIT_PTHREAD_H)) +dnl Check if we have kernel poll support +AC_CHECK_HEADER(sys/devpoll.h, AC_DEFINE(HAVE_SYS_DEVPOLL_H)) +AC_CHECK_HEADER(linux/kpoll.h, AC_DEFINE(HAVE_LINUX_KPOLL_H)) +AC_CHECK_HEADER(sys/event.h, AC_DEFINE(HAVE_SYS_EVENT_H)) + LM_DECL_SO_BSDCOMPAT LM_DECL_INADDR_LOOPBACK LM_DECL_SYS_ERRLIST --- otp_src_R8B-1/erts/emulator/sys/unix/sys.c Wed Apr 10 15:41:15 2002 +++ otp_src_R8B-1.kpoll/erts/emulator/sys/unix/sys.c Thu Jul 11 11:49:24 2002 @@ -34,12 +34,37 @@ #include #if !defined(USE_SELECT) + # ifdef HAVE_POLL_H # include # endif # ifdef HAVE_SYS_STROPTS_H # include /* some keep INFTIM here */ # endif + +# ifdef USE_KQUEUE +# ifdef HAVE_SYS_EVENT_H +# include +# endif +# ifdef USE_DEVPOLL +# undef USE_DEVPOLL +# endif +# endif + +# ifdef USE_DEVPOLL +# ifdef HAVE_SYS_DEVPOLL_H +# include +# endif +# ifdef HAVE_LINUX_KPOLL_H +# include +# include +# include +# ifndef POLLREMOVE +# define POLLREMOVE 0x1000 /* some day it will make it to bits/poll.h ;-) */ +# endif +# include +# endif +# endif #endif /* !USE_SELECT */ #ifdef ISC32 @@ -170,6 +195,43 @@ static struct readyfd* ready_fds; /* Collect after poll */ static int nof_ready_fds; /* Number of fds after poll */ +#ifdef USE_DEVPOLL + +static int dev_poll_fd; /* fd for /dev/poll */ +#ifdef HAVE_LINUX_KPOLL_H +static char * dev_poll_map; /* mmap'ed area from kernel /dev/kpoll */ +static struct k_poll dev_poll; /* control block for /dev/kpoll */ +static int max_poll_idx; /* highest non /dev/kpoll fd */ + +static void eventpoll_enable(); +#else +static struct dvpoll dev_poll; /* control block for /dev/poll */ +#endif /* !HAVE_LINUX_KPOLL_H */ +static struct pollfd* dev_poll_rfds = NULL; /* Allocated at startup */ + +static void devpoll_init(); +static void devpoll_update_pix(int pix); + +#endif /* !USE_DEVPOLL */ + +#ifdef USE_KQUEUE + +static int kqueue_fd; +static struct kevent *kqueue_res; +static int max_poll_idx; /* highest non kqueue fd */ + +static void kqueue_init(); +static void kqueue_enable(); +static void kqueue_update_pix(int pix, int old_events); + +#define ERL_POLL_READY_ENTRIES 2 + +#endif + +#endif + +#ifndef ERL_POLL_READY_ENTRIES +#define ERL_POLL_READY_ENTRIES 1 #endif static int max_fd; @@ -1644,13 +1706,22 @@ if (on) { if (mode & (DO_READ|DO_WRITE)) { int pix = fd_data[fd].pix; /* index to poll_fds */ +#if defined(USE_DEVPOLL) || defined(USE_KQUEUE) + int old_events; +#endif if (pix < 0) { /* add new slot */ max_fd++; /* FIXME: panic if max_fds >= max_files */ - pix = max_fd; fd_data[fd].pix = pix; + // init the pfd structure + poll_fds[pix].fd = fd; + poll_fds[pix].events = 0; } + +#if defined(USE_DEVPOLL) || defined(USE_KQUEUE) + old_events = poll_fds[pix].events; +#endif poll_fds[pix].fd = fd; if (mode & DO_READ) { fd_data[fd].inport = ix; @@ -1660,36 +1731,89 @@ fd_data[fd].outport = ix; poll_fds[pix].events |= POLLOUT; } + +#ifdef USE_DEVPOLL + if (poll_fds[pix].events != old_events) + devpoll_update_pix(pix); +#endif +#ifdef USE_KQUEUE + if (poll_fds[pix].events != old_events) + kqueue_update_pix(pix,old_events); +#endif } } else { int pix = fd_data[fd].pix; /* index to poll_fds */ - int rix; /* index to ready_fds */ +#if defined(USE_DEVPOLL) || defined(USE_KQUEUE) + int old_events ; +#endif + + int rix = 0; + int srix[ERL_POLL_READY_ENTRIES]; /* index(es) to ready_fds */ + int srix_idx; if (pix < 0) /* driver deselected already */ return -1; - /* Find index of this ready fd */ - for (rix = 0; rix < nof_ready_fds; rix++) - if (ready_fds[rix].pfd.fd == fd) - break; + + for(srix_idx=0;srix_idx<(sizeof(srix)/sizeof(srix[0]));srix_idx++) + srix[srix_idx]=-1; + srix_idx=0; + +#if defined(USE_DEVPOLL) || defined(USE_KQUEUE) + old_events = poll_fds[pix].events; +#endif if (mode & DO_READ) { - poll_fds[pix].events &= ~POLL_INPUT; - /* Erase POLL_INPUT event from poll result being processed */ - if ((rix < nof_ready_fds) - && (ready_fds[rix].pfd.events & POLL_INPUT)) - ready_fds[rix].pfd.revents &= ~POLL_INPUT; - } + poll_fds[pix].events &= ~POLL_INPUT; + fd_data[fd].inport = -1; + } if (mode & DO_WRITE) { - poll_fds[pix].events &= ~POLLOUT; - /* Erase POLLOUT event from poll result being processed */ - if ((rix < nof_ready_fds) - && (ready_fds[rix].pfd.events & POLLOUT)) - ready_fds[rix].pfd.revents &= ~POLLOUT; + poll_fds[pix].events &= ~POLLOUT; + fd_data[fd].outport = -1; + } + + /* Find index(es) of this fd in ready_fds */ + for (rix = 0; rix < nof_ready_fds; rix++) { + if (ready_fds[rix].pfd.fd == fd) { + + if (mode & DO_READ) + ready_fds[rix].pfd.revents &= ~POLL_INPUT; + + if (mode & DO_WRITE) + ready_fds[rix].pfd.revents &= ~POLLOUT; + + srix[srix_idx] = rix; + if (++srix_idx == (sizeof(srix)/sizeof(srix[0]))) break; + } } if (poll_fds[pix].events == 0) { +#ifdef USE_DEVPOLL + if ( old_events && (dev_poll_fd != -1) ) { + /* Tell /dev/[k]poll that we are not interested any more ... */ + poll_fds[pix].events = POLLREMOVE; + devpoll_update_pix(pix); + /* devpoll_update_pix may change the pix */ + pix = fd_data[fd].pix; + poll_fds[pix].events = 0; + } +#endif +#ifdef USE_KQUEUE + if ( old_events && (kqueue_fd != -1) ) { + /* Tell kqueue that we are not interested any more ... */ + kqueue_update_pix(pix,old_events); + /* devpoll_update_pix may change the pix */ + pix = fd_data[fd].pix; + poll_fds[pix].events = 0; + } +#endif + /* Erase all events from poll result being processed */ - if (rix < nof_ready_fds) - ready_fds[rix].pfd.revents = 0; + { + int i; + for(i=0;i= FD_SETSIZE) { erl_exit(1,"driver_select called with too large file descriptor %d" @@ -1981,7 +2115,9 @@ { SysTimeval wait_time; int r, i; +#ifndef USE_KQUEUE int max_fd_plus_one = max_fd + 1; +#endif int timeout; /* In milliseconds */ struct readyfd* rp; struct readyfd* qp; @@ -1997,31 +2133,185 @@ timeout = 0; } +#ifdef USE_DEVPOLL + if ( dev_poll_fd != -1 ) { +#ifdef HAVE_LINUX_KPOLL_H + int do_event_poll; + + do_event_poll = 0; + if ((r = poll(poll_fds, (max_poll_idx+1), timeout)) > 0 ) { +#else + dev_poll.dp_timeout = timeout; + dev_poll.dp_nfds = max_fd_plus_one; + dev_poll.dp_fds = dev_poll_rfds; + if ((r = ioctl(dev_poll_fd, DP_POLL, &dev_poll)) > 0 ) { +#endif + /* collect ready fds into the ready_fds stucture, + * this makes the calls to input ready/output ready + * independant of the poll_fds array + ** (accessed via call to driver_select etc) + */ + int rr; + int vr = 0; /* valid */ +#ifdef HAVE_LINUX_KPOLL_H + dev_poll_rfds = poll_fds; +#endif + rp = ready_fds; + rr = r; +#ifdef HAVE_LINUX_KPOLL_H + r = max_poll_idx+1; +#endif + for (i = 0; rr && (i < r); i++) { + short revents = dev_poll_rfds[i].revents; + + if (revents != 0) { +#if HAVE_LINUX_KPOLL_H + if (dev_poll_rfds[i].fd != dev_poll_fd) { +#endif + int fd = dev_poll_rfds[i].fd; + + rp->pfd = dev_poll_rfds[i]; /* COPY! */ + rp->iport = fd_data[fd].inport; + rp->oport = fd_data[fd].outport; + rp++; + rr--; + vr++; +#if HAVE_LINUX_KPOLL_H + } else { + do_event_poll = 1; + } +#endif + } + + } + nof_ready_fds = vr; + +#if HAVE_LINUX_KPOLL_H + if ( do_event_poll ) { + /* Now do the fast poll */ + dev_poll.kp_timeout = 0; + dev_poll.kp_resoff = 0; + if ((r = ioctl(dev_poll_fd, KP_POLL, &dev_poll)) > 0 ) { + dev_poll_rfds = (struct pollfd *)(dev_poll_map + dev_poll.kp_resoff); + + for (i = 0; (i < r); i++) { + short revents = dev_poll_rfds[i].revents; + + if (revents != 0) { + int fd = dev_poll_rfds[i].fd; + rp->pfd = dev_poll_rfds[i]; /* COPY! */ + rp->iport = fd_data[fd].inport; + rp->oport = fd_data[fd].outport; + rp++; + } + + } + nof_ready_fds += r; + } + } +#endif + + } else { + nof_ready_fds = 0; + rp = NULL; /* avoid 'uninitialized' warning */ + } + } else { +#endif +#ifdef USE_KQUEUE + if ((r = poll(poll_fds, max_poll_idx+1, timeout)) > 0) { +#else if ((r = poll(poll_fds, max_fd_plus_one, timeout)) > 0) { +#endif int rr = r; + int vr = 0; +#ifdef USE_KQUEUE + int do_kevent = 0; +#endif /* collect ready fds into the ready_fds stucture, * this makes the calls to input ready/output ready * independant of the poll_fds array ** (accessed via call to driver_select etc) */ rp = ready_fds; +#ifdef USE_KQUEUE + for (i = 0; rr && (i < (max_poll_idx+1)); i++) { +#else for (i = 0; rr && (i < max_fd_plus_one); i++) { +#endif short revents = poll_fds[i].revents; if (revents != 0) { + +#ifdef USE_KQUEUE + if ((kqueue_fd != -1) && (poll_fds[i].fd == kqueue_fd)) { + do_kevent=1; + } else { +#endif int fd = poll_fds[i].fd; rp->pfd = poll_fds[i]; /* COPY! */ rp->iport = fd_data[fd].inport; rp->oport = fd_data[fd].outport; rp++; rr--; + vr++; +#ifdef USE_KQUEUE } +#endif + } + } +#ifdef USE_KQUEUE + if ( do_kevent ) { + int res; + struct timespec ts; + + memset(&ts,(char)0,sizeof(ts)); + + if ( (res=kevent(kqueue_fd,NULL,0,kqueue_res,2*max_files,&ts)) < 0 ) { + erl_exit(1, "%s:%d kevent call failed. errno = %d\n",__FILE__,__LINE__,errno); + } else { + int i; + for(i=0;iident; + pix = fd_data[fd].pix; + + /* Now we should copy this into the result fd array */ + /* Please note t he kqueue version may generate two entries per fd */ + /* This is handled in dr iver_select for cleanup */ + + rp->pfd = poll_fds[pix]; /* COPY! */ + if ( kep->filter == EVFILT_READ ) { + rp->pfd.revents |= POLL_INPUT; + } else if ( kep->filter == EVFILT_WRITE ) { + rp->pfd.revents |= POLLOUT; + if ( kep->flags & EV_EOF ) + rp->pfd.revents |= POLLHUP; + if ( kep->flags & EV_ERROR ) + rp->pfd.revents |= POLLERR; + } + if ( kep->flags & EV_EOF ) + rp->pfd.revents |= POLLHUP; + if ( kep->flags & EV_ERROR ) + rp->pfd.revents |= POLLERR; + + rp->iport = fd_data[fd].inport; + rp->oport = fd_data[fd].outport; + rp++; + vr++; + } + } } - nof_ready_fds = r; +#endif + nof_ready_fds = vr; } else { nof_ready_fds = 0; rp = NULL; /* avoid 'uninitialized' warning */ } +#ifdef USE_DEVPOLL + } +#endif erts_deliver_time(NULL); /* sync the machine's idea of time */ @@ -2051,16 +2341,37 @@ int fd = qp->pfd.fd; short revents = qp->pfd.revents; +#ifdef __linux__ + /* Linux sets pollhup on fresh sockets. Mask it out if not POLL_INPUT */ + if (!(poll_fds[fd_data[fd].pix].events & POLL_INPUT)) { + revents &= ~POLLHUP; + } +#endif + if (revents & (POLL_INPUT|POLLOUT)) { - if (revents & POLLOUT) + if (revents & POLLOUT) output_ready(qp->oport, fd); - if (revents & (POLL_INPUT|POLLHUP)) - input_ready(qp->iport, fd); + /* check if output_ready affected selected events */ + if (revents & (POLL_INPUT|POLLHUP)) { + if (poll_fds[fd_data[fd].pix].events & POLL_INPUT) + if ( qp->iport != -1 ) + input_ready(qp->iport, fd); + } } else if (revents & (POLLERR|POLLHUP)) { /* let the driver handle the error condition */ - if (qp->pfd.events & POLL_INPUT) - input_ready(qp->iport, fd); + if (qp->pfd.events & POLL_INPUT) { + Port* p = &erts_port[qp->iport]; + if ( p->status == FREE ) { + erl_printf(CBUF, "Driver input on free port! fd,port,driver,name:" + " %d,%d,%s,%s\n", fd, + qp->iport, + erts_port[qp->iport].drv_ptr->driver_name, + erts_port[qp->iport].name); + } + if ( qp->iport != -1 ) + input_ready(qp->iport, fd); + } else output_ready(qp->oport, fd); } @@ -2135,7 +2446,7 @@ poll_fds = (struct pollfd *) sys_alloc_from(182, max_files * sizeof(struct pollfd)); ready_fds = (struct readyfd *) - sys_alloc_from(182, max_files * sizeof(struct readyfd)); + sys_alloc_from(182, ERL_POLL_READY_ENTRIES * max_files * sizeof(struct readyfd)); if (poll_fds == NULL) erl_exit(1, "Can't allocate %d bytes of memory\n", @@ -2143,8 +2454,9 @@ if (ready_fds == NULL) erl_exit(1, "Can't allocate %d bytes of memory\n", - max_files * sizeof(struct readyfd)); + ERL_POLL_READY_ENTRIES * max_files * sizeof(struct readyfd)); + nof_ready_fds = 0; { int i; @@ -2156,10 +2468,33 @@ fd_data[i].pix = -1; } } + + +#ifdef USE_DEVPOLL + devpoll_init(); +#else +#endif /* ! USE_DEVPOLL */ + +#ifdef USE_KQUEUE + kqueue_init(); #endif +#endif /* !USE_SELECT */ + max_fd = -1; +#ifdef USE_DEVPOLL +#if HAVE_LINUX_KPOLL_H + max_poll_idx = -1; + eventpoll_enable(); +#endif +#endif + +#ifdef USE_KQUEUE + max_poll_idx = -1; + kqueue_enable(); +#endif + #ifdef USE_THREADS { /* This is speical stuff, starting a driver from the @@ -2250,9 +2585,9 @@ #else /* ifndef sys_alloc2 */ /* ... and sys_A2 makros used; need sys_A (symbols) */ -void* sys_alloc(Uint size) { return sys_alloc2(size); } -void* sys_realloc(void* ptr, Uint size) { return sys_realloc2(ptr, size); } -void* sys_free(void* ptr) { return sys_free2(ptr); } +void* sys_alloc(Uint size) { return sys_alloc2(size); } +void* sys_realloc(void* ptr, Uint size) { return sys_realloc2(ptr, size); } +void* sys_free(void* ptr) { return sys_free2(ptr); } #endif /* ifndef sys_alloc2 */ #endif /* #ifdef SYS_ALLOC_ELSEWHERE */ @@ -2764,3 +3099,298 @@ } #endif /* HAVE_GETHRVTIME_PROCFS_IOCTL */ + +/* kqueue support */ + +#ifdef USE_KQUEUE + +static void kqueue_init() +{ + if ( getenv("ERL_NO_KERNEL_POLL") != NULL ) { + DEBUGF(("Use of kqueue disabled\n")); + kqueue_fd=-1; + return; + } + + if ( (kqueue_fd=kqueue()) < 0 ) { + DEBUGF(("Will use poll()\n")); + kqueue_fd = -1; + } else { + if ( (kqueue_res = + (struct kevent *)sys_alloc(ERL_POLL_READY_ENTRIES*sizeof(struct kevent)*max_files)) == NULL ) { + erl_exit(1, "Can't allocate %d bytes for kqueue result array\n", + ERL_POLL_READY_ENTRIES*sizeof(struct kevent)*max_files); + } + } +} + +static void kqueue_enable() +{ + int pix; + + /* Add kqueue fd to pollable descriptors */ + if ( kqueue_fd == -1 ) return; + + max_fd++; + max_poll_idx++; + pix = max_fd; + fd_data[kqueue_fd].pix = pix; + poll_fds[pix].fd = kqueue_fd; + poll_fds[pix].events = POLL_INPUT; + poll_fds[pix].revents = 0; +} + +static void kqueue_set_event(int fd, int filter, int flags) +{ + int res; + struct timespec ts; + struct kevent ke,*kep=&ke; + + memset(&ts,(char)0,sizeof(ts)); + memset(kep,(char)0,sizeof(struct kevent)); + + kep->ident = fd; + kep->filter = filter; + kep->flags = flags; + + if ( (res=kevent(kqueue_fd,kep,1,NULL,0,&ts)) == -1 ) { + fprintf(stderr,"WARNING: %s:%d kevent call failed errno = %d fd = %d filter = %d flags = %d (ignored)\r\n", + __FILE__,__LINE__,errno,fd,filter,flags); + if ( (errno == ENOENT) ) return; /* fd is not valid (closed?) */ + erl_exit(1, "%s:%d kevent call failed. fd = %d filter = %d flags = %d errno = %d\n", + __FILE__,__LINE__,fd,filter,flags,errno); + } +} + +static void kqueue_update_pix(int pix, int old_events) +{ + struct stat sb; + + if ( fstat(poll_fds[pix].fd,&sb) == -1 ) { + erl_exit(1,"Can't fstat file %d. errno = %d\n",poll_fds[pix].fd,errno); + } + + if ( (kqueue_fd != -1) && ( S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode) ) ) { + + /* Input */ + if ( (poll_fds[pix].events & POLL_INPUT) == POLL_INPUT ) + kqueue_set_event(poll_fds[pix].fd,EVFILT_READ,(EV_ADD|EV_ENABLE)); + else + if ( ( old_events & POLL_INPUT ) == POLL_INPUT ) + kqueue_set_event(poll_fds[pix].fd,EVFILT_READ,EV_DELETE); + + /* Output */ + if ( (poll_fds[pix].events & POLLOUT) == POLLOUT ) + kqueue_set_event(poll_fds[pix].fd,EVFILT_WRITE,(EV_ADD|EV_ENABLE)); + else + if ( ( old_events & POLLOUT ) == POLLOUT ) + kqueue_set_event(poll_fds[pix].fd,EVFILT_WRITE,EV_DELETE); + + } else { + if ( poll_fds[pix].events == 0 ) { + if ( pix != max_poll_idx ) { + struct pollfd tmp_pfd; + /* swap this slot with max_poll_idx and decrement */ + tmp_pfd = poll_fds[pix]; + poll_fds[pix] = poll_fds[max_poll_idx]; + fd_data[poll_fds[pix].fd].pix = pix; + poll_fds[max_poll_idx] = tmp_pfd; + fd_data[poll_fds[max_poll_idx].fd].pix = max_poll_idx; + } + max_poll_idx--; + /* the normal processing in driver_select will kick it out completely */ + } else { + if ( pix > max_poll_idx ) { + max_poll_idx++; + if ( max_poll_idx != max_fd ) { + struct pollfd tmp_pfd; + tmp_pfd = poll_fds[max_poll_idx]; + poll_fds[max_poll_idx] = poll_fds[pix]; + fd_data[poll_fds[max_poll_idx].fd].pix = max_poll_idx; + poll_fds[pix] = tmp_pfd; + fd_data[poll_fds[pix].fd].pix = pix; + } + } + } + } +} + +#endif + +/* /dev/kpoll support */ + +#ifdef USE_DEVPOLL + +#if HAVE_LINUX_KPOLL_H +static void eventpoll_enable() +{ + int pix; + + /* Add /dev/epoll fd to pollable descriptors */ + if ( dev_poll_fd == -1 ) return; + + max_fd++; + max_poll_idx++; + pix = max_fd; + fd_data[dev_poll_fd].pix = pix; + poll_fds[pix].fd = dev_poll_fd; + poll_fds[pix].events = POLL_INPUT; + poll_fds[pix].revents = 0; +} + +static int eventpoll_useable(int fd) +{ + struct pollfd pollfd = {fd,POLLIN,0}; + + + /* Davide Libenzi has integrated my pollable eventpoll support in version 0.28 */ + /* Anything before this will cause the emulator to hang. */ + /* Without the pollable support a poll will always indicate data availability. */ + if ( poll(&pollfd,1,0) > 0 ) { + /* NOT useable /dev/kpoll version */ + fprintf(stderr,"WARNING: /dev/kpoll is not useable. Upgrade to kpoll.\r\n"); + fprintf(stderr," Define environment variable ERL_NO_KERNEL_POLL to avoid this warning.\n\r"); + return 0; + } else { + return 1; + } +} + +static void eventpoll_init() +{ + if ( (dev_poll_fd=open("/dev/kpoll",O_RDWR)) < 0 ) { + /* This will happen if the module is not inserted yet as well... */ + DEBUGF(("Will use poll()\n")); + dev_poll_fd = -1; /* We will not use /dev/kpoll */ + } else { + + if ( eventpoll_useable(dev_poll_fd) ) { + DEBUGF(("Will use /dev/kpoll\n")); + + if ( ioctl(dev_poll_fd,KP_ALLOC,max_files) == -1 ) { + perror("ioctl(KP_ALLOC)"); + erl_exit(1, "Can't allocate %d /dev/kpoll file descriptors\n", + max_files); + } + + if ( (dev_poll_map = (char *)mmap(NULL,KP_MAP_SIZE(max_files), + PROT_READ|PROT_WRITE, + MAP_PRIVATE, dev_poll_fd, 0)) == NULL ) { + erl_exit(1, "Can't mmap /dev/kpoll result area.\n"); + } + + dev_poll_rfds = NULL; + } else { + close(dev_poll_fd); + dev_poll_fd = -1 ; + } + } +} + +#endif /* HAVE_LINUX_KPOLL_H */ + +#ifdef HAVE_SYS_DEVPOLL_H + +static void solaris_devpoll_init() +{ + if ( (dev_poll_fd=open("/dev/poll",O_RDWR)) < 0 ) { + DEBUGF(("Will use poll()\n")); + dev_poll_fd = -1; /* We will not use /dev/poll */ + } else { + DEBUGF(("Will use /dev/poll\n")); + dev_poll_rfds = (struct pollfd *) + sys_alloc_from(182, max_files * sizeof(struct pollfd)); + if (dev_poll_rfds == NULL) + erl_exit(1, "Can't allocate %d bytes of memory\n", + max_files * sizeof(struct pollfd)); + } +} + +#endif + +static void devpoll_init() +{ + if ( getenv("ERL_NO_KERNEL_POLL") != NULL ) { + DEBUGF(("Use of kernel poll disabled.\n")); + dev_poll_fd=-1; + } else { + /* Determine use of poll vs. /dev/poll at runtime */ +#ifdef HAVE_LINUX_KPOLL_H + eventpoll_init(); +#else +#ifdef HAVE_SYS_DEVPOLL_H + solaris_devpoll_init(); +#endif +#endif + } +} + +static int devpoll_write(int fd, void *buf, size_t count) +{ + int res; + int left = count; + + do { + if ( (res=write(fd,buf,left)) < 0 ) { + if ( errno == EINTR ) continue; + return res; + } else { + buf += res; + left -= res; + } + } while (left); + return count; +} + +static void devpoll_update_pix(int pix) +{ + int res; + +#if HAVE_LINUX_KPOLL_H + struct stat sb; + + if ( fstat(poll_fds[pix].fd,&sb) == -1 ) { + erl_exit(1,"Can't fstat file %d. errno = %d\n",poll_fds[pix].fd,errno); + } + + if ( (dev_poll_fd != -1 ) && (S_ISFIFO(sb.st_mode) || S_ISSOCK(sb.st_mode)) ) { + +#endif + if ( dev_poll_fd != -1 ) { + if ( (res=devpoll_write(dev_poll_fd,&poll_fds[pix],sizeof(struct pollfd))) != + (sizeof(struct pollfd)) ) { + erl_exit(1,"Can't write to /dev/poll\n"); + } + } +#if HAVE_LINUX_KPOLL_H + } else { + if ( poll_fds[pix].events & POLLREMOVE ) { + if ( pix != max_poll_idx ) { + struct pollfd tmp_pfd; + /* swap this slot with max_poll_idx and decrement */ + tmp_pfd = poll_fds[pix]; + poll_fds[pix] = poll_fds[max_poll_idx]; + fd_data[poll_fds[pix].fd].pix = pix; + poll_fds[max_poll_idx] = tmp_pfd; + fd_data[poll_fds[max_poll_idx].fd].pix = max_poll_idx; + } + max_poll_idx--; + /* the normal processing in driver_select will kick it out completely */ + } else { + if ( pix > max_poll_idx ) { + max_poll_idx++; + if ( max_poll_idx != max_fd ) { + struct pollfd tmp_pfd; + tmp_pfd = poll_fds[max_poll_idx]; + poll_fds[max_poll_idx] = poll_fds[pix]; + fd_data[poll_fds[max_poll_idx].fd].pix = max_poll_idx; + poll_fds[pix] = tmp_pfd; + fd_data[poll_fds[pix].fd].pix = pix; + } + } + } + } +#endif /* HAVE_LINUX_KPOLL_H */ +} + +#endif /* USE_DEVPOLL */