*** otp_src_R8B-0/erts/acconfig.h Mon Oct 8 10:46:25 2001 --- otp_src_R8B-0.devpoll/erts/acconfig.h Mon Feb 25 23:52:19 2002 *************** *** 163,164 **** --- 163,169 ---- + /* Define if you have the header file. */ + #undef HAVE_SYS_DEVPOLL_H + + /* Define if you have the header file. */ + #undef HAVE_LINUX_EVENTPOLL_H *************** *** 196,197 **** --- 201,208 ---- #define USE_SELECT + #endif + + #if !defined(USE_SELECT) + # if defined(HAVE_SYS_DEVPOLL_H) || defined(HAVE_LINUX_EVENTPOLL_H) + # define USE_DEVPOLL + # endif #endif *** otp_src_R8B-0/erts/configure.in Mon Oct 8 10:36:08 2001 --- otp_src_R8B-0.devpoll/erts/configure.in Mon Feb 25 22:57:48 2002 *************** *** 407,408 **** --- 407,412 ---- + dnl Check if we have /dev/[e]poll support + AC_CHECK_HEADER(sys/devpoll.h, AC_DEFINE(HAVE_SYS_DEVPOLL_H)) + AC_CHECK_HEADER(linux/eventpoll.h, AC_DEFINE(HAVE_LINUX_EVENTPOLL_H)) + LM_DECL_SO_BSDCOMPAT *** otp_src_R8B-0/erts/emulator/sys/unix/sys.c Mon Oct 8 10:25:08 2001 --- otp_src_R8B-0.devpoll/erts/emulator/sys/unix/sys.c Tue Feb 26 01:47:55 2002 *************** *** 1,2 **** ! /* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in --- 1,2 ---- ! /* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in *************** *** 42,43 **** --- 42,57 ---- # endif + # ifdef USE_DEVPOLL + # ifdef HAVE_SYS_DEVPOLL_H + # include + # endif + # ifdef HAVE_LINUX_EVENTPOLL_H + # include + # include + # include + # include + # ifndef POLLREMOVE + # define POLLREMOVE 0x1000 + # endif + # endif + # endif #endif /* !USE_SELECT */ *************** *** 161,162 **** --- 175,195 ---- + #ifdef USE_DEVPOLL + + static int dev_poll_fd; /* fd for /dev/poll */ + #ifdef HAVE_LINUX_EVENTPOLL_H + static char * dev_poll_map; /* mmap'ed area from kernel /dev/epoll */ + static struct evpoll dev_poll; /* control block for /dev/epoll */ + static int max_poll_idx; /* highest non /dev/epoll fd */ + + static void eventpoll_enable(); + #else + static struct dvpoll dev_poll; /* control block for /dev/poll */ + #endif /* !HAVE_LINUX_EVENTPOLL_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 */ + #endif *************** *** 1635,1636 **** --- 1668,1672 ---- int pix = fd_data[fd].pix; /* index to poll_fds */ + #ifdef USE_DEVPOLL + int old_events = poll_fds[pix].events; + #endif *************** *** 1638,1640 **** max_fd++; /* FIXME: panic if max_fds >= max_files */ - pix = max_fd; --- 1674,1675 ---- *************** *** 1651,1652 **** --- 1686,1691 ---- } + #ifdef USE_DEVPOLL + if ( poll_fds[pix].events != old_events ) + devpoll_update_pix(pix); + #endif } *************** *** 1655,1656 **** --- 1694,1698 ---- int pix = fd_data[fd].pix; /* index to poll_fds */ + #ifdef USE_DEVPOLL + int old_events = poll_fds[pix].events; + #endif int rix; /* index to ready_fds */ *************** *** 1678,1679 **** --- 1720,1732 ---- if (poll_fds[pix].events == 0) { + #ifdef USE_DEVPOLL + if ( old_events && (dev_poll_fd != -1) ) { + /* Tell /dev/[e]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 + /* Erase all events from poll result being processed */ *************** *** 1702,1703 **** --- 1755,1762 ---- } + #ifdef USE_DEVPOLL + else { + devpoll_update_pix(pix); + } + #endif + } *************** *** 1987,1988 **** --- 2046,2131 ---- + #ifdef USE_DEVPOLL + if ( dev_poll_fd != -1 ) { + #ifdef HAVE_LINUX_EVENTPOLL_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_EVENTPOLL_H + dev_poll_rfds = poll_fds; + #endif + rp = ready_fds; + rr = r; + #ifdef HAVE_LINUX_EVENTPOLL_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_EVENTPOLL_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_EVENTPOLL_H + } else { + do_event_poll = 1; + } + #endif + } + + } + nof_ready_fds = vr; + + #if HAVE_LINUX_EVENTPOLL_H + if ( do_event_poll ) { + /* Now do the fast poll */ + dev_poll.ep_timeout = 0; + dev_poll.ep_resoff = 0; + if ((r = ioctl(dev_poll_fd, EP_POLL, &dev_poll)) > 0 ) { + dev_poll_rfds = (struct pollfd *)(dev_poll_map + dev_poll.ep_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 if ((r = poll(poll_fds, max_fd_plus_one, timeout)) > 0) { *************** *** 2012,2013 **** --- 2155,2159 ---- } + #ifdef USE_DEVPOLL + } + #endif *************** *** 2042,2047 **** if (revents & (POLL_INPUT|POLLOUT)) { ! if (revents & POLLOUT) output_ready(qp->oport, fd); ! if (revents & (POLL_INPUT|POLLHUP)) ! input_ready(qp->iport, fd); } --- 2188,2196 ---- if (revents & (POLL_INPUT|POLLOUT)) { ! if (revents & POLLOUT) output_ready(qp->oport, fd); ! /* check if output_ready affected selected events */ ! if (revents & (POLL_INPUT|POLLHUP)) { ! if (poll_fds[fd_data[fd].pix].events & POLL_INPUT) ! input_ready(qp->iport, fd); ! } } *************** *** 2146,2148 **** } ! #endif --- 2295,2302 ---- } ! ! #ifdef USE_DEVPOLL ! devpoll_init(); ! #endif /* USE_DEVPOLL */ ! ! #endif /* !USE_SELECT */ *************** *** 2150,2151 **** --- 2304,2312 ---- + #ifdef USE_DEVPOLL + #if HAVE_LINUX_EVENTPOLL_H + max_poll_idx = -1; + eventpoll_enable(); + #endif + #endif + #ifdef USE_THREADS *************** *** 2718 **** --- 2879,3050 ---- } + + /* /dev/[e]poll support */ + + #ifdef USE_DEVPOLL + + #if HAVE_LINUX_EVENTPOLL_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/epoll version */ + fprintf(stderr,"WARNING: /dev/epoll is not useable. Upgrade to eventpoll 0.28 or later.\n\r"); + fprintf(stderr," Define environment variable ERL_NO_DEVPOLL to avoid this warning.\n\r"); + return 0; + } else { + return 1; + } + } + + static void eventpoll_init() + { + if ( (dev_poll_fd=open("/dev/epoll",O_RDWR)) < 0 ) { + DEBUGF(("Will use poll()\n")); + dev_poll_fd = -1; /* We will not use /dev/epoll */ + } else { + + if ( eventpoll_useable(dev_poll_fd) ) { + DEBUGF(("Will use /dev/epoll\n")); + + if ( ioctl(dev_poll_fd,EP_ALLOC,max_files) == -1 ) { + perror("ioctl(EP_ALLOC)"); + erl_exit(1, "Can't allocate %d /dev/epoll file descriptors\n", + max_files); + } + + if ( (dev_poll_map = (char *)mmap(NULL,EP_MAP_SIZE(max_files), + PROT_READ|PROT_WRITE, + MAP_PRIVATE, dev_poll_fd, 0)) == NULL ) { + erl_exit(1, "Can't mmap /dev/epoll result area.\n"); + } + + dev_poll_rfds = NULL; + } else { + close(dev_poll_fd); + dev_poll_fd = -1 ; + } + } + } + + #endif /* HAVE_LINUX_EVENTPOLL_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)); + } + } + + static void devpoll_init() + { + if ( getenv("ERL_NO_DEVPOLL") != NULL ) { + DEBUGF(("Use of /dev/poll disabled\n")); + dev_poll_fd=-1; + } else { + /* Determine use of poll vs. /dev/poll at runtime */ + #ifdef HAVE_LINUX_EVENTPOLL_H + eventpoll_init(); + #else + solaris_devpoll_init(); + #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_EVENTPOLL_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 ( 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_EVENTPOLL_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_EVENTPOLL_H */ + } + + #endif /* USE_DEVPOLL */