1/* 2 * Copyright (c) 2000-2008, Ingo Weinhold <ingo_weinhold@gmx.de>, 3 * Copyright (c) 2000-2008, Stephan Aßmus <superstippi@gmx.de>, 4 * All Rights Reserved. Distributed under the terms of the MIT license. 5 */ 6#include <new> 7#include <stdio.h> 8 9#include "Event.h" 10 11#include "EventQueue.h" 12 13using std::nothrow; 14 15 16EventQueue::EventQueue() 17 : fEvents(100), 18 fEventExecutor(-1), 19 fThreadControl(-1), 20 fNextEventTime(0), 21 fStatus(B_ERROR) 22 23{ 24 fThreadControl = create_sem(0, "event queue control"); 25 if (fThreadControl >= B_OK) 26 fStatus = B_OK; 27 else 28 fStatus = fThreadControl; 29 if (fStatus == B_OK) { 30 fEventExecutor = spawn_thread(_execute_events_, "event queue runner", 31 B_NORMAL_PRIORITY, this); 32 if (fEventExecutor >= B_OK) { 33 fStatus = B_OK; 34 resume_thread(fEventExecutor); 35 } else 36 fStatus = fEventExecutor; 37 } 38} 39 40 41EventQueue::~EventQueue() 42{ 43 if (delete_sem(fThreadControl) == B_OK) 44 wait_for_thread(fEventExecutor, &fEventExecutor); 45 while (Event *event = (Event*)fEvents.RemoveItem((int32)0)) { 46 if (event->AutoDelete()) 47 delete event; 48 } 49} 50 51 52status_t 53EventQueue::InitCheck() 54{ 55 return fStatus; 56} 57 58 59EventQueue* 60EventQueue::CreateDefault() 61{ 62 if (!fDefaultQueue) { 63 fDefaultQueue = new(nothrow) EventQueue; 64 if (fDefaultQueue && fDefaultQueue->InitCheck() != B_OK) 65 DeleteDefault(); 66 } 67 return fDefaultQueue; 68} 69 70 71void 72EventQueue::DeleteDefault() 73{ 74 if (fDefaultQueue) { 75 delete fDefaultQueue; 76 fDefaultQueue = NULL; 77 } 78} 79 80 81EventQueue& 82EventQueue::Default() 83{ 84 return *fDefaultQueue; 85} 86 87 88void 89EventQueue::AddEvent(Event* event) 90{ 91 Lock(); 92 _AddEvent(event); 93 _Reschedule(); 94 Unlock(); 95} 96 97 98bool 99EventQueue::RemoveEvent(Event* event) 100{ 101 bool result = false; 102 Lock(); 103 if ((result = fEvents.RemoveItem(event))) 104 _Reschedule(); 105 Unlock(); 106 return result; 107} 108 109 110void 111EventQueue::ChangeEvent(Event* event, bigtime_t newTime) 112{ 113 Lock(); 114 if (fEvents.RemoveItem(event)) { 115 event->SetTime(newTime); 116 _AddEvent(event); 117 _Reschedule(); 118 } 119 Unlock(); 120} 121 122 123// PRE: The object must be locked. 124void 125EventQueue::_AddEvent(Event* event) 126{ 127 // find the insertion index 128 int32 lower = 0; 129 int32 upper = fEvents.CountItems(); 130 while (lower < upper) { 131 int32 mid = (lower + upper) / 2; 132 Event* midEvent = _EventAt(mid); 133 if (event->Time() < midEvent->Time()) 134 upper = mid; 135 else 136 lower = mid + 1; 137 } 138 fEvents.AddItem(event, lower); 139} 140 141 142Event* 143EventQueue::_EventAt(int32 index) const 144{ 145 return (Event*)fEvents.ItemAtFast(index); 146} 147 148 149int32 150EventQueue::_execute_events_(void* cookie) 151{ 152 EventQueue *gc = (EventQueue*)cookie; 153 return gc->_ExecuteEvents(); 154} 155 156 157int32 158EventQueue::_ExecuteEvents() 159{ 160 bool running = true; 161 while (running) { 162 bigtime_t waitUntil = B_INFINITE_TIMEOUT; 163 if (Lock()) { 164 if (!fEvents.IsEmpty()) 165 waitUntil = _EventAt(0)->Time(); 166 fNextEventTime = waitUntil; 167 Unlock(); 168 } 169 status_t err = acquire_sem_etc(fThreadControl, 1, B_ABSOLUTE_TIMEOUT, 170 waitUntil); 171 switch (err) { 172 case B_TIMED_OUT: 173 // execute events, that are supposed to go off 174 if (Lock()) { 175 while (!fEvents.IsEmpty() 176 && system_time() >= _EventAt(0)->Time()) { 177 Event* event = (Event*)fEvents.RemoveItem((int32)0); 178 bool deleteEvent = event->AutoDelete(); 179 event->Execute(); 180 if (deleteEvent) 181 delete event; 182 } 183 Unlock(); 184 } 185 break; 186 case B_BAD_SEM_ID: 187 running = false; 188 break; 189 case B_OK: 190 default: 191 break; 192 } 193 } 194 return 0; 195} 196 197 198// PRE: The object must be locked. 199void 200EventQueue::_Reschedule() 201{ 202 if (fStatus == B_OK) { 203 if (!fEvents.IsEmpty() && _EventAt(0)->Time() < fNextEventTime) 204 release_sem(fThreadControl); 205 } 206} 207 208 209// static variables 210 211EventQueue* EventQueue::fDefaultQueue = NULL; 212 213