mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-05 03:21:42 +00:00
Implements Better Error Messages from the HAL (#172)
* Makes the HAL provide a better error message for certain things. * Makes Java error messages better * Updates C++ errors. * Moves handles header folder to HAL directory
This commit is contained in:
committed by
Peter Johnson
parent
05c00430b3
commit
d2aa168f66
@@ -67,6 +67,12 @@
|
||||
#define PARAMETER_OUT_OF_RANGE_MESSAGE "HAL: A parameter is out of range."
|
||||
#define RESOURCE_IS_ALLOCATED -1029
|
||||
#define RESOURCE_IS_ALLOCATED_MESSAGE "HAL: Resource already allocated"
|
||||
#define RESOURCE_OUT_OF_RANGE -1030
|
||||
#define RESOURCE_OUT_OF_RANGE_MESSAGE \
|
||||
"HAL: The requested resource is out of range."
|
||||
#define HAL_INVALID_ACCUMULATOR_CHANNEL -1035
|
||||
#define HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE \
|
||||
"HAL: The requested input is not an accumulator channel"
|
||||
#define HAL_COUNTER_NOT_SUPPORTED -1058
|
||||
#define HAL_COUNTER_NOT_SUPPORTED_MESSAGE \
|
||||
"HAL: Counter mode not supported for encoder method"
|
||||
|
||||
107
hal/include/HAL/handles/DigitalHandleResource.h
Normal file
107
hal/include/HAL/handles/DigitalHandleResource.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. 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 <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/priority_mutex.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 {
|
||||
friend class DigitalHandleResourceTest;
|
||||
|
||||
public:
|
||||
DigitalHandleResource(const DigitalHandleResource&) = delete;
|
||||
DigitalHandleResource operator=(const DigitalHandleResource&) = delete;
|
||||
DigitalHandleResource();
|
||||
~DigitalHandleResource();
|
||||
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);
|
||||
|
||||
private:
|
||||
// Dynamic array to shrink HAL file size.
|
||||
std::shared_ptr<TStruct>* m_structures;
|
||||
priority_mutex* m_handleMutexes;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size>
|
||||
DigitalHandleResource<THandle, TStruct, size>::DigitalHandleResource() {
|
||||
m_structures = new std::shared_ptr<TStruct>[size];
|
||||
m_handleMutexes = new priority_mutex[size];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size>
|
||||
DigitalHandleResource<THandle, TStruct, size>::~DigitalHandleResource() {
|
||||
delete[] m_structures;
|
||||
delete[] 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<priority_mutex> sync(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 (THandle)hal::createHandle(index, enumValue);
|
||||
}
|
||||
|
||||
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);
|
||||
if (index < 0 || index >= size) {
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<priority_mutex> sync(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);
|
||||
if (index < 0 || index >= size) return;
|
||||
// lock and deallocated handle
|
||||
std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
|
||||
m_structures[index].reset();
|
||||
}
|
||||
} // namespace hal
|
||||
89
hal/include/HAL/handles/HandlesInternal.h
Normal file
89
hal/include/HAL/handles/HandlesInternal.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. 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 "HAL/Types.h"
|
||||
|
||||
/* General Handle Data Layout
|
||||
* Bits 0-15: Handle Index
|
||||
* Bits 16-23: Unused
|
||||
* Bits 24-30: Handle Type
|
||||
* Bit 31: 1 if handle error, 0 if no error
|
||||
*
|
||||
* Other specialized handles will use different formats, however Bits 24-31 are
|
||||
* always reserved for type and error handling.
|
||||
*/
|
||||
|
||||
namespace hal {
|
||||
|
||||
constexpr int16_t InvalidHandleIndex = -1;
|
||||
|
||||
enum class HAL_HandleEnum {
|
||||
Undefined = 0,
|
||||
DIO = 1,
|
||||
Port = 2,
|
||||
Notifier = 3,
|
||||
Interrupt = 4,
|
||||
AnalogOutput = 5,
|
||||
AnalogInput = 6,
|
||||
AnalogTrigger = 7,
|
||||
Relay = 8,
|
||||
PWM = 9,
|
||||
DigitalPWM = 10,
|
||||
Counter = 11,
|
||||
FPGAEncoder = 12,
|
||||
Encoder = 13,
|
||||
Compressor = 14,
|
||||
Solenoid = 15,
|
||||
AnalogGyro = 16
|
||||
};
|
||||
|
||||
static inline int16_t getHandleIndex(HAL_Handle handle) {
|
||||
// mask and return last 16 bits
|
||||
return (int16_t)(handle & 0xffff);
|
||||
}
|
||||
static inline HAL_HandleEnum getHandleType(HAL_Handle handle) {
|
||||
// mask first 8 bits and cast to enum
|
||||
return (HAL_HandleEnum)((handle >> 24) & 0xff);
|
||||
}
|
||||
static inline bool isHandleType(HAL_Handle handle, HAL_HandleEnum handleType) {
|
||||
return handleType == getHandleType(handle);
|
||||
}
|
||||
static inline int16_t getHandleTypedIndex(HAL_Handle handle,
|
||||
HAL_HandleEnum enumType) {
|
||||
if (!isHandleType(handle, enumType)) return InvalidHandleIndex;
|
||||
return getHandleIndex(handle);
|
||||
}
|
||||
|
||||
/* specialized functions for Port handle
|
||||
* Port Handle Data Layout
|
||||
* Bits 0-7: Pin Number
|
||||
* Bits 8-15: Module Number
|
||||
* Bits 16-23: Unused
|
||||
* Bits 24-30: Handle Type
|
||||
* Bit 31: 1 if handle error, 0 if no error
|
||||
*/
|
||||
|
||||
// using a 16 bit value so we can store 0-255 and still report error
|
||||
static inline int16_t getPortHandlePin(HAL_PortHandle handle) {
|
||||
if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
|
||||
return (uint8_t)(handle & 0xff);
|
||||
}
|
||||
|
||||
// using a 16 bit value so we can store 0-255 and still report error
|
||||
static inline int16_t getPortHandleModule(HAL_PortHandle handle) {
|
||||
if (!isHandleType(handle, HAL_HandleEnum::Port)) return InvalidHandleIndex;
|
||||
return (uint8_t)((handle >> 8) & 0xff);
|
||||
}
|
||||
|
||||
HAL_PortHandle createPortHandle(uint8_t pin, uint8_t module);
|
||||
|
||||
HAL_Handle createHandle(int16_t index, HAL_HandleEnum handleType);
|
||||
} // namespace hal
|
||||
115
hal/include/HAL/handles/IndexedHandleResource.h
Normal file
115
hal/include/HAL/handles/IndexedHandleResource.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. 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 <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "HAL/Errors.h"
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* The IndexedHandleResource class is a way to track handles. This version
|
||||
* allows a limited number of handles that are allocated by index.
|
||||
* 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
|
||||
* @tparam enumValue The type value stored in the handle
|
||||
*
|
||||
*/
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
class IndexedHandleResource {
|
||||
friend class IndexedHandleResourceTest;
|
||||
|
||||
public:
|
||||
IndexedHandleResource(const IndexedHandleResource&) = delete;
|
||||
IndexedHandleResource operator=(const IndexedHandleResource&) = delete;
|
||||
IndexedHandleResource();
|
||||
~IndexedHandleResource();
|
||||
THandle Allocate(int16_t index, int32_t* status);
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
void Free(THandle handle);
|
||||
|
||||
private:
|
||||
// Dynamic array to shrink HAL file size.
|
||||
std::shared_ptr<TStruct>* m_structures;
|
||||
priority_mutex* m_handleMutexes;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
IndexedHandleResource<THandle, TStruct, size,
|
||||
enumValue>::IndexedHandleResource() {
|
||||
m_structures = new std::shared_ptr<TStruct>[size];
|
||||
m_handleMutexes = new priority_mutex[size];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
IndexedHandleResource<THandle, TStruct, size,
|
||||
enumValue>::~IndexedHandleResource() {
|
||||
delete[] m_structures;
|
||||
delete[] m_handleMutexes;
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
THandle IndexedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
|
||||
int16_t index, 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<priority_mutex> sync(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 (THandle)hal::createHandle(index, enumValue);
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
std::shared_ptr<TStruct>
|
||||
IndexedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue);
|
||||
if (index < 0 || index >= size) {
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<priority_mutex> sync(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,
|
||||
HAL_HandleEnum enumValue>
|
||||
void IndexedHandleResource<THandle, TStruct, size, enumValue>::Free(
|
||||
THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue);
|
||||
if (index < 0 || index >= size) return;
|
||||
// lock and deallocated handle
|
||||
std::lock_guard<priority_mutex> sync(m_handleMutexes[index]);
|
||||
m_structures[index].reset();
|
||||
}
|
||||
} // namespace hal
|
||||
117
hal/include/HAL/handles/LimitedClassedHandleResource.h
Normal file
117
hal/include/HAL/handles/LimitedClassedHandleResource.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. 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 <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* The LimitedClassedHandleResource class is a way to track handles. This
|
||||
* version
|
||||
* allows a limited number of handles that are allocated sequentially.
|
||||
*
|
||||
* @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
|
||||
* @tparam enumValue The type value stored in the handle
|
||||
*
|
||||
*/
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
class LimitedClassedHandleResource {
|
||||
friend class LimitedClassedHandleResourceTest;
|
||||
|
||||
public:
|
||||
LimitedClassedHandleResource(const LimitedClassedHandleResource&) = delete;
|
||||
LimitedClassedHandleResource operator=(const LimitedClassedHandleResource&) =
|
||||
delete;
|
||||
LimitedClassedHandleResource();
|
||||
~LimitedClassedHandleResource();
|
||||
THandle Allocate(std::shared_ptr<TStruct> toSet);
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
void Free(THandle handle);
|
||||
|
||||
private:
|
||||
// Dynamic array to shrink HAL file size.
|
||||
std::shared_ptr<TStruct>* m_structures;
|
||||
priority_mutex* m_handleMutexes;
|
||||
priority_mutex m_allocateMutex;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
LimitedClassedHandleResource<THandle, TStruct, size,
|
||||
enumValue>::LimitedClassedHandleResource() {
|
||||
m_structures = new std::shared_ptr<TStruct>[size];
|
||||
m_handleMutexes = new priority_mutex[size];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
LimitedClassedHandleResource<THandle, TStruct, size,
|
||||
enumValue>::~LimitedClassedHandleResource() {
|
||||
delete[] m_structures;
|
||||
delete[] m_handleMutexes;
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
THandle
|
||||
LimitedClassedHandleResource<THandle, TStruct, size, enumValue>::Allocate(
|
||||
std::shared_ptr<TStruct> toSet) {
|
||||
// globally lock to loop through indices
|
||||
std::lock_guard<priority_mutex> sync(m_allocateMutex);
|
||||
int16_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
if (m_structures[i] == nullptr) {
|
||||
// if a false index is found, grab its specific mutex
|
||||
// and allocate it.
|
||||
std::lock_guard<priority_mutex> sync(m_handleMutexes[i]);
|
||||
m_structures[i] = toSet;
|
||||
return (THandle)createHandle(i, enumValue);
|
||||
}
|
||||
}
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
std::shared_ptr<TStruct> LimitedClassedHandleResource<
|
||||
THandle, TStruct, size, enumValue>::Get(THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue);
|
||||
if (index < 0 || index >= size) {
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<priority_mutex> sync(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,
|
||||
HAL_HandleEnum enumValue>
|
||||
void LimitedClassedHandleResource<THandle, TStruct, size, enumValue>::Free(
|
||||
THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue);
|
||||
if (index < 0 || index >= size) return;
|
||||
// lock and deallocated handle
|
||||
std::lock_guard<priority_mutex> sync(m_allocateMutex);
|
||||
std::lock_guard<priority_mutex> lock(m_handleMutexes[index]);
|
||||
m_structures[index].reset();
|
||||
}
|
||||
} // namespace hal
|
||||
113
hal/include/HAL/handles/LimitedHandleResource.h
Normal file
113
hal/include/HAL/handles/LimitedHandleResource.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. 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 <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* The LimitedHandleResource class is a way to track handles. This version
|
||||
* allows a limited number of handles that are allocated sequentially.
|
||||
*
|
||||
* @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
|
||||
* @tparam enumValue The type value stored in the handle
|
||||
*
|
||||
*/
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
class LimitedHandleResource {
|
||||
friend class LimitedHandleResourceTest;
|
||||
|
||||
public:
|
||||
LimitedHandleResource(const LimitedHandleResource&) = delete;
|
||||
LimitedHandleResource operator=(const LimitedHandleResource&) = delete;
|
||||
LimitedHandleResource();
|
||||
~LimitedHandleResource();
|
||||
THandle Allocate();
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
void Free(THandle handle);
|
||||
|
||||
private:
|
||||
// Dynamic array to shrink HAL file size.
|
||||
std::shared_ptr<TStruct>* m_structures;
|
||||
priority_mutex* m_handleMutexes;
|
||||
priority_mutex m_allocateMutex;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
LimitedHandleResource<THandle, TStruct, size,
|
||||
enumValue>::LimitedHandleResource() {
|
||||
m_structures = new std::shared_ptr<TStruct>[size];
|
||||
m_handleMutexes = new priority_mutex[size];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
LimitedHandleResource<THandle, TStruct, size,
|
||||
enumValue>::~LimitedHandleResource() {
|
||||
delete[] m_structures;
|
||||
delete[] m_handleMutexes;
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
THandle LimitedHandleResource<THandle, TStruct, size, enumValue>::Allocate() {
|
||||
// globally lock to loop through indices
|
||||
std::lock_guard<priority_mutex> sync(m_allocateMutex);
|
||||
int16_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
if (m_structures[i] == nullptr) {
|
||||
// if a false index is found, grab its specific mutex
|
||||
// and allocate it.
|
||||
std::lock_guard<priority_mutex> sync(m_handleMutexes[i]);
|
||||
m_structures[i] = std::make_shared<TStruct>();
|
||||
return (THandle)createHandle(i, enumValue);
|
||||
}
|
||||
}
|
||||
return HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int16_t size,
|
||||
HAL_HandleEnum enumValue>
|
||||
std::shared_ptr<TStruct>
|
||||
LimitedHandleResource<THandle, TStruct, size, enumValue>::Get(THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue);
|
||||
if (index < 0 || index >= size) {
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard<priority_mutex> sync(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,
|
||||
HAL_HandleEnum enumValue>
|
||||
void LimitedHandleResource<THandle, TStruct, size, enumValue>::Free(
|
||||
THandle handle) {
|
||||
// get handle index, and fail early if index out of range or wrong handle
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue);
|
||||
if (index < 0 || index >= size) return;
|
||||
// lock and deallocated handle
|
||||
std::lock_guard<priority_mutex> sync(m_allocateMutex);
|
||||
std::lock_guard<priority_mutex> lock(m_handleMutexes[index]);
|
||||
m_structures[index].reset();
|
||||
}
|
||||
} // namespace hal
|
||||
87
hal/include/HAL/handles/UnlimitedHandleResource.h
Normal file
87
hal/include/HAL/handles/UnlimitedHandleResource.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2008-2016. 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 <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "HAL/Types.h"
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "HAL/handles/HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* The UnlimitedHandleResource class is a way to track handles. This version
|
||||
* allows an unlimted number of handles that are allocated sequentially. When
|
||||
* possible, indices are reused to save memory usage and keep the array length
|
||||
* down.
|
||||
* However, automatic array management has not been implemented, but might be in
|
||||
* the future.
|
||||
* Because we have to loop through the allocator, we must use a global mutex.
|
||||
|
||||
* @tparam THandle The Handle Type (Must be typedefed from HAL_Handle)
|
||||
* @tparam TStruct The struct type held by this resource
|
||||
* @tparam enumValue The type value stored in the handle
|
||||
*
|
||||
*/
|
||||
template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
|
||||
class UnlimitedHandleResource {
|
||||
friend class UnlimitedHandleResourceTest;
|
||||
|
||||
public:
|
||||
UnlimitedHandleResource(const UnlimitedHandleResource&) = delete;
|
||||
UnlimitedHandleResource operator=(const UnlimitedHandleResource&) = delete;
|
||||
UnlimitedHandleResource() = default;
|
||||
THandle Allocate(std::shared_ptr<TStruct> structure);
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
void Free(THandle handle);
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<TStruct>> m_structures;
|
||||
priority_mutex m_handleMutex;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
|
||||
THandle UnlimitedHandleResource<THandle, TStruct, enumValue>::Allocate(
|
||||
std::shared_ptr<TStruct> structure) {
|
||||
std::lock_guard<priority_mutex> sync(m_handleMutex);
|
||||
size_t i;
|
||||
for (i = 0; i < m_structures.size(); i++) {
|
||||
if (m_structures[i] == nullptr) {
|
||||
m_structures[i] = structure;
|
||||
return (THandle)createHandle(i, enumValue);
|
||||
}
|
||||
}
|
||||
if (i >= INT16_MAX) return HAL_kInvalidHandle;
|
||||
|
||||
m_structures.push_back(structure);
|
||||
return (THandle)createHandle(static_cast<int16_t>(i), enumValue);
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
|
||||
std::shared_ptr<TStruct>
|
||||
UnlimitedHandleResource<THandle, TStruct, enumValue>::Get(THandle handle) {
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue);
|
||||
std::lock_guard<priority_mutex> sync(m_handleMutex);
|
||||
if (index < 0 || index >= static_cast<int16_t>(m_structures.size()))
|
||||
return nullptr;
|
||||
return m_structures[index];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, HAL_HandleEnum enumValue>
|
||||
void UnlimitedHandleResource<THandle, TStruct, enumValue>::Free(
|
||||
THandle handle) {
|
||||
int16_t index = getHandleTypedIndex(handle, enumValue);
|
||||
std::lock_guard<priority_mutex> sync(m_handleMutex);
|
||||
if (index < 0 || index >= static_cast<int16_t>(m_structures.size())) return;
|
||||
m_structures[index].reset();
|
||||
}
|
||||
} // namespace hal
|
||||
Reference in New Issue
Block a user