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
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
30 /* Implements _event_queue_imp used by BTimedEventQueue, not thread save!
36 #include <InterfaceDefs.h> //defines B_DELETE
37 #include <TimedEventQueue.h>
38 #include <TimeSource.h>
40 #include "TimedEventQueuePrivate.h"
45 _event_queue_imp::_event_queue_imp() :
46 fLock(new BLocker("BTimedEventQueue locker")),
50 fCleanupHookContext(NULL
),
56 _event_queue_imp::~_event_queue_imp()
58 event_queue_entry
*entry
;
61 event_queue_entry
*deleteme
;
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) {
81 *(bigtime_t
*)&event
.queued_time
= BTimeSource::RealTime();
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
;
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
;
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
;
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
) {
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
;
134 debugger("_event_queue_imp::AddEvent failed, should not be here\n");
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
) {
157 _event_queue_imp::RemoveFirstEvent(media_timed_event
* outEvent
)
159 BAutolock
lock(fLock
);
161 if (fFirstEntry
== 0)
166 *outEvent
= fFirstEntry
->event
;
168 CleanupEvent(&fFirstEntry
->event
);
171 RemoveEntry(fFirstEntry
);
178 _event_queue_imp::HasEvents() const
180 return fEventCount
!= 0;
185 _event_queue_imp::EventCount() const
194 const media_timed_event
*
195 _event_queue_imp::FirstEvent() const
197 return fFirstEntry
? &fFirstEntry
->event
: NULL
;
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
;
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
,
228 event_queue_entry
*end
;
229 event_queue_entry
*entry
;
231 BAutolock
lock(fLock
);
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
;
241 case BTimedEventQueue::B_BEFORE_TIME
:
242 end
= GetEnd_BeforeTime(eventTime
, inclusive
);
246 for (entry
= fFirstEntry
; entry
!= end
; entry
= entry
->next
) {
247 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
248 return &entry
->event
;
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
) {
259 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
)
260 return &entry
->event
;
261 } else if (found_time
)
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
;
281 _event_queue_imp::DoForEach(BTimedEventQueue::for_each_hook hook
,
284 BTimedEventQueue::time_direction direction
,
288 event_queue_entry
*end
;
289 event_queue_entry
*entry
;
290 event_queue_entry
*remove
;
291 BTimedEventQueue::queue_action action
;
293 BAutolock
lock(fLock
);
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
);
301 case BTimedEventQueue::B_DONE
:
303 case BTimedEventQueue::B_REMOVE_EVENT
:
304 CleanupEvent(&entry
->event
);
309 case BTimedEventQueue::B_NO_ACTION
:
310 case BTimedEventQueue::B_RESORT_QUEUE
:
321 case BTimedEventQueue::B_BEFORE_TIME
:
322 end
= GetEnd_BeforeTime(eventTime
, inclusive
);
326 for (entry
= fFirstEntry
; entry
!= end
; ) {
327 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
328 action
= (*hook
)(&entry
->event
, context
);
330 case BTimedEventQueue::B_DONE
:
332 case BTimedEventQueue::B_REMOVE_EVENT
:
333 CleanupEvent(&entry
->event
);
338 case BTimedEventQueue::B_NO_ACTION
:
339 case BTimedEventQueue::B_RESORT_QUEUE
:
350 case BTimedEventQueue::B_AT_TIME
:
352 bool found_time
= false;
353 for (entry
= fFirstEntry
; entry
; ) {
354 if (eventTime
== entry
->event
.event_time
) {
356 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
357 action
= (*hook
)(&entry
->event
, context
);
359 case BTimedEventQueue::B_DONE
:
361 case BTimedEventQueue::B_REMOVE_EVENT
:
362 CleanupEvent(&entry
->event
);
367 case BTimedEventQueue::B_NO_ACTION
:
368 case BTimedEventQueue::B_RESORT_QUEUE
:
376 } else if (found_time
) {
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
);
390 case BTimedEventQueue::B_DONE
:
392 case BTimedEventQueue::B_REMOVE_EVENT
:
393 CleanupEvent(&entry
->event
);
398 case BTimedEventQueue::B_NO_ACTION
:
399 case BTimedEventQueue::B_RESORT_QUEUE
:
416 _event_queue_imp::FlushEvents(bigtime_t eventTime
,
417 BTimedEventQueue::time_direction direction
,
421 event_queue_entry
*end
;
422 event_queue_entry
*entry
;
423 event_queue_entry
*remove
;
425 BAutolock
lock(fLock
);
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
);
441 case BTimedEventQueue::B_BEFORE_TIME
:
442 end
= GetEnd_BeforeTime(eventTime
, inclusive
);
446 for (entry
= fFirstEntry
; entry
!= end
; ) {
447 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
448 CleanupEvent(&entry
->event
);
458 case BTimedEventQueue::B_AT_TIME
:
460 bool found_time
= false;
461 for (entry
= fFirstEntry
; entry
; ) {
462 if (eventTime
== entry
->event
.event_time
) {
464 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
465 CleanupEvent(&entry
->event
);
472 } else if (found_time
) {
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
);
500 _event_queue_imp::SetCleanupHook(BTimedEventQueue::cleanup_hook hook
, void *context
)
502 BAutolock
lock(fLock
);
503 fCleanupHookContext
= context
;
509 _event_queue_imp::RemoveEntry(event_queue_entry
*entry
)
511 //remove the entry from double-linked list
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
;
529 ASSERT(fEventCount
>= 0);
530 ASSERT(fEventCount
!= 0 || ((fFirstEntry
== NULL
) && (fLastEntry
== NULL
)));
535 _event_queue_imp::CleanupEvent(media_timed_event
*event
)
537 //perform the cleanup action required
538 //when deleting an event from the queue
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.
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.
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.
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:
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
) {
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
) {
578 (*fCleanupHook
)(event
,fCleanupHookContext
);
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
;
593 if ((entry
->event
.event_time
> eventTime
) || (!inclusive
&& entry
->event
.event_time
== eventTime
))
602 _event_queue_imp::event_queue_entry
*
603 _event_queue_imp::GetStart_AfterTime(bigtime_t eventTime
, bool inclusive
)
605 event_queue_entry
*entry
;
609 if ((entry
->event
.event_time
< eventTime
) || (!inclusive
&& entry
->event
.event_time
== eventTime
))
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
);