blob: 653011e04c3aca5abee8cbaebac4c3150b924273 [file] [log] [blame]
Brian Silvermanf7f267a2017-02-04 16:16:08 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2016-2017. 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 the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#pragma once
9
10#include <stdint.h>
11
12#include <array>
13#include <memory>
14
15#include "HAL/Errors.h"
16#include "HAL/Types.h"
17#include "HAL/cpp/make_unique.h"
18#include "HAL/cpp/priority_mutex.h"
19#include "HAL/handles/HandlesInternal.h"
20
21namespace hal {
22
23/**
24 * The DigitalHandleResource class is a way to track handles. This version
25 * allows a limited number of handles that are allocated by index.
26 * The enum value is seperate, as 2 enum values are allowed per handle
27 * Because they are allocated by index, each individual index holds its own
28 * mutex, which reduces contention heavily.]
29 *
30 * @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
31 * @tparam TStruct The struct type held by this resource
32 * @tparam size The number of resources allowed to be allocated
33 *
34 */
35template <typename THandle, typename TStruct, int16_t size>
36class DigitalHandleResource {
37 friend class DigitalHandleResourceTest;
38
39 public:
40 DigitalHandleResource() = default;
41 DigitalHandleResource(const DigitalHandleResource&) = delete;
42 DigitalHandleResource& operator=(const DigitalHandleResource&) = delete;
43
44 THandle Allocate(int16_t index, HAL_HandleEnum enumValue, int32_t* status);
45 std::shared_ptr<TStruct> Get(THandle handle, HAL_HandleEnum enumValue);
46 void Free(THandle handle, HAL_HandleEnum enumValue);
47
48 private:
49 std::array<std::shared_ptr<TStruct>, size> m_structures;
50 std::array<priority_mutex, size> m_handleMutexes;
51};
52
53template <typename THandle, typename TStruct, int16_t size>
54THandle DigitalHandleResource<THandle, TStruct, size>::Allocate(
55 int16_t index, HAL_HandleEnum enumValue, int32_t* status) {
56 // don't aquire the lock if we can fail early.
57 if (index < 0 || index >= size) {
58 *status = RESOURCE_OUT_OF_RANGE;
59 return HAL_kInvalidHandle;
60 }
61 std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
62 // check for allocation, otherwise allocate and return a valid handle
63 if (m_structures[index] != nullptr) {
64 *status = RESOURCE_IS_ALLOCATED;
65 return HAL_kInvalidHandle;
66 }
67 m_structures[index] = std::make_shared<TStruct>();
68 return static_cast<THandle>(hal::createHandle(index, enumValue));
69}
70
71template <typename THandle, typename TStruct, int16_t size>
72std::shared_ptr<TStruct> DigitalHandleResource<THandle, TStruct, size>::Get(
73 THandle handle, HAL_HandleEnum enumValue) {
74 // get handle index, and fail early if index out of range or wrong handle
75 int16_t index = getHandleTypedIndex(handle, enumValue);
76 if (index < 0 || index >= size) {
77 return nullptr;
78 }
79 std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
80 // return structure. Null will propogate correctly, so no need to manually
81 // check.
82 return m_structures[index];
83}
84
85template <typename THandle, typename TStruct, int16_t size>
86void DigitalHandleResource<THandle, TStruct, size>::Free(
87 THandle handle, HAL_HandleEnum enumValue) {
88 // get handle index, and fail early if index out of range or wrong handle
89 int16_t index = getHandleTypedIndex(handle, enumValue);
90 if (index < 0 || index >= size) return;
91 // lock and deallocated handle
92 std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
93 m_structures[index].reset();
94}
95} // namespace hal