blob: a68122e3606b790f44666645071f36f96ef1fb78 [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
Brian Silverman1a675112016-02-20 20:42:49 -05002/* Copyright (c) FIRST 2008-2016. All Rights Reserved. */
Brian Silverman26e4e522015-12-17 01:56:40 -05003/* Open Source Software - may be modified and shared by FRC teams. The code */
Brian Silverman1a675112016-02-20 20:42:49 -05004/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
Brian Silverman26e4e522015-12-17 01:56:40 -05006/*----------------------------------------------------------------------------*/
7
8#include "Resource.h"
9#include "WPIErrors.h"
10#include "ErrorBase.h"
11
12priority_recursive_mutex Resource::m_createLock;
13
14/**
15 * Allocate storage for a new instance of Resource.
16 * Allocate a bool array of values that will get initialized to indicate that no
17 * resources
18 * have been allocated yet. The indicies of the resources are [0 .. elements -
19 * 1].
20 */
21Resource::Resource(uint32_t elements) {
22 std::lock_guard<priority_recursive_mutex> sync(m_createLock);
23 m_isAllocated = std::vector<bool>(elements, false);
24}
25
26/**
27 * Factory method to create a Resource allocation-tracker *if* needed.
28 *
29 * @param r -- address of the caller's Resource pointer. If *r == nullptr, this
30 * will construct a Resource and make *r point to it. If *r != nullptr, i.e.
31 * the caller already has a Resource instance, this won't do anything.
32 * @param elements -- the number of elements for this Resource allocator to
33 * track, that is, it will allocate resource numbers in the range
34 * [0 .. elements - 1].
35 */
36/*static*/ void Resource::CreateResourceObject(std::unique_ptr<Resource>& r,
37 uint32_t elements) {
38 std::lock_guard<priority_recursive_mutex> sync(m_createLock);
39 if (!r) {
40 r = std::make_unique<Resource>(elements);
41 }
42}
43
44/**
45 * Allocate a resource.
46 * When a resource is requested, mark it allocated. In this case, a free
47 * resource value
48 * within the range is located and returned after it is marked allocated.
49 */
50uint32_t Resource::Allocate(const std::string &resourceDesc) {
51 std::lock_guard<priority_recursive_mutex> sync(m_allocateLock);
52 for (uint32_t i = 0; i < m_isAllocated.size(); i++) {
53 if (!m_isAllocated[i]) {
54 m_isAllocated[i] = true;
55 return i;
56 }
57 }
58 wpi_setWPIErrorWithContext(NoAvailableResources, resourceDesc);
59 return std::numeric_limits<uint32_t>::max();
60}
61
62/**
63 * Allocate a specific resource value.
64 * The user requests a specific resource value, i.e. channel number and it is
65 * verified
66 * unallocated, then returned.
67 */
68uint32_t Resource::Allocate(uint32_t index, const std::string &resourceDesc) {
69 std::lock_guard<priority_recursive_mutex> sync(m_allocateLock);
70 if (index >= m_isAllocated.size()) {
71 wpi_setWPIErrorWithContext(ChannelIndexOutOfRange, resourceDesc);
72 return std::numeric_limits<uint32_t>::max();
73 }
74 if (m_isAllocated[index]) {
75 wpi_setWPIErrorWithContext(ResourceAlreadyAllocated, resourceDesc);
76 return std::numeric_limits<uint32_t>::max();
77 }
78 m_isAllocated[index] = true;
79 return index;
80}
81
82/**
83 * Free an allocated resource.
84 * After a resource is no longer needed, for example a destructor is called for
85 * a channel assignment
86 * class, Free will release the resource value so it can be reused somewhere
87 * else in the program.
88 */
89void Resource::Free(uint32_t index) {
90 std::unique_lock<priority_recursive_mutex> sync(m_allocateLock);
91 if (index == std::numeric_limits<uint32_t>::max()) return;
92 if (index >= m_isAllocated.size()) {
93 wpi_setWPIError(NotAllocated);
94 return;
95 }
96 if (!m_isAllocated[index]) {
97 wpi_setWPIError(NotAllocated);
98 return;
99 }
100 m_isAllocated[index] = false;
101}