/* * Copyright (c) 2016, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * * 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. */ #ifndef UVISOR_POOL_QUEUE_EXPORTS_H #define UVISOR_POOL_QUEUE_EXPORTS_H #include "api/inc/magic_exports.h" #include "api/inc/uvisor_exports.h" #include "api/inc/uvisor_spinlock_exports.h" #include <stdint.h> #include <stddef.h> #define UVISOR_POOL_QUEUE_NON_BLOCKING (0) #define UVISOR_POOL_QUEUE_BLOCKING (1) #define UVISOR_POOL_SLOT_INVALID ((uint8_t) 0xFFU) #define UVISOR_POOL_SLOT_IS_DEQUEUED ((uint8_t) 0xFEU) #define UVISOR_POOL_SLOT_IS_FREE ((uint8_t) 0xFDU) #define UVISOR_POOL_MAX_VALID ((uint8_t) 0xFCU) typedef uint8_t uvisor_pool_slot_t; typedef struct uvisor_pool_queue_entry { union { struct { /* The next slot in the queue */ uvisor_pool_slot_t next; /* The previous slot in the queue */ uvisor_pool_slot_t prev; } queued; struct { /* If the slot is free, the next available slot in the free list */ uvisor_pool_slot_t next; /* If the slot is free or dequeued */ uvisor_pool_slot_t state; } dequeued; }; } uvisor_pool_queue_entry_t; /* These are assumed to only be statically allocated, so the management array * in in-place. */ typedef struct uvisor_pool { /* Magic that identifies this as a uvisor_pool type. */ uint32_t magic; /* The array holds slots of data. */ void const * array; /* The distance between elements in the array. */ size_t stride; /* The maximum number of elements that could be in the array. */ uvisor_pool_slot_t num; /* The number of items currently allocated from the pool. For testing and * debug purposes only. */ uvisor_pool_slot_t num_allocated; /* The first free slot. */ uvisor_pool_slot_t first_free; /* The spinlock serializes updates to the management array. */ UvisorSpinlock spinlock; /* This must be at the end so we can allocate memory for pools by * allocating enough room for the size of the pool appended by an array of * entries. */ uvisor_pool_queue_entry_t management_array[]; } uvisor_pool_t; typedef struct uvisor_pool_queue { /* Magic that identifies this as a uvisor_pool_queue type. */ uint32_t magic; /* The first allocated slot */ uvisor_pool_slot_t head; /* The last allocated slot */ uvisor_pool_slot_t tail; uvisor_pool_t * pool; } uvisor_pool_queue_t; /* Intialize a pool. * Return 0 on success, non-zero otherwise. */ UVISOR_EXTERN int uvisor_pool_init(uvisor_pool_t * pool, void * array, size_t stride, size_t num); /* Initialize a pool queue. * Return 0 on success, non-zero otherwise. */ UVISOR_EXTERN int uvisor_pool_queue_init(uvisor_pool_queue_t * pool_queue, uvisor_pool_t * pool, void * array, size_t stride, size_t num); /* Allocate a slot from the pool. This doesn't put anything in the slot for * you. It's up to you to do that. Return the index of the allocated slot, or * UVISOR_POOL_SLOT_INVALID if there is no available slot. This function will * spin until the spin lock serializing access to the pool can be taken. */ UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_allocate(uvisor_pool_t * pool); /* Attempt to allocate a slot. This function will fail if the spin lock * serializing access to the pool can not be taken. */ UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_try_allocate(uvisor_pool_t * pool); /* Enqueue the specified slot into the queue. */ UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_enqueue(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot); UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_try_enqueue(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot); /* Free the specified slot back into the pool. Invalid slots are ignored. * Return the slot that was freed, or UVISOR_POOL_SLOT_IS_FREE if the slot was * already freed, or UVISOR_POOL_SLOT_INVALID if the slot being requested to * free is outside the range of the queue. */ UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_free(uvisor_pool_t * pool, uvisor_pool_slot_t slot); UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_try_free(uvisor_pool_t * pool, uvisor_pool_slot_t slot); /* Remove the specified slot from the queue. This function does not free the * specified slot back into the pool. Return the slot that was dequeued, or * UVISOR_POOL_SLOT_IS_DEQUEUED if the slot was already dequeued, or * UVISOR_POOL_SLOT_INVALID if the slot being requested to dequeue is outside * the range of the queue. */ UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_try_dequeue(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot); UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_dequeue(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot); /* Remove the first slot from the queue. This function does not free the * specified slot back into the pool. Return the slot that was dequeued or * UVISOR_POOL_SLOT_INVALID if the slot being requested to dequeue is outside * the range of the queue. */ UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_dequeue_first(uvisor_pool_queue_t * pool_queue); UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_try_dequeue_first(uvisor_pool_queue_t * pool_queue); /* Find the first (in queue order) slot that the supplied query function * returns non-zero for. The query function is provided with `context` on every * invocation. This allows query functions to access additional data without * having to use global variables. `uvisor_pool_queue_find_first` is reentrant. */ typedef int (*TQueryFN_Ptr)(uvisor_pool_slot_t slot, void * context); UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_try_find_first(uvisor_pool_queue_t * pool_queue, TQueryFN_Ptr query_fn, void * context); UVISOR_EXTERN uvisor_pool_slot_t uvisor_pool_queue_find_first(uvisor_pool_queue_t * pool_queue, TQueryFN_Ptr query_fn, void * context); /* Inline helper function to make allocating slots for pool queues easier and * better encapsulated (clients don't need to pull the pool out of the pool * queue, or even realize pool_queue is implemented with a pool) */ static inline uvisor_pool_slot_t uvisor_pool_queue_allocate(uvisor_pool_queue_t * pool_queue) { return uvisor_pool_allocate(pool_queue->pool); } static inline uvisor_pool_slot_t uvisor_pool_queue_try_allocate(uvisor_pool_queue_t * pool_queue) { return uvisor_pool_try_allocate(pool_queue->pool); } /* Inline helper function to make freeing slots for pool queues easier and * better encapsulated (clients don't need to pull the pool out of the pool * queue, or even realize pool_queue is implemented with a pool) */ static inline uvisor_pool_slot_t uvisor_pool_queue_free(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot) { return uvisor_pool_free(pool_queue->pool, slot); } static inline uvisor_pool_slot_t uvisor_pool_queue_try_free(uvisor_pool_queue_t * pool_queue, uvisor_pool_slot_t slot) { return uvisor_pool_try_free(pool_queue->pool, slot); } /* Return a pointer to the specified slot within the pool. */ static inline void * uvisor_pool_pointer_to(uvisor_pool_t * pool, uvisor_pool_slot_t slot) { if (slot >= pool->num) { return NULL; } return (uint8_t *) pool->array + pool->stride * slot; } #endif