mirror of https://github.com/ARMmbed/mbed-os.git
Add the TaskQueue abstract interface and friends
Add the classes Task, TaskBase and TaskQueue. TaskQueue queue is an interface class which can be implemented by anything which can run code. Task and TaskBase are concrete classes which allow callbacks to be posted to a TaskQueue to be run.pull/9768/head
parent
322b4b72af
commit
29e59d6b83
|
@ -0,0 +1,597 @@
|
|||
/* events
|
||||
* Copyright (c) 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_TASK_H
|
||||
#define MBED_TASK_H
|
||||
|
||||
#include "events/EventQueue.h"
|
||||
#include "events/TaskBase.h"
|
||||
#include "platform/mbed_assert.h"
|
||||
#include "platform/Callback.h"
|
||||
|
||||
namespace events {
|
||||
/** \addtogroup events */
|
||||
|
||||
|
||||
template<typename F, typename A1=void, typename A2=void, typename A3=void, typename A4=void, typename A5=void>
|
||||
struct AllArgs;
|
||||
|
||||
template<typename B0>
|
||||
struct AllArgs<B0> {
|
||||
typedef AllArgs<B0> Self;
|
||||
B0 b0;
|
||||
|
||||
AllArgs(B0 b0=B0()): b0(b0) {}
|
||||
|
||||
template <typename T, typename _>
|
||||
struct Operations {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
s->b0();
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
typedef Operations<B0, void> ops;
|
||||
};
|
||||
|
||||
template<typename B0, typename B1>
|
||||
struct AllArgs<B0, B1> {
|
||||
typedef AllArgs<B0, B1> Self;
|
||||
B0 b0; B1 b1;
|
||||
|
||||
AllArgs(B0 b0=B0(), B1 b1=B1()): b0(b0), b1(b1) {}
|
||||
|
||||
template <typename T, typename _>
|
||||
struct Operations {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
s->b0(s->b1);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T*, R (U::*)()> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))();
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)() const> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))();
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)() volatile> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))();
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)() const volatile> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))();
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
typedef Operations<B0, B1> ops;
|
||||
};
|
||||
|
||||
template<typename B0, typename B1, typename B2>
|
||||
struct AllArgs<B0, B1, B2> {
|
||||
typedef AllArgs<B0, B1, B2> Self;
|
||||
B0 b0; B1 b1; B2 b2;
|
||||
|
||||
|
||||
AllArgs(B0 b0=B0(), B1 b1=B1(), B2 b2=B2()): b0(b0), b1(b1), b2(b2) {}
|
||||
|
||||
template <typename T, typename _>
|
||||
struct Operations {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
s->b0(s->b1, s->b2);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T*, R (U::*)(B2)> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2) const> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2) volatile> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2) const volatile> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
typedef Operations<B0, B1> ops;
|
||||
};
|
||||
|
||||
template<typename B0, typename B1, typename B2, typename B3>
|
||||
struct AllArgs<B0, B1, B2, B3> {
|
||||
typedef AllArgs<B0, B1, B2, B3> Self;
|
||||
B0 b0; B1 b1; B2 b2; B3 b3;
|
||||
|
||||
|
||||
AllArgs(B0 b0=B0(), B1 b1=B1(), B2 b2=B2(), B3 b3=B3()): b0(b0), b1(b1), b2(b2), b3(b3) {}
|
||||
|
||||
template <typename T, typename _>
|
||||
struct Operations {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
s->b0(s->b1, s->b2, s->b3);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T*, R (U::*)(B2, B3)> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2, B3) const> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2, B3) volatile> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2, B3) const volatile> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
typedef Operations<B0, B1> ops;
|
||||
};
|
||||
|
||||
template<typename B0, typename B1, typename B2, typename B3, typename B4>
|
||||
struct AllArgs<B0, B1, B2, B3, B4> {
|
||||
typedef AllArgs<B0, B1, B2, B3, B4> Self;
|
||||
B0 b0; B1 b1; B2 b2; B3 b3; B4 b4;
|
||||
|
||||
|
||||
AllArgs(B0 b0=B0(), B1 b1=B1(), B2 b2=B2(), B3 b3=B3(), B4 b4=B4()): b0(b0), b1(b1), b2(b2), b3(b3), b4(b4) {}
|
||||
|
||||
template <typename T, typename _>
|
||||
struct Operations {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
s->b0(s->b1, s->b2, s->b3, s->b4);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T*, R (U::*)(B2, B3, B4)> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3, s->b4);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2, B3, B4) const> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3, s->b4);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2, B3, B4) volatile> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3, s->b4);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2, B3, B4) const volatile> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3, s->b4);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
typedef Operations<B0, B1> ops;
|
||||
};
|
||||
|
||||
template<typename B0, typename B1, typename B2, typename B3, typename B4, typename B5>
|
||||
struct AllArgs {
|
||||
typedef AllArgs<B0, B1, B2, B3, B4, B5> Self;
|
||||
B0 b0; B1 b1; B2 b2; B3 b3; B4 b4; B5 b5;
|
||||
|
||||
|
||||
AllArgs(B0 b0=B0(), B1 b1=B1(), B2 b2=B2(), B3 b3=B3(), B4 b4=B4(), B5 b5=B5()): b0(b0), b1(b1), b2(b2), b3(b3), b4(b4), b5(b5) {}
|
||||
|
||||
template <typename T, typename _>
|
||||
struct Operations {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
s->b0(s->b1, s->b2, s->b3, s->b4, s->b5);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T*, R (U::*)(B2, B3, B4, B5)> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3, s->b4, s->b5);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2, B3, B4, B5) const> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3, s->b4, s->b5);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2, B3, B4, B5) volatile> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3, s->b4, s->b5);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename R, typename U>
|
||||
struct Operations<T, R (U::*)(B2, B3, B4, B5) const volatile> {
|
||||
static void copy(void *_dest, void *_src)
|
||||
{
|
||||
new (_dest) Self(*(Self*)_src);
|
||||
}
|
||||
|
||||
static void call(void *data) {
|
||||
Self *s = static_cast<Self*>(data);
|
||||
((s->b0)->*(s->b1))(s->b2, s->b3, s->b4, s->b5);
|
||||
s->~Self();
|
||||
}
|
||||
};
|
||||
|
||||
typedef Operations<B0, B1> ops;
|
||||
};
|
||||
|
||||
|
||||
template <typename F>
|
||||
class Task;
|
||||
|
||||
template <typename R>
|
||||
class Task<R()>: public TaskBase {
|
||||
public:
|
||||
|
||||
Task(TaskQueue *q=NULL, mbed::Callback<R()> cb=mbed::Callback<R()>())
|
||||
: TaskBase(q), _args(cb) {
|
||||
}
|
||||
|
||||
Task& operator=( mbed::Callback<R()> cb) {
|
||||
_args.b0 = cb;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void call() {
|
||||
post();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual uint32_t size() {
|
||||
return sizeof(_args);
|
||||
}
|
||||
|
||||
virtual run_callback_t start(void *data, uint32_t max_size) {
|
||||
All::ops::copy(data, (void*)&_args);
|
||||
return &All::ops::call;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef AllArgs<mbed::Callback<R()> > All;
|
||||
All _args;
|
||||
};
|
||||
|
||||
template <typename R, typename A0>
|
||||
class Task<R(A0)>: public TaskBase {
|
||||
public:
|
||||
|
||||
Task(TaskQueue *q=NULL, mbed::Callback<R(A0)> cb=mbed::Callback<R(A0)>())
|
||||
: TaskBase(q), _args(cb) {
|
||||
}
|
||||
|
||||
Task& operator=( mbed::Callback<R(A0)> cb) {
|
||||
_args.b0 = cb;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void call(A0 a0) {
|
||||
_args.b1 = a0;
|
||||
post();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual uint32_t size() {
|
||||
return sizeof(_args);
|
||||
}
|
||||
|
||||
virtual run_callback_t start(void *data, uint32_t max_size) {
|
||||
All::ops::copy(data, (void*)&_args);
|
||||
return &All::ops::call;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef AllArgs<mbed::Callback<R(A0)>, A0> All;
|
||||
All _args;
|
||||
};
|
||||
|
||||
/** Task
|
||||
*
|
||||
* Representation of a postable task
|
||||
* @ingroup events
|
||||
*/
|
||||
template <typename R, typename A0, typename A1>
|
||||
class Task<R(A0, A1)>: public TaskBase {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Construct a new task
|
||||
*
|
||||
* @param q TaskQueue to post to
|
||||
* @param cb Callback to run
|
||||
*/
|
||||
Task(TaskQueue *q=NULL, mbed::Callback<R(A0, A1)> cb=mbed::Callback<R(A0, A1)>())
|
||||
: TaskBase(q), _args(cb) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the callback of this task
|
||||
*
|
||||
* @param cb Callback to run
|
||||
*/
|
||||
Task& operator=(mbed::Callback<R(A0, A1)> cb) {
|
||||
_args.b0 = cb;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post this task for execution
|
||||
*
|
||||
* The number of arguments to call should match
|
||||
* the type of the callback. For example Task<void(int, int)>
|
||||
* expects two integers as arguments to call, while Task<void()>
|
||||
* expects no arguments.
|
||||
*
|
||||
* @param a0 First callback parameter
|
||||
* @param a1 Second callback parameter
|
||||
*/
|
||||
void call(A0 a0, A1 a1) {
|
||||
_args.b1 = a0;
|
||||
_args.b2 = a1;
|
||||
post();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual uint32_t size() {
|
||||
return sizeof(_args);
|
||||
}
|
||||
|
||||
virtual run_callback_t start(void *data, uint32_t max_size) {
|
||||
All::ops::copy(data, (void*)&_args);
|
||||
return &All::ops::call;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef AllArgs<mbed::Callback<R(A0, A1)>, A0, A1> All;
|
||||
All _args;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** @}*/
|
||||
|
||||
#endif
|
|
@ -0,0 +1,151 @@
|
|||
/* events
|
||||
* Copyright (c) 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 "events/TaskBase.h"
|
||||
#include "events/TaskQueue.h"
|
||||
#include "events/mbed_events.h"
|
||||
#include "rtos/Semaphore.h"
|
||||
#include "mbed.h"
|
||||
|
||||
TaskBase::TaskBase(TaskQueue *q)
|
||||
: _queue(q), _posted(false), _start_count(0), _flush_sem(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TaskBase::~TaskBase()
|
||||
{
|
||||
cancel();
|
||||
wait();
|
||||
}
|
||||
|
||||
void TaskBase::set(TaskQueue *q)
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
|
||||
// Cannot set the queue when it has been posted but has not been finished
|
||||
MBED_ASSERT(!_posted);
|
||||
_queue = q;
|
||||
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void TaskBase::cancel()
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
|
||||
if (_posted) {
|
||||
_queue->cancel(this);
|
||||
_posted = false;
|
||||
_wake_check();
|
||||
}
|
||||
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void TaskBase::wait()
|
||||
{
|
||||
// Fast path check for finished
|
||||
core_util_critical_section_enter();
|
||||
if (finished()) {
|
||||
core_util_critical_section_exit();
|
||||
return;
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
|
||||
rtos::Semaphore sem;
|
||||
|
||||
// If the event is in-flight then wait for it to complete
|
||||
core_util_critical_section_enter();
|
||||
if (finished()) {
|
||||
// This element has been flushed from the queue
|
||||
core_util_critical_section_exit();
|
||||
return;
|
||||
}
|
||||
_flush_sem = &sem;
|
||||
core_util_critical_section_exit();
|
||||
|
||||
sem.wait();
|
||||
}
|
||||
|
||||
bool TaskBase::ready()
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
|
||||
bool is_ready = !_posted;
|
||||
|
||||
core_util_critical_section_exit();
|
||||
return is_ready;
|
||||
}
|
||||
|
||||
bool TaskBase::finished()
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
|
||||
bool is_finished = !_posted && (_start_count == 0);
|
||||
|
||||
core_util_critical_section_exit();
|
||||
return is_finished;
|
||||
}
|
||||
|
||||
void TaskBase::finish()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void TaskBase::post()
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
|
||||
MBED_ASSERT(_queue);
|
||||
if (_queue) {
|
||||
MBED_ASSERT(!_posted);
|
||||
_queue->post(this);
|
||||
_posted = true;
|
||||
}
|
||||
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
TaskBase::run_callback_t TaskBase::_start(void *buffer, uint32_t size)
|
||||
{
|
||||
// Each call to _start must result in a call to _finish
|
||||
MBED_ASSERT(_start_count < 0xFFFF);
|
||||
_start_count++;
|
||||
_posted = false;
|
||||
|
||||
return start(buffer, size);
|
||||
}
|
||||
|
||||
void TaskBase::_finish()
|
||||
{
|
||||
// Each call to _finish must be preceded by a call to _start
|
||||
MBED_ASSERT(_start_count > 0);
|
||||
_start_count--;
|
||||
_wake_check();
|
||||
finish();
|
||||
}
|
||||
|
||||
void TaskBase::_wake_check()
|
||||
{
|
||||
if (!finished()) {
|
||||
return;
|
||||
}
|
||||
if (_flush_sem) {
|
||||
_flush_sem->release();
|
||||
_flush_sem = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/* events
|
||||
* Copyright (c) 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 TASK_BASE_H
|
||||
#define TASK_BASE_H
|
||||
|
||||
#include "platform/Callback.h"
|
||||
#include "platform/mbed_assert.h"
|
||||
#include "LinkEntry.h"
|
||||
|
||||
namespace rtos {
|
||||
class Semaphore;
|
||||
}
|
||||
|
||||
namespace events {
|
||||
/** \addtogroup events */
|
||||
|
||||
|
||||
class TaskQueue;
|
||||
|
||||
/** TaskBase
|
||||
*
|
||||
* Representation of a caller allocated task
|
||||
* @ingroup events
|
||||
*/
|
||||
class TaskBase : public LinkEntry {
|
||||
public:
|
||||
|
||||
typedef void (*run_callback_t)(void *data);
|
||||
|
||||
/**
|
||||
* Construct a new TaskBase object
|
||||
*
|
||||
* @param q Queue for posting to
|
||||
*/
|
||||
TaskBase(TaskQueue *q);
|
||||
|
||||
/**
|
||||
* Destroy this TaskBase
|
||||
*/
|
||||
virtual ~TaskBase();
|
||||
|
||||
/**
|
||||
* Set the queue of this task
|
||||
*
|
||||
* @param q TaskQueue to post to
|
||||
*/
|
||||
void set(TaskQueue *q);
|
||||
|
||||
/**
|
||||
* Cancel the execution of this task
|
||||
*
|
||||
* Once cancelled the task can be posted again. Previous
|
||||
* calls to post may still run. If you need to ensure the
|
||||
* callback has finished the function wait() can be used.
|
||||
*
|
||||
* @note This function is interrupt safe
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Return true if this task is ready to be posted
|
||||
*
|
||||
* Check if this task is on a queue waiting to be run.
|
||||
*
|
||||
* @return true if it is safe to call post
|
||||
*/
|
||||
bool ready();
|
||||
|
||||
/**
|
||||
* Wait for this task to finish execution
|
||||
*
|
||||
* When this function returns then this task is in the finished state.
|
||||
*/
|
||||
void wait();
|
||||
|
||||
/**
|
||||
* Check if the callback has run to completion or been fully canceled
|
||||
*
|
||||
* When an task is finished the queue is completely done with it and the
|
||||
* callback is either fully complete or has been canceled and will not run.
|
||||
*
|
||||
* @return true if this task has been flushed from the queue, false otherwise
|
||||
*/
|
||||
bool finished();
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Size of buffer required for TaskBase::start
|
||||
*
|
||||
* @return requested buffer size
|
||||
*/
|
||||
virtual uint32_t size() = 0;
|
||||
|
||||
/**
|
||||
* Copy any callback data and return a callback to run
|
||||
*
|
||||
* @param data Buffer to copy data to. Do not copy more than TaskBase::size() data.
|
||||
* @param size Maximum size to copy
|
||||
*/
|
||||
virtual run_callback_t start(void *data, uint32_t size) = 0;
|
||||
|
||||
/**
|
||||
* Inform this task that execution has finished.
|
||||
*
|
||||
*/
|
||||
virtual void finish();
|
||||
|
||||
/**
|
||||
* Post this task to the set TaskQueue for execution
|
||||
*/
|
||||
void post();
|
||||
|
||||
private:
|
||||
|
||||
TaskQueue *_queue;
|
||||
bool _posted;
|
||||
uint16_t _start_count;
|
||||
rtos::Semaphore *_flush_sem;
|
||||
|
||||
friend class TaskQueue;
|
||||
|
||||
/*
|
||||
* Must be called in a critical section
|
||||
*
|
||||
* This function should not be called directly. Instead
|
||||
* TaskQueue::task_start should be used instead.
|
||||
*/
|
||||
run_callback_t _start(void *buffer, uint32_t size);
|
||||
|
||||
/*
|
||||
* Must be called in a critical section
|
||||
*
|
||||
* This function should not be called directly. Instead
|
||||
* TaskQueue::task_finish should be used instead.
|
||||
*
|
||||
*/
|
||||
void _finish();
|
||||
|
||||
/*
|
||||
* Unblock wait if this task is finished
|
||||
*/
|
||||
void _wake_check();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/** @}*/
|
|
@ -0,0 +1,138 @@
|
|||
/* events
|
||||
* Copyright (c) 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 TASK_QUEUE_H
|
||||
#define TASK_QUEUE_H
|
||||
|
||||
#include "events/TaskBase.h"
|
||||
#include "platform/Callback.h"
|
||||
#include "mbed_critical.h"
|
||||
|
||||
#define MBED_MAX_TASK_SIZE 32
|
||||
|
||||
namespace events {
|
||||
/** \addtogroup events */
|
||||
|
||||
|
||||
|
||||
/** TaskQueue
|
||||
*
|
||||
* Flexible task queue for dispatching tasks
|
||||
* @ingroup events
|
||||
*/
|
||||
class TaskQueue {
|
||||
public:
|
||||
|
||||
/** Create a TaskQueue
|
||||
*
|
||||
* Create an event queue.
|
||||
*/
|
||||
TaskQueue()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** Destroy a TaskQueue
|
||||
*/
|
||||
virtual ~TaskQueue()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add this event to the queue for execution
|
||||
*
|
||||
* If the event is already in the queue then it is canceled and
|
||||
* added to the end of the queue.
|
||||
*
|
||||
* @param event Pointer to the event
|
||||
*/
|
||||
virtual void post(TaskBase *event) = 0;
|
||||
|
||||
/** Cancel an in-flight event
|
||||
*
|
||||
* Cancels the given event so the event's memory can be reused.
|
||||
*
|
||||
* The cancel function is irq safe.
|
||||
*
|
||||
* If called while the event queue's dispatch loop is active, the cancel
|
||||
* function does not guarantee that the event will not execute after it
|
||||
* returns, as the event may have already begun executing. It does
|
||||
* guarantee that the event queue is no longer using event data so
|
||||
* the event can be freed or reused.
|
||||
*
|
||||
* @param event Pointer to the event
|
||||
*/
|
||||
virtual void cancel(TaskBase *event) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Get the size required to run this task
|
||||
*
|
||||
* Get the minimum size required for TaskQueue::task_start
|
||||
*
|
||||
* @param task The task to check size on
|
||||
* @return required size
|
||||
* @note This call must be made in a critical section
|
||||
*/
|
||||
static uint32_t task_size(TaskBase *task)
|
||||
{
|
||||
|
||||
return task->size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start processing this event by copying out its data
|
||||
*
|
||||
* Inform this event both that callback execution has started
|
||||
* and that the event is free to be posted again.
|
||||
*
|
||||
* @param task The task to start processing
|
||||
* @param dest The buffer to copy the callback arguments to
|
||||
* @param size maximum size to copy
|
||||
* @return Pointer to function run
|
||||
*
|
||||
* @note event_start must not be called on a canceled event as the
|
||||
* memory may have been freed already
|
||||
* @note Every call to event_start must be paired with event_finish
|
||||
* @note This call must be made in a critical section
|
||||
*/
|
||||
static TaskBase::run_callback_t task_start(TaskBase *task, uint8_t *dest, uint32_t size)
|
||||
{
|
||||
|
||||
return task->_start(dest, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish processing this event
|
||||
*
|
||||
* Inform this event that the callback has run to completion.
|
||||
*
|
||||
* @param task The task to finish processing
|
||||
*
|
||||
* @note Every call to event_finish must be preceded by a call to event_start
|
||||
* @note This call must be made in a critical section
|
||||
*/
|
||||
static void task_finish(TaskBase *task)
|
||||
{
|
||||
task->_finish();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue