diff options
Diffstat (limited to 'lib/bt/common/osi/fixed_queue.c')
| -rw-r--r-- | lib/bt/common/osi/fixed_queue.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/lib/bt/common/osi/fixed_queue.c b/lib/bt/common/osi/fixed_queue.c new file mode 100644 index 00000000..0f1ba9b7 --- /dev/null +++ b/lib/bt/common/osi/fixed_queue.c @@ -0,0 +1,256 @@ +/****************************************************************************** + * + * 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. + * + ******************************************************************************/ + +#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" + +typedef struct fixed_queue_t { + + list_t *list; + osi_sem_t enqueue_sem; + osi_sem_t dequeue_sem; + osi_mutex_t lock; + size_t capacity; + + fixed_queue_cb dequeue_ready; +} fixed_queue_t; + + +fixed_queue_t *fixed_queue_new(size_t capacity) +{ + fixed_queue_t *ret = osi_calloc(sizeof(fixed_queue_t)); + if (!ret) { + goto error; + } + + osi_mutex_new(&ret->lock); + ret->capacity = capacity; + + ret->list = list_new(NULL); + if (!ret->list) { + goto error; + } + + + osi_sem_new(&ret->enqueue_sem, capacity, capacity); + if (!ret->enqueue_sem) { + goto error; + } + + osi_sem_new(&ret->dequeue_sem, capacity, 0); + if (!ret->dequeue_sem) { + goto error; + } + + return ret; + +error:; + fixed_queue_free(ret, NULL); + return NULL; +} + +void fixed_queue_free(fixed_queue_t *queue, fixed_queue_free_cb free_cb) +{ + const list_node_t *node; + + if (queue == NULL) { + return; + } + + fixed_queue_unregister_dequeue(queue); + + if (free_cb) { + for (node = list_begin(queue->list); node != list_end(queue->list); node = list_next(node)) { + free_cb(list_node(node)); + } + } + + list_free(queue->list); + osi_sem_free(&queue->enqueue_sem); + osi_sem_free(&queue->dequeue_sem); + osi_mutex_free(&queue->lock); + osi_free(queue); +} + +bool fixed_queue_is_empty(fixed_queue_t *queue) +{ + bool is_empty = false; + + if (queue == NULL) { + return true; + } + + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + is_empty = list_is_empty(queue->list); + osi_mutex_unlock(&queue->lock); + + return is_empty; +} + +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; +} +size_t fixed_queue_capacity(fixed_queue_t *queue) +{ + assert(queue != NULL); + + return queue->capacity; +} + +bool fixed_queue_enqueue(fixed_queue_t *queue, void *data, uint32_t timeout) +{ + bool status=false; //Flag whether enqueued success + + assert(queue != NULL); + assert(data != NULL); + + if (osi_sem_take(&queue->enqueue_sem, timeout) != 0) { + return false; + } + + osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT); + status = list_append(queue->list, data); //Check whether enqueued success + osi_mutex_unlock(&queue->lock); + + if(status == true ) + osi_sem_give(&queue->dequeue_sem); + + return status; +} + +void *fixed_queue_dequeue(fixed_queue_t *queue, uint32_t timeout) +{ + void *ret = NULL; + + assert(queue != NULL); + + if (osi_sem_take(&queue->dequeue_sem, timeout) != 0) { + 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); + + return ret; +} + +void *fixed_queue_try_peek_first(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_front(queue->list); + osi_mutex_unlock(&queue->lock); + + return ret; +} + +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; +} + +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; +} + +void fixed_queue_register_dequeue(fixed_queue_t *queue, fixed_queue_cb ready_cb) +{ + assert(queue != NULL); + assert(ready_cb != NULL); + + queue->dequeue_ready = ready_cb; +} + +void fixed_queue_unregister_dequeue(fixed_queue_t *queue) +{ + assert(queue != NULL); + + queue->dequeue_ready = NULL; +} + +void fixed_queue_process(fixed_queue_t *queue) +{ + assert(queue != NULL); + + if (queue->dequeue_ready) { + queue->dequeue_ready(queue); + } +} |
