Add USB utility classes

Add an allocation free linked list implementation. Additionally add
the class AsyncOp which provides blocking and wakeup funcionality
to simplify making asynchronous operations block.
pull/9768/head
Russ Butler 2018-03-02 17:13:11 -06:00
parent c0df783249
commit 0d8c8f0a28
6 changed files with 385 additions and 0 deletions

View File

@ -0,0 +1,84 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "AsyncOp.h"
#include "mbed_critical.h"
using namespace rtos;
AsyncOp::AsyncOp(Mutex *lock): _list(NULL), _signal(NULL), _signal_lock(lock)
{
}
void AsyncOp::start(LinkedListBase *list)
{
_lock();
_list = list;
list->enqueue(this);
_unlock();
}
void AsyncOp::wait()
{
if (_list == NULL) {
// Event either hasn't start or has already occurred
return;
}
// Construct semaphore to wait on
Semaphore sem(0);
// Atomically set the semaphore pointer and
// check for completion
_lock();
bool done = _list == NULL;
_signal = &sem;
_unlock();
if (!done) {
sem.wait();
}
}
void AsyncOp::complete()
{
_lock();
_list->remove(this);
_list = NULL;
if (_signal != NULL) {
_signal->release();
}
_unlock();
}
void AsyncOp::_lock()
{
if (_signal_lock) {
_signal_lock->lock();
} else {
core_util_critical_section_enter();
}
}
void AsyncOp::_unlock()
{
if (_signal_lock) {
_signal_lock->unlock();
} else {
core_util_critical_section_exit();
}
}

View File

@ -0,0 +1,62 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_ASYNC_OP_H
#define MBED_ASYNC_OP_H
#include "Mutex.h"
#include "Semaphore.h"
#include "LinkEntry.h"
#include "LinkedListBase.h"
class AsyncOp: public LinkEntry {
public:
/**
* Construct a new AsyncOp object
*
* @param lock Mutex used to serialize the object or code calling complete
* or NULL if a critical section is used
*/
AsyncOp(rtos::Mutex *lock);
/**
* Add this operation to the linked list to start it
*/
void start(LinkedListBase *list);
/**
* Wait for this asynchronous operation to complete
*/
void wait();
/**
* Mark this asynchronous operation as complete
*
* This wake the thread calling wait()
*/
void complete();
private:
void _lock();
void _unlock();
LinkedListBase *_list;
rtos::Semaphore *_signal;
rtos::Mutex *const _signal_lock;
};
#endif

View File

@ -0,0 +1,35 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_LINKED_ENTRY_H
#define MBED_LINKED_ENTRY_H
#include <cstddef>
class LinkEntry {
public:
LinkEntry(): _next(NULL)
{
}
private:
friend class LinkedListBase;
LinkEntry *_next;
};
#endif

View File

@ -0,0 +1,60 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_LINKED_LIST_H
#define MBED_LINKED_LIST_H
#include "LinkEntry.h"
#include "LinkedListBase.h"
template<class T>
class LinkedList: public LinkedListBase {
public:
LinkedList() {}
~LinkedList() {}
/**
* Return the element at the head of the list
*
* @return The element at the head of the list or NULL if the list is empty
*/
T *head()
{
return static_cast<T *>(LinkedListBase::head());
}
/**
* Add an element to the tail of the list
*
* @param entry New element to add
*/
void enqueue(T *entry)
{
LinkedListBase::enqueue(static_cast<LinkEntry *>(entry));
}
/**
* Remove the element at the head of the list
*
* @return The element at the head of the list or NULL if the list is empty
*/
T *dequeue()
{
return static_cast<T *>(LinkedListBase::dequeue());
}
};
#endif

View File

@ -0,0 +1,84 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "LinkedList.h"
#include "LinkEntry.h"
#include "mbed_assert.h"
LinkedListBase::LinkedListBase(): _head(0), _tail(0)
{
}
LinkedListBase::~LinkedListBase()
{
}
LinkEntry *LinkedListBase::head()
{
return _head;
}
void LinkedListBase::enqueue(LinkEntry *entry)
{
entry->_next = NULL;
if (_tail == NULL) {
_head = entry;
} else {
_tail->_next = entry;
}
_tail = entry;
}
LinkEntry *LinkedListBase::dequeue()
{
if (_head == NULL) {
return NULL;
}
if (_head->_next == NULL) {
_tail = NULL;
}
LinkEntry *entry = _head;
_head = _head->_next;
entry->_next = NULL;
return entry;
}
void LinkedListBase::remove(LinkEntry *entry)
{
LinkEntry *prev = NULL;
LinkEntry *cur = _head;
while (cur != entry) {
if (cur == NULL) {
// Element is not in the list
return;
}
prev = cur;
cur = cur->_next;
}
if (prev != NULL) {
prev->_next = entry->_next;
}
if (entry == _head) {
_head = entry->_next;
}
if (entry == _tail) {
_tail = prev;
}
entry->_next = NULL;
}

View File

@ -0,0 +1,60 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_LINKED_LIST_BASE_H
#define MBED_LINKED_LIST_BASE_H
#include "LinkEntry.h"
class LinkedListBase {
public:
LinkedListBase();
~LinkedListBase();
/**
* Return the element at the head of the list
*
* @return The element at the head of the list or NULL if the list is empty
*/
LinkEntry *head();
/**
* Add an element to the tail of the list
*
* @param entry New element to add
*/
void enqueue(LinkEntry *entry);
/**
* Remove the element at the head of the list
*
* @return The element at the head of the list or NULL if the list is empty
*/
LinkEntry *dequeue();
/**
* Remove the specified element if it is in the list
*
* @param entry Element to remove from the list
*/
void remove(LinkEntry *entry);
private:
LinkEntry *_head;
LinkEntry *_tail;
};
#endif