2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #if !(DEVELOPMENT || DEBUG)
30 #error "Testing is not enabled on RELEASE configurations"
33 #include <tests/xnupost.h>
34 #include <kern/thread_call.h>
35 #include <kern/locks.h>
36 #include <kern/sched_prim.h>
38 kern_return_t
test_thread_call(void);
40 lck_grp_t test_lock_grp
;
48 int wait_for_callback
;
51 int once_callback_counter
= 0;
54 test_once_callback(thread_call_param_t param0
,
55 thread_call_param_t param1
)
57 T_ASSERT_EQ_INT((test_param
)param0
, TEST_ARG1
, "param0 is correct");
58 T_ASSERT_EQ_INT((test_param
)param1
, TEST_ARG2
, "param1 is correct");
60 once_callback_counter
++;
62 T_ASSERT_EQ_INT(once_callback_counter
, 1, "only one callback");
64 lck_mtx_lock(&test_lock
);
66 thread_wakeup(&wait_for_callback
);
69 clock_interval_to_deadline(10, NSEC_PER_SEC
, &deadline
);
72 /* wait for the main thread to finish, time out after 10s */
73 kr
= lck_mtx_sleep_deadline(&test_lock
, LCK_SLEEP_DEFAULT
, &wait_for_main
, THREAD_UNINT
, deadline
);
74 T_ASSERT_EQ_INT(kr
, THREAD_AWAKENED
, " callback woken by main function");
76 lck_mtx_unlock(&test_lock
);
78 /* sleep for 1s to let the main thread begin the cancel and wait */
79 delay_for_interval(1, NSEC_PER_SEC
);
83 test_once_thread_call(void)
85 lck_grp_init(&test_lock_grp
, "test_thread_call", LCK_GRP_ATTR_NULL
);
86 lck_mtx_init(&test_lock
, &test_lock_grp
, LCK_ATTR_NULL
);
89 call
= thread_call_allocate_with_options(&test_once_callback
,
90 (thread_call_param_t
)TEST_ARG1
,
91 THREAD_CALL_PRIORITY_HIGH
,
92 THREAD_CALL_OPTIONS_ONCE
);
94 thread_call_param_t arg2_param
= (thread_call_param_t
)TEST_ARG2
;
96 lck_mtx_lock(&test_lock
);
98 thread_call_enter1(call
, arg2_param
);
101 clock_interval_to_deadline(10, NSEC_PER_SEC
, &deadline
);
104 /* wait for the call to execute, time out after 10s */
105 kr
= lck_mtx_sleep_deadline(&test_lock
, LCK_SLEEP_DEFAULT
, &wait_for_callback
, THREAD_UNINT
, deadline
);
106 T_ASSERT_EQ_INT(kr
, THREAD_AWAKENED
, "main function woken by callback");
108 lck_mtx_unlock(&test_lock
);
110 /* at this point the callback is stuck waiting */
112 T_ASSERT_EQ_INT(once_callback_counter
, 1, "callback fired");
114 boolean_t canceled
, pending
, freed
;
116 canceled
= thread_call_cancel(call
);
117 T_ASSERT_EQ_INT(canceled
, FALSE
, "thread_call_cancel should not succeed");
119 pending
= thread_call_enter1(call
, arg2_param
);
120 T_ASSERT_EQ_INT(pending
, FALSE
, "call should not be pending");
122 /* sleep for 10ms, the call should not execute */
123 delay_for_interval(10, NSEC_PER_MSEC
);
125 canceled
= thread_call_cancel(call
);
126 T_ASSERT_EQ_INT(canceled
, TRUE
, "thread_call_cancel should succeed");
128 pending
= thread_call_enter1(call
, arg2_param
);
129 T_ASSERT_EQ_INT(pending
, FALSE
, "call should not be pending");
131 freed
= thread_call_free(call
);
132 T_ASSERT_EQ_INT(freed
, FALSE
, "thread_call_free should not succeed");
134 pending
= thread_call_enter1(call
, arg2_param
);
135 T_ASSERT_EQ_INT(pending
, TRUE
, "call should be pending");
137 thread_wakeup(&wait_for_main
);
139 canceled
= thread_call_cancel_wait(call
);
140 T_ASSERT_EQ_INT(canceled
, TRUE
, "thread_call_cancel_wait should succeed");
142 canceled
= thread_call_cancel(call
);
143 T_ASSERT_EQ_INT(canceled
, FALSE
, "thread_call_cancel should not succeed");
145 freed
= thread_call_free(call
);
146 T_ASSERT_EQ_INT(freed
, TRUE
, "thread_call_free should succeed");
149 int signal_callback_counter
= 0;
152 test_signal_callback(__unused thread_call_param_t param0
,
153 __unused thread_call_param_t param1
)
156 * ktest sometimes panics if you assert from interrupt context,
157 * and the serial logging will blow past the delay to wait for the interrupt
158 * so don't print in this context.
161 signal_callback_counter
++;
165 test_signal_thread_call(void)
168 call
= thread_call_allocate_with_options(&test_signal_callback
,
169 (thread_call_param_t
)TEST_ARG1
,
170 THREAD_CALL_PRIORITY_HIGH
,
171 THREAD_CALL_OPTIONS_ONCE
| THREAD_CALL_OPTIONS_SIGNAL
);
173 thread_call_param_t arg2_param
= (thread_call_param_t
)TEST_ARG2
;
177 boolean_t canceled
, pending
, freed
;
179 clock_interval_to_deadline(10, NSEC_PER_SEC
, &deadline
);
180 pending
= thread_call_enter1_delayed(call
, arg2_param
, deadline
);
181 T_ASSERT_EQ_INT(pending
, FALSE
, "call should not be pending");
183 canceled
= thread_call_cancel(call
);
184 T_ASSERT_EQ_INT(canceled
, TRUE
, "thread_call_cancel should succeed");
186 clock_interval_to_deadline(10, NSEC_PER_MSEC
, &deadline
);
187 pending
= thread_call_enter1_delayed(call
, arg2_param
, deadline
);
188 T_ASSERT_EQ_INT(pending
, FALSE
, "call should not be pending");
190 /* sleep for 50ms to let the interrupt fire */
191 delay_for_interval(50, NSEC_PER_MSEC
);
193 T_ASSERT_EQ_INT(signal_callback_counter
, 1, "callback fired");
195 canceled
= thread_call_cancel(call
);
196 T_ASSERT_EQ_INT(canceled
, FALSE
, "thread_call_cancel should not succeed");
198 freed
= thread_call_free(call
);
199 T_ASSERT_EQ_INT(freed
, TRUE
, "thread_call_free should succeed");
203 test_thread_call(void)
205 test_once_thread_call();
206 test_signal_thread_call();