#include <sys/kdebug.h>
-decl_simple_lock_data(static,thread_call_lock)
static zone_t thread_call_zone;
struct thread_call_group {
queue_head_t pending_queue;
- uint32_t pending_count;
+ uint32_t pending_count;
queue_head_t delayed_queue;
struct wait_queue idle_wqueue;
struct wait_queue daemon_wqueue;
- uint32_t idle_count, active_count;
+ uint32_t idle_count, active_count;
};
typedef struct thread_call_group *thread_call_group_t;
thread_call_thread(
thread_call_group_t group);
-static void thread_call_delayed_timer(
+extern void thread_call_delayed_timer(
timer_call_param_t p0,
timer_call_param_t p1);
#define qe(x) ((queue_entry_t)(x))
#define TC(x) ((thread_call_t)(x))
+
+lck_grp_t thread_call_queues_lck_grp;
+lck_grp_t thread_call_lck_grp;
+lck_attr_t thread_call_lck_attr;
+lck_grp_attr_t thread_call_lck_grp_attr;
+
+#if defined(__i386__) || defined(__x86_64__)
+lck_mtx_t thread_call_lock_data;
+#else
+lck_spin_t thread_call_lock_data;
+#endif
+
+#define thread_call_lock_spin() \
+ lck_mtx_lock_spin_always(&thread_call_lock_data)
+
+#define thread_call_unlock() \
+ lck_mtx_unlock_always(&thread_call_lock_data)
+
+
/*
* thread_call_initialize:
*
void
thread_call_initialize(void)
{
- thread_call_t call;
+ thread_call_t call;
thread_call_group_t group = &thread_call_group0;
kern_return_t result;
thread_t thread;
i = sizeof (thread_call_data_t);
thread_call_zone = zinit(i, 4096 * i, 16 * i, "thread_call");
+ zone_change(thread_call_zone, Z_CALLERACCT, FALSE);
zone_change(thread_call_zone, Z_NOENCRYPT, TRUE);
- simple_lock_init(&thread_call_lock, 0);
+ lck_attr_setdefault(&thread_call_lck_attr);
+ lck_grp_attr_setdefault(&thread_call_lck_grp_attr);
+ lck_grp_init(&thread_call_queues_lck_grp, "thread_call_queues", &thread_call_lck_grp_attr);
+ lck_grp_init(&thread_call_lck_grp, "thread_call", &thread_call_lck_grp_attr);
- s = splsched();
- simple_lock(&thread_call_lock);
+#if defined(__i386__) || defined(__x86_64__)
+ lck_mtx_init(&thread_call_lock_data, &thread_call_lck_grp, &thread_call_lck_attr);
+#else
+ lck_spin_init(&thread_call_lock_data, &thread_call_lck_grp, &thread_call_lck_attr);
+#endif
+ queue_init(&group->pending_queue);
+ queue_init(&group->delayed_queue);
- queue_init(&group->pending_queue);
- queue_init(&group->delayed_queue);
+ s = splsched();
+ thread_call_lock_spin();
timer_call_setup(&group->delayed_timer, thread_call_delayed_timer, group);
wait_queue_init(&group->idle_wqueue, SYNC_POLICY_FIFO);
wait_queue_init(&group->daemon_wqueue, SYNC_POLICY_FIFO);
- queue_init(&thread_call_internal_queue);
- for (
+ queue_init(&thread_call_internal_queue);
+ for (
call = internal_call_storage;
call < &internal_call_storage[internal_call_count];
call++) {
enqueue_tail(&thread_call_internal_queue, qe(call));
- }
+ }
thread_call_daemon_awake = TRUE;
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
splx(s);
result = kernel_thread_start_priority((thread_continue_t)thread_call_daemon, group, BASEPRI_PREEMPT + 1, &thread);
thread_call_t call,
thread_call_group_t group)
{
- queue_t old_queue;
+ queue_head_t *old_queue;
old_queue = call_entry_enqueue_tail(call, &group->pending_queue);
_delayed_call_enqueue(
thread_call_t call,
thread_call_group_t group,
- uint64_t deadline)
+ uint64_t deadline)
{
- queue_t old_queue;
+ queue_head_t *old_queue;
old_queue = call_entry_enqueue_deadline(call, &group->delayed_queue, deadline);
thread_call_t call,
thread_call_group_t group)
{
- queue_t old_queue;
+ queue_head_t *old_queue;
old_queue = call_entry_dequeue(call);
thread_call_t call,
thread_call_group_t group)
{
- timer_call_enter(&group->delayed_timer, call->deadline);
+ timer_call_enter(&group->delayed_timer, call->deadline, 0);
}
/*
thread_call_param_t param0,
boolean_t remove_all)
{
- boolean_t call_removed = FALSE;
+ boolean_t call_removed = FALSE;
thread_call_t call;
thread_call_group_t group = &thread_call_group0;
spl_t s;
s = splsched();
- simple_lock(&thread_call_lock);
+ thread_call_lock_spin();
call = TC(queue_first(&group->pending_queue));
thread_call_wake(group);
}
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
splx(s);
}
spl_t s;
s = splsched();
- simple_lock(&thread_call_lock);
+ thread_call_lock_spin();
call = _internal_call_allocate();
call->func = func;
if (queue_first(&group->delayed_queue) == qe(call))
_set_delayed_call_timer(call, group);
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
splx(s);
}
spl_t s;
s = splsched();
- simple_lock(&thread_call_lock);
+ thread_call_lock_spin();
if (cancel_all)
result = _remove_from_pending_queue(func, param, cancel_all) |
result = _remove_from_pending_queue(func, param, cancel_all) ||
_remove_from_delayed_queue(func, param, cancel_all);
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
splx(s);
return (result);
spl_t s;
s = splsched();
- simple_lock(&thread_call_lock);
+ thread_call_lock_spin();
if (call->queue != NULL) {
- simple_unlock(&thread_call_lock);
- splx(s);
+ thread_call_unlock();
+ splx(s);
- return (FALSE);
+ return (FALSE);
}
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
splx(s);
zfree(thread_call_zone, call);
{
boolean_t result = TRUE;
thread_call_group_t group = &thread_call_group0;
- spl_t s;
+ spl_t s;
- s = splsched();
- simple_lock(&thread_call_lock);
+ s = splsched();
+ thread_call_lock_spin();
if (call->queue != &group->pending_queue) {
result = _pending_call_enqueue(call, group);
call->param1 = 0;
- simple_unlock(&thread_call_lock);
- splx(s);
+ thread_call_unlock();
+ splx(s);
return (result);
}
{
boolean_t result = TRUE;
thread_call_group_t group = &thread_call_group0;
- spl_t s;
+ spl_t s;
- s = splsched();
- simple_lock(&thread_call_lock);
+ s = splsched();
+ thread_call_lock_spin();
if (call->queue != &group->pending_queue) {
result = _pending_call_enqueue(call, group);
call->param1 = param1;
- simple_unlock(&thread_call_lock);
- splx(s);
+ thread_call_unlock();
+ splx(s);
return (result);
}
{
boolean_t result = TRUE;
thread_call_group_t group = &thread_call_group0;
- spl_t s;
+ spl_t s;
- s = splsched();
- simple_lock(&thread_call_lock);
+ s = splsched();
+ thread_call_lock_spin();
result = _delayed_call_enqueue(call, group, deadline);
call->param1 = 0;
- simple_unlock(&thread_call_lock);
- splx(s);
+ thread_call_unlock();
+ splx(s);
return (result);
}
{
boolean_t result = TRUE;
thread_call_group_t group = &thread_call_group0;
- spl_t s;
+ spl_t s;
- s = splsched();
- simple_lock(&thread_call_lock);
+ s = splsched();
+ thread_call_lock_spin();
result = _delayed_call_enqueue(call, group, deadline);
call->param1 = param1;
- simple_unlock(&thread_call_lock);
- splx(s);
+ thread_call_unlock();
+ splx(s);
return (result);
}
{
boolean_t result;
thread_call_group_t group = &thread_call_group0;
- spl_t s;
+ spl_t s;
- s = splsched();
- simple_lock(&thread_call_lock);
+ s = splsched();
+ thread_call_lock_spin();
result = _call_dequeue(call, group);
- simple_unlock(&thread_call_lock);
- splx(s);
+ thread_call_unlock();
+ splx(s);
return (result);
}
spl_t s;
s = splsched();
- simple_lock(&thread_call_lock);
+ thread_call_lock_spin();
if (call->queue == &group->delayed_queue) {
if (deadline != NULL)
result = TRUE;
}
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
splx(s);
return (result);
thread_call_wake(
thread_call_group_t group)
{
- if (group->idle_count > 0 && wait_queue_wakeup_one(&group->idle_wqueue, NULL, THREAD_AWAKENED) == KERN_SUCCESS) {
+ if (group->idle_count > 0 && wait_queue_wakeup_one(&group->idle_wqueue, NO_EVENT, THREAD_AWAKENED, -1) == KERN_SUCCESS) {
group->idle_count--; group->active_count++;
}
else
if (!thread_call_daemon_awake) {
thread_call_daemon_awake = TRUE;
- wait_queue_wakeup_one(&group->daemon_wqueue, NULL, THREAD_AWAKENED);
+ wait_queue_wakeup_one(&group->daemon_wqueue, NO_EVENT, THREAD_AWAKENED, -1);
}
}
{
thread_call_group_t group = &thread_call_group0;
- simple_lock(&thread_call_lock);
+ thread_call_lock_spin();
switch (type) {
break;
}
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
}
/*
{
thread_t self = current_thread();
- (void) splsched();
- simple_lock(&thread_call_lock);
+ (void) splsched();
+ thread_call_lock_spin();
thread_sched_call(self, sched_call_thread);
_internal_call_release(call);
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
(void) spllo();
KERNEL_DEBUG_CONSTANT(
(*func)(param0, param1);
+ if (get_preemption_level() != 0) {
+ int pl = get_preemption_level();
+ panic("thread_call_thread: preemption_level %d, last callout %p(%p, %p)",
+ pl, func, param0, param1);
+ }
+
(void)thread_funnel_set(self->funnel_lock, FALSE); /* XXX */
(void) splsched();
- simple_lock(&thread_call_lock);
+ thread_call_lock_spin();
}
thread_sched_call(self, NULL);
if (group->idle_count < thread_call_thread_min) {
group->idle_count++;
- wait_queue_assert_wait(&group->idle_wqueue, NULL, THREAD_UNINT, 0);
+ wait_queue_assert_wait(&group->idle_wqueue, NO_EVENT, THREAD_UNINT, 0);
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
(void) spllo();
thread_block_parameter((thread_continue_t)thread_call_thread, group);
/* NOTREACHED */
}
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
(void) spllo();
thread_terminate(self);
thread_t thread;
(void) splsched();
- simple_lock(&thread_call_lock);
+ thread_call_lock_spin();
while (group->active_count == 0 && group->pending_count > 0) {
group->active_count++;
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
(void) spllo();
result = kernel_thread_start_priority((thread_continue_t)thread_call_thread, group, BASEPRI_PREEMPT, &thread);
thread_deallocate(thread);
(void) splsched();
- simple_lock(&thread_call_lock);
+ thread_call_lock_spin();
}
thread_call_daemon_awake = FALSE;
- wait_queue_assert_wait(&group->daemon_wqueue, NULL, THREAD_UNINT, 0);
+ wait_queue_assert_wait(&group->daemon_wqueue, NO_EVENT, THREAD_UNINT, 0);
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
(void) spllo();
thread_block_parameter((thread_continue_t)thread_call_daemon_continue, group);
/* NOTREACHED */
}
-static void
+void
thread_call_delayed_timer(
timer_call_param_t p0,
__unused timer_call_param_t p1
boolean_t new_pending = FALSE;
uint64_t timestamp;
- simple_lock(&thread_call_lock);
+ thread_call_lock_spin();
timestamp = mach_absolute_time();
if (new_pending && group->active_count == 0)
thread_call_wake(group);
- simple_unlock(&thread_call_lock);
+ thread_call_unlock();
}