mbed-os/drivers/usb/source/AsyncOp.cpp

147 lines
3.1 KiB
C++

/*
* Copyright (c) 2018-2019, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* 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"
#include "mbed_assert.h"
using namespace rtos;
AsyncOp::AsyncOp():
_list(NULL), _wait(NULL), _aborted(false), _timeout(false)
{
}
AsyncOp::AsyncOp(mbed::Callback<void()> &callback):
_list(NULL), _wait(NULL), _aborted(false), _timeout(false)
{
_callback = callback;
}
AsyncOp::~AsyncOp()
{
MBED_ASSERT(_list == NULL);
}
void AsyncOp::wait(rtos::Mutex *host_mutex, rtos::Kernel::Clock::duration_u32 rel_time)
{
// Optimization so semaphore is only created if necessary
core_util_critical_section_enter();
bool done = _list == NULL;
core_util_critical_section_exit();
if (done) {
return;
}
// Construct semaphore to wait on
Semaphore sem(0);
core_util_critical_section_enter();
done = _list == NULL;
// Wait is only allowed to be called from one thread
MBED_ASSERT(_wait == NULL);
_wait = &sem;
core_util_critical_section_exit();
if (done) {
// Operation was signaled before semaphore was set
return;
}
if (sem.try_acquire_for(rel_time)) {
// Operation completion signaled semaphore
return;
}
_host_lock(host_mutex);
_abort(true);
_host_unlock(host_mutex);
}
void AsyncOp::abort()
{
// Host lock must be held
_abort(false);
}
void AsyncOp::complete()
{
core_util_critical_section_enter();
mbed::Callback<void()> cb = _callback;
_callback = nullptr;
_list = nullptr;
if (_wait != nullptr) {
_wait->release();
}
core_util_critical_section_exit();
if (cb) {
cb();
}
}
bool AsyncOp::timeout()
{
core_util_critical_section_enter();
bool ret = _timeout;
core_util_critical_section_exit();
return ret;
}
void AsyncOp::_abort(bool timeout)
{
// host lock must be held
core_util_critical_section_enter();
OperationListBase *list = _list;
if (list) {
_callback = nullptr;
_aborted = true;
_wait = nullptr;
_timeout = timeout;
_list = nullptr;
}
core_util_critical_section_exit();
if (list) {
list->remove(this);
}
}
void AsyncOp::_host_lock(rtos::Mutex *host_mutex)
{
if (host_mutex) {
host_mutex->lock();
} else {
core_util_critical_section_enter();
}
}
void AsyncOp::_host_unlock(rtos::Mutex *host_mutex)
{
if (host_mutex) {
host_mutex->unlock();
} else {
core_util_critical_section_exit();
}
}