Skip to content

mbed_events.h: Add ability to request a shared event queue #4406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions events/mbed_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include "events/EventQueue.h"
#include "events/Event.h"

#include "events/mbed_shared_queues.h"

using namespace events;

#endif
Expand Down
22 changes: 21 additions & 1 deletion events/mbed_lib.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
{
"name": "events",
"config": {
"present": 1
"present": 1,
"shared-stacksize": {
"help": "Stack size (bytes) for shared event queue thread",
"value": 1024
},
"shared-eventsize": {
"help": "Event buffer size (bytes) for shared event queue",
"value": 256
},
"shared-dispatch-from-application": {
"help": "No thread created for shared event queue - application will call dispatch from another thread (eg dispatch_forever at end of main)",
"value": false
},
"shared-highprio-stacksize": {
"help": "Stack size (bytes) for shared high-priority event queue thread",
"value": 1024
},
"shared-highprio-eventsize": {
"help": "Event buffer size (bytes) for shared high-priority event queue",
"value": 256
}
}
}
72 changes: 72 additions & 0 deletions events/mbed_shared_queues.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/* events
* Copyright (c) 2017 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/mbed_shared_queues.h"
#include "mbed.h"

using namespace events;

namespace mbed {

#ifdef MBED_CONF_RTOS_PRESENT
/* Create an event queue, and start the thread that dispatches it. Static
* variables mean this happens once the first time each template instantiation
* is called. This is currently instantiated no more than twice.
*/
template
<osPriority Priority, size_t QueueSize, size_t StackSize>
EventQueue *do_shared_event_queue_with_thread()
{
static uint64_t queue_buffer[QueueSize / sizeof(uint64_t)];
static EventQueue queue(sizeof queue_buffer, (unsigned char *) queue_buffer);

static uint64_t stack[StackSize / sizeof(uint64_t)];
static Thread thread(Priority, StackSize, (unsigned char *) stack);

Thread::State state = thread.get_state();
if (state == Thread::Inactive || state == Thread::Deleted) {
osStatus status = thread.start(callback(&queue, &EventQueue::dispatch_forever));
MBED_ASSERT(status == osOK);
if (status != osOK) {
return NULL;
}
}

return &queue;
}
#endif

EventQueue *mbed_event_queue()
{
#if MBED_CONF_EVENTS_SHARED_DISPATCH_FROM_APPLICATION || !defined MBED_CONF_RTOS_PRESENT
/* Only create the EventQueue, but no dispatching thread */
static unsigned char queue_buffer[MBED_CONF_EVENTS_SHARED_EVENTSIZE];
static EventQueue queue(sizeof queue_buffer, queue_buffer);

return &queue;
#else
return do_shared_event_queue_with_thread<osPriorityNormal, MBED_CONF_EVENTS_SHARED_EVENTSIZE, MBED_CONF_EVENTS_SHARED_STACKSIZE>();
#endif
}

#ifdef MBED_CONF_RTOS_PRESENT
EventQueue *mbed_highprio_event_queue()
{
return do_shared_event_queue_with_thread<osPriorityHigh, MBED_CONF_EVENTS_SHARED_HIGHPRIO_EVENTSIZE, MBED_CONF_EVENTS_SHARED_HIGHPRIO_STACKSIZE>();
}
#endif

}
81 changes: 81 additions & 0 deletions events/mbed_shared_queues.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@

/** \addtogroup events */
/** @{*/
/* events
* Copyright (c) 2017 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_SHARED_QUEUES_H
#define MBED_SHARED_QUEUES_H

#include "events/EventQueue.h"

namespace mbed {

/**
* Return a pointer to an EventQueue, on which normal tasks can be queued.
*
* All calls to this return the same EventQueue - it and its dispatch thread
* are created on the first call to this function. The dispatch thread
* runs at default priority (currently osPriorityNormal).
*
* The EventQueue returned may be used to call() Events, or to chain() other
* EventQueues so that they are run in the same context.
*
* Events (or chained EventQueues) executing on the normal event queue should
* normally take less than 10ms to execute, to avoid starving other users. As
* such, users can expect that event latency will typically be 10ms or less,
* but could occasionally be significantly higher if many events are queued.
*
* If an RTOS is not present or the configuration option
* `events.shared-dispatch-from-application` is set to true, then this
* does not create a dedicated dispatch thread - instead the application is
* expected to run the EventQueue's dispatch, eg from main. This is necessary
* for the event loop to work without an RTOS, or an RTOS system can can save
* memory by reusing the main stack.
*
* @return pointer to event queue
*/
events::EventQueue *mbed_event_queue();

#ifdef MBED_CONF_RTOS_PRESENT
/**
* Return a pointer to an EventQueue, on which small high-priority tasks can
* be queues, such as simple deferrals from interrupt.
*
* All calls to this return the same EventQueue - it and its thread are
* created on the first call to this function. The dispatch thread
* runs at a high priority (currently osPriorityHigh).
*
* The EventQueue returned may be used to call() Events, or to chain() other
* EventQueues so that they are run in the same context.
*
* Events (or chained EventQueues) executing on the high-priority event queue
* should normally take less than 100us to execute, to avoid starving other
* users. As such, users can expect that event latency will typically be 100us
* or less, but could occasionally be significantly higher if many events are
* queued.
*
* @return pointer to high-priority event queue
*/

events::EventQueue *mbed_highprio_event_queue();

#endif // MBED_CONF_RTOS_PRESENT

};

#endif

/** @}*/
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,23 @@

// Include before mbed.h to properly get UINT*_C()
#include "ns_types.h"

#include "mbed.h"
#include "cmsis_os2.h"
#include "rtx_os.h"
#include "platform/arm_hal_timer.h"
#include "platform/arm_hal_interrupt.h"
#include <mbed_assert.h>

static osThreadId_t timer_thread_id;
static uint64_t timer_thread_stk[2048/sizeof(uint64_t)];
static osRtxThread_t timer_thread_tcb;

static Timer timer;
static Timeout timeout;
static EventQueue *equeue;
static uint32_t due;
static void (*arm_hal_callback)(void);

static void timer_thread(void *arg)
{
(void)arg;
for (;;) {
osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever);
// !!! We don't do our own enter/exit critical - we rely on callback
// doing it (ns_timer_interrupt_handler does)
//platform_enter_critical();
arm_hal_callback();
//platform_exit_critical();
}
}

// Called once at boot
void platform_timer_enable(void)
{
static osThreadAttr_t timer_thread_attr = {0};
timer_thread_attr.name = "pal_timer_thread";
timer_thread_attr.stack_mem = &timer_thread_stk[0];
timer_thread_attr.cb_mem = &timer_thread_tcb;
timer_thread_attr.stack_size = sizeof(timer_thread_stk);
timer_thread_attr.cb_size = sizeof(timer_thread_tcb);
timer_thread_attr.priority = osPriorityRealtime;
timer_thread_id = osThreadNew(timer_thread, NULL, &timer_thread_attr);
MBED_ASSERT(timer_thread_id != NULL);
timer.start();
equeue = mbed_highprio_event_queue();
MBED_ASSERT(equeue != NULL);
}

// Actually cancels a timer, not the opposite of enable
Expand All @@ -63,7 +38,7 @@ void platform_timer_set_cb(void (*new_fp)(void))
static void timer_callback(void)
{
due = 0;
osThreadFlagsSet(timer_thread_id, 1);
equeue->call(arm_hal_callback);
}

// This is called from inside platform_enter_critical - IRQs can't happen
Expand Down