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
35struct reactor_t {
36  int event_fd;
37  list_t *objects;
38};
39
40static reactor_status_t run_reactor(reactor_t *reactor, int iterations, struct timeval *tv);
41
42reactor_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
59error:;
60  list_free(ret->objects);
61  close(ret->event_fd);
62  free(ret);
63  return NULL;
64}
65
66void 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
75reactor_status_t reactor_start(reactor_t *reactor) {
76  assert(reactor != NULL);
77  return run_reactor(reactor, 0, NULL);
78}
79
80reactor_status_t reactor_run_once(reactor_t *reactor) {
81  assert(reactor != NULL);
82  return run_reactor(reactor, 1, NULL);
83}
84
85reactor_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
94void reactor_stop(reactor_t *reactor) {
95  assert(reactor != NULL);
96
97  eventfd_write(reactor->event_fd, 1);
98}
99
100void 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
107void 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.
118static 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