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) {
82 if (fFirstEntry
== NULL
) {
83 ASSERT(fEventCount
== 0);
84 ASSERT(fLastEntry
== NULL
);
85 fFirstEntry
= fLastEntry
= new event_queue_entry
;
86 fFirstEntry
->event
= event
;
87 fFirstEntry
->prev
= NULL
;
88 fFirstEntry
->next
= NULL
;
93 //insert at queue begin
94 if (fFirstEntry
->event
.event_time
>= event
.event_time
) {
95 event_queue_entry
*newentry
= new event_queue_entry
;
96 newentry
->event
= event
;
97 newentry
->prev
= NULL
;
98 newentry
->next
= fFirstEntry
;
99 fFirstEntry
->prev
= newentry
;
100 fFirstEntry
= newentry
;
105 //insert at queue end
106 if (fLastEntry
->event
.event_time
<= event
.event_time
) {
107 event_queue_entry
*newentry
= new event_queue_entry
;
108 newentry
->event
= event
;
109 newentry
->prev
= fLastEntry
;
110 newentry
->next
= NULL
;
111 fLastEntry
->next
= newentry
;
112 fLastEntry
= newentry
;
117 //insert into the queue
118 for (event_queue_entry
*entry
= fLastEntry
; entry
; entry
= entry
->prev
) {
119 if (entry
->event
.event_time
<= event
.event_time
) {
121 event_queue_entry
*newentry
= new event_queue_entry
;
122 newentry
->event
= event
;
123 newentry
->prev
= entry
;
124 newentry
->next
= entry
->next
;
125 (entry
->next
)->prev
= newentry
;
126 entry
->next
= newentry
;
132 debugger("_event_queue_imp::AddEvent failed, should not be here\n");
138 _event_queue_imp::RemoveEvent(const media_timed_event
*event
)
140 BAutolock
lock(fLock
);
142 for (event_queue_entry
*entry
= fFirstEntry
; entry
; entry
= entry
->next
) {
143 if (entry
->event
== *event
) {
155 _event_queue_imp::RemoveFirstEvent(media_timed_event
* outEvent
)
157 BAutolock
lock(fLock
);
159 if (fFirstEntry
== 0)
164 *outEvent
= fFirstEntry
->event
;
166 CleanupEvent(&fFirstEntry
->event
);
169 RemoveEntry(fFirstEntry
);
176 _event_queue_imp::HasEvents() const
178 return fEventCount
!= 0;
183 _event_queue_imp::EventCount() const
192 const media_timed_event
*
193 _event_queue_imp::FirstEvent() const
195 return fFirstEntry
? &fFirstEntry
->event
: NULL
;
200 _event_queue_imp::FirstEventTime() const
202 return fFirstEntry
? fFirstEntry
->event
.event_time
: B_INFINITE_TIMEOUT
;
206 const media_timed_event
*
207 _event_queue_imp::LastEvent() const
209 return fLastEntry
? &fLastEntry
->event
: NULL
;
214 _event_queue_imp::LastEventTime() const
216 return fLastEntry
? fLastEntry
->event
.event_time
: B_INFINITE_TIMEOUT
;
220 const media_timed_event
*
221 _event_queue_imp::FindFirstMatch(bigtime_t eventTime
,
222 BTimedEventQueue::time_direction direction
,
226 event_queue_entry
*end
;
227 event_queue_entry
*entry
;
229 BAutolock
lock(fLock
);
232 case BTimedEventQueue::B_ALWAYS
:
233 for (entry
= fFirstEntry
; entry
; entry
= entry
->next
) {
234 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
)
235 return &entry
->event
;
239 case BTimedEventQueue::B_BEFORE_TIME
:
240 end
= GetEnd_BeforeTime(eventTime
, inclusive
);
244 for (entry
= fFirstEntry
; entry
!= end
; entry
= entry
->next
) {
245 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
246 return &entry
->event
;
251 case BTimedEventQueue::B_AT_TIME
:
253 bool found_time
= false;
254 for (entry
= fFirstEntry
; entry
; entry
= entry
->next
) {
255 if (eventTime
== entry
->event
.event_time
) {
257 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
)
258 return &entry
->event
;
259 } else if (found_time
)
265 case BTimedEventQueue::B_AFTER_TIME
:
266 for (entry
= GetStart_AfterTime(eventTime
, inclusive
); entry
; entry
= entry
->next
) {
267 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
268 return &entry
->event
;
279 _event_queue_imp::DoForEach(BTimedEventQueue::for_each_hook hook
,
282 BTimedEventQueue::time_direction direction
,
286 event_queue_entry
*end
;
287 event_queue_entry
*entry
;
288 event_queue_entry
*remove
;
289 BTimedEventQueue::queue_action action
;
291 BAutolock
lock(fLock
);
294 case BTimedEventQueue::B_ALWAYS
:
295 for (entry
= fFirstEntry
; entry
; ) {
296 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
297 action
= (*hook
)(&entry
->event
, context
);
299 case BTimedEventQueue::B_DONE
:
301 case BTimedEventQueue::B_REMOVE_EVENT
:
302 CleanupEvent(&entry
->event
);
307 case BTimedEventQueue::B_NO_ACTION
:
308 case BTimedEventQueue::B_RESORT_QUEUE
:
319 case BTimedEventQueue::B_BEFORE_TIME
:
320 end
= GetEnd_BeforeTime(eventTime
, inclusive
);
324 for (entry
= fFirstEntry
; entry
!= end
; ) {
325 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
326 action
= (*hook
)(&entry
->event
, context
);
328 case BTimedEventQueue::B_DONE
:
330 case BTimedEventQueue::B_REMOVE_EVENT
:
331 CleanupEvent(&entry
->event
);
336 case BTimedEventQueue::B_NO_ACTION
:
337 case BTimedEventQueue::B_RESORT_QUEUE
:
348 case BTimedEventQueue::B_AT_TIME
:
350 bool found_time
= false;
351 for (entry
= fFirstEntry
; entry
; ) {
352 if (eventTime
== entry
->event
.event_time
) {
354 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
355 action
= (*hook
)(&entry
->event
, context
);
357 case BTimedEventQueue::B_DONE
:
359 case BTimedEventQueue::B_REMOVE_EVENT
:
360 CleanupEvent(&entry
->event
);
365 case BTimedEventQueue::B_NO_ACTION
:
366 case BTimedEventQueue::B_RESORT_QUEUE
:
374 } else if (found_time
) {
383 case BTimedEventQueue::B_AFTER_TIME
:
384 for (entry
= GetStart_AfterTime(eventTime
, inclusive
); entry
; ) {
385 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
386 action
= (*hook
)(&entry
->event
, context
);
388 case BTimedEventQueue::B_DONE
:
390 case BTimedEventQueue::B_REMOVE_EVENT
:
391 CleanupEvent(&entry
->event
);
396 case BTimedEventQueue::B_NO_ACTION
:
397 case BTimedEventQueue::B_RESORT_QUEUE
:
414 _event_queue_imp::FlushEvents(bigtime_t eventTime
,
415 BTimedEventQueue::time_direction direction
,
419 event_queue_entry
*end
;
420 event_queue_entry
*entry
;
421 event_queue_entry
*remove
;
423 BAutolock
lock(fLock
);
426 case BTimedEventQueue::B_ALWAYS
:
427 for (entry
= fFirstEntry
; entry
; ) {
428 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
429 CleanupEvent(&entry
->event
);
439 case BTimedEventQueue::B_BEFORE_TIME
:
440 end
= GetEnd_BeforeTime(eventTime
, inclusive
);
444 for (entry
= fFirstEntry
; entry
!= end
; ) {
445 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
446 CleanupEvent(&entry
->event
);
456 case BTimedEventQueue::B_AT_TIME
:
458 bool found_time
= false;
459 for (entry
= fFirstEntry
; entry
; ) {
460 if (eventTime
== entry
->event
.event_time
) {
462 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
463 CleanupEvent(&entry
->event
);
470 } else if (found_time
) {
479 case BTimedEventQueue::B_AFTER_TIME
:
480 for (entry
= GetStart_AfterTime(eventTime
, inclusive
); entry
; ) {
481 if (eventType
== BTimedEventQueue::B_ANY_EVENT
|| eventType
== entry
->event
.type
) {
482 CleanupEvent(&entry
->event
);
498 _event_queue_imp::SetCleanupHook(BTimedEventQueue::cleanup_hook hook
, void *context
)
500 BAutolock
lock(fLock
);
501 fCleanupHookContext
= context
;
507 _event_queue_imp::RemoveEntry(event_queue_entry
*entry
)
509 //remove the entry from double-linked list
511 if (entry
->prev
!= NULL
)
512 (entry
->prev
)->next
= entry
->next
;
513 if (entry
->next
!= NULL
)
514 (entry
->next
)->prev
= entry
->prev
;
515 if (entry
== fFirstEntry
) {
516 fFirstEntry
= entry
->next
;
517 if (fFirstEntry
!= NULL
)
518 fFirstEntry
->prev
= NULL
;
520 if (entry
== fLastEntry
) {
521 fLastEntry
= entry
->prev
;
522 if (fLastEntry
!= NULL
)
523 fLastEntry
->next
= NULL
;
527 ASSERT(fEventCount
>= 0);
528 ASSERT(fEventCount
!= 0 || ((fFirstEntry
== NULL
) && (fLastEntry
== NULL
)));
533 _event_queue_imp::CleanupEvent(media_timed_event
*event
)
535 //perform the cleanup action required
536 //when deleting an event from the queue
539 // Each event has a cleanup flag associated with it that indicates
540 // what sort of special action needs to be performed when the event is
541 // removed from the queue. If this value is B_NO_CLEANUP, nothing is done.
542 // If it's B_RECYCLE, and the event is a B_HANDLE_BUFFER event, BTimedEventQueue
543 // will automatically recycle the buffer associated with the event.
544 // If the cleanup flag is B_DELETE or is B_USER_CLEANUP or greater,
545 // the cleanup hook function will be called.
547 // cleanup hook function specified by hook to be called for events
548 // as they're removed from the queue. The hook will be called only
549 // for events with cleanup_flag values of B_DELETE or B_USER_CLEANUP or greater.
551 // These values define how BTimedEventQueue should handle removing
552 // events from the queue. If the flag is B_USER_CLEANUP or greater,
553 // the cleanup hook function is called when the event is removed.
555 // B_DELETE is a keyboard code! (seems to have existed in early
556 // sample code as a cleanup flag)
558 // exiting cleanup flags are:
560 // B_RECYCLE_BUFFER, // recycle buffers handled by BTimedEventQueue
561 // B_EXPIRE_TIMER, // call TimerExpired() on the event->data
562 // B_USER_CLEANUP = 0x4000 // others go to the cleanup func
565 if (event
->cleanup
== BTimedEventQueue::B_NO_CLEANUP
) {
567 } else if (event
->type
== BTimedEventQueue::B_HANDLE_BUFFER
568 && event
->cleanup
== BTimedEventQueue::B_RECYCLE_BUFFER
) {
569 ((BBuffer
*)event
->pointer
)->Recycle();
570 DEBUG_ONLY(*const_cast<void **>(&event
->pointer
) = NULL
);
571 } else if (event
->cleanup
== BTimedEventQueue::B_EXPIRE_TIMER
) {
572 // do nothing, called in BMediaEventLooper::DispatchEvent
573 } else if (event
->cleanup
== B_DELETE
574 || event
->cleanup
>= BTimedEventQueue::B_USER_CLEANUP
) {
576 (*fCleanupHook
)(event
,fCleanupHookContext
);
578 ERROR("BTimedEventQueue cleanup unhandled! type = %" B_PRId32
579 ", cleanup = %" B_PRId32
"\n", event
->type
, event
->cleanup
);
584 _event_queue_imp::event_queue_entry
*
585 _event_queue_imp::GetEnd_BeforeTime(bigtime_t eventTime
, bool inclusive
)
587 event_queue_entry
*entry
;
591 if ((entry
->event
.event_time
> eventTime
) || (!inclusive
&& entry
->event
.event_time
== eventTime
))
600 _event_queue_imp::event_queue_entry
*
601 _event_queue_imp::GetStart_AfterTime(bigtime_t eventTime
, bool inclusive
)
603 event_queue_entry
*entry
;
607 if ((entry
->event
.event_time
< eventTime
) || (!inclusive
&& entry
->event
.event_time
== eventTime
))
618 _event_queue_imp::Dump() const
620 TRACE("fEventCount = %" B_PRId32
"\n", fEventCount
);
621 TRACE("fFirstEntry = 0x%p\n", (void*)fFirstEntry
);
622 TRACE("fLastEntry = 0x%p\n", (void*)fLastEntry
);
623 for (event_queue_entry
*entry
= fFirstEntry
; entry
; entry
= entry
->next
) {
624 TRACE("entry = 0x%p\n", (void*)entry
);
625 TRACE(" entry.prev = 0x%p\n", (void*)entry
->prev
);
626 TRACE(" entry.next = 0x%p\n", (void*)entry
->next
);
627 TRACE(" entry.event.event_time = %" B_PRId64
"\n",
628 entry
->event
.event_time
);