new print option escape-newlines, defaults to #t
[bpt/guile.git] / libguile / poll.c
CommitLineData
6f81b18a
AW
1/* Copyright (C) 2010 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19
20\f
21
22#define _GNU_SOURCE
23
24#ifdef HAVE_CONFIG_H
25# include <config.h>
26#endif
27
28#include "libguile/_scm.h"
29#include "libguile/bytevectors.h"
30#include "libguile/numbers.h"
31#include "libguile/error.h"
32#include "libguile/validate.h"
33
34#include "libguile/poll.h"
35
36\f
37#ifdef HAVE_POLL_H
38#include <poll.h>
39#endif
40
41\f
42
43/* {Poll}
44 */
45
46/* Poll a set of file descriptors, waiting until one or more of them is
47 ready to perform input or output.
48
49 This is a low-level interface. See the `(ice-9 poll)' module for a more
50 usable wrapper.
51
52 `pollfds' is expected to be a bytevector, laid out in contiguous blocks of 64
53 bits. Each block has the format of one `struct pollfd': a 32-bit int file
54 descriptor, a 16-bit int events mask, and a 16-bit int revents mask.
55
56 The number of pollfd structures in `pollfds' is specified in
57 `nfds'. `pollfds' must be at least long enough to support that number of
58 structures. It may be longer, in which case the trailing entries are left
59 untouched.
60
61 The pollfds bytevector is modified directly, setting the returned events in
62 the final two bytes (the revents member).
63
e9634465
AW
64 Since Scheme ports can buffer input or output in userspace, a Scheme
65 poll interface needs to take that into account as well. The `ports'
66 argument, a vector big enough for `nfds' elements, is given for this
67 purpose. If a pollfd entry has a corresponding open port, that port
68 is scanned for available input or output before dropping into the
69 poll. If any port has buffered I/O available, the poll syscall is
70 still issued, but with a timeout of 0 milliseconds, and a full port
71 scan occurs after the poll returns.
72
6f81b18a
AW
73 If timeout is given and is non-negative, the poll will return after that
74 number of milliseconds if no fd became active.
75 */
76#ifdef HAVE_POLL
77static SCM
e9634465 78scm_primitive_poll (SCM pollfds, SCM nfds, SCM ports, SCM timeout)
6f81b18a
AW
79#define FUNC_NAME "primitive-poll"
80{
e9634465
AW
81 int rv = 0;
82 nfds_t i;
6f81b18a
AW
83 nfds_t c_nfds;
84 int c_timeout;
e9634465 85 int have_buffered_io = 0;
6f81b18a
AW
86 struct pollfd *fds;
87
88 SCM_VALIDATE_BYTEVECTOR (SCM_ARG1, pollfds);
89 c_nfds = scm_to_uint32 (nfds);
90 c_timeout = scm_to_int (timeout);
91
92 if (SCM_UNLIKELY (SCM_BYTEVECTOR_LENGTH (pollfds)
93 < c_nfds * sizeof(struct pollfd)))
e9634465 94 SCM_OUT_OF_RANGE (SCM_ARG2, nfds);
6f81b18a 95
e9634465
AW
96 SCM_VALIDATE_VECTOR (SCM_ARG3, ports);
97 if (SCM_UNLIKELY (SCM_SIMPLE_VECTOR_LENGTH (ports) < c_nfds))
98 SCM_OUT_OF_RANGE (SCM_ARG3, ports);
99
6f81b18a
AW
100 fds = (struct pollfd*)SCM_BYTEVECTOR_CONTENTS (pollfds);
101
e9634465
AW
102 for (i = 0; i < c_nfds; i++)
103 {
104 SCM port = SCM_SIMPLE_VECTOR_REF (ports, i);
105 short int revents = 0;
106
107 if (SCM_PORTP (port))
108 {
109 if (SCM_CLOSEDP (port))
110 revents |= POLLERR;
111 else
112 {
113 scm_t_port *pt = SCM_PTAB_ENTRY (port);
114
115 if (pt->read_pos < pt->read_end)
116 /* Buffered input waiting to be read. */
117 revents |= POLLIN;
118 if (pt->write_pos < pt->write_end)
119 /* Buffered output possible. */
120 revents |= POLLOUT;
121 }
122 }
123
124 if (revents & fds[i].events)
125 {
126 have_buffered_io = 1;
127 c_timeout = 0;
128 break;
129 }
130 }
131
6f81b18a
AW
132 SCM_SYSCALL (rv = poll (fds, c_nfds, c_timeout));
133
134 if (rv == -1)
135 SCM_SYSERROR;
136
e9634465
AW
137 if (have_buffered_io)
138 for (i = 0; i < c_nfds; i++)
139 {
140 SCM port = SCM_SIMPLE_VECTOR_REF (ports, i);
141 short int revents = 0;
142
143 if (SCM_PORTP (port))
144 {
145 if (SCM_CLOSEDP (port))
146 revents |= POLLERR;
147 else
148 {
149 scm_t_port *pt = SCM_PTAB_ENTRY (port);
150
151 if (pt->read_pos < pt->read_end)
152 /* Buffered input waiting to be read. */
153 revents |= POLLIN;
557abc49 154 if (SCM_OUTPUT_PORT_P (port) && pt->write_pos < pt->write_end)
e9634465
AW
155 /* Buffered output possible. */
156 revents |= POLLOUT;
157 }
158 }
159
557abc49
AW
160 /* Mask in the events we are interested, and test if any are
161 interesting. */
162 if ((revents &= fds[i].events))
163 {
164 /* Could be the underlying fd is also ready for reading. */
165 if (!fds[i].revents)
166 rv++;
167
168 /* In any case, add these events to whatever the syscall
169 set. */
170 fds[i].revents |= revents;
171 }
e9634465
AW
172 }
173
6f81b18a
AW
174 return scm_from_int (rv);
175}
176#undef FUNC_NAME
177#endif /* HAVE_POLL */
178
179
180\f
181
182static void
183scm_init_poll (void)
184{
185#if HAVE_POLL
e9634465 186 scm_c_define_gsubr ("primitive-poll", 4, 0, 0, scm_primitive_poll);
6f81b18a
AW
187#else
188 scm_misc_error ("%init-poll", "`poll' unavailable on this platform", SCM_EOL);
189#endif
190
191#ifdef POLLIN
192 scm_c_define ("POLLIN", scm_from_int (POLLIN));
193#endif
194#ifdef POLLPRI
195 scm_c_define ("POLLPRI", scm_from_int (POLLPRI));
196#endif
197#ifdef POLLOUT
198 scm_c_define ("POLLOUT", scm_from_int (POLLOUT));
199#endif
200#ifdef POLLRDHUP
201 scm_c_define ("POLLRDHUP", scm_from_int (POLLRDHUP));
202#endif
203#ifdef POLLERR
204 scm_c_define ("POLLERR", scm_from_int (POLLERR));
205#endif
206#ifdef POLLHUP
207 scm_c_define ("POLLHUP", scm_from_int (POLLHUP));
208#endif
209#ifdef POLLNVAL
210 scm_c_define ("POLLNVAL", scm_from_int (POLLNVAL));
211#endif
212
213}
214
215void
216scm_register_poll (void)
217{
218 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
219 "scm_init_poll",
220 (scm_t_extension_init_func) scm_init_poll,
221 NULL);
222}
223
224/*
225 Local Variables:
226 c-file-style: "gnu"
227 End:
228*/