xref: /xnu-12377.41.6/osfmk/kern/testpoints.h (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1 /*
2  * Copyright (c) 2023 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
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.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
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.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #ifndef _TESTPOINTS_H_
30 #define _TESTPOINTS_H_
31 
32 #ifdef KERNEL
33 #include <kern/kern_types.h>
34 #include <kern/assert.h>
35 #include <kern/locks.h>
36 #else /* KERNEL */
37 #include <sys/types.h>
38 #include <assert.h>
39 #endif /* KERNEL */
40 
41 #include <sys/cdefs.h>
42 
43 /* Testpoints are intended as a generic mechanism which would allow developers
44  * to call a test code from various places of source code by inserting one line
45  * only. What will happen when testpoint is called is determined by current
46  * test scenario which can be set via sysctl. */
47 
48 /* Testpoints scenarios */
49 __enum_decl(tps_id_t, uint64_t, {
50 	TPS_NONE,                       // nothing enabled
51 	TPS_STACKSHOT_UPCALL,           // c-hello-exclaves thread is going to hang in upcall during stackshot and tries to return as soon as it can
52 	TPS_STACKSHOT_LONG_UPCALL,      // c-hello-exclaves thread is going to hang in upcall during stackshot and returns when stackshot is completely done
53 });
54 
55 /* Testpoint definitions */
56 __enum_decl(tp_id_t, uint16_t, {
57 	TP_BLOCK_START_STACKSHOT,       // this action will mark stackshot blocked
58 	TP_WAIT_START_STACKSHOT,        // stackshot thread is waiting here until test thread is in upcall
59 	TP_UPCALL,                      // upcall handler, unblocks stackshot and waits
60 	TP_START_COLLECTION,            // just before exclave threads collection starts, unblocks upcall and waits
61 	TP_AST,                         // before going back to exclaves, unblocks exclaves collection
62 	TP_STACKSHOT_DONE,              // stackshot is done
63 	TESTPOINT_COUNT,
64 });
65 
66 typedef uint32_t tp_val_t;
67 
68 // must fit 64 bits
69 typedef struct tp_sysctl_msg {
70 	uint16_t id;
71 	uint16_t _unused;
72 	uint32_t val;
73 } tp_sysctl_msg_t;
74 
75 static_assert(sizeof(uint64_t) == sizeof(tp_sysctl_msg_t), "tp_sysctl_msg_t does have 64 bits");
76 
77 
78 #if DEBUG || DEVELOPMENT || TESTPOINTS
79 
80 /* Action is determined by current scenario */
81 void
82 tp_call(tp_id_t testpoint, tp_val_t val);
83 
84 #define TESTPOINT(x) tp_call(x, 0);
85 
86 #else /* DEBUG || DEVELOPMENT || TESTPOINTS */
87 
88 #define TESTPOINT(x) ;
89 
90 #endif /* DEBUG || DEVELOPMENT || TESTPOINTS */
91 
92 #if (DEBUG || DEVELOPMENT) && KERNEL
93 
94 /* Below functions are intended for kernel tests implementations. They are not
95  * thread safe and should be protected by tp_mtx. See exclaves_test_stackshot.c
96  * for sample code. */
97 
98 extern lck_mtx_t tp_mtx;
99 
100 /* Set given testpoint value to 1. */
101 void
102 tp_block(tp_id_t testpoint);
103 
104 /* Set given testpoint value to 0 and wakeup waiting threads. */
105 void
106 tp_unblock(tp_id_t other_testpoint);
107 
108 /* Wait until given testpoint value is zero. */
109 void
110 tp_wait(tp_id_t testpoint);
111 
112 /* Unblock other testpoint, then block and wait. */
113 void
114 tp_relay(tp_id_t testpoint, tp_id_t other_testpoint);
115 
116 #endif /* (DEBUG || DEVELOPMENT) && KERNEL */
117 
118 #endif /* _TESTPOINTS_H_ */
119