blob: a5a763ed4f5679aa7d79a1bc51d35ea28eaac6ad [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001/*----------------------------------------------------------------------------*/
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"
brians343bc112013-02-10 01:53:46 +00009
briansab45cad2013-03-03 05:31:33 +000010ReentrantSemaphore Resource::m_createLock;
brians343bc112013-02-10 01:53:46 +000011
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
briansab45cad2013-03-03 05:31:33 +000015 * have been allocated yet. The indicies of the resources are [0 .. elements - 1].
brians343bc112013-02-10 01:53:46 +000016 */
Brian Silverman68749472014-01-05 14:50:00 -080017Resource::Resource(uint32_t elements)
brians343bc112013-02-10 01:53:46 +000018{
briansab45cad2013-03-03 05:31:33 +000019 Synchronized sync(m_createLock);
brians343bc112013-02-10 01:53:46 +000020 m_size = elements;
21 m_isAllocated = new bool[m_size];
Brian Silverman68749472014-01-05 14:50:00 -080022 for (uint32_t i=0; i < m_size; i++)
briansab45cad2013-03-03 05:31:33 +000023 {
brians343bc112013-02-10 01:53:46 +000024 m_isAllocated[i] = false;
briansab45cad2013-03-03 05:31:33 +000025 }
brians343bc112013-02-10 01:53:46 +000026}
27
briansab45cad2013-03-03 05:31:33 +000028/**
29 * Factory method to create a Resource allocation-tracker *if* needed.
Brian Silverman362a7ad2013-04-17 15:28:29 -070030 * Handles the necessary synchronization internally.
briansab45cad2013-03-03 05:31:33 +000031 *
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 Silverman68749472014-01-05 14:50:00 -080039/*static*/ void Resource::CreateResourceObject(Resource **r, uint32_t elements)
brians343bc112013-02-10 01:53:46 +000040{
41 Synchronized sync(m_createLock);
42 if (*r == NULL)
briansab45cad2013-03-03 05:31:33 +000043 {
brians343bc112013-02-10 01:53:46 +000044 *r = new Resource(elements);
briansab45cad2013-03-03 05:31:33 +000045 }
brians343bc112013-02-10 01:53:46 +000046}
47
48/**
49 * Delete the allocated array or resources.
50 * This happens when the module is unloaded (provided it was statically allocated).
51 */
52Resource::~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 Silverman71a0cc02014-01-05 16:04:23 -080062uint32_t Resource::Allocate(const char *resourceDesc, const ErrorBase *error)
brians343bc112013-02-10 01:53:46 +000063{
64 Synchronized sync(m_allocateLock);
Brian Silverman68749472014-01-05 14:50:00 -080065 for (uint32_t i=0; i < m_size; i++)
brians343bc112013-02-10 01:53:46 +000066 {
67 if (!m_isAllocated[i])
68 {
69 m_isAllocated[i] = true;
70 return i;
71 }
72 }
Brian Silverman362a7ad2013-04-17 15:28:29 -070073 wpi_setStaticWPIErrorWithContext(error, NoAvailableResources, resourceDesc);
brians343bc112013-02-10 01:53:46 +000074 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 Silverman71a0cc02014-01-05 16:04:23 -080082uint32_t Resource::Allocate(uint32_t index, const char *resourceDesc,
83 const ErrorBase *error)
brians343bc112013-02-10 01:53:46 +000084{
85 Synchronized sync(m_allocateLock);
86 if (index >= m_size)
87 {
Brian Silverman362a7ad2013-04-17 15:28:29 -070088 wpi_setStaticWPIErrorWithContext(error, ChannelIndexOutOfRange, resourceDesc);
brians343bc112013-02-10 01:53:46 +000089 return ~0ul;
90 }
91 if ( m_isAllocated[index] )
92 {
Brian Silverman362a7ad2013-04-17 15:28:29 -070093 wpi_setStaticWPIErrorWithContext(error, ResourceAlreadyAllocated, resourceDesc);
brians343bc112013-02-10 01:53:46 +000094 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 Silverman71a0cc02014-01-05 16:04:23 -0800106void Resource::Free(uint32_t index, const ErrorBase *error)
brians343bc112013-02-10 01:53:46 +0000107{
108 Synchronized sync(m_allocateLock);
109 if (index == ~0ul) return;
110 if (index >= m_size)
111 {
Brian Silverman362a7ad2013-04-17 15:28:29 -0700112 wpi_setStaticWPIError(error, NotAllocated);
brians343bc112013-02-10 01:53:46 +0000113 return;
114 }
115 if (!m_isAllocated[index])
116 {
Brian Silverman362a7ad2013-04-17 15:28:29 -0700117 wpi_setStaticWPIError(error, NotAllocated);
brians343bc112013-02-10 01:53:46 +0000118 return;
119 }
120 m_isAllocated[index] = false;
121}