diff --git a/usb/device/utilities/AsyncOp.cpp b/usb/device/utilities/AsyncOp.cpp new file mode 100644 index 0000000000..5f6939be2c --- /dev/null +++ b/usb/device/utilities/AsyncOp.cpp @@ -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(); + } +} diff --git a/usb/device/utilities/AsyncOp.h b/usb/device/utilities/AsyncOp.h new file mode 100644 index 0000000000..be28c28cde --- /dev/null +++ b/usb/device/utilities/AsyncOp.h @@ -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 diff --git a/usb/device/utilities/LinkEntry.h b/usb/device/utilities/LinkEntry.h new file mode 100644 index 0000000000..c74a7c4b76 --- /dev/null +++ b/usb/device/utilities/LinkEntry.h @@ -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 + +class LinkEntry { +public: + LinkEntry(): _next(NULL) + { + + } + +private: + friend class LinkedListBase; + LinkEntry *_next; +}; + + +#endif diff --git a/usb/device/utilities/LinkedList.h b/usb/device/utilities/LinkedList.h new file mode 100644 index 0000000000..41a6f35d7e --- /dev/null +++ b/usb/device/utilities/LinkedList.h @@ -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 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(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(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(LinkedListBase::dequeue()); + } +}; + +#endif diff --git a/usb/device/utilities/LinkedListBase.cpp b/usb/device/utilities/LinkedListBase.cpp new file mode 100644 index 0000000000..f66a27aaed --- /dev/null +++ b/usb/device/utilities/LinkedListBase.cpp @@ -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; +} diff --git a/usb/device/utilities/LinkedListBase.h b/usb/device/utilities/LinkedListBase.h new file mode 100644 index 0000000000..c778f45bd6 --- /dev/null +++ b/usb/device/utilities/LinkedListBase.h @@ -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