blob: 1650c1d7b5678f63f801cd19f3c32e9a1e56e0bb [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>
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070023#include <pthread.h>
Sharvil Nanavati19084c62014-06-23 16:30:46 -070024#include <stdlib.h>
Etan Cohen3e59b5b2015-03-31 17:15:53 -070025#include <string.h>
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070026#include <sys/epoll.h>
Sharvil Nanavati19084c62014-06-23 16:30:46 -070027#include <sys/eventfd.h>
Sharvil Nanavati19084c62014-06-23 16:30:46 -070028
Sharvil Nanavati0f9b91e2015-03-12 15:42:50 -070029#include "osi/include/allocator.h"
30#include "osi/include/list.h"
Sharvil Nanavati44802762014-12-23 23:08:58 -080031#include "osi/include/log.h"
Sharvil Nanavati0f9b91e2015-03-12 15:42:50 -070032#include "osi/include/reactor.h"
Sharvil Nanavati19084c62014-06-23 16:30:46 -070033
34#if !defined(EFD_SEMAPHORE)
35# define EFD_SEMAPHORE (1 << 0)
36#endif
37
38struct reactor_t {
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070039 int epoll_fd;
Sharvil Nanavati19084c62014-06-23 16:30:46 -070040 int event_fd;
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070041 pthread_mutex_t list_lock; // protects invalidation_list.
42 list_t *invalidation_list; // reactor objects that have been unregistered.
43 pthread_t run_thread; // the pthread on which reactor_run is executing.
44 bool is_running; // indicates whether |run_thread| is valid.
45 bool object_removed;
Sharvil Nanavati19084c62014-06-23 16:30:46 -070046};
47
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070048struct reactor_object_t {
49 int fd; // the file descriptor to monitor for events.
50 void *context; // a context that's passed back to the *_ready functions.
51 reactor_t *reactor; // the reactor instance this object is registered with.
52 pthread_mutex_t lock; // protects the lifetime of this object and all variables.
Sharvil Nanavati19084c62014-06-23 16:30:46 -070053
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070054 void (*read_ready)(void *context); // function to call when the file descriptor becomes readable.
55 void (*write_ready)(void *context); // function to call when the file descriptor becomes writeable.
56};
57
58static reactor_status_t run_reactor(reactor_t *reactor, int iterations);
59
60static const size_t MAX_EVENTS = 64;
61static const eventfd_t EVENT_REACTOR_STOP = 1;
Sharvil Nanavati13959e02014-07-25 15:12:36 -070062
Sharvil Nanavati19084c62014-06-23 16:30:46 -070063reactor_t *reactor_new(void) {
Zach Johnson384f8a92014-08-25 23:22:24 -070064 reactor_t *ret = (reactor_t *)osi_calloc(sizeof(reactor_t));
Sharvil Nanavati19084c62014-06-23 16:30:46 -070065 if (!ret)
66 return NULL;
67
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070068 ret->epoll_fd = INVALID_FD;
69 ret->event_fd = INVALID_FD;
70
71 ret->epoll_fd = epoll_create(MAX_EVENTS);
72 if (ret->epoll_fd == INVALID_FD) {
Sharvil Nanavati44802762014-12-23 23:08:58 -080073 LOG_ERROR("%s unable to create epoll instance: %s", __func__, strerror(errno));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070074 goto error;
75 }
76
Sharvil Nanavati13959e02014-07-25 15:12:36 -070077 ret->event_fd = eventfd(0, 0);
Sharvil Nanavati2cb29982014-08-01 17:00:12 -070078 if (ret->event_fd == INVALID_FD) {
Sharvil Nanavati44802762014-12-23 23:08:58 -080079 LOG_ERROR("%s unable to create eventfd: %s", __func__, strerror(errno));
Sharvil Nanavati19084c62014-06-23 16:30:46 -070080 goto error;
81 }
82
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070083 pthread_mutex_init(&ret->list_lock, NULL);
84 ret->invalidation_list = list_new(NULL);
85 if (!ret->invalidation_list) {
Sharvil Nanavati44802762014-12-23 23:08:58 -080086 LOG_ERROR("%s unable to allocate object invalidation list.", __func__);
Sharvil Nanavati19084c62014-06-23 16:30:46 -070087 goto error;
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070088 }
89
Mark Salyzyna9962ce2015-04-16 11:13:39 -070090 struct epoll_event event;
91 memset(&event, 0, sizeof(event));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070092 event.events = EPOLLIN;
93 event.data.ptr = NULL;
94 if (epoll_ctl(ret->epoll_fd, EPOLL_CTL_ADD, ret->event_fd, &event) == -1) {
Sharvil Nanavati44802762014-12-23 23:08:58 -080095 LOG_ERROR("%s unable to register eventfd with epoll set: %s", __func__, strerror(errno));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -070096 goto error;
97 }
Sharvil Nanavati19084c62014-06-23 16:30:46 -070098
99 return ret;
100
101error:;
Zach Johnsonec4059a2014-08-04 20:49:49 -0700102 reactor_free(ret);
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700103 return NULL;
104}
105
106void reactor_free(reactor_t *reactor) {
107 if (!reactor)
108 return;
109
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700110 list_free(reactor->invalidation_list);
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700111 close(reactor->event_fd);
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700112 close(reactor->epoll_fd);
Zach Johnson384f8a92014-08-25 23:22:24 -0700113 osi_free(reactor);
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700114}
115
116reactor_status_t reactor_start(reactor_t *reactor) {
117 assert(reactor != NULL);
Ajay Kumar7be78292015-01-09 10:19:20 +0530118 if(reactor)
119 return run_reactor(reactor, 0);
120 else {
121 ALOGE("%s :reactor is NULL",__func__);
122 return REACTOR_STATUS_ERROR;
123 }
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700124}
125
126reactor_status_t reactor_run_once(reactor_t *reactor) {
127 assert(reactor != NULL);
Ajay Kumar7be78292015-01-09 10:19:20 +0530128 if(reactor)
129 return run_reactor(reactor, 1);
130 else {
131 ALOGE("%s :reactor is NULL",__func__);
132 return REACTOR_STATUS_ERROR;
133 }
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700134}
135
136void reactor_stop(reactor_t *reactor) {
137 assert(reactor != NULL);
138
Sharvil Nanavati13959e02014-07-25 15:12:36 -0700139 eventfd_write(reactor->event_fd, EVENT_REACTOR_STOP);
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700140}
141
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700142reactor_object_t *reactor_register(reactor_t *reactor,
143 int fd, void *context,
144 void (*read_ready)(void *context),
145 void (*write_ready)(void *context)) {
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700146 assert(reactor != NULL);
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700147 assert(fd != INVALID_FD);
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700148
Zach Johnson384f8a92014-08-25 23:22:24 -0700149 reactor_object_t *object = (reactor_object_t *)osi_calloc(sizeof(reactor_object_t));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700150 if (!object) {
Sharvil Nanavati44802762014-12-23 23:08:58 -0800151 LOG_ERROR("%s unable to allocate reactor object: %s", __func__, strerror(errno));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700152 return NULL;
153 }
154
155 object->reactor = reactor;
156 object->fd = fd;
157 object->context = context;
158 object->read_ready = read_ready;
159 object->write_ready = write_ready;
160 pthread_mutex_init(&object->lock, NULL);
161
Mark Salyzyna9962ce2015-04-16 11:13:39 -0700162 struct epoll_event event;
163 memset(&event, 0, sizeof(event));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700164 if (read_ready)
165 event.events |= (EPOLLIN | EPOLLRDHUP);
166 if (write_ready)
167 event.events |= EPOLLOUT;
168 event.data.ptr = object;
169
170 if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1) {
Sharvil Nanavati44802762014-12-23 23:08:58 -0800171 LOG_ERROR("%s unable to register fd %d to epoll set: %s", __func__, fd, strerror(errno));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700172 pthread_mutex_destroy(&object->lock);
Zach Johnson384f8a92014-08-25 23:22:24 -0700173 osi_free(object);
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700174 return NULL;
175 }
176
177 return object;
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700178}
179
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700180bool reactor_change_registration(reactor_object_t *object,
181 void (*read_ready)(void *context),
182 void (*write_ready)(void *context)) {
183 assert(object != NULL);
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700184
Mark Salyzyna9962ce2015-04-16 11:13:39 -0700185 struct epoll_event event;
186 memset(&event, 0, sizeof(event));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700187 if (read_ready)
188 event.events |= (EPOLLIN | EPOLLRDHUP);
189 if (write_ready)
190 event.events |= EPOLLOUT;
191 event.data.ptr = object;
192
193 if (epoll_ctl(object->reactor->epoll_fd, EPOLL_CTL_MOD, object->fd, &event) == -1) {
Sharvil Nanavati44802762014-12-23 23:08:58 -0800194 LOG_ERROR("%s unable to modify interest set for fd %d: %s", __func__, object->fd, strerror(errno));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700195 return false;
196 }
197
198 pthread_mutex_lock(&object->lock);
199 object->read_ready = read_ready;
200 object->write_ready = write_ready;
201 pthread_mutex_unlock(&object->lock);
202
203 return true;
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700204}
205
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700206void reactor_unregister(reactor_object_t *obj) {
207 assert(obj != NULL);
Ajay Kumar7be78292015-01-09 10:19:20 +0530208 if(!obj) {
209 ALOGE("%s :obj is NULL",__func__);
210 return;
211 }
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700212
213 reactor_t *reactor = obj->reactor;
214
215 if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_DEL, obj->fd, NULL) == -1)
Sharvil Nanavati44802762014-12-23 23:08:58 -0800216 LOG_ERROR("%s unable to unregister fd %d from epoll set: %s", __func__, obj->fd, strerror(errno));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700217
218 if (reactor->is_running && pthread_equal(pthread_self(), reactor->run_thread)) {
219 reactor->object_removed = true;
220 return;
221 }
222
223 pthread_mutex_lock(&reactor->list_lock);
224 list_append(reactor->invalidation_list, obj);
225 pthread_mutex_unlock(&reactor->list_lock);
226
227 // Taking the object lock here makes sure a callback for |obj| isn't
228 // currently executing. The reactor thread must then either be before
229 // the callbacks or after. If after, we know that the object won't be
230 // referenced because it has been taken out of the epoll set. If before,
231 // it won't be referenced because the reactor thread will check the
232 // invalidation_list and find it in there. So by taking this lock, we
233 // are waiting until the reactor thread drops all references to |obj|.
234 // One the wait completes, we can unlock and destroy |obj| safely.
235 pthread_mutex_lock(&obj->lock);
236 pthread_mutex_unlock(&obj->lock);
237 pthread_mutex_destroy(&obj->lock);
Zach Johnson384f8a92014-08-25 23:22:24 -0700238 osi_free(obj);
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700239}
240
241// Runs the reactor loop for a maximum of |iterations|.
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700242// 0 |iterations| means loop forever.
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700243// |reactor| may not be NULL.
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700244static reactor_status_t run_reactor(reactor_t *reactor, int iterations) {
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700245 assert(reactor != NULL);
Ajay Kumar7be78292015-01-09 10:19:20 +0530246 if(!reactor) {
247 ALOGE("%s :reactor is NULL",__func__);
248 return REACTOR_STATUS_ERROR;
249 }
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700250
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700251 reactor->run_thread = pthread_self();
252 reactor->is_running = true;
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700253
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700254 struct epoll_event events[MAX_EVENTS];
255 for (int i = 0; iterations == 0 || i < iterations; ++i) {
256 pthread_mutex_lock(&reactor->list_lock);
257 list_clear(reactor->invalidation_list);
258 pthread_mutex_unlock(&reactor->list_lock);
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700259
260 int ret;
261 do {
Sharvil Nanavatiae973d52016-06-20 19:16:12 -0700262 ret = TEMP_FAILURE_RETRY(epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, -1));
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700263 } while (ret == -1 && errno == EINTR);
264
265 if (ret == -1) {
Sharvil Nanavati44802762014-12-23 23:08:58 -0800266 LOG_ERROR("%s error in epoll_wait: %s", __func__, strerror(errno));
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700267 reactor->is_running = false;
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700268 return REACTOR_STATUS_ERROR;
269 }
270
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700271 for (int j = 0; j < ret; ++j) {
272 // The event file descriptor is the only one that registers with
273 // a NULL data pointer. We use the NULL to identify it and break
274 // out of the reactor loop.
275 if (events[j].data.ptr == NULL) {
276 eventfd_t value;
277 eventfd_read(reactor->event_fd, &value);
278 reactor->is_running = false;
279 return REACTOR_STATUS_STOP;
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700280 }
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700281
282 reactor_object_t *object = (reactor_object_t *)events[j].data.ptr;
283
284 pthread_mutex_lock(&reactor->list_lock);
285 if (list_contains(reactor->invalidation_list, object)) {
286 pthread_mutex_unlock(&reactor->list_lock);
287 continue;
288 }
289
290 // Downgrade the list lock to an object lock.
291 pthread_mutex_lock(&object->lock);
292 pthread_mutex_unlock(&reactor->list_lock);
293
294 reactor->object_removed = false;
295 if (events[j].events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) && object->read_ready)
296 object->read_ready(object->context);
297 if (!reactor->object_removed && events[j].events & EPOLLOUT && object->write_ready)
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700298 object->write_ready(object->context);
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700299 pthread_mutex_unlock(&object->lock);
300
301 if (reactor->object_removed) {
302 pthread_mutex_destroy(&object->lock);
Zach Johnson384f8a92014-08-25 23:22:24 -0700303 osi_free(object);
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700304 }
305 }
306 }
Zach Johnsonec4059a2014-08-04 20:49:49 -0700307
Sharvil Nanavatifbf89082014-08-13 00:40:49 -0700308 reactor->is_running = false;
Sharvil Nanavati19084c62014-06-23 16:30:46 -0700309 return REACTOR_STATUS_DONE;
310}