| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | /******************************************************************************
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Copyright (C) 2014 Google, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  *  you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  *  You may obtain a copy of the License at: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  *  distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  *  See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  *  limitations under the License. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  ******************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-08 12:10:50 +08:00
										 |  |  | #include "osi/allocator.h"
 | 
					
						
							|  |  |  | #include "osi/fixed_queue.h"
 | 
					
						
							|  |  |  | #include "osi/list.h"
 | 
					
						
							|  |  |  | #include "osi/osi.h"
 | 
					
						
							|  |  |  | #include "osi/mutex.h"
 | 
					
						
							|  |  |  | #include "osi/semaphore.h"
 | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef struct fixed_queue_t { | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     list_t *list; | 
					
						
							|  |  |  |     osi_sem_t enqueue_sem; | 
					
						
							|  |  |  |     osi_sem_t dequeue_sem; | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     osi_mutex_t lock; | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     size_t capacity; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fixed_queue_cb dequeue_ready; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | } fixed_queue_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  | fixed_queue_t *fixed_queue_new(size_t capacity) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     fixed_queue_t *ret = osi_calloc(sizeof(fixed_queue_t)); | 
					
						
							|  |  |  |     if (!ret) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     osi_mutex_new(&ret->lock); | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     ret->capacity = capacity; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     ret->list = list_new(NULL); | 
					
						
							|  |  |  |     if (!ret->list) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-10 20:37:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     osi_sem_new(&ret->enqueue_sem, capacity, capacity); | 
					
						
							|  |  |  |     if (!ret->enqueue_sem) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     osi_sem_new(&ret->dequeue_sem, capacity, 0); | 
					
						
							|  |  |  |     if (!ret->dequeue_sem) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-10-10 20:37:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | error:; | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     fixed_queue_free(ret, NULL); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  | void fixed_queue_free(fixed_queue_t *queue, fixed_queue_free_cb free_cb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const list_node_t *node; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     if (queue == NULL) { | 
					
						
							|  |  |  | 	    return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fixed_queue_unregister_dequeue(queue); | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     if (free_cb) { | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |         for (node = list_begin(queue->list); node != list_end(queue->list); node = list_next(node)) { | 
					
						
							|  |  |  |             free_cb(list_node(node)); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     list_free(queue->list); | 
					
						
							|  |  |  |     osi_sem_free(&queue->enqueue_sem); | 
					
						
							|  |  |  |     osi_sem_free(&queue->dequeue_sem); | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     osi_mutex_free(&queue->lock); | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     osi_free(queue); | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  | bool fixed_queue_is_empty(fixed_queue_t *queue) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     bool is_empty = false; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     if (queue == NULL) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     is_empty = list_is_empty(queue->list); | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     osi_mutex_unlock(&queue->lock); | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     return is_empty; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  | size_t fixed_queue_length(fixed_queue_t *queue) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     size_t length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (queue == NULL) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); | 
					
						
							|  |  |  |     length = list_length(queue->list); | 
					
						
							|  |  |  |     osi_mutex_unlock(&queue->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return length; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  | size_t fixed_queue_capacity(fixed_queue_t *queue) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(queue != NULL); | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     return queue->capacity; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-18 11:57:28 +08:00
										 |  |  | bool fixed_queue_enqueue(fixed_queue_t *queue, void *data, uint32_t timeout) | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(queue != NULL); | 
					
						
							|  |  |  |     assert(data != NULL); | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-18 11:57:28 +08:00
										 |  |  |     if (osi_sem_take(&queue->enqueue_sem, timeout) != 0) { | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     list_append(queue->list, data); | 
					
						
							|  |  |  |     osi_mutex_unlock(&queue->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     osi_sem_give(&queue->dequeue_sem); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-18 11:57:28 +08:00
										 |  |  | void *fixed_queue_dequeue(fixed_queue_t *queue, uint32_t timeout) | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  | { | 
					
						
							|  |  |  |     void *ret = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-18 11:57:28 +08:00
										 |  |  |     assert(queue != NULL); | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-18 11:57:28 +08:00
										 |  |  |     if (osi_sem_take(queue->dequeue_sem, timeout) != 0) { | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); | 
					
						
							|  |  |  |     ret = list_front(queue->list); | 
					
						
							|  |  |  |     list_remove(queue->list, ret); | 
					
						
							|  |  |  |     osi_mutex_unlock(&queue->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     osi_sem_give(&queue->enqueue_sem); | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *fixed_queue_try_peek_first(fixed_queue_t *queue) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     void *ret = NULL; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     if (queue == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); | 
					
						
							|  |  |  |     ret = list_is_empty(queue->list) ? NULL : list_front(queue->list); | 
					
						
							|  |  |  |     osi_mutex_unlock(&queue->lock); | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  | void *fixed_queue_try_peek_last(fixed_queue_t *queue) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     void *ret = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (queue == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); | 
					
						
							|  |  |  |     ret = list_is_empty(queue->list) ? NULL : list_back(queue->list); | 
					
						
							|  |  |  |     osi_mutex_unlock(&queue->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | void *fixed_queue_try_remove_from_queue(fixed_queue_t *queue, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     bool removed = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (queue == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); | 
					
						
							|  |  |  |     if (list_contains(queue->list, data) && | 
					
						
							|  |  |  |             osi_sem_take(queue->dequeue_sem, 0) == 0) { | 
					
						
							|  |  |  |         removed = list_remove(queue->list, data); | 
					
						
							|  |  |  |         assert(removed); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     osi_mutex_unlock(&queue->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (removed) { | 
					
						
							|  |  |  |         osi_sem_give(queue->enqueue_sem); | 
					
						
							|  |  |  |         return data; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | list_t *fixed_queue_get_list(fixed_queue_t *queue) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(queue != NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // NOTE: This function is not thread safe, and there is no point for
 | 
					
						
							|  |  |  |     // calling osi_mutex_lock() / osi_mutex_unlock()
 | 
					
						
							|  |  |  |     return queue->list; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  | void fixed_queue_register_dequeue(fixed_queue_t *queue, fixed_queue_cb ready_cb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(queue != NULL); | 
					
						
							|  |  |  |     assert(ready_cb != NULL); | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     queue->dequeue_ready = ready_cb; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  | void fixed_queue_unregister_dequeue(fixed_queue_t *queue) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(queue != NULL); | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     queue->dequeue_ready = NULL; | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  | void fixed_queue_process(fixed_queue_t *queue) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-08-17 21:13:45 +08:00
										 |  |  |     assert(queue != NULL); | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-25 02:10:15 +08:00
										 |  |  |     if (queue->dequeue_ready) { | 
					
						
							|  |  |  |         queue->dequeue_ready(queue); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-09-26 21:37:39 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 |