tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / media / TimedEventQueuePrivate.cpp
blob3cc337c50a7f68beb863d33660b789872f89c562
1 /*
2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files or portions
6 * thereof (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so, subject
10 * to the following conditions:
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright notice
16 * in the binary, as well as this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided with
18 * the distribution.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
30 /* Implements _event_queue_imp used by BTimedEventQueue, not thread save!
32 #include <string.h>
34 #include <Autolock.h>
35 #include <Buffer.h>
36 #include <InterfaceDefs.h> //defines B_DELETE
37 #include <TimedEventQueue.h>
38 #include <TimeSource.h>
40 #include "TimedEventQueuePrivate.h"
42 #include "Debug.h"
43 #include "debug.h"
45 _event_queue_imp::_event_queue_imp() :
46 fLock(new BLocker("BTimedEventQueue locker")),
47 fEventCount(0),
48 fFirstEntry(NULL),
49 fLastEntry(NULL),
50 fCleanupHookContext(NULL),
51 fCleanupHook(0)
56 _event_queue_imp::~_event_queue_imp()
58 event_queue_entry *entry;
59 entry = fFirstEntry;
60 while (entry) {
61 event_queue_entry *deleteme;
62 deleteme = entry;
63 entry = entry->next;
64 delete deleteme;
66 delete fLock;
70 status_t
71 _event_queue_imp::AddEvent(const media_timed_event &event)
73 BAutolock lock(fLock);
75 // printf(" adding %12Ld at %12Ld\n", event.event_time, system_time());
77 if (event.type <= 0) {
78 return B_BAD_VALUE;
81 *(bigtime_t *)&event.queued_time = BTimeSource::RealTime();
83 //create a new queue
84 if (fFirstEntry == NULL) {
85 ASSERT(fEventCount == 0);
86 ASSERT(fLastEntry == NULL);
87 fFirstEntry = fLastEntry = new event_queue_entry;
88 fFirstEntry->event = event;
89 fFirstEntry->prev = NULL;
90 fFirstEntry->next = NULL;
91 fEventCount++;
92 return B_OK;
95 //insert at queue begin
96 if (fFirstEntry->event.event_time >= event.event_time) {
97 event_queue_entry *newentry = new event_queue_entry;
98 newentry->event = event;
99 newentry->prev = NULL;
100 newentry->next = fFirstEntry;
101 fFirstEntry->prev = newentry;
102 fFirstEntry = newentry;
103 fEventCount++;
104 return B_OK;
107 //insert at queue end
108 if (fLastEntry->event.event_time <= event.event_time) {
109 event_queue_entry *newentry = new event_queue_entry;
110 newentry->event = event;
111 newentry->prev = fLastEntry;
112 newentry->next = NULL;
113 fLastEntry->next = newentry;
114 fLastEntry = newentry;
115 fEventCount++;
116 return B_OK;
119 //insert into the queue
120 for (event_queue_entry *entry = fLastEntry; entry; entry = entry->prev) {
121 if (entry->event.event_time <= event.event_time) {
122 //insert after entry
123 event_queue_entry *newentry = new event_queue_entry;
124 newentry->event = event;
125 newentry->prev = entry;
126 newentry->next = entry->next;
127 (entry->next)->prev = newentry;
128 entry->next = newentry;
129 fEventCount++;
130 return B_OK;
134 debugger("_event_queue_imp::AddEvent failed, should not be here\n");
135 return B_OK;
139 status_t
140 _event_queue_imp::RemoveEvent(const media_timed_event *event)
142 BAutolock lock(fLock);
144 for (event_queue_entry *entry = fFirstEntry; entry; entry = entry->next) {
145 if (entry->event == *event) {
146 // No cleanup here
147 RemoveEntry(entry);
148 return B_OK;
152 return B_ERROR;
156 status_t
157 _event_queue_imp::RemoveFirstEvent(media_timed_event * outEvent)
159 BAutolock lock(fLock);
161 if (fFirstEntry == 0)
162 return B_ERROR;
164 if (outEvent != 0) {
165 // No cleanup here
166 *outEvent = fFirstEntry->event;
167 } else {
168 CleanupEvent(&fFirstEntry->event);
171 RemoveEntry(fFirstEntry);
173 return B_OK;
177 bool
178 _event_queue_imp::HasEvents() const
180 return fEventCount != 0;
184 int32
185 _event_queue_imp::EventCount() const
187 #if DEBUG > 1
188 Dump();
189 #endif
190 return fEventCount;
194 const media_timed_event *
195 _event_queue_imp::FirstEvent() const
197 return fFirstEntry ? &fFirstEntry->event : NULL;
201 bigtime_t
202 _event_queue_imp::FirstEventTime() const
204 return fFirstEntry ? fFirstEntry->event.event_time : B_INFINITE_TIMEOUT;
208 const media_timed_event *
209 _event_queue_imp::LastEvent() const
211 return fLastEntry ? &fLastEntry->event : NULL;
215 bigtime_t
216 _event_queue_imp::LastEventTime() const
218 return fLastEntry ? fLastEntry->event.event_time : B_INFINITE_TIMEOUT;
222 const media_timed_event *
223 _event_queue_imp::FindFirstMatch(bigtime_t eventTime,
224 BTimedEventQueue::time_direction direction,
225 bool inclusive,
226 int32 eventType)
228 event_queue_entry *end;
229 event_queue_entry *entry;
231 BAutolock lock(fLock);
233 switch (direction) {
234 case BTimedEventQueue::B_ALWAYS:
235 for (entry = fFirstEntry; entry; entry = entry->next) {
236 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type)
237 return &entry->event;
239 return NULL;
241 case BTimedEventQueue::B_BEFORE_TIME:
242 end = GetEnd_BeforeTime(eventTime, inclusive);
243 if (end == NULL)
244 return NULL;
245 end = end->next;
246 for (entry = fFirstEntry; entry != end; entry = entry->next) {
247 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
248 return &entry->event;
251 return NULL;
253 case BTimedEventQueue::B_AT_TIME:
255 bool found_time = false;
256 for (entry = fFirstEntry; entry; entry = entry->next) {
257 if (eventTime == entry->event.event_time) {
258 found_time = true;
259 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type)
260 return &entry->event;
261 } else if (found_time)
262 return NULL;
264 return NULL;
267 case BTimedEventQueue::B_AFTER_TIME:
268 for (entry = GetStart_AfterTime(eventTime, inclusive); entry; entry = entry->next) {
269 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
270 return &entry->event;
273 return NULL;
276 return NULL;
280 status_t
281 _event_queue_imp::DoForEach(BTimedEventQueue::for_each_hook hook,
282 void *context,
283 bigtime_t eventTime,
284 BTimedEventQueue::time_direction direction,
285 bool inclusive,
286 int32 eventType)
288 event_queue_entry *end;
289 event_queue_entry *entry;
290 event_queue_entry *remove;
291 BTimedEventQueue::queue_action action;
293 BAutolock lock(fLock);
295 switch (direction) {
296 case BTimedEventQueue::B_ALWAYS:
297 for (entry = fFirstEntry; entry; ) {
298 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
299 action = (*hook)(&entry->event, context);
300 switch (action) {
301 case BTimedEventQueue::B_DONE:
302 return B_OK;
303 case BTimedEventQueue::B_REMOVE_EVENT:
304 CleanupEvent(&entry->event);
305 remove = entry;
306 entry = entry->next;
307 RemoveEntry(remove);
308 break;
309 case BTimedEventQueue::B_NO_ACTION:
310 case BTimedEventQueue::B_RESORT_QUEUE:
311 default:
312 entry = entry->next;
313 break;
315 } else {
316 entry = entry->next;
319 return B_OK;
321 case BTimedEventQueue::B_BEFORE_TIME:
322 end = GetEnd_BeforeTime(eventTime, inclusive);
323 if (end == NULL)
324 return B_OK;
325 end = end->next;
326 for (entry = fFirstEntry; entry != end; ) {
327 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
328 action = (*hook)(&entry->event, context);
329 switch (action) {
330 case BTimedEventQueue::B_DONE:
331 return B_OK;
332 case BTimedEventQueue::B_REMOVE_EVENT:
333 CleanupEvent(&entry->event);
334 remove = entry;
335 entry = entry->next;
336 RemoveEntry(remove);
337 break;
338 case BTimedEventQueue::B_NO_ACTION:
339 case BTimedEventQueue::B_RESORT_QUEUE:
340 default:
341 entry = entry->next;
342 break;
344 } else {
345 entry = entry->next;
348 return B_OK;
350 case BTimedEventQueue::B_AT_TIME:
352 bool found_time = false;
353 for (entry = fFirstEntry; entry; ) {
354 if (eventTime == entry->event.event_time) {
355 found_time = true;
356 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
357 action = (*hook)(&entry->event, context);
358 switch (action) {
359 case BTimedEventQueue::B_DONE:
360 return B_OK;
361 case BTimedEventQueue::B_REMOVE_EVENT:
362 CleanupEvent(&entry->event);
363 remove = entry;
364 entry = entry->next;
365 RemoveEntry(remove);
366 break;
367 case BTimedEventQueue::B_NO_ACTION:
368 case BTimedEventQueue::B_RESORT_QUEUE:
369 default:
370 entry = entry->next;
371 break;
373 } else {
374 entry = entry->next;
376 } else if (found_time) {
377 break;
378 } else {
379 entry = entry->next;
382 return B_OK;
385 case BTimedEventQueue::B_AFTER_TIME:
386 for (entry = GetStart_AfterTime(eventTime, inclusive); entry; ) {
387 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
388 action = (*hook)(&entry->event, context);
389 switch (action) {
390 case BTimedEventQueue::B_DONE:
391 return B_OK;
392 case BTimedEventQueue::B_REMOVE_EVENT:
393 CleanupEvent(&entry->event);
394 remove = entry;
395 entry = entry->next;
396 RemoveEntry(remove);
397 break;
398 case BTimedEventQueue::B_NO_ACTION:
399 case BTimedEventQueue::B_RESORT_QUEUE:
400 default:
401 entry = entry->next;
402 break;
404 } else {
405 entry = entry->next;
408 return B_OK;
411 return B_ERROR;
415 status_t
416 _event_queue_imp::FlushEvents(bigtime_t eventTime,
417 BTimedEventQueue::time_direction direction,
418 bool inclusive,
419 int32 eventType)
421 event_queue_entry *end;
422 event_queue_entry *entry;
423 event_queue_entry *remove;
425 BAutolock lock(fLock);
427 switch (direction) {
428 case BTimedEventQueue::B_ALWAYS:
429 for (entry = fFirstEntry; entry; ) {
430 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
431 CleanupEvent(&entry->event);
432 remove = entry;
433 entry = entry->next;
434 RemoveEntry(remove);
435 } else {
436 entry = entry->next;
439 return B_OK;
441 case BTimedEventQueue::B_BEFORE_TIME:
442 end = GetEnd_BeforeTime(eventTime, inclusive);
443 if (end == NULL)
444 return B_OK;
445 end = end->next;
446 for (entry = fFirstEntry; entry != end; ) {
447 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
448 CleanupEvent(&entry->event);
449 remove = entry;
450 entry = entry->next;
451 RemoveEntry(remove);
452 } else {
453 entry = entry->next;
456 return B_OK;
458 case BTimedEventQueue::B_AT_TIME:
460 bool found_time = false;
461 for (entry = fFirstEntry; entry; ) {
462 if (eventTime == entry->event.event_time) {
463 found_time = true;
464 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
465 CleanupEvent(&entry->event);
466 remove = entry;
467 entry = entry->next;
468 RemoveEntry(remove);
469 } else {
470 entry = entry->next;
472 } else if (found_time) {
473 break;
474 } else {
475 entry = entry->next;
478 return B_OK;
481 case BTimedEventQueue::B_AFTER_TIME:
482 for (entry = GetStart_AfterTime(eventTime, inclusive); entry; ) {
483 if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
484 CleanupEvent(&entry->event);
485 remove = entry;
486 entry = entry->next;
487 RemoveEntry(remove);
488 } else {
489 entry = entry->next;
492 return B_OK;
495 return B_ERROR;
499 void
500 _event_queue_imp::SetCleanupHook(BTimedEventQueue::cleanup_hook hook, void *context)
502 BAutolock lock(fLock);
503 fCleanupHookContext = context;
504 fCleanupHook = hook;
508 void
509 _event_queue_imp::RemoveEntry(event_queue_entry *entry)
511 //remove the entry from double-linked list
512 //and delete it
513 if (entry->prev != NULL)
514 (entry->prev)->next = entry->next;
515 if (entry->next != NULL)
516 (entry->next)->prev = entry->prev;
517 if (entry == fFirstEntry) {
518 fFirstEntry = entry->next;
519 if (fFirstEntry != NULL)
520 fFirstEntry->prev = NULL;
522 if (entry == fLastEntry) {
523 fLastEntry = entry->prev;
524 if (fLastEntry != NULL)
525 fLastEntry->next = NULL;
527 delete entry;
528 fEventCount--;
529 ASSERT(fEventCount >= 0);
530 ASSERT(fEventCount != 0 || ((fFirstEntry == NULL) && (fLastEntry == NULL)));
534 void
535 _event_queue_imp::CleanupEvent(media_timed_event *event)
537 //perform the cleanup action required
538 //when deleting an event from the queue
540 //BeBook says:
541 // Each event has a cleanup flag associated with it that indicates
542 // what sort of special action needs to be performed when the event is
543 // removed from the queue. If this value is B_NO_CLEANUP, nothing is done.
544 // If it's B_RECYCLE, and the event is a B_HANDLE_BUFFER event, BTimedEventQueue
545 // will automatically recycle the buffer associated with the event.
546 // If the cleanup flag is B_DELETE or is B_USER_CLEANUP or greater,
547 // the cleanup hook function will be called.
548 //and:
549 // cleanup hook function specified by hook to be called for events
550 // as they're removed from the queue. The hook will be called only
551 // for events with cleanup_flag values of B_DELETE or B_USER_CLEANUP or greater.
552 //and:
553 // These values define how BTimedEventQueue should handle removing
554 // events from the queue. If the flag is B_USER_CLEANUP or greater,
555 // the cleanup hook function is called when the event is removed.
556 //Problems:
557 // B_DELETE is a keyboard code! (seems to have existed in early
558 // sample code as a cleanup flag)
560 // exiting cleanup flags are:
561 // B_NO_CLEANUP = 0,
562 // B_RECYCLE_BUFFER, // recycle buffers handled by BTimedEventQueue
563 // B_EXPIRE_TIMER, // call TimerExpired() on the event->data
564 // B_USER_CLEANUP = 0x4000 // others go to the cleanup func
567 if (event->cleanup == BTimedEventQueue::B_NO_CLEANUP) {
568 // do nothing
569 } else if (event->type == BTimedEventQueue::B_HANDLE_BUFFER
570 && event->cleanup == BTimedEventQueue::B_RECYCLE_BUFFER) {
571 ((BBuffer *)event->pointer)->Recycle();
572 DEBUG_ONLY(*const_cast<void **>(&event->pointer) = NULL);
573 } else if (event->cleanup == BTimedEventQueue::B_EXPIRE_TIMER) {
574 // do nothing, called in BMediaEventLooper::DispatchEvent
575 } else if (event->cleanup == B_DELETE
576 || event->cleanup >= BTimedEventQueue::B_USER_CLEANUP) {
577 if (fCleanupHook)
578 (*fCleanupHook)(event,fCleanupHookContext);
579 } else {
580 ERROR("BTimedEventQueue cleanup unhandled! type = %" B_PRId32
581 ", cleanup = %" B_PRId32 "\n", event->type, event->cleanup);
586 _event_queue_imp::event_queue_entry *
587 _event_queue_imp::GetEnd_BeforeTime(bigtime_t eventTime, bool inclusive)
589 event_queue_entry *entry;
591 entry = fLastEntry;
592 while (entry) {
593 if ((entry->event.event_time > eventTime) || (!inclusive && entry->event.event_time == eventTime))
594 entry = entry->prev;
595 else
596 break;
598 return entry;
602 _event_queue_imp::event_queue_entry *
603 _event_queue_imp::GetStart_AfterTime(bigtime_t eventTime, bool inclusive)
605 event_queue_entry *entry;
607 entry = fFirstEntry;
608 while (entry) {
609 if ((entry->event.event_time < eventTime) || (!inclusive && entry->event.event_time == eventTime))
610 entry = entry->next;
611 else
612 break;
614 return entry;
618 #if DEBUG > 1
619 void
620 _event_queue_imp::Dump() const
622 TRACE("fEventCount = 0x%x\n",(int)fEventCount);
623 TRACE("fFirstEntry = 0x%x\n",(int)fFirstEntry);
624 TRACE("fLastEntry = 0x%x\n",(int)fLastEntry);
625 for (event_queue_entry *entry = fFirstEntry; entry; entry = entry->next) {
626 TRACE("entry = 0x%x\n",(int)entry);
627 TRACE(" entry.prev = 0x%x\n",(int)entry->prev);
628 TRACE(" entry.next = 0x%x\n",(int)entry->next);
629 TRACE(" entry.event.event_time = 0x%x\n",(int)entry->event.event_time);
632 #endif