blob: 3c6bca175bdab6d81927fc93dd6a3d931e8149c3 [file] [log] [blame]
Sharvil Nanavati19084c62014-06-23 16:30:46 -07001/******************************************************************************
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);
Ajay Kumar6dded6a2015-01-09 10:19:20 +053077 if(reactor)
78 return run_reactor(reactor, 0, NULL);
79 else {
80 ALOGE("%s :reactor is NULL",__func__);
81 return REACTOR_STATUS_ERROR;
82 }
Sharvil Nanavati19084c62014-06-23 16:30:46 -070083}
84
85reactor_status_t reactor_run_once(reactor_t *reactor) {
86 assert(reactor != NULL);
Ajay Kumar6dded6a2015-01-09 10:19:20 +053087 if(reactor)
88 return run_reactor(reactor, 1, NULL);
89 else {
90 ALOGE("%s :reactor is NULL",__func__);
91 return REACTOR_STATUS_ERROR;
92 }
Sharvil Nanavati19084c62014-06-23 16:30:46 -070093}
94
95reactor_status_t reactor_run_once_timeout(reactor_t *reactor, timeout_t timeout_ms) {
96 assert(reactor != NULL);
97
98 struct timeval tv;
99 tv.tv_sec = timeout_ms / 1000;
100 tv.tv_usec = (timeout_ms % 1000) * 1000;
Ajay Kumar6dded6a2015-01-09 10:19:20 +0530101 if(reactor)
102 return run_reactor(reactor, 1, &tv);
103 else {
104 ALOGE("%s :reactor is NULL",__func__);
105 return REACTOR_STATUS_ERROR;
106 }
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700107}
108
109void reactor_stop(reactor_t *reactor) {
110 assert(reactor != NULL);
Ajay Kumar6dded6a2015-01-09 10:19:20 +0530111 if(reactor)
112 eventfd_write(reactor->event_fd, 1);
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700113}
114
115void reactor_register(reactor_t *reactor, reactor_object_t *obj) {
116 assert(reactor != NULL);
117 assert(obj != NULL);
Ajay Kumar6dded6a2015-01-09 10:19:20 +0530118 if(reactor && obj)
119 list_append(reactor->objects, obj);
120 else
121 ALOGE("%s :reactor or reactor obj is NULL",__func__);
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700122}
123
124void reactor_unregister(reactor_t *reactor, reactor_object_t *obj) {
125 assert(reactor != NULL);
126 assert(obj != NULL);
Ajay Kumar6dded6a2015-01-09 10:19:20 +0530127 if(!reactor || !obj) {
128 ALOGE("%s :reactor or obj is NULL",__func__);
129 return;
130 }
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700131 list_remove(reactor->objects, obj);
132}
133
134// Runs the reactor loop for a maximum of |iterations| with the given timeout, |tv|.
135// 0 |iterations| means loop forever.
136// NULL |tv| means no timeout (block until an event occurs).
137// |reactor| may not be NULL.
138static reactor_status_t run_reactor(reactor_t *reactor, int iterations, struct timeval *tv) {
139 assert(reactor != NULL);
Ajay Kumar6dded6a2015-01-09 10:19:20 +0530140 if(!reactor) {
141 ALOGE("%s :reactor is NULL",__func__);
142 return REACTOR_STATUS_ERROR;
143 }
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700144 for (int i = 0; iterations == 0 || i < iterations; ++i) {
145 fd_set read_set;
146 fd_set write_set;
147 FD_ZERO(&read_set);
148 FD_ZERO(&write_set);
149 FD_SET(reactor->event_fd, &read_set);
150
151 int max_fd = reactor->event_fd;
152 for (const list_node_t *iter = list_begin(reactor->objects); iter != list_end(reactor->objects); iter = list_next(iter)) {
153 reactor_object_t *object = (reactor_object_t *)list_node(iter);
154 int fd = object->fd;
155 reactor_interest_t interest = object->interest;
156 if (interest & REACTOR_INTEREST_READ)
157 FD_SET(fd, &read_set);
158 if (interest & REACTOR_INTEREST_WRITE)
159 FD_SET(fd, &write_set);
160 if (fd > max_fd)
161 max_fd = fd;
162 }
163
164 int ret;
165 do {
Sharvil Nanavati405b5c92016-06-17 14:15:46 -0700166 ret = TEMP_FAILURE_RETRY(select(max_fd + 1, &read_set, &write_set, NULL, tv));
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700167 } while (ret == -1 && errno == EINTR);
168
169 if (ret == -1) {
170 ALOGE("%s error in select: %s", __func__, strerror(errno));
171 return REACTOR_STATUS_ERROR;
172 }
173
174 if (ret == 0)
175 return REACTOR_STATUS_TIMEOUT;
176
177 if (FD_ISSET(reactor->event_fd, &read_set)) {
178 eventfd_t value;
179 eventfd_read(reactor->event_fd, &value);
180 return REACTOR_STATUS_STOP;
181 }
182
183 for (const list_node_t *iter = list_begin(reactor->objects); ret > 0 && iter != list_end(reactor->objects); iter = list_next(iter)) {
184 reactor_object_t *object = (reactor_object_t *)list_node(iter);
185 int fd = object->fd;
186 if (FD_ISSET(fd, &read_set)) {
187 object->read_ready(object->context);
188 --ret;
189 }
190 if (FD_ISSET(fd, &write_set)) {
191 object->write_ready(object->context);
192 --ret;
193 }
194 }
195 }
196 return REACTOR_STATUS_DONE;
197}