]>
Commit | Line | Data |
---|---|---|
6a8d3f1c OZ |
1 | /* |
2 | * BIRD -- I/O and event loop | |
3 | * | |
4 | * Can be freely distributed and used under the terms of the GNU GPL. | |
5 | */ | |
6 | ||
7 | #include <stdio.h> | |
8 | #include <stdlib.h> | |
9 | #include <unistd.h> | |
10 | #include <errno.h> | |
11 | #include <fcntl.h> | |
12 | #include <poll.h> | |
13 | #include <pthread.h> | |
14 | #include <time.h> | |
15 | #include <sys/time.h> | |
16 | ||
17 | #include "nest/bird.h" | |
18 | #include "proto/bfd/io.h" | |
bf139664 OZ |
19 | |
20 | #include "lib/buffer.h" | |
21 | #include "lib/heap.h" | |
6a8d3f1c OZ |
22 | #include "lib/lists.h" |
23 | #include "lib/resource.h" | |
24 | #include "lib/event.h" | |
25 | #include "lib/socket.h" | |
26 | ||
bf139664 OZ |
27 | |
28 | struct birdloop | |
29 | { | |
30 | pool *pool; | |
6a8d3f1c OZ |
31 | pthread_t thread; |
32 | pthread_mutex_t mutex; | |
bf139664 | 33 | |
6a8d3f1c OZ |
34 | btime last_time; |
35 | btime real_time; | |
bf139664 OZ |
36 | u8 use_monotonic_clock; |
37 | ||
6a8d3f1c OZ |
38 | u8 poll_active; |
39 | u8 wakeup_masked; | |
40 | int wakeup_fds[2]; | |
41 | ||
bf139664 OZ |
42 | BUFFER(timer2 *) timers; |
43 | list event_list; | |
44 | list sock_list; | |
45 | uint sock_num; | |
46 | ||
47 | BUFFER(sock *) poll_sk; | |
48 | BUFFER(struct pollfd) poll_fd; | |
49 | u8 poll_changed; | |
50 | u8 close_scheduled; | |
bf139664 OZ |
51 | }; |
52 | ||
53 | ||
6a8d3f1c OZ |
54 | |
55 | static pthread_key_t current_loop_key; | |
56 | ||
57 | static inline struct birdloop * | |
58 | birdloop_current(void) | |
59 | { | |
60 | return pthread_getspecific(current_loop_key); | |
61 | } | |
62 | ||
63 | static inline void | |
64 | birdloop_set_current(struct birdloop *loop) | |
65 | { | |
66 | pthread_setspecific(current_loop_key, loop); | |
67 | } | |
68 | ||
69 | static inline void | |
70 | birdloop_init_current(void) | |
71 | { | |
72 | pthread_key_create(¤t_loop_key, NULL); | |
73 | } | |
74 | ||
75 | ||
76 | ||
bf139664 OZ |
77 | static void times_update_alt(struct birdloop *loop); |
78 | ||
6a8d3f1c | 79 | static void |
bf139664 OZ |
80 | times_init(struct birdloop *loop) |
81 | { | |
82 | struct timespec ts; | |
83 | int rv; | |
84 | ||
85 | rv = clock_gettime(CLOCK_MONOTONIC, &ts); | |
86 | if (rv < 0) | |
87 | { | |
88 | // log(L_WARN "Monotonic clock is missing"); | |
89 | ||
90 | loop->use_monotonic_clock = 0; | |
91 | loop->last_time = 0; | |
92 | loop->real_time = 0; | |
93 | times_update_alt(loop); | |
94 | return; | |
95 | } | |
96 | ||
97 | /* | |
6a8d3f1c | 98 | if ((ts.tv_sec < 0) || (((s64) ts.tv_sec) > ((s64) 1 << 40))) |
bf139664 OZ |
99 | log(L_WARN "Monotonic clock is crazy"); |
100 | */ | |
101 | ||
102 | loop->use_monotonic_clock = 1; | |
6a8d3f1c | 103 | loop->last_time = (ts.tv_sec S) + (ts.tv_nsec / 1000); |
bf139664 OZ |
104 | loop->real_time = 0; |
105 | } | |
106 | ||
107 | static void | |
108 | times_update_pri(struct birdloop *loop) | |
109 | { | |
110 | struct timespec ts; | |
111 | int rv; | |
112 | ||
113 | rv = clock_gettime(CLOCK_MONOTONIC, &ts); | |
114 | if (rv < 0) | |
115 | die("clock_gettime: %m"); | |
116 | ||
6a8d3f1c | 117 | btime new_time = (ts.tv_sec S) + (ts.tv_nsec / 1000); |
bf139664 OZ |
118 | |
119 | /* | |
120 | if (new_time < loop->last_time) | |
121 | log(L_ERR "Monotonic clock is broken"); | |
122 | */ | |
123 | ||
124 | loop->last_time = new_time; | |
125 | loop->real_time = 0; | |
126 | } | |
127 | ||
128 | static void | |
129 | times_update_alt(struct birdloop *loop) | |
130 | { | |
131 | struct timeval tv; | |
132 | int rv; | |
133 | ||
134 | rv = gettimeofday(&tv, NULL); | |
135 | if (rv < 0) | |
136 | die("gettimeofday: %m"); | |
137 | ||
6a8d3f1c OZ |
138 | btime new_time = (tv.tv_sec S) + tv.tv_usec; |
139 | btime delta = new_time - loop->real_time; | |
bf139664 OZ |
140 | |
141 | if ((delta < 0) || (delta > (60 S))) | |
142 | { | |
143 | /* | |
144 | if (loop->real_time) | |
145 | log(L_WARN "Time jump, delta %d us", (int) delta); | |
146 | */ | |
147 | ||
148 | delta = 100 MS; | |
149 | } | |
150 | ||
151 | loop->last_time += delta; | |
152 | loop->real_time = new_time; | |
153 | } | |
154 | ||
155 | static void | |
156 | times_update(struct birdloop *loop) | |
157 | { | |
158 | if (loop->use_monotonic_clock) | |
159 | times_update_pri(loop); | |
160 | else | |
161 | times_update_alt(loop); | |
162 | } | |
163 | ||
6a8d3f1c OZ |
164 | btime |
165 | current_time(void) | |
166 | { | |
167 | return birdloop_current()->last_time; | |
168 | } | |
169 | ||
bf139664 OZ |
170 | |
171 | ||
172 | static void | |
173 | pipe_new(int *pfds) | |
174 | { | |
6a8d3f1c | 175 | int rv = pipe(pfds); |
bf139664 OZ |
176 | if (rv < 0) |
177 | die("pipe: %m"); | |
178 | ||
179 | if (fcntl(pfds[0], F_SETFL, O_NONBLOCK) < 0) | |
180 | die("fcntl(O_NONBLOCK): %m"); | |
181 | ||
182 | if (fcntl(pfds[1], F_SETFL, O_NONBLOCK) < 0) | |
183 | die("fcntl(O_NONBLOCK): %m"); | |
184 | } | |
185 | ||
6a8d3f1c OZ |
186 | void |
187 | pipe_drain(int fd) | |
bf139664 OZ |
188 | { |
189 | char buf[64]; | |
190 | int rv; | |
191 | ||
192 | try: | |
6a8d3f1c | 193 | rv = read(fd, buf, 64); |
bf139664 OZ |
194 | if (rv < 0) |
195 | { | |
196 | if (errno == EINTR) | |
197 | goto try; | |
198 | if (errno == EAGAIN) | |
199 | return; | |
200 | die("wakeup read: %m"); | |
201 | } | |
202 | if (rv == 64) | |
203 | goto try; | |
204 | } | |
205 | ||
6a8d3f1c OZ |
206 | void |
207 | pipe_kick(int fd) | |
bf139664 OZ |
208 | { |
209 | u64 v = 1; | |
210 | int rv; | |
211 | ||
212 | try: | |
6a8d3f1c | 213 | rv = write(fd, &v, sizeof(u64)); |
bf139664 OZ |
214 | if (rv < 0) |
215 | { | |
216 | if (errno == EINTR) | |
217 | goto try; | |
218 | if (errno == EAGAIN) | |
219 | return; | |
220 | die("wakeup write: %m"); | |
221 | } | |
222 | } | |
223 | ||
6a8d3f1c OZ |
224 | static inline void |
225 | wakeup_init(struct birdloop *loop) | |
226 | { | |
227 | pipe_new(loop->wakeup_fds); | |
228 | } | |
bf139664 | 229 | |
6a8d3f1c OZ |
230 | static inline void |
231 | wakeup_drain(struct birdloop *loop) | |
232 | { | |
233 | pipe_drain(loop->wakeup_fds[0]); | |
234 | } | |
bf139664 | 235 | |
6a8d3f1c OZ |
236 | static inline void |
237 | wakeup_do_kick(struct birdloop *loop) | |
238 | { | |
239 | pipe_kick(loop->wakeup_fds[1]); | |
240 | } | |
bf139664 | 241 | |
6a8d3f1c OZ |
242 | static inline void |
243 | wakeup_kick(struct birdloop *loop) | |
244 | { | |
245 | if (!loop->wakeup_masked) | |
246 | wakeup_do_kick(loop); | |
247 | else | |
248 | loop->wakeup_masked = 2; | |
249 | } | |
bf139664 | 250 | |
6a8d3f1c OZ |
251 | |
252 | ||
253 | static inline uint | |
254 | events_waiting(struct birdloop *loop) | |
255 | { | |
256 | return !EMPTY_LIST(loop->event_list); | |
257 | } | |
258 | ||
259 | static inline void | |
bf139664 OZ |
260 | events_init(struct birdloop *loop) |
261 | { | |
6a8d3f1c | 262 | init_list(&loop->event_list); |
bf139664 OZ |
263 | } |
264 | ||
265 | static void | |
266 | events_fire(struct birdloop *loop) | |
267 | { | |
268 | times_update(loop); | |
269 | ev_run_list(&loop->event_list); | |
270 | } | |
271 | ||
272 | void | |
273 | ev2_schedule(event *e) | |
274 | { | |
6a8d3f1c OZ |
275 | struct birdloop *loop = birdloop_current(); |
276 | ||
bf139664 OZ |
277 | if (loop->poll_active && EMPTY_LIST(loop->event_list)) |
278 | wakeup_kick(loop); | |
279 | ||
280 | if (e->n.next) | |
281 | rem_node(&e->n); | |
282 | ||
283 | add_tail(&loop->event_list, &e->n); | |
284 | } | |
285 | ||
286 | ||
6a8d3f1c | 287 | |
bf139664 OZ |
288 | #define TIMER_LESS(a,b) ((a)->expires < (b)->expires) |
289 | #define TIMER_SWAP(heap,a,b,t) (t = heap[a], heap[a] = heap[b], heap[b] = t, \ | |
290 | heap[a]->index = (a), heap[b]->index = (b)) | |
291 | ||
292 | ||
293 | static inline uint timers_count(struct birdloop *loop) | |
294 | { return loop->timers.used - 1; } | |
295 | ||
296 | static inline timer2 *timers_first(struct birdloop *loop) | |
297 | { return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; } | |
298 | ||
299 | ||
300 | static void | |
301 | tm2_free(resource *r) | |
302 | { | |
303 | timer2 *t = (timer2 *) r; | |
304 | ||
305 | tm2_stop(t); | |
306 | } | |
307 | ||
308 | static void | |
309 | tm2_dump(resource *r) | |
310 | { | |
311 | timer2 *t = (timer2 *) r; | |
312 | ||
313 | debug("(code %p, data %p, ", t->hook, t->data); | |
314 | if (t->randomize) | |
315 | debug("rand %d, ", t->randomize); | |
316 | if (t->recurrent) | |
317 | debug("recur %d, ", t->recurrent); | |
318 | if (t->expires) | |
6a8d3f1c | 319 | debug("expires in %d ms)\n", (t->expires - current_time()) TO_MS); |
bf139664 OZ |
320 | else |
321 | debug("inactive)\n"); | |
322 | } | |
323 | ||
6a8d3f1c | 324 | |
bf139664 OZ |
325 | static struct resclass tm2_class = { |
326 | "Timer", | |
6a8d3f1c | 327 | sizeof(timer2), |
bf139664 OZ |
328 | tm2_free, |
329 | tm2_dump, | |
330 | NULL, | |
331 | NULL | |
332 | }; | |
333 | ||
334 | timer2 * | |
335 | tm2_new(pool *p) | |
336 | { | |
337 | timer2 *t = ralloc(p, &tm2_class); | |
338 | t->index = -1; | |
339 | return t; | |
340 | } | |
341 | ||
342 | void | |
6a8d3f1c | 343 | tm2_set(timer2 *t, btime when) |
bf139664 | 344 | { |
6a8d3f1c | 345 | struct birdloop *loop = birdloop_current(); |
bf139664 OZ |
346 | uint tc = timers_count(loop); |
347 | ||
348 | if (!t->expires) | |
349 | { | |
350 | t->index = ++tc; | |
351 | t->expires = when; | |
352 | BUFFER_PUSH(loop->timers) = t; | |
353 | HEAP_INSERT(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP); | |
354 | } | |
355 | else if (t->expires < when) | |
356 | { | |
357 | t->expires = when; | |
358 | HEAP_INCREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index); | |
359 | } | |
360 | else if (t->expires > when) | |
361 | { | |
362 | t->expires = when; | |
363 | HEAP_DECREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index); | |
364 | } | |
365 | ||
366 | if (loop->poll_active && (t->index == 1)) | |
367 | wakeup_kick(loop); | |
368 | } | |
369 | ||
6a8d3f1c OZ |
370 | void |
371 | tm2_start(timer2 *t, btime after) | |
372 | { | |
373 | tm2_set(t, current_time() + MAX(after, 0)); | |
374 | } | |
375 | ||
bf139664 OZ |
376 | void |
377 | tm2_stop(timer2 *t) | |
378 | { | |
379 | if (!t->expires) | |
380 | return; | |
381 | ||
6a8d3f1c OZ |
382 | struct birdloop *loop = birdloop_current(); |
383 | uint tc = timers_count(loop); | |
384 | ||
bf139664 OZ |
385 | HEAP_DELETE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index); |
386 | BUFFER_POP(loop->timers); | |
387 | ||
388 | t->index = -1; | |
389 | t->expires = 0; | |
390 | } | |
391 | ||
392 | static void | |
393 | timers_init(struct birdloop *loop) | |
394 | { | |
395 | BUFFER_INIT(loop->timers, loop->pool, 4); | |
396 | BUFFER_PUSH(loop->timers) = NULL; | |
397 | } | |
398 | ||
399 | static void | |
400 | timers_fire(struct birdloop *loop) | |
401 | { | |
6a8d3f1c | 402 | btime base_time; |
bf139664 OZ |
403 | timer2 *t; |
404 | ||
405 | times_update(loop); | |
406 | base_time = loop->last_time; | |
407 | ||
408 | while (t = timers_first(loop)) | |
409 | { | |
410 | if (t->expires > base_time) | |
411 | return; | |
412 | ||
413 | if (t->recurrent) | |
414 | { | |
6a8d3f1c | 415 | btime when = t->expires + t->recurrent; |
bf139664 | 416 | |
6a8d3f1c OZ |
417 | if (when <= loop->last_time) |
418 | when = loop->last_time + t->recurrent; | |
bf139664 | 419 | |
6a8d3f1c OZ |
420 | if (t->randomize) |
421 | when += random() % (t->randomize + 1); | |
bf139664 | 422 | |
6a8d3f1c | 423 | tm2_set(t, when); |
bf139664 OZ |
424 | } |
425 | else | |
426 | tm2_stop(t); | |
427 | ||
428 | t->hook(t); | |
429 | } | |
430 | } | |
431 | ||
432 | ||
6a8d3f1c | 433 | |
bf139664 OZ |
434 | static void |
435 | sockets_init(struct birdloop *loop) | |
436 | { | |
6a8d3f1c OZ |
437 | init_list(&loop->sock_list); |
438 | loop->sock_num = 0; | |
bf139664 OZ |
439 | |
440 | BUFFER_INIT(loop->poll_sk, loop->pool, 4); | |
441 | BUFFER_INIT(loop->poll_fd, loop->pool, 4); | |
6a8d3f1c | 442 | loop->poll_changed = 1; /* add wakeup fd */ |
bf139664 OZ |
443 | } |
444 | ||
445 | static void | |
446 | sockets_add(struct birdloop *loop, sock *s) | |
447 | { | |
448 | add_tail(&loop->sock_list, &s->n); | |
449 | loop->sock_num++; | |
450 | ||
451 | s->index = -1; | |
452 | loop->poll_changed = 1; | |
453 | ||
454 | if (loop->poll_active) | |
455 | wakeup_kick(loop); | |
456 | } | |
457 | ||
458 | void | |
459 | sk_start(sock *s) | |
460 | { | |
6a8d3f1c OZ |
461 | struct birdloop *loop = birdloop_current(); |
462 | ||
463 | sockets_add(loop, s); | |
bf139664 OZ |
464 | } |
465 | ||
466 | static void | |
467 | sockets_remove(struct birdloop *loop, sock *s) | |
468 | { | |
469 | rem_node(&s->n); | |
470 | loop->sock_num--; | |
471 | ||
472 | if (s->index >= 0) | |
6a8d3f1c | 473 | loop->poll_sk.data[s->index] = NULL; |
bf139664 OZ |
474 | |
475 | s->index = -1; | |
476 | loop->poll_changed = 1; | |
477 | ||
478 | /* Wakeup moved to sk_stop() */ | |
479 | } | |
480 | ||
481 | void | |
482 | sk_stop(sock *s) | |
483 | { | |
6a8d3f1c OZ |
484 | struct birdloop *loop = birdloop_current(); |
485 | ||
486 | sockets_remove(loop, s); | |
bf139664 OZ |
487 | |
488 | if (loop->poll_active) | |
489 | { | |
490 | loop->close_scheduled = 1; | |
491 | wakeup_kick(loop); | |
492 | } | |
493 | else | |
494 | close(s->fd); | |
495 | ||
496 | s->fd = -1; | |
497 | } | |
498 | ||
499 | static inline uint sk_want_events(sock *s) | |
500 | { return (s->rx_hook ? POLLIN : 0) | ((s->ttx != s->tpos) ? POLLOUT : 0); } | |
501 | ||
502 | static void | |
503 | sockets_update(struct birdloop *loop, sock *s) | |
504 | { | |
505 | if (s->index >= 0) | |
6a8d3f1c | 506 | loop->poll_fd.data[s->index].events = sk_want_events(s); |
bf139664 OZ |
507 | } |
508 | ||
509 | static void | |
510 | sockets_prepare(struct birdloop *loop) | |
511 | { | |
512 | BUFFER_SET(loop->poll_sk, loop->sock_num + 1); | |
513 | BUFFER_SET(loop->poll_fd, loop->sock_num + 1); | |
514 | ||
515 | struct pollfd *pfd = loop->poll_fd.data; | |
516 | sock **psk = loop->poll_sk.data; | |
517 | int i = 0; | |
518 | node *n; | |
519 | ||
6a8d3f1c | 520 | WALK_LIST(n, loop->sock_list) |
bf139664 OZ |
521 | { |
522 | sock *s = SKIP_BACK(sock, n, n); | |
523 | ||
524 | ASSERT(i < loop->sock_num); | |
525 | ||
526 | s->index = i; | |
527 | *psk = s; | |
528 | pfd->fd = s->fd; | |
529 | pfd->events = sk_want_events(s); | |
530 | pfd->revents = 0; | |
531 | ||
532 | pfd++; | |
533 | psk++; | |
534 | i++; | |
535 | } | |
536 | ||
537 | ASSERT(i == loop->sock_num); | |
538 | ||
539 | /* Add internal wakeup fd */ | |
540 | *psk = NULL; | |
541 | pfd->fd = loop->wakeup_fds[0]; | |
542 | pfd->events = POLLIN; | |
543 | pfd->revents = 0; | |
544 | ||
545 | loop->poll_changed = 0; | |
546 | } | |
547 | ||
548 | static void | |
549 | sockets_close_fds(struct birdloop *loop) | |
550 | { | |
551 | struct pollfd *pfd = loop->poll_fd.data; | |
552 | sock **psk = loop->poll_sk.data; | |
553 | int poll_num = loop->poll_fd.used - 1; | |
554 | ||
555 | int i; | |
556 | for (i = 0; i < poll_num; i++) | |
557 | if (psk[i] == NULL) | |
558 | close(pfd[i].fd); | |
559 | ||
560 | loop->close_scheduled = 0; | |
561 | } | |
562 | ||
6a8d3f1c OZ |
563 | int sk_read(sock *s); |
564 | int sk_write(sock *s); | |
bf139664 OZ |
565 | |
566 | static void | |
567 | sockets_fire(struct birdloop *loop) | |
568 | { | |
569 | struct pollfd *pfd = loop->poll_fd.data; | |
570 | sock **psk = loop->poll_sk.data; | |
571 | int poll_num = loop->poll_fd.used - 1; | |
572 | ||
573 | times_update(loop); | |
574 | ||
575 | /* Last fd is internal wakeup fd */ | |
576 | if (pfd[loop->sock_num].revents & POLLIN) | |
577 | wakeup_drain(loop); | |
578 | ||
579 | int i; | |
580 | for (i = 0; i < poll_num; pfd++, psk++, i++) | |
581 | { | |
582 | int e = 1; | |
583 | ||
584 | if (! pfd->revents) | |
585 | continue; | |
586 | ||
587 | if (pfd->revents & POLLNVAL) | |
588 | die("poll: invalid fd %d", pfd->fd); | |
589 | ||
590 | if (pfd->revents & POLLIN) | |
591 | while (e && *psk && (*psk)->rx_hook) | |
592 | e = sk_read(*psk); | |
593 | ||
594 | e = 1; | |
595 | if (pfd->revents & POLLOUT) | |
596 | while (e && *psk) | |
597 | e = sk_write(*psk); | |
598 | } | |
599 | } | |
600 | ||
601 | ||
6a8d3f1c OZ |
602 | |
603 | static void * birdloop_main(void *arg); | |
604 | ||
bf139664 OZ |
605 | struct birdloop * |
606 | birdloop_new(pool *p) | |
607 | { | |
6a8d3f1c OZ |
608 | /* FIXME: this init should be elsewhere and thread-safe */ |
609 | static int init = 0; | |
610 | if (!init) | |
611 | { birdloop_init_current(); init = 1; } | |
612 | ||
bf139664 | 613 | struct birdloop *loop = mb_allocz(p, sizeof(struct birdloop)); |
6a8d3f1c OZ |
614 | loop->pool = p; |
615 | pthread_mutex_init(&loop->mutex, NULL); | |
bf139664 OZ |
616 | |
617 | times_init(loop); | |
618 | wakeup_init(loop); | |
619 | ||
620 | events_init(loop); | |
621 | timers_init(loop); | |
622 | sockets_init(loop); | |
623 | ||
6a8d3f1c OZ |
624 | |
625 | int rv = pthread_create(&loop->thread, NULL, birdloop_main, loop); | |
626 | if (rv < 0) | |
627 | die("pthread_create(): %m"); | |
628 | ||
bf139664 OZ |
629 | return loop; |
630 | } | |
631 | ||
632 | void | |
633 | birdloop_enter(struct birdloop *loop) | |
634 | { | |
6a8d3f1c OZ |
635 | /* TODO: these functions could save and restore old context */ |
636 | pthread_mutex_lock(&loop->mutex); | |
637 | birdloop_set_current(loop); | |
bf139664 OZ |
638 | } |
639 | ||
640 | void | |
641 | birdloop_leave(struct birdloop *loop) | |
642 | { | |
6a8d3f1c OZ |
643 | /* TODO: these functions could save and restore old context */ |
644 | birdloop_set_current(NULL); | |
645 | pthread_mutex_unlock(&loop->mutex); | |
bf139664 OZ |
646 | } |
647 | ||
6a8d3f1c OZ |
648 | void |
649 | birdloop_mask_wakeups(struct birdloop *loop) | |
650 | { | |
651 | pthread_mutex_lock(&loop->mutex); | |
652 | loop->wakeup_masked = 1; | |
653 | pthread_mutex_unlock(&loop->mutex); | |
654 | } | |
bf139664 OZ |
655 | |
656 | void | |
6a8d3f1c | 657 | birdloop_unmask_wakeups(struct birdloop *loop) |
bf139664 | 658 | { |
6a8d3f1c OZ |
659 | pthread_mutex_lock(&loop->mutex); |
660 | if (loop->wakeup_masked == 2) | |
661 | wakeup_do_kick(loop); | |
662 | loop->wakeup_masked = 0; | |
663 | pthread_mutex_unlock(&loop->mutex); | |
664 | } | |
665 | ||
666 | static void * | |
667 | birdloop_main(void *arg) | |
668 | { | |
669 | struct birdloop *loop = arg; | |
bf139664 | 670 | timer2 *t; |
6a8d3f1c | 671 | int rv, timeout; |
bf139664 | 672 | |
6a8d3f1c OZ |
673 | birdloop_set_current(loop); |
674 | ||
675 | pthread_mutex_lock(&loop->mutex); | |
bf139664 OZ |
676 | while (1) |
677 | { | |
678 | events_fire(loop); | |
679 | timers_fire(loop); | |
680 | ||
681 | times_update(loop); | |
682 | if (events_waiting(loop)) | |
683 | timeout = 0; | |
684 | else if (t = timers_first(loop)) | |
685 | timeout = (tm2_remains(t) TO_MS) + 1; | |
686 | else | |
687 | timeout = -1; | |
688 | ||
689 | if (loop->poll_changed) | |
690 | sockets_prepare(loop); | |
691 | ||
692 | loop->poll_active = 1; | |
6a8d3f1c | 693 | pthread_mutex_unlock(&loop->mutex); |
bf139664 OZ |
694 | |
695 | try: | |
696 | rv = poll(loop->poll_fd.data, loop->poll_fd.used, timeout); | |
697 | if (rv < 0) | |
698 | { | |
699 | if (errno == EINTR || errno == EAGAIN) | |
700 | goto try; | |
701 | die("poll: %m"); | |
702 | } | |
703 | ||
6a8d3f1c | 704 | pthread_mutex_lock(&loop->mutex); |
bf139664 OZ |
705 | loop->poll_active = 0; |
706 | ||
707 | if (loop->close_scheduled) | |
708 | sockets_close_fds(loop); | |
709 | ||
710 | if (rv) | |
711 | sockets_fire(loop); | |
712 | ||
713 | timers_fire(loop); | |
714 | } | |
6a8d3f1c OZ |
715 | |
716 | return NULL; | |
bf139664 OZ |
717 | } |
718 | ||
719 | ||
720 |