No Changes

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit

Fork of microbit-dal by Lancaster University

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:17:54 2016 +0100
Revision:
22:23d7b9a4b082
Parent:
5:f0f1cecd65d8
Child:
23:6055f6c19fa6
Synchronized with git rev 7cf98c22
Author: James Devine
microbit-dal: patch for fiber_wake_on_event

fiber_wake_on_event used to crash after forking a FOB fiber.

It would attempt to obtain a new fiber context, and would place it on the wait queue.
Then when that fiber was paged in, the context of that fiber would not have been
initialised, as the function presumed schedule would be called immediately after
fiber initialisation.

This patch catches that edge case.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Jonathan Austin 1:8aa5cdb4ab67 1 /*
Jonathan Austin 1:8aa5cdb4ab67 2 The MIT License (MIT)
Jonathan Austin 1:8aa5cdb4ab67 3
Jonathan Austin 1:8aa5cdb4ab67 4 Copyright (c) 2016 British Broadcasting Corporation.
Jonathan Austin 1:8aa5cdb4ab67 5 This software is provided by Lancaster University by arrangement with the BBC.
Jonathan Austin 1:8aa5cdb4ab67 6
Jonathan Austin 1:8aa5cdb4ab67 7 Permission is hereby granted, free of charge, to any person obtaining a
Jonathan Austin 1:8aa5cdb4ab67 8 copy of this software and associated documentation files (the "Software"),
Jonathan Austin 1:8aa5cdb4ab67 9 to deal in the Software without restriction, including without limitation
Jonathan Austin 1:8aa5cdb4ab67 10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
Jonathan Austin 1:8aa5cdb4ab67 11 and/or sell copies of the Software, and to permit persons to whom the
Jonathan Austin 1:8aa5cdb4ab67 12 Software is furnished to do so, subject to the following conditions:
Jonathan Austin 1:8aa5cdb4ab67 13
Jonathan Austin 1:8aa5cdb4ab67 14 The above copyright notice and this permission notice shall be included in
Jonathan Austin 1:8aa5cdb4ab67 15 all copies or substantial portions of the Software.
Jonathan Austin 1:8aa5cdb4ab67 16
Jonathan Austin 1:8aa5cdb4ab67 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Jonathan Austin 1:8aa5cdb4ab67 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Jonathan Austin 1:8aa5cdb4ab67 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Jonathan Austin 1:8aa5cdb4ab67 20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Jonathan Austin 1:8aa5cdb4ab67 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Jonathan Austin 1:8aa5cdb4ab67 22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Jonathan Austin 1:8aa5cdb4ab67 23 DEALINGS IN THE SOFTWARE.
Jonathan Austin 1:8aa5cdb4ab67 24 */
Jonathan Austin 1:8aa5cdb4ab67 25
Jonathan Austin 1:8aa5cdb4ab67 26 /**
Jonathan Austin 1:8aa5cdb4ab67 27 * Class definition for the MicroBitMessageBus.
Jonathan Austin 1:8aa5cdb4ab67 28 *
Jonathan Austin 1:8aa5cdb4ab67 29 * The MicroBitMessageBus is the common mechanism to deliver asynchronous events on the
Jonathan Austin 1:8aa5cdb4ab67 30 * MicroBit platform. It serves a number of purposes:
Jonathan Austin 1:8aa5cdb4ab67 31 *
Jonathan Austin 1:8aa5cdb4ab67 32 * 1) It provides an eventing abstraction that is independent of the underlying substrate.
Jonathan Austin 1:8aa5cdb4ab67 33 *
Jonathan Austin 1:8aa5cdb4ab67 34 * 2) It provides a mechanism to decouple user code from trusted system code
Jonathan Austin 1:8aa5cdb4ab67 35 * i.e. the basis of a message passing nano kernel.
Jonathan Austin 1:8aa5cdb4ab67 36 *
Jonathan Austin 1:8aa5cdb4ab67 37 * 3) It allows a common high level eventing abstraction across a range of hardware types.e.g. buttons, BLE...
Jonathan Austin 1:8aa5cdb4ab67 38 *
Jonathan Austin 1:8aa5cdb4ab67 39 * 4) It provides a mechanim for extensibility - new devices added via I/O pins can have OO based
Jonathan Austin 1:8aa5cdb4ab67 40 * drivers and communicate via the message bus with minima impact on user level languages.
Jonathan Austin 1:8aa5cdb4ab67 41 *
Jonathan Austin 1:8aa5cdb4ab67 42 * 5) It allows for the possiblility of event / data aggregation, which in turn can save energy.
Jonathan Austin 1:8aa5cdb4ab67 43 *
Jonathan Austin 1:8aa5cdb4ab67 44 * It has the following design principles:
Jonathan Austin 1:8aa5cdb4ab67 45 *
Jonathan Austin 1:8aa5cdb4ab67 46 * 1) Maintain a low RAM footprint where possible
Jonathan Austin 1:8aa5cdb4ab67 47 *
Jonathan Austin 1:8aa5cdb4ab67 48 * 2) Make few assumptions about the underlying platform, but allow optimizations where possible.
Jonathan Austin 1:8aa5cdb4ab67 49 */
Jonathan Austin 1:8aa5cdb4ab67 50 #include "MicroBitConfig.h"
Jonathan Austin 1:8aa5cdb4ab67 51 #include "MicroBitMessageBus.h"
Jonathan Austin 1:8aa5cdb4ab67 52 #include "MicroBitFiber.h"
Jonathan Austin 1:8aa5cdb4ab67 53 #include "ErrorNo.h"
Jonathan Austin 1:8aa5cdb4ab67 54
Jonathan Austin 1:8aa5cdb4ab67 55 /**
Jonathan Austin 1:8aa5cdb4ab67 56 * Default constructor.
Jonathan Austin 1:8aa5cdb4ab67 57 *
Jonathan Austin 1:8aa5cdb4ab67 58 * Adds itself as a fiber component, and also configures itself to be the
Jonathan Austin 1:8aa5cdb4ab67 59 * default EventModel if defaultEventBus is NULL.
Jonathan Austin 1:8aa5cdb4ab67 60 */
Jonathan Austin 1:8aa5cdb4ab67 61 MicroBitMessageBus::MicroBitMessageBus()
Jonathan Austin 1:8aa5cdb4ab67 62 {
Jonathan Austin 1:8aa5cdb4ab67 63 this->listeners = NULL;
Jonathan Austin 1:8aa5cdb4ab67 64 this->evt_queue_head = NULL;
Jonathan Austin 1:8aa5cdb4ab67 65 this->evt_queue_tail = NULL;
Jonathan Austin 1:8aa5cdb4ab67 66 this->queueLength = 0;
Jonathan Austin 1:8aa5cdb4ab67 67
Jonathan Austin 1:8aa5cdb4ab67 68 fiber_add_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 69
Jonathan Austin 1:8aa5cdb4ab67 70 if(EventModel::defaultEventBus == NULL)
Jonathan Austin 1:8aa5cdb4ab67 71 EventModel::defaultEventBus = this;
Jonathan Austin 1:8aa5cdb4ab67 72 }
Jonathan Austin 1:8aa5cdb4ab67 73
Jonathan Austin 1:8aa5cdb4ab67 74 /**
Jonathan Austin 1:8aa5cdb4ab67 75 * Invokes a callback on a given MicroBitListener
Jonathan Austin 1:8aa5cdb4ab67 76 *
Jonathan Austin 1:8aa5cdb4ab67 77 * Internal wrapper function, used to enable
Jonathan Austin 1:8aa5cdb4ab67 78 * parameterised callbacks through the fiber scheduler.
Jonathan Austin 1:8aa5cdb4ab67 79 */
Jonathan Austin 1:8aa5cdb4ab67 80 void async_callback(void *param)
Jonathan Austin 1:8aa5cdb4ab67 81 {
Jonathan Austin 1:8aa5cdb4ab67 82 MicroBitListener *listener = (MicroBitListener *)param;
Jonathan Austin 1:8aa5cdb4ab67 83
Jonathan Austin 1:8aa5cdb4ab67 84 // OK, now we need to decide how to behave depending on our configuration.
Jonathan Austin 1:8aa5cdb4ab67 85 // If this a fiber f already active within this listener then check our
Jonathan Austin 1:8aa5cdb4ab67 86 // configuration to determine the correct course of action.
Jonathan Austin 1:8aa5cdb4ab67 87 //
Jonathan Austin 1:8aa5cdb4ab67 88
Jonathan Austin 1:8aa5cdb4ab67 89 if (listener->flags & MESSAGE_BUS_LISTENER_BUSY)
Jonathan Austin 1:8aa5cdb4ab67 90 {
Jonathan Austin 1:8aa5cdb4ab67 91 // Drop this event, if that's how we've been configured.
Jonathan Austin 1:8aa5cdb4ab67 92 if (listener->flags & MESSAGE_BUS_LISTENER_DROP_IF_BUSY)
Jonathan Austin 1:8aa5cdb4ab67 93 return;
Jonathan Austin 1:8aa5cdb4ab67 94
Jonathan Austin 1:8aa5cdb4ab67 95 // Queue this event up for later, if that's how we've been configured.
Jonathan Austin 1:8aa5cdb4ab67 96 if (listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY)
Jonathan Austin 1:8aa5cdb4ab67 97 {
Jonathan Austin 1:8aa5cdb4ab67 98 listener->queue(listener->evt);
Jonathan Austin 1:8aa5cdb4ab67 99 return;
Jonathan Austin 1:8aa5cdb4ab67 100 }
Jonathan Austin 1:8aa5cdb4ab67 101 }
Jonathan Austin 1:8aa5cdb4ab67 102
Jonathan Austin 1:8aa5cdb4ab67 103 // Determine the calling convention for the callback, and invoke...
Jonathan Austin 1:8aa5cdb4ab67 104 // C++ is really bad at this! Especially as the ARM compiler is yet to support C++ 11 :-/
Jonathan Austin 1:8aa5cdb4ab67 105
Jonathan Austin 1:8aa5cdb4ab67 106 // Record that we have a fiber going into this listener...
Jonathan Austin 1:8aa5cdb4ab67 107 listener->flags |= MESSAGE_BUS_LISTENER_BUSY;
Jonathan Austin 1:8aa5cdb4ab67 108
Jonathan Austin 1:8aa5cdb4ab67 109 while (1)
Jonathan Austin 1:8aa5cdb4ab67 110 {
Jonathan Austin 1:8aa5cdb4ab67 111 // Firstly, check for a method callback into an object.
Jonathan Austin 1:8aa5cdb4ab67 112 if (listener->flags & MESSAGE_BUS_LISTENER_METHOD)
Jonathan Austin 1:8aa5cdb4ab67 113 listener->cb_method->fire(listener->evt);
Jonathan Austin 1:8aa5cdb4ab67 114
Jonathan Austin 1:8aa5cdb4ab67 115 // Now a parameterised C function
Jonathan Austin 1:8aa5cdb4ab67 116 else if (listener->flags & MESSAGE_BUS_LISTENER_PARAMETERISED)
Jonathan Austin 1:8aa5cdb4ab67 117 listener->cb_param(listener->evt, listener->cb_arg);
Jonathan Austin 1:8aa5cdb4ab67 118
Jonathan Austin 1:8aa5cdb4ab67 119 // We must have a plain C function
Jonathan Austin 1:8aa5cdb4ab67 120 else
Jonathan Austin 1:8aa5cdb4ab67 121 listener->cb(listener->evt);
Jonathan Austin 1:8aa5cdb4ab67 122
Jonathan Austin 1:8aa5cdb4ab67 123 // If there are more events to process, dequeue the next one and process it.
Jonathan Austin 1:8aa5cdb4ab67 124 if ((listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY) && listener->evt_queue)
Jonathan Austin 1:8aa5cdb4ab67 125 {
Jonathan Austin 1:8aa5cdb4ab67 126 MicroBitEventQueueItem *item = listener->evt_queue;
Jonathan Austin 1:8aa5cdb4ab67 127
Jonathan Austin 1:8aa5cdb4ab67 128 listener->evt = item->evt;
Jonathan Austin 1:8aa5cdb4ab67 129 listener->evt_queue = listener->evt_queue->next;
Jonathan Austin 1:8aa5cdb4ab67 130 delete item;
Jonathan Austin 1:8aa5cdb4ab67 131
Jonathan Austin 1:8aa5cdb4ab67 132 // We spin the scheduler here, to preven any particular event handler from continuously holding onto resources.
Jonathan Austin 1:8aa5cdb4ab67 133 schedule();
Jonathan Austin 1:8aa5cdb4ab67 134 }
Jonathan Austin 1:8aa5cdb4ab67 135 else
Jonathan Austin 1:8aa5cdb4ab67 136 break;
Jonathan Austin 1:8aa5cdb4ab67 137 }
Jonathan Austin 1:8aa5cdb4ab67 138
Jonathan Austin 1:8aa5cdb4ab67 139 // The fiber of exiting... clear our state.
Jonathan Austin 1:8aa5cdb4ab67 140 listener->flags &= ~MESSAGE_BUS_LISTENER_BUSY;
Jonathan Austin 1:8aa5cdb4ab67 141 }
Jonathan Austin 1:8aa5cdb4ab67 142
Jonathan Austin 1:8aa5cdb4ab67 143 /**
Jonathan Austin 1:8aa5cdb4ab67 144 * Queue the given event for processing at a later time.
Jonathan Austin 1:8aa5cdb4ab67 145 * Add the given event at the tail of our queue.
Jonathan Austin 1:8aa5cdb4ab67 146 *
Jonathan Austin 1:8aa5cdb4ab67 147 * @param The event to queue.
Jonathan Austin 1:8aa5cdb4ab67 148 */
Jonathan Austin 1:8aa5cdb4ab67 149 void MicroBitMessageBus::queueEvent(MicroBitEvent &evt)
Jonathan Austin 1:8aa5cdb4ab67 150 {
Jonathan Austin 1:8aa5cdb4ab67 151 int processingComplete;
Jonathan Austin 1:8aa5cdb4ab67 152
Jonathan Austin 1:8aa5cdb4ab67 153 MicroBitEventQueueItem *prev = evt_queue_tail;
Jonathan Austin 1:8aa5cdb4ab67 154
Jonathan Austin 1:8aa5cdb4ab67 155 // Now process all handler regsitered as URGENT.
Jonathan Austin 1:8aa5cdb4ab67 156 // These pre-empt the queue, and are useful for fast, high priority services.
Jonathan Austin 1:8aa5cdb4ab67 157 processingComplete = this->process(evt, true);
Jonathan Austin 1:8aa5cdb4ab67 158
Jonathan Austin 1:8aa5cdb4ab67 159 // If we've already processed all event handlers, we're all done.
Jonathan Austin 1:8aa5cdb4ab67 160 // No need to queue the event.
Jonathan Austin 1:8aa5cdb4ab67 161 if (processingComplete)
Jonathan Austin 1:8aa5cdb4ab67 162 return;
Jonathan Austin 1:8aa5cdb4ab67 163
Jonathan Austin 1:8aa5cdb4ab67 164 // If we need to queue, but there is no space, then there's nothg we can do.
Jonathan Austin 1:8aa5cdb4ab67 165 if (queueLength >= MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH)
Jonathan Austin 1:8aa5cdb4ab67 166 return;
Jonathan Austin 1:8aa5cdb4ab67 167
Jonathan Austin 1:8aa5cdb4ab67 168 // Otherwise, we need to queue this event for later processing...
Jonathan Austin 1:8aa5cdb4ab67 169 // We queue this event at the tail of the queue at the point where we entered queueEvent()
Jonathan Austin 1:8aa5cdb4ab67 170 // This is important as the processing above *may* have generated further events, and
Jonathan Austin 1:8aa5cdb4ab67 171 // we want to maintain ordering of events.
Jonathan Austin 1:8aa5cdb4ab67 172 MicroBitEventQueueItem *item = new MicroBitEventQueueItem(evt);
Jonathan Austin 1:8aa5cdb4ab67 173
Jonathan Austin 1:8aa5cdb4ab67 174 // The queue was empty when we entered this function, so queue our event at the start of the queue.
Jonathan Austin 1:8aa5cdb4ab67 175 __disable_irq();
Jonathan Austin 1:8aa5cdb4ab67 176
Jonathan Austin 1:8aa5cdb4ab67 177 if (prev == NULL)
Jonathan Austin 1:8aa5cdb4ab67 178 {
Jonathan Austin 1:8aa5cdb4ab67 179 item->next = evt_queue_head;
Jonathan Austin 1:8aa5cdb4ab67 180 evt_queue_head = item;
Jonathan Austin 1:8aa5cdb4ab67 181 }
Jonathan Austin 1:8aa5cdb4ab67 182 else
Jonathan Austin 1:8aa5cdb4ab67 183 {
Jonathan Austin 1:8aa5cdb4ab67 184 item->next = prev->next;
Jonathan Austin 1:8aa5cdb4ab67 185 prev->next = item;
Jonathan Austin 1:8aa5cdb4ab67 186 }
Jonathan Austin 1:8aa5cdb4ab67 187
Jonathan Austin 1:8aa5cdb4ab67 188 if (item->next == NULL)
Jonathan Austin 1:8aa5cdb4ab67 189 evt_queue_tail = item;
Jonathan Austin 1:8aa5cdb4ab67 190
Jonathan Austin 1:8aa5cdb4ab67 191 queueLength++;
Jonathan Austin 1:8aa5cdb4ab67 192
Jonathan Austin 1:8aa5cdb4ab67 193 __enable_irq();
Jonathan Austin 1:8aa5cdb4ab67 194 }
Jonathan Austin 1:8aa5cdb4ab67 195
Jonathan Austin 1:8aa5cdb4ab67 196 /**
Jonathan Austin 1:8aa5cdb4ab67 197 * Extract the next event from the front of the event queue (if present).
Jonathan Austin 1:8aa5cdb4ab67 198 *
Jonathan Austin 1:8aa5cdb4ab67 199 * @return a pointer to the MicroBitEventQueueItem that is at the head of the list.
Jonathan Austin 1:8aa5cdb4ab67 200 */
Jonathan Austin 1:8aa5cdb4ab67 201 MicroBitEventQueueItem* MicroBitMessageBus::dequeueEvent()
Jonathan Austin 1:8aa5cdb4ab67 202 {
Jonathan Austin 1:8aa5cdb4ab67 203 MicroBitEventQueueItem *item = NULL;
Jonathan Austin 1:8aa5cdb4ab67 204
Jonathan Austin 1:8aa5cdb4ab67 205 __disable_irq();
Jonathan Austin 1:8aa5cdb4ab67 206
Jonathan Austin 1:8aa5cdb4ab67 207 if (evt_queue_head != NULL)
Jonathan Austin 1:8aa5cdb4ab67 208 {
Jonathan Austin 1:8aa5cdb4ab67 209 item = evt_queue_head;
Jonathan Austin 1:8aa5cdb4ab67 210 evt_queue_head = item->next;
Jonathan Austin 1:8aa5cdb4ab67 211
Jonathan Austin 1:8aa5cdb4ab67 212 if (evt_queue_head == NULL)
Jonathan Austin 1:8aa5cdb4ab67 213 evt_queue_tail = NULL;
Jonathan Austin 1:8aa5cdb4ab67 214
Jonathan Austin 1:8aa5cdb4ab67 215 queueLength--;
Jonathan Austin 1:8aa5cdb4ab67 216 }
Jonathan Austin 1:8aa5cdb4ab67 217
Jonathan Austin 1:8aa5cdb4ab67 218 __enable_irq();
Jonathan Austin 1:8aa5cdb4ab67 219
Jonathan Austin 1:8aa5cdb4ab67 220
Jonathan Austin 1:8aa5cdb4ab67 221 return item;
Jonathan Austin 1:8aa5cdb4ab67 222 }
Jonathan Austin 1:8aa5cdb4ab67 223
Jonathan Austin 1:8aa5cdb4ab67 224 /**
Jonathan Austin 1:8aa5cdb4ab67 225 * Cleanup any MicroBitListeners marked for deletion from the list.
Jonathan Austin 1:8aa5cdb4ab67 226 *
Jonathan Austin 1:8aa5cdb4ab67 227 * @return The number of listeners removed from the list.
Jonathan Austin 1:8aa5cdb4ab67 228 */
Jonathan Austin 1:8aa5cdb4ab67 229 int MicroBitMessageBus::deleteMarkedListeners()
Jonathan Austin 1:8aa5cdb4ab67 230 {
Jonathan Austin 1:8aa5cdb4ab67 231 MicroBitListener *l, *p;
Jonathan Austin 1:8aa5cdb4ab67 232 int removed = 0;
Jonathan Austin 1:8aa5cdb4ab67 233
Jonathan Austin 1:8aa5cdb4ab67 234 l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 235 p = NULL;
Jonathan Austin 1:8aa5cdb4ab67 236
Jonathan Austin 1:8aa5cdb4ab67 237 // Walk this list of event handlers. Delete any that match the given listener.
Jonathan Austin 1:8aa5cdb4ab67 238 while (l != NULL)
Jonathan Austin 1:8aa5cdb4ab67 239 {
Jonathan Austin 1:8aa5cdb4ab67 240 if (l->flags & MESSAGE_BUS_LISTENER_DELETING && !l->flags & MESSAGE_BUS_LISTENER_BUSY)
Jonathan Austin 1:8aa5cdb4ab67 241 {
Jonathan Austin 1:8aa5cdb4ab67 242 if (p == NULL)
Jonathan Austin 1:8aa5cdb4ab67 243 listeners = l->next;
Jonathan Austin 1:8aa5cdb4ab67 244 else
Jonathan Austin 1:8aa5cdb4ab67 245 p->next = l->next;
Jonathan Austin 1:8aa5cdb4ab67 246
Jonathan Austin 1:8aa5cdb4ab67 247 // delete the listener.
Jonathan Austin 1:8aa5cdb4ab67 248 MicroBitListener *t = l;
Jonathan Austin 1:8aa5cdb4ab67 249 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 250
Jonathan Austin 1:8aa5cdb4ab67 251 delete t;
Jonathan Austin 1:8aa5cdb4ab67 252 removed++;
Jonathan Austin 1:8aa5cdb4ab67 253
Jonathan Austin 1:8aa5cdb4ab67 254 continue;
Jonathan Austin 1:8aa5cdb4ab67 255 }
Jonathan Austin 1:8aa5cdb4ab67 256
Jonathan Austin 1:8aa5cdb4ab67 257 p = l;
Jonathan Austin 1:8aa5cdb4ab67 258 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 259 }
Jonathan Austin 1:8aa5cdb4ab67 260
Jonathan Austin 1:8aa5cdb4ab67 261 return removed;
Jonathan Austin 1:8aa5cdb4ab67 262 }
Jonathan Austin 1:8aa5cdb4ab67 263
Jonathan Austin 1:8aa5cdb4ab67 264 /**
Jonathan Austin 1:8aa5cdb4ab67 265 * Periodic callback from MicroBit.
Jonathan Austin 1:8aa5cdb4ab67 266 *
Jonathan Austin 1:8aa5cdb4ab67 267 * Process at least one event from the event queue, if it is not empty.
Jonathan Austin 1:8aa5cdb4ab67 268 * We then continue processing events until something appears on the runqueue.
Jonathan Austin 1:8aa5cdb4ab67 269 */
Jonathan Austin 1:8aa5cdb4ab67 270 void MicroBitMessageBus::idleTick()
Jonathan Austin 1:8aa5cdb4ab67 271 {
Jonathan Austin 1:8aa5cdb4ab67 272 // Clear out any listeners marked for deletion
Jonathan Austin 1:8aa5cdb4ab67 273 this->deleteMarkedListeners();
Jonathan Austin 1:8aa5cdb4ab67 274
Jonathan Austin 1:8aa5cdb4ab67 275 MicroBitEventQueueItem *item = this->dequeueEvent();
Jonathan Austin 1:8aa5cdb4ab67 276
Jonathan Austin 1:8aa5cdb4ab67 277 // Whilst there are events to process and we have no useful other work to do, pull them off the queue and process them.
Jonathan Austin 1:8aa5cdb4ab67 278 while (item)
Jonathan Austin 1:8aa5cdb4ab67 279 {
Jonathan Austin 1:8aa5cdb4ab67 280 // send the event to all standard event listeners.
Jonathan Austin 1:8aa5cdb4ab67 281 this->process(item->evt);
Jonathan Austin 1:8aa5cdb4ab67 282
Jonathan Austin 1:8aa5cdb4ab67 283 // Free the queue item.
Jonathan Austin 1:8aa5cdb4ab67 284 delete item;
Jonathan Austin 1:8aa5cdb4ab67 285
Jonathan Austin 1:8aa5cdb4ab67 286 // If we have created some useful work to do, we stop processing.
Jonathan Austin 1:8aa5cdb4ab67 287 // This helps to minimise the number of blocked fibers we create at any point in time, therefore
Jonathan Austin 1:8aa5cdb4ab67 288 // also reducing the RAM footprint.
Jonathan Austin 1:8aa5cdb4ab67 289 if(!scheduler_runqueue_empty())
Jonathan Austin 1:8aa5cdb4ab67 290 break;
Jonathan Austin 1:8aa5cdb4ab67 291
Jonathan Austin 1:8aa5cdb4ab67 292 // Pull the next event to process, if there is one.
Jonathan Austin 1:8aa5cdb4ab67 293 item = this->dequeueEvent();
Jonathan Austin 1:8aa5cdb4ab67 294 }
Jonathan Austin 1:8aa5cdb4ab67 295 }
Jonathan Austin 1:8aa5cdb4ab67 296
Jonathan Austin 1:8aa5cdb4ab67 297 /**
Jonathan Austin 1:8aa5cdb4ab67 298 * Indicates whether or not we have any background work to do.
Jonathan Austin 1:8aa5cdb4ab67 299 *
Jonathan Austin 1:8aa5cdb4ab67 300 * @return 1 if there are any events waitingto be processed, 0 otherwise.
Jonathan Austin 1:8aa5cdb4ab67 301 */
Jonathan Austin 1:8aa5cdb4ab67 302 int MicroBitMessageBus::isIdleCallbackNeeded()
Jonathan Austin 1:8aa5cdb4ab67 303 {
Jonathan Austin 1:8aa5cdb4ab67 304 return !(evt_queue_head == NULL);
Jonathan Austin 1:8aa5cdb4ab67 305 }
Jonathan Austin 1:8aa5cdb4ab67 306
Jonathan Austin 1:8aa5cdb4ab67 307 /**
Jonathan Austin 1:8aa5cdb4ab67 308 * Queues the given event to be sent to all registered recipients.
Jonathan Austin 1:8aa5cdb4ab67 309 *
Jonathan Austin 1:8aa5cdb4ab67 310 * @param evt The event to send.
Jonathan Austin 1:8aa5cdb4ab67 311 *
Jonathan Austin 1:8aa5cdb4ab67 312 * @code
Jonathan Austin 1:8aa5cdb4ab67 313 * MicroBitMessageBus bus;
Jonathan Austin 1:8aa5cdb4ab67 314 *
Jonathan Austin 1:8aa5cdb4ab67 315 * // Creates and sends the MicroBitEvent using bus.
Jonathan Austin 1:8aa5cdb4ab67 316 * MicrobitEvent evt(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK);
Jonathan Austin 1:8aa5cdb4ab67 317 *
Jonathan Austin 1:8aa5cdb4ab67 318 * // Creates the MicrobitEvent, but delays the sending of that event.
Jonathan Austin 1:8aa5cdb4ab67 319 * MicrobitEvent evt1(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, CREATE_ONLY);
Jonathan Austin 1:8aa5cdb4ab67 320 *
Jonathan Austin 1:8aa5cdb4ab67 321 * bus.send(evt1);
Jonathan Austin 1:8aa5cdb4ab67 322 *
Jonathan Austin 1:8aa5cdb4ab67 323 * // This has the same effect!
Jonathan Austin 1:8aa5cdb4ab67 324 * evt1.fire()
Jonathan Austin 1:8aa5cdb4ab67 325 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 326 */
Jonathan Austin 1:8aa5cdb4ab67 327 int MicroBitMessageBus::send(MicroBitEvent evt)
Jonathan Austin 1:8aa5cdb4ab67 328 {
Jonathan Austin 1:8aa5cdb4ab67 329 // We simply queue processing of the event until we're scheduled in normal thread context.
Jonathan Austin 1:8aa5cdb4ab67 330 // We do this to avoid the possibility of executing event handler code in IRQ context, which may bring
Jonathan Austin 1:8aa5cdb4ab67 331 // hidden race conditions to kids code. Queuing all events ensures causal ordering (total ordering in fact).
Jonathan Austin 1:8aa5cdb4ab67 332 this->queueEvent(evt);
Jonathan Austin 1:8aa5cdb4ab67 333 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 334 }
Jonathan Austin 1:8aa5cdb4ab67 335
Jonathan Austin 1:8aa5cdb4ab67 336 /**
Jonathan Austin 1:8aa5cdb4ab67 337 * Internal function, used to deliver the given event to all relevant recipients.
Jonathan Austin 1:8aa5cdb4ab67 338 * Normally, this is called once an event has been removed from the event queue.
Jonathan Austin 1:8aa5cdb4ab67 339 *
Jonathan Austin 1:8aa5cdb4ab67 340 * @param evt The event to send.
Jonathan Austin 1:8aa5cdb4ab67 341 *
Jonathan Austin 1:8aa5cdb4ab67 342 * @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and non-blocking will be processed
Jonathan Austin 1:8aa5cdb4ab67 343 * otherwise, all other (standard) listeners will be processed. Defaults to false.
Jonathan Austin 1:8aa5cdb4ab67 344 *
Jonathan Austin 1:8aa5cdb4ab67 345 * @return 1 if all matching listeners were processed, 0 if further processing is required.
Jonathan Austin 1:8aa5cdb4ab67 346 *
Jonathan Austin 1:8aa5cdb4ab67 347 * @note It is recommended that all external code uses the send() function instead of this function,
Jonathan Austin 1:8aa5cdb4ab67 348 * or the constructors provided by MicrobitEvent.
Jonathan Austin 1:8aa5cdb4ab67 349 */
Jonathan Austin 1:8aa5cdb4ab67 350 int MicroBitMessageBus::process(MicroBitEvent &evt, bool urgent)
Jonathan Austin 1:8aa5cdb4ab67 351 {
Jonathan Austin 1:8aa5cdb4ab67 352 MicroBitListener *l;
Jonathan Austin 1:8aa5cdb4ab67 353 int complete = 1;
Jonathan Austin 1:8aa5cdb4ab67 354 bool listenerUrgent;
Jonathan Austin 1:8aa5cdb4ab67 355
Jonathan Austin 1:8aa5cdb4ab67 356 l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 357 while (l != NULL)
Jonathan Austin 1:8aa5cdb4ab67 358 {
Jonathan Austin 1:8aa5cdb4ab67 359 if((l->id == evt.source || l->id == MICROBIT_ID_ANY) && (l->value == evt.value || l->value == MICROBIT_EVT_ANY))
Jonathan Austin 1:8aa5cdb4ab67 360 {
LancasterUniversity 5:f0f1cecd65d8 361 // If we're running under the fiber scheduler, then derive the THREADING_MODE for the callback based on the
LancasterUniversity 5:f0f1cecd65d8 362 // metadata in the listener itself.
LancasterUniversity 5:f0f1cecd65d8 363 if (fiber_scheduler_running())
LancasterUniversity 5:f0f1cecd65d8 364 listenerUrgent = (l->flags & MESSAGE_BUS_LISTENER_IMMEDIATE) == MESSAGE_BUS_LISTENER_IMMEDIATE;
LancasterUniversity 5:f0f1cecd65d8 365 else
LancasterUniversity 5:f0f1cecd65d8 366 listenerUrgent = true;
LancasterUniversity 5:f0f1cecd65d8 367
LancasterUniversity 5:f0f1cecd65d8 368 // If we should process this event hander in this pass, then activate the listener.
Jonathan Austin 1:8aa5cdb4ab67 369 if(listenerUrgent == urgent && !(l->flags & MESSAGE_BUS_LISTENER_DELETING))
Jonathan Austin 1:8aa5cdb4ab67 370 {
Jonathan Austin 1:8aa5cdb4ab67 371 l->evt = evt;
Jonathan Austin 1:8aa5cdb4ab67 372
Jonathan Austin 1:8aa5cdb4ab67 373 // OK, if this handler has regisitered itself as non-blocking, we just execute it directly...
Jonathan Austin 1:8aa5cdb4ab67 374 // This is normally only done for trusted system components.
Jonathan Austin 1:8aa5cdb4ab67 375 // Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber
Jonathan Austin 1:8aa5cdb4ab67 376 // should the event handler attempt a blocking operation, but doesn't have the overhead
Jonathan Austin 1:8aa5cdb4ab67 377 // of creating a fiber needlessly. (cool huh?)
LancasterUniversity 22:23d7b9a4b082 378 if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING || !fiber_scheduler_running())
LancasterUniversity 22:23d7b9a4b082 379 async_callback(l);
LancasterUniversity 22:23d7b9a4b082 380 else
LancasterUniversity 22:23d7b9a4b082 381 invoke(async_callback, l);
Jonathan Austin 1:8aa5cdb4ab67 382 }
Jonathan Austin 1:8aa5cdb4ab67 383 else
Jonathan Austin 1:8aa5cdb4ab67 384 {
Jonathan Austin 1:8aa5cdb4ab67 385 complete = 0;
Jonathan Austin 1:8aa5cdb4ab67 386 }
Jonathan Austin 1:8aa5cdb4ab67 387 }
Jonathan Austin 1:8aa5cdb4ab67 388
Jonathan Austin 1:8aa5cdb4ab67 389 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 390 }
Jonathan Austin 1:8aa5cdb4ab67 391
Jonathan Austin 1:8aa5cdb4ab67 392 return complete;
Jonathan Austin 1:8aa5cdb4ab67 393 }
Jonathan Austin 1:8aa5cdb4ab67 394
Jonathan Austin 1:8aa5cdb4ab67 395 /**
Jonathan Austin 1:8aa5cdb4ab67 396 * Add the given MicroBitListener to the list of event handlers, unconditionally.
Jonathan Austin 1:8aa5cdb4ab67 397 *
Jonathan Austin 1:8aa5cdb4ab67 398 * @param listener The MicroBitListener to add.
Jonathan Austin 1:8aa5cdb4ab67 399 *
Jonathan Austin 1:8aa5cdb4ab67 400 * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
Jonathan Austin 1:8aa5cdb4ab67 401 */
Jonathan Austin 1:8aa5cdb4ab67 402 int MicroBitMessageBus::add(MicroBitListener *newListener)
Jonathan Austin 1:8aa5cdb4ab67 403 {
Jonathan Austin 1:8aa5cdb4ab67 404 MicroBitListener *l, *p;
Jonathan Austin 1:8aa5cdb4ab67 405 int methodCallback;
Jonathan Austin 1:8aa5cdb4ab67 406
Jonathan Austin 1:8aa5cdb4ab67 407 //handler can't be NULL!
Jonathan Austin 1:8aa5cdb4ab67 408 if (newListener == NULL)
Jonathan Austin 1:8aa5cdb4ab67 409 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 410
Jonathan Austin 1:8aa5cdb4ab67 411 l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 412
Jonathan Austin 1:8aa5cdb4ab67 413 // Firstly, we treat a listener as an idempotent operation. Ensure we don't already have this handler
Jonathan Austin 1:8aa5cdb4ab67 414 // registered in a that will already capture these events. If we do, silently ignore.
Jonathan Austin 1:8aa5cdb4ab67 415
Jonathan Austin 1:8aa5cdb4ab67 416 // We always check the ID, VALUE and CB_METHOD fields.
Jonathan Austin 1:8aa5cdb4ab67 417 // If we have a callback to a method, check the cb_method class. Otherwise, the cb function point is sufficient.
Jonathan Austin 1:8aa5cdb4ab67 418 while (l != NULL)
Jonathan Austin 1:8aa5cdb4ab67 419 {
Jonathan Austin 1:8aa5cdb4ab67 420 methodCallback = (newListener->flags & MESSAGE_BUS_LISTENER_METHOD) && (l->flags & MESSAGE_BUS_LISTENER_METHOD);
Jonathan Austin 1:8aa5cdb4ab67 421
Jonathan Austin 1:8aa5cdb4ab67 422 if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb))
Jonathan Austin 1:8aa5cdb4ab67 423 {
Jonathan Austin 1:8aa5cdb4ab67 424 // We have a perfect match for this event listener already registered.
Jonathan Austin 1:8aa5cdb4ab67 425 // If it's marked for deletion, we simply resurrect the listener, and we're done.
Jonathan Austin 1:8aa5cdb4ab67 426 // Either way, we return an error code, as the *new* listener should be released...
Jonathan Austin 1:8aa5cdb4ab67 427 if(l->flags & MESSAGE_BUS_LISTENER_DELETING)
Jonathan Austin 1:8aa5cdb4ab67 428 l->flags &= ~MESSAGE_BUS_LISTENER_DELETING;
Jonathan Austin 1:8aa5cdb4ab67 429
Jonathan Austin 1:8aa5cdb4ab67 430 return MICROBIT_NOT_SUPPORTED;
Jonathan Austin 1:8aa5cdb4ab67 431 }
Jonathan Austin 1:8aa5cdb4ab67 432
Jonathan Austin 1:8aa5cdb4ab67 433 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 434 }
Jonathan Austin 1:8aa5cdb4ab67 435
Jonathan Austin 1:8aa5cdb4ab67 436 // We have a valid, new event handler. Add it to the list.
Jonathan Austin 1:8aa5cdb4ab67 437 // if listeners is null - we can automatically add this listener to the list at the beginning...
Jonathan Austin 1:8aa5cdb4ab67 438 if (listeners == NULL)
Jonathan Austin 1:8aa5cdb4ab67 439 {
Jonathan Austin 1:8aa5cdb4ab67 440 listeners = newListener;
Jonathan Austin 1:8aa5cdb4ab67 441 MicroBitEvent(MICROBIT_ID_MESSAGE_BUS_LISTENER, newListener->id);
Jonathan Austin 1:8aa5cdb4ab67 442
Jonathan Austin 1:8aa5cdb4ab67 443 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 444 }
Jonathan Austin 1:8aa5cdb4ab67 445
Jonathan Austin 1:8aa5cdb4ab67 446 // We maintain an ordered list of listeners.
Jonathan Austin 1:8aa5cdb4ab67 447 // The chain is held stictly in increasing order of ID (first level), then value code (second level).
Jonathan Austin 1:8aa5cdb4ab67 448 // Find the correct point in the chain for this event.
Jonathan Austin 1:8aa5cdb4ab67 449 // Adding a listener is a rare occurance, so we just walk the list...
Jonathan Austin 1:8aa5cdb4ab67 450
Jonathan Austin 1:8aa5cdb4ab67 451 p = listeners;
Jonathan Austin 1:8aa5cdb4ab67 452 l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 453
Jonathan Austin 1:8aa5cdb4ab67 454 while (l != NULL && l->id < newListener->id)
Jonathan Austin 1:8aa5cdb4ab67 455 {
Jonathan Austin 1:8aa5cdb4ab67 456 p = l;
Jonathan Austin 1:8aa5cdb4ab67 457 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 458 }
Jonathan Austin 1:8aa5cdb4ab67 459
Jonathan Austin 1:8aa5cdb4ab67 460 while (l != NULL && l->id == newListener->id && l->value < newListener->value)
Jonathan Austin 1:8aa5cdb4ab67 461 {
Jonathan Austin 1:8aa5cdb4ab67 462 p = l;
Jonathan Austin 1:8aa5cdb4ab67 463 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 464 }
Jonathan Austin 1:8aa5cdb4ab67 465
Jonathan Austin 1:8aa5cdb4ab67 466 //add at front of list
Jonathan Austin 1:8aa5cdb4ab67 467 if (p == listeners && (newListener->id < p->id || (p->id == newListener->id && p->value > newListener->value)))
Jonathan Austin 1:8aa5cdb4ab67 468 {
Jonathan Austin 1:8aa5cdb4ab67 469 newListener->next = p;
Jonathan Austin 1:8aa5cdb4ab67 470
Jonathan Austin 1:8aa5cdb4ab67 471 //this new listener is now the front!
Jonathan Austin 1:8aa5cdb4ab67 472 listeners = newListener;
Jonathan Austin 1:8aa5cdb4ab67 473 }
Jonathan Austin 1:8aa5cdb4ab67 474
Jonathan Austin 1:8aa5cdb4ab67 475 //add after p
Jonathan Austin 1:8aa5cdb4ab67 476 else
Jonathan Austin 1:8aa5cdb4ab67 477 {
Jonathan Austin 1:8aa5cdb4ab67 478 newListener->next = p->next;
Jonathan Austin 1:8aa5cdb4ab67 479 p->next = newListener;
Jonathan Austin 1:8aa5cdb4ab67 480 }
Jonathan Austin 1:8aa5cdb4ab67 481
Jonathan Austin 1:8aa5cdb4ab67 482 MicroBitEvent(MICROBIT_ID_MESSAGE_BUS_LISTENER, newListener->id);
Jonathan Austin 1:8aa5cdb4ab67 483 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 484 }
Jonathan Austin 1:8aa5cdb4ab67 485
Jonathan Austin 1:8aa5cdb4ab67 486 /**
Jonathan Austin 1:8aa5cdb4ab67 487 * Remove the given MicroBitListener from the list of event handlers.
Jonathan Austin 1:8aa5cdb4ab67 488 *
Jonathan Austin 1:8aa5cdb4ab67 489 * @param listener The MicroBitListener to remove.
Jonathan Austin 1:8aa5cdb4ab67 490 *
Jonathan Austin 1:8aa5cdb4ab67 491 * @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
Jonathan Austin 1:8aa5cdb4ab67 492 */
Jonathan Austin 1:8aa5cdb4ab67 493 int MicroBitMessageBus::remove(MicroBitListener *listener)
Jonathan Austin 1:8aa5cdb4ab67 494 {
Jonathan Austin 1:8aa5cdb4ab67 495 MicroBitListener *l;
Jonathan Austin 1:8aa5cdb4ab67 496 int removed = 0;
Jonathan Austin 1:8aa5cdb4ab67 497
Jonathan Austin 1:8aa5cdb4ab67 498 //handler can't be NULL!
Jonathan Austin 1:8aa5cdb4ab67 499 if (listener == NULL)
Jonathan Austin 1:8aa5cdb4ab67 500 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 501
Jonathan Austin 1:8aa5cdb4ab67 502 l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 503
Jonathan Austin 1:8aa5cdb4ab67 504 // Walk this list of event handlers. Delete any that match the given listener.
Jonathan Austin 1:8aa5cdb4ab67 505 while (l != NULL)
Jonathan Austin 1:8aa5cdb4ab67 506 {
Jonathan Austin 1:8aa5cdb4ab67 507 if ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD))
Jonathan Austin 1:8aa5cdb4ab67 508 {
Jonathan Austin 1:8aa5cdb4ab67 509 if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) ||
Jonathan Austin 1:8aa5cdb4ab67 510 ((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb)))
Jonathan Austin 1:8aa5cdb4ab67 511 {
Jonathan Austin 1:8aa5cdb4ab67 512 if ((listener->id == MICROBIT_ID_ANY || listener->id == l->id) && (listener->value == MICROBIT_EVT_ANY || listener->value == l->value))
Jonathan Austin 1:8aa5cdb4ab67 513 {
Jonathan Austin 1:8aa5cdb4ab67 514 // Found a match. mark this to be removed from the list.
Jonathan Austin 1:8aa5cdb4ab67 515 l->flags |= MESSAGE_BUS_LISTENER_DELETING;
Jonathan Austin 1:8aa5cdb4ab67 516 removed++;
Jonathan Austin 1:8aa5cdb4ab67 517 }
Jonathan Austin 1:8aa5cdb4ab67 518 }
Jonathan Austin 1:8aa5cdb4ab67 519 }
Jonathan Austin 1:8aa5cdb4ab67 520
Jonathan Austin 1:8aa5cdb4ab67 521 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 522 }
Jonathan Austin 1:8aa5cdb4ab67 523
Jonathan Austin 1:8aa5cdb4ab67 524 if (removed > 0)
Jonathan Austin 1:8aa5cdb4ab67 525 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 526 else
Jonathan Austin 1:8aa5cdb4ab67 527 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 528 }
Jonathan Austin 1:8aa5cdb4ab67 529
Jonathan Austin 1:8aa5cdb4ab67 530 /**
Jonathan Austin 1:8aa5cdb4ab67 531 * Returns the microBitListener with the given position in our list.
Jonathan Austin 1:8aa5cdb4ab67 532 *
Jonathan Austin 1:8aa5cdb4ab67 533 * @param n The position in the list to return.
Jonathan Austin 1:8aa5cdb4ab67 534 *
Jonathan Austin 1:8aa5cdb4ab67 535 * @return the MicroBitListener at postion n in the list, or NULL if the position is invalid.
Jonathan Austin 1:8aa5cdb4ab67 536 */
Jonathan Austin 1:8aa5cdb4ab67 537 MicroBitListener* MicroBitMessageBus::elementAt(int n)
Jonathan Austin 1:8aa5cdb4ab67 538 {
Jonathan Austin 1:8aa5cdb4ab67 539 MicroBitListener *l = listeners;
Jonathan Austin 1:8aa5cdb4ab67 540
Jonathan Austin 1:8aa5cdb4ab67 541 while (n > 0)
Jonathan Austin 1:8aa5cdb4ab67 542 {
Jonathan Austin 1:8aa5cdb4ab67 543 if (l == NULL)
Jonathan Austin 1:8aa5cdb4ab67 544 return NULL;
Jonathan Austin 1:8aa5cdb4ab67 545
Jonathan Austin 1:8aa5cdb4ab67 546 n--;
Jonathan Austin 1:8aa5cdb4ab67 547 l = l->next;
Jonathan Austin 1:8aa5cdb4ab67 548 }
Jonathan Austin 1:8aa5cdb4ab67 549
Jonathan Austin 1:8aa5cdb4ab67 550 return l;
Jonathan Austin 1:8aa5cdb4ab67 551 }
Jonathan Austin 1:8aa5cdb4ab67 552
Jonathan Austin 1:8aa5cdb4ab67 553 /**
Jonathan Austin 1:8aa5cdb4ab67 554 * Destructor for MicroBitMessageBus, where we deregister this instance from the array of fiber components.
Jonathan Austin 1:8aa5cdb4ab67 555 */
Jonathan Austin 1:8aa5cdb4ab67 556 MicroBitMessageBus::~MicroBitMessageBus()
Jonathan Austin 1:8aa5cdb4ab67 557 {
Jonathan Austin 1:8aa5cdb4ab67 558 fiber_remove_idle_component(this);
LancasterUniversity 5:f0f1cecd65d8 559 }