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.
EventFramework.cpp
- Committer:
- raulMrello
- Date:
- 2012-10-03
- Revision:
- 1:ec12f2e32faf
- Parent:
- 0:9d09acc8f9d9
File content as of revision 1:ec12f2e32faf:
/* 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){ nesting--; 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(); } }