Sharvil Nanavati | c5856ba | 2014-06-23 12:25:40 -0700 | [diff] [blame] | 1 | /****************************************************************************** |
| 2 | * |
Jakub Pawlowski | 5b790fe | 2017-09-18 09:00:20 -0700 | [diff] [blame] | 3 | * Copyright 2014 Google, Inc. |
Sharvil Nanavati | c5856ba | 2014-06-23 12:25:40 -0700 | [diff] [blame] | 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 | |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 19 | #include <base/logging.h> |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 20 | #include <string.h> |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 21 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 22 | #include <mutex> |
| 23 | |
Sharvil Nanavati | 0f9b91e | 2015-03-12 15:42:50 -0700 | [diff] [blame] | 24 | #include "osi/include/allocator.h" |
| 25 | #include "osi/include/fixed_queue.h" |
| 26 | #include "osi/include/list.h" |
| 27 | #include "osi/include/osi.h" |
Sharvil Nanavati | 0f9b91e | 2015-03-12 15:42:50 -0700 | [diff] [blame] | 28 | #include "osi/include/reactor.h" |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 29 | #include "osi/include/semaphore.h" |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 30 | |
Etan Cohen | 3e59b5b | 2015-03-31 17:15:53 -0700 | [diff] [blame] | 31 | typedef struct fixed_queue_t { |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 32 | list_t* list; |
| 33 | semaphore_t* enqueue_sem; |
| 34 | semaphore_t* dequeue_sem; |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 35 | std::mutex* mutex; |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 36 | size_t capacity; |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 37 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 38 | reactor_object_t* dequeue_object; |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 39 | fixed_queue_cb dequeue_ready; |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 40 | void* dequeue_context; |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 41 | } fixed_queue_t; |
| 42 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 43 | static void internal_dequeue_ready(void* context); |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 44 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 45 | fixed_queue_t* fixed_queue_new(size_t capacity) { |
| 46 | fixed_queue_t* ret = |
| 47 | static_cast<fixed_queue_t*>(osi_calloc(sizeof(fixed_queue_t))); |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 48 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 49 | ret->mutex = new std::mutex; |
Zach Johnson | 384f8a9 | 2014-08-25 23:22:24 -0700 | [diff] [blame] | 50 | ret->capacity = capacity; |
| 51 | |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 52 | ret->list = list_new(NULL); |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 53 | if (!ret->list) goto error; |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 54 | |
| 55 | ret->enqueue_sem = semaphore_new(capacity); |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 56 | if (!ret->enqueue_sem) goto error; |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 57 | |
| 58 | ret->dequeue_sem = semaphore_new(0); |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 59 | if (!ret->dequeue_sem) goto error; |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 60 | |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 61 | return ret; |
| 62 | |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 63 | error: |
Zach Johnson | 384f8a9 | 2014-08-25 23:22:24 -0700 | [diff] [blame] | 64 | fixed_queue_free(ret, NULL); |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 65 | return NULL; |
| 66 | } |
| 67 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 68 | void fixed_queue_free(fixed_queue_t* queue, fixed_queue_free_cb free_cb) { |
| 69 | if (!queue) return; |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 70 | |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 71 | fixed_queue_unregister_dequeue(queue); |
| 72 | |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 73 | if (free_cb) |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 74 | for (const list_node_t* node = list_begin(queue->list); |
| 75 | node != list_end(queue->list); node = list_next(node)) |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 76 | free_cb(list_node(node)); |
| 77 | |
| 78 | list_free(queue->list); |
| 79 | semaphore_free(queue->enqueue_sem); |
| 80 | semaphore_free(queue->dequeue_sem); |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 81 | delete queue->mutex; |
Zach Johnson | 384f8a9 | 2014-08-25 23:22:24 -0700 | [diff] [blame] | 82 | osi_free(queue); |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 83 | } |
| 84 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 85 | void fixed_queue_flush(fixed_queue_t* queue, fixed_queue_free_cb free_cb) { |
| 86 | if (!queue) return; |
Pavlin Radoslavov | 3335cf4 | 2016-08-19 15:32:30 -0700 | [diff] [blame] | 87 | |
| 88 | while (!fixed_queue_is_empty(queue)) { |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 89 | void* data = fixed_queue_try_dequeue(queue); |
Pavlin Radoslavov | 3335cf4 | 2016-08-19 15:32:30 -0700 | [diff] [blame] | 90 | if (free_cb != NULL) { |
| 91 | free_cb(data); |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 96 | bool fixed_queue_is_empty(fixed_queue_t* queue) { |
| 97 | if (queue == NULL) return true; |
Zach Johnson | 93a1c80 | 2014-07-30 13:40:09 -0700 | [diff] [blame] | 98 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 99 | std::lock_guard<std::mutex> lock(*queue->mutex); |
| 100 | return list_is_empty(queue->list); |
Zach Johnson | 93a1c80 | 2014-07-30 13:40:09 -0700 | [diff] [blame] | 101 | } |
| 102 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 103 | size_t fixed_queue_length(fixed_queue_t* queue) { |
| 104 | if (queue == NULL) return 0; |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 105 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 106 | std::lock_guard<std::mutex> lock(*queue->mutex); |
| 107 | return list_length(queue->list); |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 108 | } |
| 109 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 110 | size_t fixed_queue_capacity(fixed_queue_t* queue) { |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 111 | CHECK(queue != NULL); |
Chris Manton | c446cbe | 2014-08-05 11:07:23 -0700 | [diff] [blame] | 112 | |
| 113 | return queue->capacity; |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 114 | } |
| 115 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 116 | void fixed_queue_enqueue(fixed_queue_t* queue, void* data) { |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 117 | CHECK(queue != NULL); |
| 118 | CHECK(data != NULL); |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 119 | |
| 120 | semaphore_wait(queue->enqueue_sem); |
| 121 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 122 | { |
| 123 | std::lock_guard<std::mutex> lock(*queue->mutex); |
| 124 | list_append(queue->list, data); |
| 125 | } |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 126 | |
| 127 | semaphore_post(queue->dequeue_sem); |
| 128 | } |
| 129 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 130 | void* fixed_queue_dequeue(fixed_queue_t* queue) { |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 131 | CHECK(queue != NULL); |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 132 | |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 133 | semaphore_wait(queue->dequeue_sem); |
| 134 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 135 | void* ret = NULL; |
| 136 | { |
| 137 | std::lock_guard<std::mutex> lock(*queue->mutex); |
| 138 | ret = list_front(queue->list); |
| 139 | list_remove(queue->list, ret); |
| 140 | } |
Sharvil Nanavati | c5856ba | 2014-06-23 12:25:40 -0700 | [diff] [blame] | 141 | |
| 142 | semaphore_post(queue->enqueue_sem); |
| 143 | |
| 144 | return ret; |
| 145 | } |
| 146 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 147 | bool fixed_queue_try_enqueue(fixed_queue_t* queue, void* data) { |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 148 | CHECK(queue != NULL); |
| 149 | CHECK(data != NULL); |
Sharvil Nanavati | c5856ba | 2014-06-23 12:25:40 -0700 | [diff] [blame] | 150 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 151 | if (!semaphore_try_wait(queue->enqueue_sem)) return false; |
Sharvil Nanavati | c5856ba | 2014-06-23 12:25:40 -0700 | [diff] [blame] | 152 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 153 | { |
| 154 | std::lock_guard<std::mutex> lock(*queue->mutex); |
| 155 | list_append(queue->list, data); |
| 156 | } |
Sharvil Nanavati | c5856ba | 2014-06-23 12:25:40 -0700 | [diff] [blame] | 157 | |
| 158 | semaphore_post(queue->dequeue_sem); |
| 159 | return true; |
| 160 | } |
| 161 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 162 | void* fixed_queue_try_dequeue(fixed_queue_t* queue) { |
| 163 | if (queue == NULL) return NULL; |
Sharvil Nanavati | c5856ba | 2014-06-23 12:25:40 -0700 | [diff] [blame] | 164 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 165 | if (!semaphore_try_wait(queue->dequeue_sem)) return NULL; |
Sharvil Nanavati | c5856ba | 2014-06-23 12:25:40 -0700 | [diff] [blame] | 166 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 167 | void* ret = NULL; |
| 168 | { |
| 169 | std::lock_guard<std::mutex> lock(*queue->mutex); |
| 170 | ret = list_front(queue->list); |
| 171 | list_remove(queue->list, ret); |
| 172 | } |
Sharvil Nanavati | c11b407 | 2014-05-02 23:55:09 -0700 | [diff] [blame] | 173 | |
| 174 | semaphore_post(queue->enqueue_sem); |
| 175 | |
| 176 | return ret; |
| 177 | } |
Sharvil Nanavati | ab606b5 | 2014-07-04 16:33:37 -0700 | [diff] [blame] | 178 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 179 | void* fixed_queue_try_peek_first(fixed_queue_t* queue) { |
| 180 | if (queue == NULL) return NULL; |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 181 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 182 | std::lock_guard<std::mutex> lock(*queue->mutex); |
| 183 | return list_is_empty(queue->list) ? NULL : list_front(queue->list); |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 184 | } |
| 185 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 186 | void* fixed_queue_try_peek_last(fixed_queue_t* queue) { |
| 187 | if (queue == NULL) return NULL; |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 188 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 189 | std::lock_guard<std::mutex> lock(*queue->mutex); |
| 190 | return list_is_empty(queue->list) ? NULL : list_back(queue->list); |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 191 | } |
| 192 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 193 | void* fixed_queue_try_remove_from_queue(fixed_queue_t* queue, void* data) { |
| 194 | if (queue == NULL) return NULL; |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 195 | |
Pavlin Radoslavov | 153bdfb | 2015-11-13 18:36:56 -0800 | [diff] [blame] | 196 | bool removed = false; |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 197 | { |
| 198 | std::lock_guard<std::mutex> lock(*queue->mutex); |
| 199 | if (list_contains(queue->list, data) && |
| 200 | semaphore_try_wait(queue->dequeue_sem)) { |
| 201 | removed = list_remove(queue->list, data); |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 202 | CHECK(removed); |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 203 | } |
Pavlin Radoslavov | 153bdfb | 2015-11-13 18:36:56 -0800 | [diff] [blame] | 204 | } |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 205 | |
Pavlin Radoslavov | 153bdfb | 2015-11-13 18:36:56 -0800 | [diff] [blame] | 206 | if (removed) { |
| 207 | semaphore_post(queue->enqueue_sem); |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 208 | return data; |
Pavlin Radoslavov | 153bdfb | 2015-11-13 18:36:56 -0800 | [diff] [blame] | 209 | } |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 210 | return NULL; |
| 211 | } |
| 212 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 213 | list_t* fixed_queue_get_list(fixed_queue_t* queue) { |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 214 | CHECK(queue != NULL); |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 215 | |
Marie Janssen | 21da637 | 2016-11-02 18:31:55 -0700 | [diff] [blame] | 216 | // NOTE: Using the list in this way is not thread-safe. |
| 217 | // Using this list in any context where threads can call other functions |
| 218 | // to the queue can break our assumptions and the queue in general. |
Pavlin Radoslavov | 1a3844f | 2015-09-25 11:21:15 -0700 | [diff] [blame] | 219 | return queue->list; |
| 220 | } |
| 221 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 222 | int fixed_queue_get_dequeue_fd(const fixed_queue_t* queue) { |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 223 | CHECK(queue != NULL); |
Sharvil Nanavati | ab606b5 | 2014-07-04 16:33:37 -0700 | [diff] [blame] | 224 | return semaphore_get_fd(queue->dequeue_sem); |
| 225 | } |
| 226 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 227 | int fixed_queue_get_enqueue_fd(const fixed_queue_t* queue) { |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 228 | CHECK(queue != NULL); |
Sharvil Nanavati | ab606b5 | 2014-07-04 16:33:37 -0700 | [diff] [blame] | 229 | return semaphore_get_fd(queue->enqueue_sem); |
| 230 | } |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 231 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 232 | void fixed_queue_register_dequeue(fixed_queue_t* queue, reactor_t* reactor, |
| 233 | fixed_queue_cb ready_cb, void* context) { |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 234 | CHECK(queue != NULL); |
| 235 | CHECK(reactor != NULL); |
| 236 | CHECK(ready_cb != NULL); |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 237 | |
| 238 | // Make sure we're not already registered |
| 239 | fixed_queue_unregister_dequeue(queue); |
| 240 | |
| 241 | queue->dequeue_ready = ready_cb; |
| 242 | queue->dequeue_context = context; |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 243 | queue->dequeue_object = |
| 244 | reactor_register(reactor, fixed_queue_get_dequeue_fd(queue), queue, |
| 245 | internal_dequeue_ready, NULL); |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 246 | } |
| 247 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 248 | void fixed_queue_unregister_dequeue(fixed_queue_t* queue) { |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 249 | CHECK(queue != NULL); |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 250 | |
| 251 | if (queue->dequeue_object) { |
| 252 | reactor_unregister(queue->dequeue_object); |
| 253 | queue->dequeue_object = NULL; |
| 254 | } |
| 255 | } |
| 256 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 257 | static void internal_dequeue_ready(void* context) { |
Jack He | f2af1c4 | 2016-12-13 01:59:12 -0800 | [diff] [blame] | 258 | CHECK(context != NULL); |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 259 | |
Myles Watson | b55040c | 2016-10-19 13:15:34 -0700 | [diff] [blame] | 260 | fixed_queue_t* queue = static_cast<fixed_queue_t*>(context); |
Zach Johnson | bd522a4 | 2014-08-15 16:44:46 -0700 | [diff] [blame] | 261 | queue->dequeue_ready(queue, queue->dequeue_context); |
| 262 | } |