EventFramework library allows the creation of an event-driven infrastructure in which small "threads" can handle events in a multithreaded execution context. The EventFramework can be configured to act as a cooperative or a fully-preemptive kernel with fixed-priority scheduling. Furthermore, this kernel matches run-to-completion semantics, and hence a single-stack configuration is enough to keep running this multithreaded execution environment. As running threads shares global stack, a huge quantity of RAM is saved in contrast with traditional RTOSes.
Diff: EventFramework.cpp
- Revision:
- 0:9d09acc8f9d9
- Child:
- 1:ec12f2e32faf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EventFramework.cpp Mon Oct 01 10:38:45 2012 +0000 @@ -0,0 +1,238 @@ +/* mbed EventFramework Library + * Copyright (c) 2012 raulMrello + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "EventFramework.h" +#include "../Node/Node.h" + +void EmptyFn(void){} + +EventFramework::EventFramework(uint32_t schpol, void (*cbEI)(void), void (*lock)(void), void (*unlock)(void)){ + currPrio = 0xFFFF; + nesting = 0; + cbLock = EmptyFn; + cbUnlock = EmptyFn; + cbEnableInterrupts = EmptyFn; + list = NULL; + queue = NULL; + event = NULL; + ctflags |= (EventFramework::SCHED_KEY & schpol); + if(cbEI){ + cbEnableInterrupts = cbEI; + } + if(lock){ + cbLock = lock; + } + if(unlock){ + cbUnlock = unlock; + } +} + +EventFramework::~EventFramework(){ + if(list) + delete list; + if(queue) + delete queue; +} + +void EventFramework::AddEvent(Event* ev){ + cbLock(); + if(!list){ + list = new List(ev); + return; + } + AddEventToList(ev,list); + cbUnlock(); +} + +void EventFramework::AddPendingEvent(Event* ev){ + cbLock(); + if(!queue){ + queue = new List(ev); + return; + } + AddEventToList(ev,queue); + cbUnlock(); +} + +void EventFramework::AddEventToList(Event* ev, List* plist){ + Node* node = plist->GetFirstNode(); + Event* data = (Event*)node->GetData(); + while(data->GetPrio() <= ev->GetPrio()){ + Node* next = node->GetNext(); + if(!next){ + plist->AddAfter(node, ev); + return; + } + data = (Event*)next->GetData(); + node = next; + } + Node* newHead = plist->AddBefore(node, ev); + if(newHead){ + plist->SetFirstNode(newHead); + } +} + +void EventFramework::RemoveEvent(Event* ev){ + cbLock(); + list->RemoveItem(ev); + cbUnlock(); +} + +void EventFramework::AddEventListener(Event* ev, EventHandler* hnd, EventDispatchingRoutine* func){ + if(func){ + hnd->Attach(func); + } + ev->Subscribe(hnd); +} + +void EventFramework::RemoveEventListener(Event* ev, EventHandler* hnd){ + ev->Unsubscribe(hnd); +} + +void EventFramework::RemovePendingEvent(Event* ev){ + cbLock(); + queue->RemoveItem(ev); + cbUnlock(); + delete ev; +} + +void EventFramework::PublishEvent(Event* evt, void* args){ + Event* raised = new Event(evt->GetPrio()); + raised->SetData(args); + raised->SetBase(evt); + cbLock(); + AddPendingEvent(raised); + if(nesting){ + cbUnlock(); + return; + } + cbUnlock(); + if(IsPreemptive()){ + Schedule(); + } +} + +void EventFramework::Configure(uint32_t key, uint32_t value){ + ctflags &= ~key; + ctflags |= (key & value); +} + +Event* EventFramework::GetEvent(void){ + return event; +} + +bool EventFramework::IsPreemptive(void){ + if((ctflags & SCHED_KEY) == SCHED_VALUE_PREEMPTIVE) + return true; + return false; +} + +void EventFramework::SaveContext(void){ + cbLock(); + nesting++; + cbUnlock(); +} + +void EventFramework::RestoreContext(void){ + cbLock(); + if(nesting > 1){ + cbUnlock(); + return; + } + nesting = 0; + cbUnlock(); + if(cbEnableInterrupts){ + cbEnableInterrupts(); + } + Schedule(); +} + +void EventFramework::Schedule(void){ + volatile static uint16_t curr = 0xFFFF; + volatile uint16_t prev; + volatile uint16_t next; + + for(;;){ + cbLock(); + // if no pending events, then quit + if(!queue){ + cbUnlock(); + return; + } + // extract most priority event + Node* firstNode = queue->GetFirstNode(); + Event* rdyEvent = (Event*)firstNode->GetData(); + next = rdyEvent->GetPrio(); + + // if worst then exit + if(next >= currPrio){ + cbUnlock(); + return; + } + + // else update context + prev = curr; + curr = next; + currPrio = curr; + + // extract event from queue, if no more events, the free queue + queue->Remove(firstNode); + if(!queue->GetFirstNode()){ + delete queue; + queue = NULL; + } + + // get event + Node* nodeHnd = rdyEvent->GetBase()->GetList()->GetFirstNode(); + while(nodeHnd){ + EventHandler* hnd = (EventHandler*)nodeHnd->GetData(); + cbUnlock(); + hnd->Execute(rdyEvent->GetData()); + cbLock(); + nodeHnd = nodeHnd->GetNext(); + } + delete rdyEvent; + curr = prev; + currPrio = curr; + cbUnlock(); + } +// // extract most priority event +// Node* firstNode = queue->GetFirstNode(); +// this->event = (Event*)firstNode->GetData(); +// queue->Remove(firstNode); +// // if no more events, then free queue +// if(!queue->GetFirstNode()){ +// delete queue; +// queue = NULL; +// } +// // get event +// Node* nodeHnd = this->event->GetBase()->GetList()->GetFirstNode(); +// while(nodeHnd){ +// EventHandler* hnd = (EventHandler*)nodeHnd->GetData(); +// hnd->Execute(); +// nodeHnd = nodeHnd->GetNext(); +// } + +} + + +