brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 1 | /*----------------------------------------------------------------------------*/ |
| 2 | /* Copyright (c) FIRST 2008. All Rights Reserved. */ |
| 3 | /* Open Source Software - may be modified and shared by FRC teams. The code */ |
| 4 | /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ |
| 5 | /*----------------------------------------------------------------------------*/ |
| 6 | |
| 7 | #include "Resource.h" |
| 8 | #include "WPIErrors.h" |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 9 | |
brians | ab45cad | 2013-03-03 05:31:33 +0000 | [diff] [blame] | 10 | ReentrantSemaphore Resource::m_createLock; |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 11 | |
| 12 | /** |
| 13 | * Allocate storage for a new instance of Resource. |
| 14 | * Allocate a bool array of values that will get initialized to indicate that no resources |
brians | ab45cad | 2013-03-03 05:31:33 +0000 | [diff] [blame] | 15 | * have been allocated yet. The indicies of the resources are [0 .. elements - 1]. |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 16 | */ |
Brian Silverman | 6874947 | 2014-01-05 14:50:00 -0800 | [diff] [blame] | 17 | Resource::Resource(uint32_t elements) |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 18 | { |
brians | ab45cad | 2013-03-03 05:31:33 +0000 | [diff] [blame] | 19 | Synchronized sync(m_createLock); |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 20 | m_size = elements; |
| 21 | m_isAllocated = new bool[m_size]; |
Brian Silverman | 6874947 | 2014-01-05 14:50:00 -0800 | [diff] [blame] | 22 | for (uint32_t i=0; i < m_size; i++) |
brians | ab45cad | 2013-03-03 05:31:33 +0000 | [diff] [blame] | 23 | { |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 24 | m_isAllocated[i] = false; |
brians | ab45cad | 2013-03-03 05:31:33 +0000 | [diff] [blame] | 25 | } |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 26 | } |
| 27 | |
brians | ab45cad | 2013-03-03 05:31:33 +0000 | [diff] [blame] | 28 | /** |
| 29 | * Factory method to create a Resource allocation-tracker *if* needed. |
Brian Silverman | 362a7ad | 2013-04-17 15:28:29 -0700 | [diff] [blame] | 30 | * Handles the necessary synchronization internally. |
brians | ab45cad | 2013-03-03 05:31:33 +0000 | [diff] [blame] | 31 | * |
| 32 | * @param r -- address of the caller's Resource pointer. If *r == NULL, this |
| 33 | * will construct a Resource and make *r point to it. If *r != NULL, i.e. |
| 34 | * the caller already has a Resource instance, this won't do anything. |
| 35 | * @param elements -- the number of elements for this Resource allocator to |
| 36 | * track, that is, it will allocate resource numbers in the range |
| 37 | * [0 .. elements - 1]. |
| 38 | */ |
Brian Silverman | 6874947 | 2014-01-05 14:50:00 -0800 | [diff] [blame] | 39 | /*static*/ void Resource::CreateResourceObject(Resource **r, uint32_t elements) |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 40 | { |
| 41 | Synchronized sync(m_createLock); |
| 42 | if (*r == NULL) |
brians | ab45cad | 2013-03-03 05:31:33 +0000 | [diff] [blame] | 43 | { |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 44 | *r = new Resource(elements); |
brians | ab45cad | 2013-03-03 05:31:33 +0000 | [diff] [blame] | 45 | } |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 46 | } |
| 47 | |
| 48 | /** |
| 49 | * Delete the allocated array or resources. |
| 50 | * This happens when the module is unloaded (provided it was statically allocated). |
| 51 | */ |
| 52 | Resource::~Resource() |
| 53 | { |
| 54 | delete[] m_isAllocated; |
| 55 | } |
| 56 | |
| 57 | /** |
| 58 | * Allocate a resource. |
| 59 | * When a resource is requested, mark it allocated. In this case, a free resource value |
| 60 | * within the range is located and returned after it is marked allocated. |
| 61 | */ |
Brian Silverman | 71a0cc0 | 2014-01-05 16:04:23 -0800 | [diff] [blame] | 62 | uint32_t Resource::Allocate(const char *resourceDesc, const ErrorBase *error) |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 63 | { |
| 64 | Synchronized sync(m_allocateLock); |
Brian Silverman | 6874947 | 2014-01-05 14:50:00 -0800 | [diff] [blame] | 65 | for (uint32_t i=0; i < m_size; i++) |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 66 | { |
| 67 | if (!m_isAllocated[i]) |
| 68 | { |
| 69 | m_isAllocated[i] = true; |
| 70 | return i; |
| 71 | } |
| 72 | } |
Brian Silverman | 362a7ad | 2013-04-17 15:28:29 -0700 | [diff] [blame] | 73 | wpi_setStaticWPIErrorWithContext(error, NoAvailableResources, resourceDesc); |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 74 | return ~0ul; |
| 75 | } |
| 76 | |
| 77 | /** |
| 78 | * Allocate a specific resource value. |
| 79 | * The user requests a specific resource value, i.e. channel number and it is verified |
| 80 | * unallocated, then returned. |
| 81 | */ |
Brian Silverman | 71a0cc0 | 2014-01-05 16:04:23 -0800 | [diff] [blame] | 82 | uint32_t Resource::Allocate(uint32_t index, const char *resourceDesc, |
| 83 | const ErrorBase *error) |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 84 | { |
| 85 | Synchronized sync(m_allocateLock); |
| 86 | if (index >= m_size) |
| 87 | { |
Brian Silverman | 362a7ad | 2013-04-17 15:28:29 -0700 | [diff] [blame] | 88 | wpi_setStaticWPIErrorWithContext(error, ChannelIndexOutOfRange, resourceDesc); |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 89 | return ~0ul; |
| 90 | } |
| 91 | if ( m_isAllocated[index] ) |
| 92 | { |
Brian Silverman | 362a7ad | 2013-04-17 15:28:29 -0700 | [diff] [blame] | 93 | wpi_setStaticWPIErrorWithContext(error, ResourceAlreadyAllocated, resourceDesc); |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 94 | return ~0ul; |
| 95 | } |
| 96 | m_isAllocated[index] = true; |
| 97 | return index; |
| 98 | } |
| 99 | |
| 100 | |
| 101 | /** |
| 102 | * Free an allocated resource. |
| 103 | * After a resource is no longer needed, for example a destructor is called for a channel assignment |
| 104 | * class, Free will release the resource value so it can be reused somewhere else in the program. |
| 105 | */ |
Brian Silverman | 71a0cc0 | 2014-01-05 16:04:23 -0800 | [diff] [blame] | 106 | void Resource::Free(uint32_t index, const ErrorBase *error) |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 107 | { |
| 108 | Synchronized sync(m_allocateLock); |
| 109 | if (index == ~0ul) return; |
| 110 | if (index >= m_size) |
| 111 | { |
Brian Silverman | 362a7ad | 2013-04-17 15:28:29 -0700 | [diff] [blame] | 112 | wpi_setStaticWPIError(error, NotAllocated); |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 113 | return; |
| 114 | } |
| 115 | if (!m_isAllocated[index]) |
| 116 | { |
Brian Silverman | 362a7ad | 2013-04-17 15:28:29 -0700 | [diff] [blame] | 117 | wpi_setStaticWPIError(error, NotAllocated); |
brians | 343bc11 | 2013-02-10 01:53:46 +0000 | [diff] [blame] | 118 | return; |
| 119 | } |
| 120 | m_isAllocated[index] = false; |
| 121 | } |