mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
107 lines
4.0 KiB
C++
107 lines
4.0 KiB
C++
/*----------------------------------------------------------------------------*/
|
|
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
/* the project. */
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <array>
|
|
#include <memory>
|
|
|
|
#include <support/mutex.h>
|
|
|
|
#include "HAL/Errors.h"
|
|
#include "HAL/Types.h"
|
|
#include "HAL/cpp/make_unique.h"
|
|
#include "HAL/handles/HandlesInternal.h"
|
|
|
|
namespace hal {
|
|
|
|
/**
|
|
* The DigitalHandleResource class is a way to track handles. This version
|
|
* allows a limited number of handles that are allocated by index.
|
|
* The enum value is seperate, as 2 enum values are allowed per handle
|
|
* Because they are allocated by index, each individual index holds its own
|
|
* mutex, which reduces contention heavily.]
|
|
*
|
|
* @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
|
|
* @tparam TStruct The struct type held by this resource
|
|
* @tparam size The number of resources allowed to be allocated
|
|
*
|
|
*/
|
|
template <typename THandle, typename TStruct, int16_t size>
|
|
class DigitalHandleResource : public HandleBase {
|
|
friend class DigitalHandleResourceTest;
|
|
|
|
public:
|
|
DigitalHandleResource() = default;
|
|
DigitalHandleResource(const DigitalHandleResource&) = delete;
|
|
DigitalHandleResource& operator=(const DigitalHandleResource&) = delete;
|
|
|
|
THandle Allocate(int16_t index, HAL_HandleEnum enumValue, int32_t* status);
|
|
std::shared_ptr<TStruct> Get(THandle handle, HAL_HandleEnum enumValue);
|
|
void Free(THandle handle, HAL_HandleEnum enumValue);
|
|
void ResetHandles() override;
|
|
|
|
private:
|
|
std::array<std::shared_ptr<TStruct>, size> m_structures;
|
|
std::array<wpi::mutex, size> m_handleMutexes;
|
|
};
|
|
|
|
template <typename THandle, typename TStruct, int16_t size>
|
|
THandle DigitalHandleResource<THandle, TStruct, size>::Allocate(
|
|
int16_t index, HAL_HandleEnum enumValue, int32_t* status) {
|
|
// don't aquire the lock if we can fail early.
|
|
if (index < 0 || index >= size) {
|
|
*status = RESOURCE_OUT_OF_RANGE;
|
|
return HAL_kInvalidHandle;
|
|
}
|
|
std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
|
|
// check for allocation, otherwise allocate and return a valid handle
|
|
if (m_structures[index] != nullptr) {
|
|
*status = RESOURCE_IS_ALLOCATED;
|
|
return HAL_kInvalidHandle;
|
|
}
|
|
m_structures[index] = std::make_shared<TStruct>();
|
|
return static_cast<THandle>(hal::createHandle(index, enumValue, m_version));
|
|
}
|
|
|
|
template <typename THandle, typename TStruct, int16_t size>
|
|
std::shared_ptr<TStruct> DigitalHandleResource<THandle, TStruct, size>::Get(
|
|
THandle handle, HAL_HandleEnum enumValue) {
|
|
// get handle index, and fail early if index out of range or wrong handle
|
|
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
|
if (index < 0 || index >= size) {
|
|
return nullptr;
|
|
}
|
|
std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
|
|
// return structure. Null will propogate correctly, so no need to manually
|
|
// check.
|
|
return m_structures[index];
|
|
}
|
|
|
|
template <typename THandle, typename TStruct, int16_t size>
|
|
void DigitalHandleResource<THandle, TStruct, size>::Free(
|
|
THandle handle, HAL_HandleEnum enumValue) {
|
|
// get handle index, and fail early if index out of range or wrong handle
|
|
int16_t index = getHandleTypedIndex(handle, enumValue, m_version);
|
|
if (index < 0 || index >= size) return;
|
|
// lock and deallocated handle
|
|
std::lock_guard<wpi::mutex> lock(m_handleMutexes[index]);
|
|
m_structures[index].reset();
|
|
}
|
|
|
|
template <typename THandle, typename TStruct, int16_t size>
|
|
void DigitalHandleResource<THandle, TStruct, size>::ResetHandles() {
|
|
for (int i = 0; i < size; i++) {
|
|
std::lock_guard<wpi::mutex> lock(m_handleMutexes[i]);
|
|
m_structures[i].reset();
|
|
}
|
|
HandleBase::ResetHandles();
|
|
}
|
|
} // namespace hal
|