2 * Copyright 2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
13 # include <sys/callout.h>
14 # include <sys/mutex.h>
17 #include <util/AutoLock.h>
20 //#define TRACE_CALLOUT
22 # define TRACE(x...) dprintf(x)
24 # define TRACE(x...) ;
28 static struct list sTimers
;
30 static sem_id sWaitSem
;
31 static callout
* sCurrentCallout
;
32 static thread_id sThread
;
33 static bigtime_t sTimeout
;
37 callout_thread(void* /*data*/)
39 status_t status
= B_OK
;
42 bigtime_t timeout
= B_INFINITE_TIMEOUT
;
44 if (status
== B_TIMED_OUT
|| status
== B_OK
) {
45 // scan timers for new timeout and/or execute a timer
48 struct callout
* c
= NULL
;
50 c
= (callout
*)list_get_next_item(&sTimers
, c
);
54 if (c
->due
< system_time()) {
55 struct mtx
*mutex
= c
->c_mtx
;
58 list_remove_item(&sTimers
, c
);
74 sCurrentCallout
= NULL
;
76 // restart scanning as we unlocked the list
78 // calculate new timeout
88 status
= acquire_sem_etc(sWaitSem
, 1, B_ABSOLUTE_TIMEOUT
, timeout
);
89 // the wait sem normally can't be acquired, so we
90 // have to look at the status value the call returns:
92 // B_OK - a new timer has been added or canceled
93 // B_TIMED_OUT - look for timers to be executed
94 // B_BAD_SEM_ID - we are asked to quit
95 } while (status
!= B_BAD_SEM_ID
);
101 // #pragma mark - private API
108 sTimeout
= B_INFINITE_TIMEOUT
;
110 status_t status
= B_OK
;
111 mutex_init(&sLock
, "fbsd callout");
113 sWaitSem
= create_sem(0, "fbsd callout wait");
119 sThread
= spawn_kernel_thread(callout_thread
, "fbsd callout",
120 B_DISPLAY_PRIORITY
, NULL
);
126 return resume_thread(sThread
);
129 mutex_destroy(&sLock
);
131 delete_sem(sWaitSem
);
139 delete_sem(sWaitSem
);
142 mutex_destroy(&sLock
);
145 wait_for_thread(sThread
, &status
);
149 // #pragma mark - public API
153 callout_init(struct callout
*callout
, int mpsafe
)
156 callout_init_mtx(callout
, NULL
, 0);
158 callout_init_mtx(callout
, &Giant
, 0);
163 callout_init_mtx(struct callout
*c
, struct mtx
*mtx
, int flags
)
176 callout_reset(struct callout
*c
, int ticks
, void (*func
)(void *), void *arg
)
178 int canceled
= callout_stop(c
);
180 MutexLocker
locker(sLock
);
185 TRACE("callout_reset %p, func %p, arg %p\n", c
, c
->c_func
, c
->c_arg
);
188 // reschedule or add this timer
190 list_add_item(&sTimers
, c
);
192 c
->due
= system_time() + ticks_to_usecs(ticks
);
194 // notify timer about the change if necessary
195 if (sTimeout
> c
->due
)
196 release_sem(sWaitSem
);
204 callout_schedule(struct callout
*callout
, int ticks
)
206 return callout_reset(callout
, ticks
, callout
->c_func
, callout
->c_arg
);
211 _callout_stop_safe(struct callout
*c
, int safe
)
213 MutexLocker
locker(sLock
);
215 TRACE("_callout_stop_safe %p, func %p, arg %p\n", c
, c
->c_func
, c
->c_arg
);
220 // this timer is scheduled, cancel it
221 list_remove_item(&sTimers
, c
);
228 callout_pending(struct callout
*c
)
235 callout_active(struct callout
*c
)
237 return c
== sCurrentCallout
;