Rizin
unix-like reverse engineering framework and cli tools
posix-poll.c
Go to the documentation of this file.
1 /* Copyright libuv project contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #include "uv.h"
23 #include "internal.h"
24 
25 /* POSIX defines poll() as a portable way to wait on file descriptors.
26  * Here we maintain a dynamically sized array of file descriptors and
27  * events to pass as the first argument to poll().
28  */
29 
30 #include <assert.h>
31 #include <stddef.h>
32 #include <stdint.h>
33 #include <errno.h>
34 #include <unistd.h>
35 
37  loop->poll_fds = NULL;
38  loop->poll_fds_used = 0;
39  loop->poll_fds_size = 0;
40  loop->poll_fds_iterating = 0;
41  return 0;
42 }
43 
45  uv__free(loop->poll_fds);
46  loop->poll_fds = NULL;
47 }
48 
52 }
53 
54 /* Allocate or dynamically resize our poll fds array. */
56  size_t i;
57  size_t n;
58  struct pollfd* p;
59 
60  if (loop->poll_fds_used < loop->poll_fds_size)
61  return;
62 
63  n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64;
64  p = uv__reallocf(loop->poll_fds, n * sizeof(*loop->poll_fds));
65  if (p == NULL)
66  abort();
67 
68  loop->poll_fds = p;
69  for (i = loop->poll_fds_size; i < n; i++) {
70  loop->poll_fds[i].fd = -1;
71  loop->poll_fds[i].events = 0;
72  loop->poll_fds[i].revents = 0;
73  }
74  loop->poll_fds_size = n;
75 }
76 
77 /* Primitive swap operation on poll fds array elements. */
78 static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) {
79  struct pollfd pfd;
80  pfd = loop->poll_fds[l];
81  loop->poll_fds[l] = loop->poll_fds[r];
82  loop->poll_fds[r] = pfd;
83 }
84 
85 /* Add a watcher's fd to our poll fds array with its pending events. */
87  size_t i;
88  struct pollfd* pe;
89 
90  /* If the fd is already in the set just update its events. */
91  assert(!loop->poll_fds_iterating);
92  for (i = 0; i < loop->poll_fds_used; ++i) {
93  if (loop->poll_fds[i].fd == w->fd) {
94  loop->poll_fds[i].events = w->pevents;
95  return;
96  }
97  }
98 
99  /* Otherwise, allocate a new slot in the set for the fd. */
101  pe = &loop->poll_fds[loop->poll_fds_used++];
102  pe->fd = w->fd;
103  pe->events = w->pevents;
104 }
105 
106 /* Remove a watcher's fd from our poll fds array. */
107 static void uv__pollfds_del(uv_loop_t* loop, int fd) {
108  size_t i;
109  assert(!loop->poll_fds_iterating);
110  for (i = 0; i < loop->poll_fds_used;) {
111  if (loop->poll_fds[i].fd == fd) {
112  /* swap to last position and remove */
113  --loop->poll_fds_used;
114  uv__pollfds_swap(loop, i, loop->poll_fds_used);
115  loop->poll_fds[loop->poll_fds_used].fd = -1;
116  loop->poll_fds[loop->poll_fds_used].events = 0;
117  loop->poll_fds[loop->poll_fds_used].revents = 0;
118  /* This method is called with an fd of -1 to purge the invalidated fds,
119  * so we may possibly have multiples to remove.
120  */
121  if (-1 != fd)
122  return;
123  } else {
124  /* We must only increment the loop counter when the fds do not match.
125  * Otherwise, when we are purging an invalidated fd, the value just
126  * swapped here from the previous end of the array will be skipped.
127  */
128  ++i;
129  }
130  }
131 }
132 
133 
135  sigset_t* pset;
136  sigset_t set;
137  uint64_t time_base;
138  uint64_t time_diff;
139  QUEUE* q;
140  uv__io_t* w;
141  size_t i;
142  unsigned int nevents;
143  int nfds;
144  int have_signals;
145  struct pollfd* pe;
146  int fd;
147  int user_timeout;
148  int reset_timeout;
149 
150  if (loop->nfds == 0) {
151  assert(QUEUE_EMPTY(&loop->watcher_queue));
152  return;
153  }
154 
155  /* Take queued watchers and add their fds to our poll fds array. */
156  while (!QUEUE_EMPTY(&loop->watcher_queue)) {
157  q = QUEUE_HEAD(&loop->watcher_queue);
158  QUEUE_REMOVE(q);
159  QUEUE_INIT(q);
160 
161  w = QUEUE_DATA(q, uv__io_t, watcher_queue);
162  assert(w->pevents != 0);
163  assert(w->fd >= 0);
164  assert(w->fd < (int) loop->nwatchers);
165 
167 
168  w->events = w->pevents;
169  }
170 
171  /* Prepare a set of signals to block around poll(), if any. */
172  pset = NULL;
173  if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
174  pset = &set;
175  sigemptyset(pset);
176  sigaddset(pset, SIGPROF);
177  }
178 
179  assert(timeout >= -1);
180  time_base = loop->time;
181 
183  reset_timeout = 1;
184  user_timeout = timeout;
185  timeout = 0;
186  } else {
187  reset_timeout = 0;
188  }
189 
190  /* Loop calls to poll() and processing of results. If we get some
191  * results from poll() but they turn out not to be interesting to
192  * our caller then we need to loop around and poll() again.
193  */
194  for (;;) {
195  /* Only need to set the provider_entry_time if timeout != 0. The function
196  * will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
197  */
198  if (timeout != 0)
200 
201  if (pset != NULL)
202  if (pthread_sigmask(SIG_BLOCK, pset, NULL))
203  abort();
204  nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout);
205  if (pset != NULL)
206  if (pthread_sigmask(SIG_UNBLOCK, pset, NULL))
207  abort();
208 
209  /* Update loop->time unconditionally. It's tempting to skip the update when
210  * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
211  * operating system didn't reschedule our process while in the syscall.
212  */
213  SAVE_ERRNO(uv__update_time(loop));
214 
215  if (nfds == 0) {
216  if (reset_timeout != 0) {
217  timeout = user_timeout;
218  reset_timeout = 0;
219  if (timeout == -1)
220  continue;
221  if (timeout > 0)
222  goto update_timeout;
223  }
224 
225  assert(timeout != -1);
226  return;
227  }
228 
229  if (nfds == -1) {
230  if (errno != EINTR)
231  abort();
232 
233  if (reset_timeout != 0) {
234  timeout = user_timeout;
235  reset_timeout = 0;
236  }
237 
238  if (timeout == -1)
239  continue;
240 
241  if (timeout == 0)
242  return;
243 
244  /* Interrupted by a signal. Update timeout and poll again. */
245  goto update_timeout;
246  }
247 
248  /* Tell uv__platform_invalidate_fd not to manipulate our array
249  * while we are iterating over it.
250  */
251  loop->poll_fds_iterating = 1;
252 
253  /* Initialize a count of events that we care about. */
254  nevents = 0;
255  have_signals = 0;
256 
257  /* Loop over the entire poll fds array looking for returned events. */
258  for (i = 0; i < loop->poll_fds_used; i++) {
259  pe = loop->poll_fds + i;
260  fd = pe->fd;
261 
262  /* Skip invalidated events, see uv__platform_invalidate_fd. */
263  if (fd == -1)
264  continue;
265 
266  assert(fd >= 0);
267  assert((unsigned) fd < loop->nwatchers);
268 
269  w = loop->watchers[fd];
270 
271  if (w == NULL) {
272  /* File descriptor that we've stopped watching, ignore. */
274  continue;
275  }
276 
277  /* Filter out events that user has not requested us to watch
278  * (e.g. POLLNVAL).
279  */
280  pe->revents &= w->pevents | POLLERR | POLLHUP;
281 
282  if (pe->revents != 0) {
283  /* Run signal watchers last. */
284  if (w == &loop->signal_io_watcher) {
285  have_signals = 1;
286  } else {
288  w->cb(loop, w, pe->revents);
289  }
290 
291  nevents++;
292  }
293  }
294 
295  if (reset_timeout != 0) {
296  timeout = user_timeout;
297  reset_timeout = 0;
298  }
299 
300  if (have_signals != 0) {
302  loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
303  }
304 
305  loop->poll_fds_iterating = 0;
306 
307  /* Purge invalidated fds from our poll fds array. */
308  uv__pollfds_del(loop, -1);
309 
310  if (have_signals != 0)
311  return; /* Event loop should cycle now so don't poll again. */
312 
313  if (nevents != 0)
314  return;
315 
316  if (timeout == 0)
317  return;
318 
319  if (timeout == -1)
320  continue;
321 
322 update_timeout:
323  assert(timeout > 0);
324 
325  time_diff = loop->time - time_base;
326  if (time_diff >= (uint64_t) timeout)
327  return;
328 
329  timeout -= time_diff;
330  }
331 }
332 
333 /* Remove the given fd from our poll fds array because no one
334  * is interested in its events anymore.
335  */
337  size_t i;
338 
339  assert(fd >= 0);
340 
341  if (loop->poll_fds_iterating) {
342  /* uv__io_poll is currently iterating. Just invalidate fd. */
343  for (i = 0; i < loop->poll_fds_used; i++)
344  if (loop->poll_fds[i].fd == fd) {
345  loop->poll_fds[i].fd = -1;
346  loop->poll_fds[i].events = 0;
347  loop->poll_fds[i].revents = 0;
348  }
349  } else {
350  /* uv__io_poll is not iterating. Delete fd from the set. */
352  }
353 }
354 
355 /* Check whether the given fd is supported by poll(). */
357  struct pollfd p[1];
358  int rv;
359 
360  p[0].fd = fd;
361  p[0].events = POLLIN;
362 
363  do
364  rv = poll(p, 1, 0);
365  while (rv == -1 && (errno == EINTR || errno == EAGAIN));
366 
367  if (rv == -1)
368  return UV__ERR(errno);
369 
370  if (p[0].revents & POLLNVAL)
371  return UV_EINVAL;
372 
373  return 0;
374 }
lzma_index ** i
Definition: index.h:629
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
#define w
Definition: crypto_rc6.c:13
#define UV__ERR(x)
Definition: errno.h:29
void * p
Definition: libc.cpp:67
static const char struct stat static buf struct stat static buf static vhangup int struct rusage static rusage struct sysinfo static info unsigned static __unused struct utsname static buf const char static size const char static name static pid unsigned static persona static fsgid const void static flags const struct iovec static count static fd const void static len static munlockall struct sched_param static p static sched_yield static policy const struct timespec struct timespec static rem uid_t uid_t uid_t static suid poll
Definition: sflib.h:196
static const char struct stat static buf struct stat static buf static vhangup int struct rusage static rusage struct sysinfo static info unsigned static __unused struct utsname static buf const char static size const char static name static pid unsigned static persona static fsgid const void static flags const struct iovec static count static fd const void static len static munlockall struct sched_param static p static sched_yield static policy const struct timespec struct timespec static rem uid_t uid_t uid_t static suid struct pollfd unsigned nfds
Definition: sflib.h:196
assert(limit<=UINT32_MAX/2)
int n
Definition: mipsasm.c:19
static void uv__pollfds_add(uv_loop_t *loop, uv__io_t *w)
Definition: posix-poll.c:86
static void uv__pollfds_maybe_resize(uv_loop_t *loop)
Definition: posix-poll.c:55
void uv__platform_invalidate_fd(uv_loop_t *loop, int fd)
Definition: posix-poll.c:336
void uv__io_poll(uv_loop_t *loop, int timeout)
Definition: posix-poll.c:134
static void uv__pollfds_swap(uv_loop_t *loop, size_t l, size_t r)
Definition: posix-poll.c:78
int uv__io_check_fd(uv_loop_t *loop, int fd)
Definition: posix-poll.c:356
int uv__platform_loop_init(uv_loop_t *loop)
Definition: posix-poll.c:36
int uv__io_fork(uv_loop_t *loop)
Definition: posix-poll.c:49
void uv__platform_loop_delete(uv_loop_t *loop)
Definition: posix-poll.c:44
static void uv__pollfds_del(uv_loop_t *loop, int fd)
Definition: posix-poll.c:107
#define QUEUE_DATA(ptr, type, field)
Definition: queue.h:30
#define QUEUE_EMPTY(q)
Definition: queue.h:39
#define QUEUE_HEAD(q)
Definition: queue.h:42
#define QUEUE_INIT(q)
Definition: queue.h:45
void * QUEUE[2]
Definition: queue.h:21
#define QUEUE_REMOVE(q)
Definition: queue.h:101
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
#define EINTR
Definition: sftypes.h:114
unsigned long uint64_t
Definition: sftypes.h:28
#define EAGAIN
Definition: sftypes.h:121
int sigset_t
Definition: sftypes.h:63
Definition: sftypes.h:75
Definition: unix.h:96
Definition: uv.h:1780
uv_loop_t * loop
Definition: main.c:7
uv_timer_t timeout
Definition: main.c:9
@ UV_LOOP_BLOCK_SIGPROF
Definition: internal.h:137
#define SAVE_ERRNO(block)
Definition: internal.h:92
void * uv__reallocf(void *ptr, size_t size)
Definition: uv-common.c:103
void uv__metrics_update_idle_time(uv_loop_t *loop)
Definition: uv-common.c:872
void uv__free(void *ptr)
Definition: uv-common.c:81
void uv__metrics_set_provider_entry_time(uv_loop_t *loop)
Definition: uv-common.c:899
#define uv__get_internal_fields(loop)
Definition: uv-common.h:336
@ UV_METRICS_IDLE_TIME
Definition: uv.h:251
static const z80_opcode fd[]
Definition: z80_tab.h:997