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 13 using std::nothrow; 14 15 16 EventQueue::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 41 EventQueue::~EventQueue() 42 { 43 if (delete_sem(fThreadControl) == B_OK) 44 wait_for_thread(fEventExecutor, &fEventExecutor); 45 while (Event *event = (Event*)fEvents.RemoveItem(0L)) { 46 if (event->AutoDelete()) 47 delete event; 48 } 49 } 50 51 52 status_t 53 EventQueue::InitCheck() 54 { 55 return fStatus; 56 } 57 58 59 EventQueue* 60 EventQueue::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 71 void 72 EventQueue::DeleteDefault() 73 { 74 if (fDefaultQueue) { 75 delete fDefaultQueue; 76 fDefaultQueue = NULL; 77 } 78 } 79 80 81 EventQueue& 82 EventQueue::Default() 83 { 84 return *fDefaultQueue; 85 } 86 87 88 void 89 EventQueue::AddEvent(Event* event) 90 { 91 Lock(); 92 _AddEvent(event); 93 _Reschedule(); 94 Unlock(); 95 } 96 97 98 bool 99 EventQueue::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 110 void 111 EventQueue::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. 124 void 125 EventQueue::_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 142 Event* 143 EventQueue::_EventAt(int32 index) const 144 { 145 return (Event*)fEvents.ItemAtFast(index); 146 } 147 148 149 int32 150 EventQueue::_execute_events_(void* cookie) 151 { 152 EventQueue *gc = (EventQueue*)cookie; 153 return gc->_ExecuteEvents(); 154 } 155 156 157 int32 158 EventQueue::_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(0L); 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. 199 void 200 EventQueue::_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 211 EventQueue* EventQueue::fDefaultQueue = NULL; 212 213