Annotation of embedaddon/bird2/proto/bfd/io.c, revision 1.1.1.1

1.1       misho       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"
                     19: 
                     20: #include "lib/buffer.h"
                     21: #include "lib/lists.h"
                     22: #include "lib/resource.h"
                     23: #include "lib/event.h"
                     24: #include "lib/timer.h"
                     25: #include "lib/socket.h"
                     26: 
                     27: 
                     28: struct birdloop
                     29: {
                     30:   pool *pool;
                     31:   pthread_t thread;
                     32:   pthread_mutex_t mutex;
                     33: 
                     34:   u8 stop_called;
                     35:   u8 poll_active;
                     36:   u8 wakeup_masked;
                     37:   int wakeup_fds[2];
                     38: 
                     39:   struct timeloop time;
                     40:   list event_list;
                     41:   list sock_list;
                     42:   uint sock_num;
                     43: 
                     44:   BUFFER(sock *) poll_sk;
                     45:   BUFFER(struct pollfd) poll_fd;
                     46:   u8 poll_changed;
                     47:   u8 close_scheduled;
                     48: };
                     49: 
                     50: 
                     51: /*
                     52:  *     Current thread context
                     53:  */
                     54: 
                     55: static pthread_key_t current_loop_key;
                     56: extern pthread_key_t current_time_key;
                     57: 
                     58: static inline struct birdloop *
                     59: birdloop_current(void)
                     60: {
                     61:   return pthread_getspecific(current_loop_key);
                     62: }
                     63: 
                     64: static inline void
                     65: birdloop_set_current(struct birdloop *loop)
                     66: {
                     67:   pthread_setspecific(current_loop_key, loop);
                     68:   pthread_setspecific(current_time_key, loop ? &loop->time : &main_timeloop);
                     69: }
                     70: 
                     71: static inline void
                     72: birdloop_init_current(void)
                     73: {
                     74:   pthread_key_create(&current_loop_key, NULL);
                     75: }
                     76: 
                     77: 
                     78: /*
                     79:  *     Wakeup code for birdloop
                     80:  */
                     81: 
                     82: static void
                     83: pipe_new(int *pfds)
                     84: {
                     85:   int rv = pipe(pfds);
                     86:   if (rv < 0)
                     87:     die("pipe: %m");
                     88: 
                     89:   if (fcntl(pfds[0], F_SETFL, O_NONBLOCK) < 0)
                     90:     die("fcntl(O_NONBLOCK): %m");
                     91: 
                     92:   if (fcntl(pfds[1], F_SETFL, O_NONBLOCK) < 0)
                     93:     die("fcntl(O_NONBLOCK): %m");
                     94: }
                     95: 
                     96: void
                     97: pipe_drain(int fd)
                     98: {
                     99:   char buf[64];
                    100:   int rv;
                    101:   
                    102:  try:
                    103:   rv = read(fd, buf, 64);
                    104:   if (rv < 0)
                    105:   {
                    106:     if (errno == EINTR)
                    107:       goto try;
                    108:     if (errno == EAGAIN)
                    109:       return;
                    110:     die("wakeup read: %m");
                    111:   }
                    112:   if (rv == 64)
                    113:     goto try;
                    114: }
                    115: 
                    116: void
                    117: pipe_kick(int fd)
                    118: {
                    119:   u64 v = 1;
                    120:   int rv;
                    121: 
                    122:  try:
                    123:   rv = write(fd, &v, sizeof(u64));
                    124:   if (rv < 0)
                    125:   {
                    126:     if (errno == EINTR)
                    127:       goto try;
                    128:     if (errno == EAGAIN)
                    129:       return;
                    130:     die("wakeup write: %m");
                    131:   }
                    132: }
                    133: 
                    134: static inline void
                    135: wakeup_init(struct birdloop *loop)
                    136: {
                    137:   pipe_new(loop->wakeup_fds);
                    138: }
                    139: 
                    140: static inline void
                    141: wakeup_drain(struct birdloop *loop)
                    142: {
                    143:   pipe_drain(loop->wakeup_fds[0]);
                    144: }
                    145: 
                    146: static inline void
                    147: wakeup_do_kick(struct birdloop *loop)
                    148: {
                    149:   pipe_kick(loop->wakeup_fds[1]);
                    150: }
                    151: 
                    152: static inline void
                    153: wakeup_kick(struct birdloop *loop)
                    154: {
                    155:   if (!loop->wakeup_masked)
                    156:     wakeup_do_kick(loop);
                    157:   else
                    158:     loop->wakeup_masked = 2;
                    159: }
                    160: 
                    161: /* For notifications from outside */
                    162: void
                    163: wakeup_kick_current(void)
                    164: {
                    165:   struct birdloop *loop = birdloop_current();
                    166: 
                    167:   if (loop && loop->poll_active)
                    168:     wakeup_kick(loop);
                    169: }
                    170: 
                    171: 
                    172: /*
                    173:  *     Events
                    174:  */
                    175: 
                    176: static inline uint
                    177: events_waiting(struct birdloop *loop)
                    178: {
                    179:   return !EMPTY_LIST(loop->event_list);
                    180: }
                    181: 
                    182: static inline void
                    183: events_init(struct birdloop *loop)
                    184: {
                    185:   init_list(&loop->event_list);
                    186: }
                    187: 
                    188: static void
                    189: events_fire(struct birdloop *loop)
                    190: {
                    191:   times_update(&loop->time);
                    192:   ev_run_list(&loop->event_list);
                    193: }
                    194: 
                    195: void
                    196: ev2_schedule(event *e)
                    197: {
                    198:   struct birdloop *loop = birdloop_current();
                    199: 
                    200:   if (loop->poll_active && EMPTY_LIST(loop->event_list))
                    201:     wakeup_kick(loop);
                    202: 
                    203:   if (e->n.next)
                    204:     rem_node(&e->n);
                    205: 
                    206:   add_tail(&loop->event_list, &e->n);
                    207: }
                    208: 
                    209: 
                    210: /*
                    211:  *     Sockets
                    212:  */
                    213: 
                    214: static void
                    215: sockets_init(struct birdloop *loop)
                    216: {
                    217:   init_list(&loop->sock_list);
                    218:   loop->sock_num = 0;
                    219: 
                    220:   BUFFER_INIT(loop->poll_sk, loop->pool, 4);
                    221:   BUFFER_INIT(loop->poll_fd, loop->pool, 4);
                    222:   loop->poll_changed = 1;      /* add wakeup fd */
                    223: }
                    224: 
                    225: static void
                    226: sockets_add(struct birdloop *loop, sock *s)
                    227: {
                    228:   add_tail(&loop->sock_list, &s->n);
                    229:   loop->sock_num++;
                    230: 
                    231:   s->index = -1;
                    232:   loop->poll_changed = 1;
                    233: 
                    234:   if (loop->poll_active)
                    235:     wakeup_kick(loop);
                    236: }
                    237: 
                    238: void
                    239: sk_start(sock *s)
                    240: {
                    241:   struct birdloop *loop = birdloop_current();
                    242: 
                    243:   sockets_add(loop, s);
                    244: }
                    245: 
                    246: static void
                    247: sockets_remove(struct birdloop *loop, sock *s)
                    248: {
                    249:   rem_node(&s->n);
                    250:   loop->sock_num--;
                    251: 
                    252:   if (s->index >= 0)
                    253:     loop->poll_sk.data[s->index] = NULL;
                    254: 
                    255:   s->index = -1;
                    256:   loop->poll_changed = 1;
                    257: 
                    258:   /* Wakeup moved to sk_stop() */
                    259: }
                    260: 
                    261: void
                    262: sk_stop(sock *s)
                    263: {
                    264:   struct birdloop *loop = birdloop_current();
                    265: 
                    266:   sockets_remove(loop, s);
                    267: 
                    268:   if (loop->poll_active)
                    269:   {
                    270:     loop->close_scheduled = 1;
                    271:     wakeup_kick(loop);
                    272:   }
                    273:   else
                    274:     close(s->fd);
                    275: 
                    276:   s->fd = -1;
                    277: }
                    278: 
                    279: static inline uint sk_want_events(sock *s)
                    280: { return (s->rx_hook ? POLLIN : 0) | ((s->ttx != s->tpos) ? POLLOUT : 0); }
                    281: 
                    282: /*
                    283: FIXME: this should be called from sock code
                    284: 
                    285: static void
                    286: sockets_update(struct birdloop *loop, sock *s)
                    287: {
                    288:   if (s->index >= 0)
                    289:     loop->poll_fd.data[s->index].events = sk_want_events(s);
                    290: }
                    291: */
                    292: 
                    293: static void
                    294: sockets_prepare(struct birdloop *loop)
                    295: {
                    296:   BUFFER_SET(loop->poll_sk, loop->sock_num + 1);
                    297:   BUFFER_SET(loop->poll_fd, loop->sock_num + 1);
                    298: 
                    299:   struct pollfd *pfd = loop->poll_fd.data;
                    300:   sock **psk = loop->poll_sk.data;
                    301:   uint i = 0;
                    302:   node *n;
                    303: 
                    304:   WALK_LIST(n, loop->sock_list)
                    305:   {
                    306:     sock *s = SKIP_BACK(sock, n, n);
                    307: 
                    308:     ASSERT(i < loop->sock_num);
                    309: 
                    310:     s->index = i;
                    311:     *psk = s;
                    312:     pfd->fd = s->fd;
                    313:     pfd->events = sk_want_events(s);
                    314:     pfd->revents = 0;
                    315: 
                    316:     pfd++;
                    317:     psk++;
                    318:     i++;
                    319:   }
                    320: 
                    321:   ASSERT(i == loop->sock_num);
                    322: 
                    323:   /* Add internal wakeup fd */
                    324:   *psk = NULL;
                    325:   pfd->fd = loop->wakeup_fds[0];
                    326:   pfd->events = POLLIN;
                    327:   pfd->revents = 0;
                    328: 
                    329:   loop->poll_changed = 0;
                    330: }
                    331: 
                    332: static void
                    333: sockets_close_fds(struct birdloop *loop)
                    334: {
                    335:   struct pollfd *pfd = loop->poll_fd.data;
                    336:   sock **psk = loop->poll_sk.data;
                    337:   int poll_num = loop->poll_fd.used - 1;
                    338: 
                    339:   int i;
                    340:   for (i = 0; i < poll_num; i++)
                    341:     if (psk[i] == NULL)
                    342:       close(pfd[i].fd);
                    343: 
                    344:   loop->close_scheduled = 0;
                    345: }
                    346: 
                    347: int sk_read(sock *s, int revents);
                    348: int sk_write(sock *s);
                    349: 
                    350: static void
                    351: sockets_fire(struct birdloop *loop)
                    352: {
                    353:   struct pollfd *pfd = loop->poll_fd.data;
                    354:   sock **psk = loop->poll_sk.data;
                    355:   int poll_num = loop->poll_fd.used - 1;
                    356: 
                    357:   times_update(&loop->time);
                    358: 
                    359:   /* Last fd is internal wakeup fd */
                    360:   if (pfd[poll_num].revents & POLLIN)
                    361:     wakeup_drain(loop);
                    362: 
                    363:   int i;
                    364:   for (i = 0; i < poll_num; pfd++, psk++, i++)
                    365:   {
                    366:     int e = 1;
                    367: 
                    368:     if (! pfd->revents)
                    369:       continue;
                    370: 
                    371:     if (pfd->revents & POLLNVAL)
                    372:       die("poll: invalid fd %d", pfd->fd);
                    373: 
                    374:     if (pfd->revents & POLLIN)
                    375:       while (e && *psk && (*psk)->rx_hook)
                    376:        e = sk_read(*psk, 0);
                    377: 
                    378:     e = 1;
                    379:     if (pfd->revents & POLLOUT)
                    380:       while (e && *psk)
                    381:        e = sk_write(*psk);
                    382:   }
                    383: }
                    384: 
                    385: 
                    386: /*
                    387:  *     Birdloop
                    388:  */
                    389: 
                    390: static void * birdloop_main(void *arg);
                    391: 
                    392: struct birdloop *
                    393: birdloop_new(void)
                    394: {
                    395:   /* FIXME: this init should be elsewhere and thread-safe */
                    396:   static int init = 0;
                    397:   if (!init)
                    398:     { birdloop_init_current(); init = 1; }
                    399: 
                    400:   pool *p = rp_new(NULL, "Birdloop root");
                    401:   struct birdloop *loop = mb_allocz(p, sizeof(struct birdloop));
                    402:   loop->pool = p;
                    403:   pthread_mutex_init(&loop->mutex, NULL);
                    404: 
                    405:   wakeup_init(loop);
                    406: 
                    407:   events_init(loop);
                    408:   timers_init(&loop->time, p);
                    409:   sockets_init(loop);
                    410: 
                    411:   return loop;
                    412: }
                    413: 
                    414: void
                    415: birdloop_start(struct birdloop *loop)
                    416: {
                    417:   int rv = pthread_create(&loop->thread, NULL, birdloop_main, loop);
                    418:   if (rv)
                    419:     die("pthread_create(): %M", rv);
                    420: }
                    421: 
                    422: void
                    423: birdloop_stop(struct birdloop *loop)
                    424: {
                    425:   pthread_mutex_lock(&loop->mutex);
                    426:   loop->stop_called = 1;
                    427:   wakeup_do_kick(loop);
                    428:   pthread_mutex_unlock(&loop->mutex);
                    429: 
                    430:   int rv = pthread_join(loop->thread, NULL);
                    431:   if (rv)
                    432:     die("pthread_join(): %M", rv);
                    433: }
                    434: 
                    435: void
                    436: birdloop_free(struct birdloop *loop)
                    437: {
                    438:   rfree(loop->pool);
                    439: }
                    440: 
                    441: 
                    442: void
                    443: birdloop_enter(struct birdloop *loop)
                    444: {
                    445:   /* TODO: these functions could save and restore old context */
                    446:   pthread_mutex_lock(&loop->mutex);
                    447:   birdloop_set_current(loop);
                    448: }
                    449: 
                    450: void
                    451: birdloop_leave(struct birdloop *loop)
                    452: {
                    453:   /* TODO: these functions could save and restore old context */
                    454:   birdloop_set_current(NULL);
                    455:   pthread_mutex_unlock(&loop->mutex);
                    456: }
                    457: 
                    458: void
                    459: birdloop_mask_wakeups(struct birdloop *loop)
                    460: {
                    461:   pthread_mutex_lock(&loop->mutex);
                    462:   loop->wakeup_masked = 1;
                    463:   pthread_mutex_unlock(&loop->mutex);
                    464: }
                    465: 
                    466: void
                    467: birdloop_unmask_wakeups(struct birdloop *loop)
                    468: {
                    469:   pthread_mutex_lock(&loop->mutex);
                    470:   if (loop->wakeup_masked == 2)
                    471:     wakeup_do_kick(loop);
                    472:   loop->wakeup_masked = 0;
                    473:   pthread_mutex_unlock(&loop->mutex);
                    474: }
                    475: 
                    476: static void *
                    477: birdloop_main(void *arg)
                    478: {
                    479:   struct birdloop *loop = arg;
                    480:   timer *t;
                    481:   int rv, timeout;
                    482: 
                    483:   birdloop_set_current(loop);
                    484: 
                    485:   pthread_mutex_lock(&loop->mutex);
                    486:   while (1)
                    487:   {
                    488:     events_fire(loop);
                    489:     timers_fire(&loop->time);
                    490: 
                    491:     times_update(&loop->time);
                    492:     if (events_waiting(loop))
                    493:       timeout = 0;
                    494:     else if (t = timers_first(&loop->time))
                    495:       timeout = (tm_remains(t) TO_MS) + 1;
                    496:     else
                    497:       timeout = -1;
                    498: 
                    499:     if (loop->poll_changed)
                    500:       sockets_prepare(loop);
                    501: 
                    502:     loop->poll_active = 1;
                    503:     pthread_mutex_unlock(&loop->mutex);
                    504: 
                    505:   try:
                    506:     rv = poll(loop->poll_fd.data, loop->poll_fd.used, timeout);
                    507:     if (rv < 0)
                    508:     {
                    509:       if (errno == EINTR || errno == EAGAIN)
                    510:        goto try;
                    511:       die("poll: %m");
                    512:     }
                    513: 
                    514:     pthread_mutex_lock(&loop->mutex);
                    515:     loop->poll_active = 0;
                    516: 
                    517:     if (loop->close_scheduled)
                    518:       sockets_close_fds(loop);
                    519: 
                    520:     if (loop->stop_called)
                    521:       break;
                    522: 
                    523:     if (rv)
                    524:       sockets_fire(loop);
                    525: 
                    526:     timers_fire(&loop->time);
                    527:   }
                    528: 
                    529:   loop->stop_called = 0;
                    530:   pthread_mutex_unlock(&loop->mutex);
                    531: 
                    532:   return NULL;
                    533: }
                    534: 
                    535: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>