OSDN Git Service

968fe4bba85fbf56df49de211f0a8a8a9ab04abb
[android-x86/system-bt.git] / osi / src / reactor.c
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 <pthread.h>
24 #include <stdlib.h>
25 #include <sys/epoll.h>
26 #include <sys/eventfd.h>
27
28 #include "osi/include/allocator.h"
29 #include "osi/include/list.h"
30 #include "osi/include/log.h"
31 #include "osi/include/reactor.h"
32
33 #if !defined(EFD_SEMAPHORE)
34 #  define EFD_SEMAPHORE (1 << 0)
35 #endif
36
37 struct reactor_t {
38   int epoll_fd;
39   int event_fd;
40   pthread_mutex_t list_lock;  // protects invalidation_list.
41   list_t *invalidation_list;  // reactor objects that have been unregistered.
42   pthread_t run_thread;       // the pthread on which reactor_run is executing.
43   bool is_running;            // indicates whether |run_thread| is valid.
44   bool object_removed;
45 };
46
47 struct reactor_object_t {
48   int fd;                              // the file descriptor to monitor for events.
49   void *context;                       // a context that's passed back to the *_ready functions.
50   reactor_t *reactor;                  // the reactor instance this object is registered with.
51   pthread_mutex_t lock;                // protects the lifetime of this object and all variables.
52
53   void (*read_ready)(void *context);   // function to call when the file descriptor becomes readable.
54   void (*write_ready)(void *context);  // function to call when the file descriptor becomes writeable.
55 };
56
57 static reactor_status_t run_reactor(reactor_t *reactor, int iterations);
58
59 static const size_t MAX_EVENTS = 64;
60 static const eventfd_t EVENT_REACTOR_STOP = 1;
61
62 reactor_t *reactor_new(void) {
63   reactor_t *ret = (reactor_t *)osi_calloc(sizeof(reactor_t));
64   if (!ret)
65     return NULL;
66
67   ret->epoll_fd = INVALID_FD;
68   ret->event_fd = INVALID_FD;
69
70   ret->epoll_fd = epoll_create(MAX_EVENTS);
71   if (ret->epoll_fd == INVALID_FD) {
72     LOG_ERROR("%s unable to create epoll instance: %s", __func__, strerror(errno));
73     goto error;
74   }
75
76   ret->event_fd = eventfd(0, 0);
77   if (ret->event_fd == INVALID_FD) {
78     LOG_ERROR("%s unable to create eventfd: %s", __func__, strerror(errno));
79     goto error;
80   }
81
82   pthread_mutex_init(&ret->list_lock, NULL);
83   ret->invalidation_list = list_new(NULL);
84   if (!ret->invalidation_list) {
85     LOG_ERROR("%s unable to allocate object invalidation list.", __func__);
86     goto error;
87   }
88
89   struct epoll_event event = { 0 };
90   event.events = EPOLLIN;
91   event.data.ptr = NULL;
92   if (epoll_ctl(ret->epoll_fd, EPOLL_CTL_ADD, ret->event_fd, &event) == -1) {
93     LOG_ERROR("%s unable to register eventfd with epoll set: %s", __func__, strerror(errno));
94     goto error;
95   }
96
97   return ret;
98
99 error:;
100   reactor_free(ret);
101   return NULL;
102 }
103
104 void reactor_free(reactor_t *reactor) {
105   if (!reactor)
106     return;
107
108   list_free(reactor->invalidation_list);
109   close(reactor->event_fd);
110   close(reactor->epoll_fd);
111   osi_free(reactor);
112 }
113
114 reactor_status_t reactor_start(reactor_t *reactor) {
115   assert(reactor != NULL);
116   return run_reactor(reactor, 0);
117 }
118
119 reactor_status_t reactor_run_once(reactor_t *reactor) {
120   assert(reactor != NULL);
121   return run_reactor(reactor, 1);
122 }
123
124 void reactor_stop(reactor_t *reactor) {
125   assert(reactor != NULL);
126
127   eventfd_write(reactor->event_fd, EVENT_REACTOR_STOP);
128 }
129
130 reactor_object_t *reactor_register(reactor_t *reactor,
131     int fd, void *context,
132     void (*read_ready)(void *context),
133     void (*write_ready)(void *context)) {
134   assert(reactor != NULL);
135   assert(fd != INVALID_FD);
136
137   reactor_object_t *object = (reactor_object_t *)osi_calloc(sizeof(reactor_object_t));
138   if (!object) {
139     LOG_ERROR("%s unable to allocate reactor object: %s", __func__, strerror(errno));
140     return NULL;
141   }
142
143   object->reactor = reactor;
144   object->fd = fd;
145   object->context = context;
146   object->read_ready = read_ready;
147   object->write_ready = write_ready;
148   pthread_mutex_init(&object->lock, NULL);
149
150   struct epoll_event event = { 0 };
151   event.events = 0;
152   if (read_ready)
153     event.events |= (EPOLLIN | EPOLLRDHUP);
154   if (write_ready)
155     event.events |= EPOLLOUT;
156   event.data.ptr = object;
157
158   if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1) {
159     LOG_ERROR("%s unable to register fd %d to epoll set: %s", __func__, fd, strerror(errno));
160     pthread_mutex_destroy(&object->lock);
161     osi_free(object);
162     return NULL;
163   }
164
165   return object;
166 }
167
168 bool reactor_change_registration(reactor_object_t *object,
169     void (*read_ready)(void *context),
170     void (*write_ready)(void *context)) {
171   assert(object != NULL);
172
173   struct epoll_event event = { 0 };
174   event.events = 0;
175   if (read_ready)
176     event.events |= (EPOLLIN | EPOLLRDHUP);
177   if (write_ready)
178     event.events |= EPOLLOUT;
179   event.data.ptr = object;
180
181   if (epoll_ctl(object->reactor->epoll_fd, EPOLL_CTL_MOD, object->fd, &event) == -1) {
182     LOG_ERROR("%s unable to modify interest set for fd %d: %s", __func__, object->fd, strerror(errno));
183     return false;
184   }
185
186   pthread_mutex_lock(&object->lock);
187   object->read_ready = read_ready;
188   object->write_ready = write_ready;
189   pthread_mutex_unlock(&object->lock);
190
191   return true;
192 }
193
194 void reactor_unregister(reactor_object_t *obj) {
195   assert(obj != NULL);
196
197   reactor_t *reactor = obj->reactor;
198
199   if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_DEL, obj->fd, NULL) == -1)
200     LOG_ERROR("%s unable to unregister fd %d from epoll set: %s", __func__, obj->fd, strerror(errno));
201
202   if (reactor->is_running && pthread_equal(pthread_self(), reactor->run_thread)) {
203     reactor->object_removed = true;
204     return;
205   }
206
207   pthread_mutex_lock(&reactor->list_lock);
208   list_append(reactor->invalidation_list, obj);
209   pthread_mutex_unlock(&reactor->list_lock);
210
211   // Taking the object lock here makes sure a callback for |obj| isn't
212   // currently executing. The reactor thread must then either be before
213   // the callbacks or after. If after, we know that the object won't be
214   // referenced because it has been taken out of the epoll set. If before,
215   // it won't be referenced because the reactor thread will check the
216   // invalidation_list and find it in there. So by taking this lock, we
217   // are waiting until the reactor thread drops all references to |obj|.
218   // One the wait completes, we can unlock and destroy |obj| safely.
219   pthread_mutex_lock(&obj->lock);
220   pthread_mutex_unlock(&obj->lock);
221   pthread_mutex_destroy(&obj->lock);
222   osi_free(obj);
223 }
224
225 // Runs the reactor loop for a maximum of |iterations|.
226 // 0 |iterations| means loop forever.
227 // |reactor| may not be NULL.
228 static reactor_status_t run_reactor(reactor_t *reactor, int iterations) {
229   assert(reactor != NULL);
230
231   reactor->run_thread = pthread_self();
232   reactor->is_running = true;
233
234   struct epoll_event events[MAX_EVENTS];
235   for (int i = 0; iterations == 0 || i < iterations; ++i) {
236     pthread_mutex_lock(&reactor->list_lock);
237     list_clear(reactor->invalidation_list);
238     pthread_mutex_unlock(&reactor->list_lock);
239
240     int ret;
241     do {
242       ret = epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, -1);
243     } while (ret == -1 && errno == EINTR);
244
245     if (ret == -1) {
246       LOG_ERROR("%s error in epoll_wait: %s", __func__, strerror(errno));
247       reactor->is_running = false;
248       return REACTOR_STATUS_ERROR;
249     }
250
251     for (int j = 0; j < ret; ++j) {
252       // The event file descriptor is the only one that registers with
253       // a NULL data pointer. We use the NULL to identify it and break
254       // out of the reactor loop.
255       if (events[j].data.ptr == NULL) {
256         eventfd_t value;
257         eventfd_read(reactor->event_fd, &value);
258         reactor->is_running = false;
259         return REACTOR_STATUS_STOP;
260       }
261
262       reactor_object_t *object = (reactor_object_t *)events[j].data.ptr;
263
264       pthread_mutex_lock(&reactor->list_lock);
265       if (list_contains(reactor->invalidation_list, object)) {
266         pthread_mutex_unlock(&reactor->list_lock);
267         continue;
268       }
269
270       // Downgrade the list lock to an object lock.
271       pthread_mutex_lock(&object->lock);
272       pthread_mutex_unlock(&reactor->list_lock);
273
274       reactor->object_removed = false;
275       if (events[j].events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) && object->read_ready)
276         object->read_ready(object->context);
277       if (!reactor->object_removed && events[j].events & EPOLLOUT && object->write_ready)
278         object->write_ready(object->context);
279       pthread_mutex_unlock(&object->lock);
280
281       if (reactor->object_removed) {
282         pthread_mutex_destroy(&object->lock);
283         osi_free(object);
284       }
285     }
286   }
287
288   reactor->is_running = false;
289   return REACTOR_STATUS_DONE;
290 }