diff options
author | Andy Wingo <wingo@pobox.com> | 2010-12-03 13:09:43 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2010-12-03 15:16:37 +0100 |
commit | 6f81b18abed11b7a2dd1dad15d8281ed7036b602 (patch) | |
tree | ac02bb478be68e87446dcea21f629f35cbf623d5 | |
parent | 0d4e6ca38f1c51f5f92effc7d97c8b69eb85d071 (diff) |
add (ice-9 poll), a poll wrapper
* libguile/poll.c:
* libguile/poll.h:
* module/ice-9/poll.scm: New module, (ice-9 poll).
* module/Makefile.am:
* libguile/init.c:
* libguile/Makefile.am: Adapt.
* configure.ac: Check for poll.h and poll.
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | libguile/Makefile.am | 2 | ||||
-rw-r--r-- | libguile/init.c | 2 | ||||
-rw-r--r-- | libguile/poll.c | 146 | ||||
-rw-r--r-- | libguile/poll.h | 38 | ||||
-rw-r--r-- | module/Makefile.am | 1 | ||||
-rw-r--r-- | module/ice-9/poll.scm | 175 |
7 files changed, 367 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac index 631198b04..1aa6f057a 100644 --- a/configure.ac +++ b/configure.ac @@ -644,7 +644,7 @@ AC_CHECK_HEADERS([complex.h fenv.h io.h libc.h limits.h malloc.h memory.h proces regex.h rxposix.h rx/rxposix.h sys/dir.h sys/ioctl.h sys/select.h \ sys/time.h sys/timeb.h sys/times.h sys/stdtypes.h sys/types.h \ sys/utime.h time.h unistd.h utime.h pwd.h grp.h sys/utsname.h \ -direct.h langinfo.h nl_types.h machine/fpu.h]) +direct.h langinfo.h nl_types.h machine/fpu.h poll.h]) # Reasons for testing: # nl_item - lacking on Cygwin @@ -741,6 +741,7 @@ AC_CHECK_HEADERS([assert.h crt_externs.h]) # gmtime_r - recent posix, not on old systems # pipe - not in mingw # _pipe - specific to mingw, taking 3 args +# poll - since posix 2001 # readdir_r - recent posix, not on old systems # readdir64_r - not available on HP-UX 11.11 # stat64 - SuS largefile stuff, not on old systems @@ -753,7 +754,7 @@ AC_CHECK_HEADERS([assert.h crt_externs.h]) # utimensat: posix.1-2008 # sched_getaffinity, sched_setaffinity: GNU extensions (glibc) # -AC_CHECK_FUNCS([DINFINITY DQNAN cexp chsize clog clog10 ctermid fesetround ftime ftruncate fchown getcwd geteuid getsid gettimeofday gmtime_r ioctl lstat mkdir mknod nice pipe _pipe readdir_r readdir64_r readlink rename rmdir select setegid seteuid setlocale setpgid setsid sigaction siginterrupt stat64 strftime strptime symlink sync sysconf tcgetpgrp tcsetpgrp times uname waitpid strdup system usleep atexit on_exit chown link fcntl ttyname getpwent getgrent kill getppid getpgrp fork setitimer getitimer strchr strcmp index bcopy memcpy rindex truncate unsetenv isblank _NSGetEnviron strcoll strcoll_l newlocale nl_langinfo utimensat sched_getaffinity sched_setaffinity]) +AC_CHECK_FUNCS([DINFINITY DQNAN cexp chsize clog clog10 ctermid fesetround ftime ftruncate fchown getcwd geteuid getsid gettimeofday gmtime_r ioctl lstat mkdir mknod nice pipe _pipe poll readdir_r readdir64_r readlink rename rmdir select setegid seteuid setlocale setpgid setsid sigaction siginterrupt stat64 strftime strptime symlink sync sysconf tcgetpgrp tcsetpgrp times uname waitpid strdup system usleep atexit on_exit chown link fcntl ttyname getpwent getgrent kill getppid getpgrp fork setitimer getitimer strchr strcmp index bcopy memcpy rindex truncate unsetenv isblank _NSGetEnviron strcoll strcoll_l newlocale nl_langinfo utimensat sched_getaffinity sched_setaffinity]) # Reasons for testing: # netdb.h - not in mingw diff --git a/libguile/Makefile.am b/libguile/Makefile.am index 55a976445..dd797eaad 100644 --- a/libguile/Makefile.am +++ b/libguile/Makefile.am @@ -170,6 +170,7 @@ libguile_@GUILE_EFFECTIVE_VERSION@_la_SOURCES = \ objprop.c \ options.c \ pairs.c \ + poll.c \ ports.c \ print.c \ procprop.c \ @@ -541,6 +542,7 @@ modinclude_HEADERS = \ objprop.h \ options.h \ pairs.h \ + poll.h \ ports.h \ posix.h \ print.h \ diff --git a/libguile/init.c b/libguile/init.c index bb916dcd2..c2b80e0b2 100644 --- a/libguile/init.c +++ b/libguile/init.c @@ -88,6 +88,7 @@ #include "libguile/objprop.h" #include "libguile/options.h" #include "libguile/pairs.h" +#include "libguile/poll.h" #include "libguile/ports.h" #include "libguile/posix.h" #ifdef HAVE_REGCOMP @@ -459,6 +460,7 @@ scm_i_init_guile (SCM_STACKITEM *base) scm_register_foreign (); scm_register_srfi_1 (); scm_register_srfi_60 (); + scm_register_poll (); scm_init_strings (); /* Requires array-handle */ scm_init_struct (); /* Requires strings */ diff --git a/libguile/poll.c b/libguile/poll.c new file mode 100644 index 000000000..0304448fa --- /dev/null +++ b/libguile/poll.c @@ -0,0 +1,146 @@ +/* Copyright (C) 2010 Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + + + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libguile/_scm.h" +#include "libguile/bytevectors.h" +#include "libguile/numbers.h" +#include "libguile/error.h" +#include "libguile/validate.h" + +#include "libguile/poll.h" + + +#ifdef HAVE_POLL_H +#include <poll.h> +#endif + + + +/* {Poll} + */ + +/* Poll a set of file descriptors, waiting until one or more of them is + ready to perform input or output. + + This is a low-level interface. See the `(ice-9 poll)' module for a more + usable wrapper. + + `pollfds' is expected to be a bytevector, laid out in contiguous blocks of 64 + bits. Each block has the format of one `struct pollfd': a 32-bit int file + descriptor, a 16-bit int events mask, and a 16-bit int revents mask. + + The number of pollfd structures in `pollfds' is specified in + `nfds'. `pollfds' must be at least long enough to support that number of + structures. It may be longer, in which case the trailing entries are left + untouched. + + The pollfds bytevector is modified directly, setting the returned events in + the final two bytes (the revents member). + + If timeout is given and is non-negative, the poll will return after that + number of milliseconds if no fd became active. + */ +#ifdef HAVE_POLL +static SCM +scm_primitive_poll (SCM pollfds, SCM nfds, SCM timeout) +#define FUNC_NAME "primitive-poll" +{ + int rv; + nfds_t c_nfds; + int c_timeout; + struct pollfd *fds; + + SCM_VALIDATE_BYTEVECTOR (SCM_ARG1, pollfds); + c_nfds = scm_to_uint32 (nfds); + c_timeout = scm_to_int (timeout); + + if (SCM_UNLIKELY (SCM_BYTEVECTOR_LENGTH (pollfds) + < c_nfds * sizeof(struct pollfd))) + SCM_OUT_OF_RANGE (SCM_ARG1, nfds); + + fds = (struct pollfd*)SCM_BYTEVECTOR_CONTENTS (pollfds); + + SCM_SYSCALL (rv = poll (fds, c_nfds, c_timeout)); + + if (rv == -1) + SCM_SYSERROR; + + return scm_from_int (rv); +} +#undef FUNC_NAME +#endif /* HAVE_POLL */ + + + + +static void +scm_init_poll (void) +{ +#if HAVE_POLL + scm_c_define_gsubr ("primitive-poll", 3, 0, 0, scm_primitive_poll); +#else + scm_misc_error ("%init-poll", "`poll' unavailable on this platform", SCM_EOL); +#endif + +#ifdef POLLIN + scm_c_define ("POLLIN", scm_from_int (POLLIN)); +#endif +#ifdef POLLPRI + scm_c_define ("POLLPRI", scm_from_int (POLLPRI)); +#endif +#ifdef POLLOUT + scm_c_define ("POLLOUT", scm_from_int (POLLOUT)); +#endif +#ifdef POLLRDHUP + scm_c_define ("POLLRDHUP", scm_from_int (POLLRDHUP)); +#endif +#ifdef POLLERR + scm_c_define ("POLLERR", scm_from_int (POLLERR)); +#endif +#ifdef POLLHUP + scm_c_define ("POLLHUP", scm_from_int (POLLHUP)); +#endif +#ifdef POLLNVAL + scm_c_define ("POLLNVAL", scm_from_int (POLLNVAL)); +#endif + +} + +void +scm_register_poll (void) +{ + scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION, + "scm_init_poll", + (scm_t_extension_init_func) scm_init_poll, + NULL); +} + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ diff --git a/libguile/poll.h b/libguile/poll.h new file mode 100644 index 000000000..ab3195008 --- /dev/null +++ b/libguile/poll.h @@ -0,0 +1,38 @@ +/* classes: h_files */ + +#ifndef SCM_POLL_H +#define SCM_POLL_H + +/* Copyright (C) 2010 Free Software Foundation, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + + +#include "libguile/__scm.h" + + + +SCM_INTERNAL void scm_register_poll (void); + +#endif /* SCM_POLL_H */ + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ diff --git a/module/Makefile.am b/module/Makefile.am index e16cd557f..67d530ada 100644 --- a/module/Makefile.am +++ b/module/Makefile.am @@ -200,6 +200,7 @@ ICE_9_SOURCES = \ ice-9/occam-channel.scm \ ice-9/optargs.scm \ ice-9/poe.scm \ + ice-9/poll.scm \ ice-9/popen.scm \ ice-9/posix.scm \ ice-9/q.scm \ diff --git a/module/ice-9/poll.scm b/module/ice-9/poll.scm new file mode 100644 index 000000000..e506e2ac4 --- /dev/null +++ b/module/ice-9/poll.scm @@ -0,0 +1,175 @@ +;; poll + +;;;; Copyright (C) 2010 Free Software Foundation, Inc. +;;;; +;;;; This library is free software; you can redistribute it and/or +;;;; modify it under the terms of the GNU Lesser General Public +;;;; License as published by the Free Software Foundation; either +;;;; version 3 of the License, or (at your option) any later version. +;;;; +;;;; This library is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;;; Lesser General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU Lesser General Public +;;;; License along with this library; if not, write to the Free Software +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;;;; + +(define-module (ice-9 poll) + #:use-module (srfi srfi-9) + #:use-module (srfi srfi-9 gnu) + #:use-module (rnrs bytevectors) + #:export (make-empty-poll-set + poll-set? + poll-set-nfds + poll-set-find-port + poll-set-port + poll-set-events + set-poll-set-events! + poll-set-revents + set-poll-set-revents! + poll-set-add! + poll-set-remove! + poll)) + +(eval-when (eval load compile) + (load-extension (string-append "libguile-" (effective-version)) + "scm_init_poll")) + +(if (defined? 'POLLIN) + (export POLLIN)) + +(if (defined? 'POLLPRI) + (export POLLPRI)) + +(if (defined? 'POLLOUT) + (export POLLOUT)) + +(if (defined? 'POLLRDHUP) + (export POLLRDHUP)) + +(if (defined? 'POLLERR) + (export POLLERR)) + +(if (defined? 'POLLHUP) + (export POLLHUP)) + +(if (defined? 'POLLNVAL) + (export POLLNVAL)) + + +(define-record-type <poll-set> + (make-poll-set pollfds nfds ports) + poll-set? + (pollfds pset-pollfds set-pset-pollfds!) + (nfds poll-set-nfds set-pset-nfds!) + (ports pset-ports set-pset-ports!) + ) + +(define-syntax pollfd-offset + (syntax-rules () + ((_ n) (* n 8)))) + +(define* (make-empty-poll-set #:optional (pre-allocated 4)) + (make-poll-set (make-bytevector (pollfd-offset pre-allocated) 0) + 0 + (make-vector pre-allocated #f))) + +(define (pset-size set) + (vector-length (pset-ports set))) + +(define (ensure-pset-size! set size) + (let ((prev (pset-size set))) + (if (< prev size) + (let lp ((new prev)) + (if (< new size) + (lp (* new 2)) + (let ((old-pollfds (pset-pollfds set)) + (nfds (poll-set-nfds set)) + (old-ports (pset-ports set)) + (new-pollfds (make-bytevector (pollfd-offset new) 0)) + (new-ports (make-vector new #f))) + (bytevector-copy! old-pollfds 0 new-pollfds 0 + (pollfd-offset nfds)) + (vector-move-left! old-ports 0 nfds new-ports 0) + (set-pset-pollfds! set new-pollfds) + (set-pset-ports! set new-ports))))))) + +(define (poll-set-find-port set port) + (let lp ((i 0)) + (if (< i (poll-set-nfds set)) + (if (equal? (vector-ref (pset-ports set) i) port) + i + (lp (1+ i))) + #f))) + +(define (poll-set-port set idx) + (if (< idx (poll-set-nfds set)) + (vector-ref (pset-ports set) idx) + (error "poll set index out of bounds" set idx))) + +(define (poll-set-events set idx) + (if (< idx (poll-set-nfds set)) + (bytevector-u16-native-ref (pset-pollfds set) (+ (pollfd-offset idx) 4)) + (error "poll set index out of bounds" set idx))) + +(define (set-poll-set-events! set idx events) + (if (< idx (poll-set-nfds set)) + (bytevector-u16-native-set! (pset-pollfds set) (+ (pollfd-offset idx) 4) + events) + (error "poll set index out of bounds" set idx))) + +(define (poll-set-revents set idx) + (if (< idx (poll-set-nfds set)) + (bytevector-u16-native-ref (pset-pollfds set) (+ (pollfd-offset idx) 6)) + (error "poll set index out of bounds" set idx))) + +(define (set-poll-set-revents! set idx revents) + (if (< idx (poll-set-nfds set)) + (bytevector-u16-native-set! (pset-pollfds set) (+ (pollfd-offset idx) 6) + revents) + (error "poll set index out of bounds" set idx))) + +(define (poll-set-add! set fd-or-port events) + (let* ((idx (poll-set-nfds set)) + (off (pollfd-offset idx)) + (fd (if (integer? fd-or-port) + fd-or-port + (port->fdes fd-or-port)))) + + (if (port? fd-or-port) + ;; As we store the port in the fdset, there is no need to + ;; increment the revealed count to prevent the fd from being + ;; closed by a gc'd port. + (release-port-handle fd-or-port)) + + (ensure-pset-size! set (1+ idx)) + (bytevector-s32-native-set! (pset-pollfds set) off fd) + (bytevector-u16-native-set! (pset-pollfds set) (+ off 4) events) + (bytevector-u16-native-set! (pset-pollfds set) (+ off 6) 0) ; revents + (vector-set! (pset-ports set) idx fd-or-port) + (set-pset-nfds! set (1+ idx)))) + +(define (poll-set-remove! set idx) + (if (not (< idx (poll-set-nfds set))) + (error "poll set index out of bounds" set idx)) + (let ((nfds (poll-set-nfds set)) + (off (pollfd-offset idx)) + (port (vector-ref (pset-ports set) idx))) + (vector-move-left! (pset-ports set) (1+ idx) nfds + (pset-ports set) idx) + (vector-set! (pset-ports set) (1- nfds) #f) + (bytevector-copy! (pset-pollfds set) (pollfd-offset (1+ idx)) + (pset-pollfds set) off + (- (pollfd-offset nfds) (pollfd-offset (1+ idx)))) + ;; zero the struct pollfd all at once + (bytevector-u64-native-set! (pset-pollfds set) (pollfd-offset (1- nfds)) 0) + (set-pset-nfds! set (1- nfds)) + port)) + +(define* (poll poll-set #:optional (timeout -1)) + (primitive-poll (pset-pollfds poll-set) + (poll-set-nfds poll-set) + timeout)) |