Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 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> |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 23 | #include <pthread.h> |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 24 | #include <stdlib.h> |
Etan Cohen | 3e59b5b | 2015-03-31 17:15:53 -0700 | [diff] [blame] | 25 | #include <string.h> |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 26 | #include <sys/epoll.h> |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 27 | #include <sys/eventfd.h> |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 28 | |
Sharvil Nanavati | 0f9b91e | 2015-03-12 15:42:50 -0700 | [diff] [blame] | 29 | #include "osi/include/allocator.h" |
| 30 | #include "osi/include/list.h" |
Sharvil Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 31 | #include "osi/include/log.h" |
Sharvil Nanavati | 0f9b91e | 2015-03-12 15:42:50 -0700 | [diff] [blame] | 32 | #include "osi/include/reactor.h" |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 33 | |
| 34 | #if !defined(EFD_SEMAPHORE) |
| 35 | # define EFD_SEMAPHORE (1 << 0) |
| 36 | #endif |
| 37 | |
| 38 | struct reactor_t { |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 39 | int epoll_fd; |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 40 | int event_fd; |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 41 | 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 Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 46 | }; |
| 47 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 48 | struct 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 Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 53 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 54 | 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 | |
| 58 | static reactor_status_t run_reactor(reactor_t *reactor, int iterations); |
| 59 | |
| 60 | static const size_t MAX_EVENTS = 64; |
| 61 | static const eventfd_t EVENT_REACTOR_STOP = 1; |
Sharvil Nanavati | 13959e0 | 2014-07-25 15:12:36 -0700 | [diff] [blame] | 62 | |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 63 | reactor_t *reactor_new(void) { |
Zach Johnson | 384f8a9 | 2014-08-25 23:22:24 -0700 | [diff] [blame] | 64 | reactor_t *ret = (reactor_t *)osi_calloc(sizeof(reactor_t)); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 65 | if (!ret) |
| 66 | return NULL; |
| 67 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 68 | 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 Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 73 | LOG_ERROR("%s unable to create epoll instance: %s", __func__, strerror(errno)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 74 | goto error; |
| 75 | } |
| 76 | |
Sharvil Nanavati | 13959e0 | 2014-07-25 15:12:36 -0700 | [diff] [blame] | 77 | ret->event_fd = eventfd(0, 0); |
Sharvil Nanavati | 2cb2998 | 2014-08-01 17:00:12 -0700 | [diff] [blame] | 78 | if (ret->event_fd == INVALID_FD) { |
Sharvil Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 79 | LOG_ERROR("%s unable to create eventfd: %s", __func__, strerror(errno)); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 80 | goto error; |
| 81 | } |
| 82 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 83 | pthread_mutex_init(&ret->list_lock, NULL); |
| 84 | ret->invalidation_list = list_new(NULL); |
| 85 | if (!ret->invalidation_list) { |
Sharvil Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 86 | LOG_ERROR("%s unable to allocate object invalidation list.", __func__); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 87 | goto error; |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 88 | } |
| 89 | |
Mark Salyzyn | a9962ce | 2015-04-16 11:13:39 -0700 | [diff] [blame] | 90 | struct epoll_event event; |
| 91 | memset(&event, 0, sizeof(event)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 92 | event.events = EPOLLIN; |
| 93 | event.data.ptr = NULL; |
| 94 | if (epoll_ctl(ret->epoll_fd, EPOLL_CTL_ADD, ret->event_fd, &event) == -1) { |
Sharvil Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 95 | LOG_ERROR("%s unable to register eventfd with epoll set: %s", __func__, strerror(errno)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 96 | goto error; |
| 97 | } |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 98 | |
| 99 | return ret; |
| 100 | |
| 101 | error:; |
Zach Johnson | ec4059a | 2014-08-04 20:49:49 -0700 | [diff] [blame] | 102 | reactor_free(ret); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 103 | return NULL; |
| 104 | } |
| 105 | |
| 106 | void reactor_free(reactor_t *reactor) { |
| 107 | if (!reactor) |
| 108 | return; |
| 109 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 110 | list_free(reactor->invalidation_list); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 111 | close(reactor->event_fd); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 112 | close(reactor->epoll_fd); |
Zach Johnson | 384f8a9 | 2014-08-25 23:22:24 -0700 | [diff] [blame] | 113 | osi_free(reactor); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 114 | } |
| 115 | |
| 116 | reactor_status_t reactor_start(reactor_t *reactor) { |
| 117 | assert(reactor != NULL); |
Ajay Kumar | 7be7829 | 2015-01-09 10:19:20 +0530 | [diff] [blame] | 118 | if(reactor) |
| 119 | return run_reactor(reactor, 0); |
| 120 | else { |
| 121 | ALOGE("%s :reactor is NULL",__func__); |
| 122 | return REACTOR_STATUS_ERROR; |
| 123 | } |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 124 | } |
| 125 | |
| 126 | reactor_status_t reactor_run_once(reactor_t *reactor) { |
| 127 | assert(reactor != NULL); |
Ajay Kumar | 7be7829 | 2015-01-09 10:19:20 +0530 | [diff] [blame] | 128 | if(reactor) |
| 129 | return run_reactor(reactor, 1); |
| 130 | else { |
| 131 | ALOGE("%s :reactor is NULL",__func__); |
| 132 | return REACTOR_STATUS_ERROR; |
| 133 | } |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 134 | } |
| 135 | |
| 136 | void reactor_stop(reactor_t *reactor) { |
| 137 | assert(reactor != NULL); |
| 138 | |
Sharvil Nanavati | 13959e0 | 2014-07-25 15:12:36 -0700 | [diff] [blame] | 139 | eventfd_write(reactor->event_fd, EVENT_REACTOR_STOP); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 140 | } |
| 141 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 142 | reactor_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 Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 146 | assert(reactor != NULL); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 147 | assert(fd != INVALID_FD); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 148 | |
Zach Johnson | 384f8a9 | 2014-08-25 23:22:24 -0700 | [diff] [blame] | 149 | reactor_object_t *object = (reactor_object_t *)osi_calloc(sizeof(reactor_object_t)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 150 | if (!object) { |
Sharvil Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 151 | LOG_ERROR("%s unable to allocate reactor object: %s", __func__, strerror(errno)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 152 | 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 Salyzyn | a9962ce | 2015-04-16 11:13:39 -0700 | [diff] [blame] | 162 | struct epoll_event event; |
| 163 | memset(&event, 0, sizeof(event)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 164 | 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 Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 171 | LOG_ERROR("%s unable to register fd %d to epoll set: %s", __func__, fd, strerror(errno)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 172 | pthread_mutex_destroy(&object->lock); |
Zach Johnson | 384f8a9 | 2014-08-25 23:22:24 -0700 | [diff] [blame] | 173 | osi_free(object); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 174 | return NULL; |
| 175 | } |
| 176 | |
| 177 | return object; |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 178 | } |
| 179 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 180 | bool reactor_change_registration(reactor_object_t *object, |
| 181 | void (*read_ready)(void *context), |
| 182 | void (*write_ready)(void *context)) { |
| 183 | assert(object != NULL); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 184 | |
Mark Salyzyn | a9962ce | 2015-04-16 11:13:39 -0700 | [diff] [blame] | 185 | struct epoll_event event; |
| 186 | memset(&event, 0, sizeof(event)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 187 | 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 Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 194 | LOG_ERROR("%s unable to modify interest set for fd %d: %s", __func__, object->fd, strerror(errno)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 195 | 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 Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 204 | } |
| 205 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 206 | void reactor_unregister(reactor_object_t *obj) { |
| 207 | assert(obj != NULL); |
Ajay Kumar | 7be7829 | 2015-01-09 10:19:20 +0530 | [diff] [blame] | 208 | if(!obj) { |
| 209 | ALOGE("%s :obj is NULL",__func__); |
| 210 | return; |
| 211 | } |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 212 | |
| 213 | reactor_t *reactor = obj->reactor; |
| 214 | |
| 215 | if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_DEL, obj->fd, NULL) == -1) |
Sharvil Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 216 | LOG_ERROR("%s unable to unregister fd %d from epoll set: %s", __func__, obj->fd, strerror(errno)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 217 | |
| 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 Johnson | 384f8a9 | 2014-08-25 23:22:24 -0700 | [diff] [blame] | 238 | osi_free(obj); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 239 | } |
| 240 | |
| 241 | // Runs the reactor loop for a maximum of |iterations|. |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 242 | // 0 |iterations| means loop forever. |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 243 | // |reactor| may not be NULL. |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 244 | static reactor_status_t run_reactor(reactor_t *reactor, int iterations) { |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 245 | assert(reactor != NULL); |
Ajay Kumar | 7be7829 | 2015-01-09 10:19:20 +0530 | [diff] [blame] | 246 | if(!reactor) { |
| 247 | ALOGE("%s :reactor is NULL",__func__); |
| 248 | return REACTOR_STATUS_ERROR; |
| 249 | } |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 250 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 251 | reactor->run_thread = pthread_self(); |
| 252 | reactor->is_running = true; |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 253 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 254 | 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 Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 259 | |
| 260 | int ret; |
| 261 | do { |
Sharvil Nanavati | ae973d5 | 2016-06-20 19:16:12 -0700 | [diff] [blame] | 262 | ret = TEMP_FAILURE_RETRY(epoll_wait(reactor->epoll_fd, events, MAX_EVENTS, -1)); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 263 | } while (ret == -1 && errno == EINTR); |
| 264 | |
| 265 | if (ret == -1) { |
Sharvil Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 266 | LOG_ERROR("%s error in epoll_wait: %s", __func__, strerror(errno)); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 267 | reactor->is_running = false; |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 268 | return REACTOR_STATUS_ERROR; |
| 269 | } |
| 270 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 271 | 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 Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 280 | } |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 281 | |
| 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 Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 298 | object->write_ready(object->context); |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 299 | pthread_mutex_unlock(&object->lock); |
| 300 | |
| 301 | if (reactor->object_removed) { |
| 302 | pthread_mutex_destroy(&object->lock); |
Zach Johnson | 384f8a9 | 2014-08-25 23:22:24 -0700 | [diff] [blame] | 303 | osi_free(object); |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 304 | } |
| 305 | } |
| 306 | } |
Zach Johnson | ec4059a | 2014-08-04 20:49:49 -0700 | [diff] [blame] | 307 | |
Sharvil Nanavati | fbf8908 | 2014-08-13 00:40:49 -0700 | [diff] [blame] | 308 | reactor->is_running = false; |
Sharvil Nanavati | 19084c6 | 2014-06-23 16:30:46 -0700 | [diff] [blame] | 309 | return REACTOR_STATUS_DONE; |
| 310 | } |