Home | History | Annotate | Download | only in src
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2014 Google, Inc.
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 
     19 #define LOG_TAG "bt_osi_reactor"
     20 
     21 #include <assert.h>
     22 #include <errno.h>
     23 #include <stdlib.h>
     24 #include <sys/eventfd.h>
     25 #include <sys/select.h>
     26 #include <utils/Log.h>
     27 
     28 #include "list.h"
     29 #include "reactor.h"
     30 
     31 #if !defined(EFD_SEMAPHORE)
     32 #  define EFD_SEMAPHORE (1 << 0)
     33 #endif
     34 
     35 struct reactor_t {
     36   int event_fd;
     37   list_t *objects;
     38 };
     39 
     40 static reactor_status_t run_reactor(reactor_t *reactor, int iterations, struct timeval *tv);
     41 
     42 reactor_t *reactor_new(void) {
     43   reactor_t *ret = (reactor_t *)calloc(1, sizeof(reactor_t));
     44   if (!ret)
     45     return NULL;
     46 
     47   ret->event_fd = eventfd(0, EFD_SEMAPHORE);
     48   if (ret->event_fd == -1) {
     49     ALOGE("%s unable to create eventfd: %s", __func__, strerror(errno));
     50     goto error;
     51   }
     52 
     53   ret->objects = list_new(NULL);
     54   if (!ret->objects)
     55     goto error;
     56 
     57   return ret;
     58 
     59 error:;
     60   list_free(ret->objects);
     61   close(ret->event_fd);
     62   free(ret);
     63   return NULL;
     64 }
     65 
     66 void reactor_free(reactor_t *reactor) {
     67   if (!reactor)
     68     return;
     69 
     70   list_free(reactor->objects);
     71   close(reactor->event_fd);
     72   free(reactor);
     73 }
     74 
     75 reactor_status_t reactor_start(reactor_t *reactor) {
     76   assert(reactor != NULL);
     77   return run_reactor(reactor, 0, NULL);
     78 }
     79 
     80 reactor_status_t reactor_run_once(reactor_t *reactor) {
     81   assert(reactor != NULL);
     82   return run_reactor(reactor, 1, NULL);
     83 }
     84 
     85 reactor_status_t reactor_run_once_timeout(reactor_t *reactor, timeout_t timeout_ms) {
     86   assert(reactor != NULL);
     87 
     88   struct timeval tv;
     89   tv.tv_sec = timeout_ms / 1000;
     90   tv.tv_usec = (timeout_ms % 1000) * 1000;
     91   return run_reactor(reactor, 1, &tv);
     92 }
     93 
     94 void reactor_stop(reactor_t *reactor) {
     95   assert(reactor != NULL);
     96 
     97   eventfd_write(reactor->event_fd, 1);
     98 }
     99 
    100 void reactor_register(reactor_t *reactor, reactor_object_t *obj) {
    101   assert(reactor != NULL);
    102   assert(obj != NULL);
    103 
    104   list_append(reactor->objects, obj);
    105 }
    106 
    107 void reactor_unregister(reactor_t *reactor, reactor_object_t *obj) {
    108   assert(reactor != NULL);
    109   assert(obj != NULL);
    110 
    111   list_remove(reactor->objects, obj);
    112 }
    113 
    114 // Runs the reactor loop for a maximum of |iterations| with the given timeout, |tv|.
    115 // 0 |iterations| means loop forever.
    116 // NULL |tv| means no timeout (block until an event occurs).
    117 // |reactor| may not be NULL.
    118 static reactor_status_t run_reactor(reactor_t *reactor, int iterations, struct timeval *tv) {
    119   assert(reactor != NULL);
    120 
    121   for (int i = 0; iterations == 0 || i < iterations; ++i) {
    122     fd_set read_set;
    123     fd_set write_set;
    124     FD_ZERO(&read_set);
    125     FD_ZERO(&write_set);
    126     FD_SET(reactor->event_fd, &read_set);
    127 
    128     int max_fd = reactor->event_fd;
    129     for (const list_node_t *iter = list_begin(reactor->objects); iter != list_end(reactor->objects); iter = list_next(iter)) {
    130       reactor_object_t *object = (reactor_object_t *)list_node(iter);
    131       int fd = object->fd;
    132       reactor_interest_t interest = object->interest;
    133       if (interest & REACTOR_INTEREST_READ)
    134         FD_SET(fd, &read_set);
    135       if (interest & REACTOR_INTEREST_WRITE)
    136         FD_SET(fd, &write_set);
    137       if (fd > max_fd)
    138         max_fd = fd;
    139     }
    140 
    141     int ret;
    142     do {
    143       ret = select(max_fd + 1, &read_set, &write_set, NULL, tv);
    144     } while (ret == -1 && errno == EINTR);
    145 
    146     if (ret == -1) {
    147       ALOGE("%s error in select: %s", __func__, strerror(errno));
    148       return REACTOR_STATUS_ERROR;
    149     }
    150 
    151     if (ret == 0)
    152       return REACTOR_STATUS_TIMEOUT;
    153 
    154     if (FD_ISSET(reactor->event_fd, &read_set)) {
    155       eventfd_t value;
    156       eventfd_read(reactor->event_fd, &value);
    157       return REACTOR_STATUS_STOP;
    158     }
    159 
    160     for (const list_node_t *iter = list_begin(reactor->objects); ret > 0 && iter != list_end(reactor->objects); iter = list_next(iter)) {
    161       reactor_object_t *object = (reactor_object_t *)list_node(iter);
    162       int fd = object->fd;
    163       if (FD_ISSET(fd, &read_set)) {
    164         object->read_ready(object->context);
    165         --ret;
    166       }
    167       if (FD_ISSET(fd, &write_set)) {
    168         object->write_ready(object->context);
    169         --ret;
    170       }
    171     }
    172   }
    173   return REACTOR_STATUS_DONE;
    174 }
    175