vfs: check userland buffers before reading them.
[haiku.git] / src / apps / mediaplayer / support / EventQueue.cpp
blob2d8acf57873ef30af3baafcb9ae861f9d21ac346
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>
9 #include "Event.h"
11 #include "EventQueue.h"
13 using std::nothrow;
16 EventQueue::EventQueue()
17 : fEvents(100),
18 fEventExecutor(-1),
19 fThreadControl(-1),
20 fNextEventTime(0),
21 fStatus(B_ERROR)
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;
41 EventQueue::~EventQueue()
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;
52 status_t
53 EventQueue::InitCheck()
55 return fStatus;
59 EventQueue*
60 EventQueue::CreateDefault()
62 if (!fDefaultQueue) {
63 fDefaultQueue = new(nothrow) EventQueue;
64 if (fDefaultQueue && fDefaultQueue->InitCheck() != B_OK)
65 DeleteDefault();
67 return fDefaultQueue;
71 void
72 EventQueue::DeleteDefault()
74 if (fDefaultQueue) {
75 delete fDefaultQueue;
76 fDefaultQueue = NULL;
81 EventQueue&
82 EventQueue::Default()
84 return *fDefaultQueue;
88 void
89 EventQueue::AddEvent(Event* event)
91 Lock();
92 _AddEvent(event);
93 _Reschedule();
94 Unlock();
98 bool
99 EventQueue::RemoveEvent(Event* event)
101 bool result = false;
102 Lock();
103 if ((result = fEvents.RemoveItem(event)))
104 _Reschedule();
105 Unlock();
106 return result;
110 void
111 EventQueue::ChangeEvent(Event* event, bigtime_t newTime)
113 Lock();
114 if (fEvents.RemoveItem(event)) {
115 event->SetTime(newTime);
116 _AddEvent(event);
117 _Reschedule();
119 Unlock();
123 // PRE: The object must be locked.
124 void
125 EventQueue::_AddEvent(Event* event)
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;
138 fEvents.AddItem(event, lower);
142 Event*
143 EventQueue::_EventAt(int32 index) const
145 return (Event*)fEvents.ItemAtFast(index);
149 int32
150 EventQueue::_execute_events_(void* cookie)
152 EventQueue *gc = (EventQueue*)cookie;
153 return gc->_ExecuteEvents();
157 int32
158 EventQueue::_ExecuteEvents()
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();
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;
183 Unlock();
185 break;
186 case B_BAD_SEM_ID:
187 running = false;
188 break;
189 case B_OK:
190 default:
191 break;
194 return 0;
198 // PRE: The object must be locked.
199 void
200 EventQueue::_Reschedule()
202 if (fStatus == B_OK) {
203 if (!fEvents.IsEmpty() && _EventAt(0)->Time() < fNextEventTime)
204 release_sem(fThreadControl);
209 // static variables
211 EventQueue* EventQueue::fDefaultQueue = NULL;