xref: /NextBSD/lib/libdispatch/src/shims/yield.h (revision 33da5adc555b3bc29986eeadca03829e4ad06b1e)
1 /*
2  * Copyright (c) 2013 Apple Inc. All rights reserved.
3  *
4  * @APPLE_APACHE_LICENSE_HEADER_START@
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * @APPLE_APACHE_LICENSE_HEADER_END@
19  */
20 
21 /*
22  * IMPORTANT: This header file describes INTERNAL interfaces to libdispatch
23  * which are subject to change in future releases of Mac OS X. Any applications
24  * relying on these interfaces WILL break.
25  */
26 
27 #ifndef __DISPATCH_SHIMS_YIELD__
28 #define __DISPATCH_SHIMS_YIELD__
29 
30 #pragma mark -
31 #pragma mark _dispatch_wait_until
32 
33 #if DISPATCH_HW_CONFIG_UP
34 #define _dispatch_wait_until(c) do { \
35 		int _spins = 0; \
36 		while (!(c)) { \
37 			_spins++; \
38 			_dispatch_preemption_yield(_spins); \
39 		} } while (0)
40 #elif TARGET_OS_EMBEDDED
41 // <rdar://problem/15440575>
42 #ifndef DISPATCH_WAIT_SPINS
43 #define DISPATCH_WAIT_SPINS 1024
44 #endif
45 #define _dispatch_wait_until(c) do { \
46 		int _spins = -(DISPATCH_WAIT_SPINS); \
47 		while (!(c)) { \
48 			if (slowpath(_spins++ >= 0)) { \
49 				_dispatch_preemption_yield(_spins); \
50 			} else { \
51 				dispatch_hardware_pause(); \
52 			} \
53 		} } while (0)
54 #else
55 #define _dispatch_wait_until(c) do { \
56 		while (!(c)) { \
57 			dispatch_hardware_pause(); \
58 		} } while (0)
59 #endif
60 
61 #pragma mark -
62 #pragma mark _dispatch_contention_wait_until
63 
64 #if DISPATCH_HW_CONFIG_UP
65 #define _dispatch_contention_wait_until(c) false
66 #else
67 #ifndef DISPATCH_CONTENTION_SPINS_MAX
68 #define DISPATCH_CONTENTION_SPINS_MAX (128 - 1)
69 #endif
70 #ifndef DISPATCH_CONTENTION_SPINS_MIN
71 #define DISPATCH_CONTENTION_SPINS_MIN (32 - 1)
72 #endif
73 #if TARGET_OS_EMBEDDED
74 #define _dispatch_contention_spins() \
75 		((DISPATCH_CONTENTION_SPINS_MIN) + ((DISPATCH_CONTENTION_SPINS_MAX) - \
76 		(DISPATCH_CONTENTION_SPINS_MIN)) / 2)
77 #else
78 // Use randomness to prevent threads from resonating at the same
79 // frequency and permanently contending. All threads sharing the same
80 // seed value is safe with the FreeBSD rand_r implementation.
81 #define _dispatch_contention_spins() ({ \
82 		static unsigned int _seed; \
83 		((unsigned int)rand_r(&_seed) & (DISPATCH_CONTENTION_SPINS_MAX)) | \
84 				(DISPATCH_CONTENTION_SPINS_MIN); })
85 #endif
86 #define _dispatch_contention_wait_until(c) ({ \
87 		bool _out = false; \
88 		unsigned int _spins = _dispatch_contention_spins(); \
89 		while (_spins--) { \
90 			dispatch_hardware_pause(); \
91 			if ((_out = fastpath(c))) break; \
92 		}; _out; })
93 #endif
94 
95 #pragma mark -
96 #pragma mark dispatch_hardware_pause
97 
98 #if defined(__x86_64__) || defined(__i386__)
99 #define dispatch_hardware_pause() __asm__("pause")
100 #elif (defined(__arm__) && defined(_ARM_ARCH_7) && defined(__thumb__)) || \
101 		defined(__arm64__)
102 #define dispatch_hardware_pause() __asm__("yield")
103 #define dispatch_hardware_wfe()   __asm__("wfe")
104 #else
105 #define dispatch_hardware_pause() __asm__("")
106 #endif
107 
108 #pragma mark -
109 #pragma mark _dispatch_preemption_yield
110 
111 #if HAVE_MACH
112 #if defined(SWITCH_OPTION_OSLOCK_DEPRESS) && !(TARGET_IPHONE_SIMULATOR && \
113 		IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED < 1090)
114 #define DISPATCH_YIELD_THREAD_SWITCH_OPTION SWITCH_OPTION_OSLOCK_DEPRESS
115 #else
116 #define DISPATCH_YIELD_THREAD_SWITCH_OPTION SWITCH_OPTION_DEPRESS
117 #endif
118 #define _dispatch_preemption_yield(n) _dispatch_thread_switch(MACH_PORT_NULL, \
119 		DISPATCH_YIELD_THREAD_SWITCH_OPTION, (mach_msg_timeout_t)(n))
120 #else
121 #define _dispatch_preemption_yield(n) pthread_yield_np()
122 #endif // HAVE_MACH
123 
124 #pragma mark -
125 #pragma mark _dispatch_contention_usleep
126 
127 #ifndef DISPATCH_CONTENTION_USLEEP_START
128 #define DISPATCH_CONTENTION_USLEEP_START 500
129 #endif
130 #ifndef DISPATCH_CONTENTION_USLEEP_MAX
131 #define DISPATCH_CONTENTION_USLEEP_MAX 100000
132 #endif
133 
134 #if HAVE_MACH
135 #if defined(SWITCH_OPTION_DISPATCH_CONTENTION) && !(TARGET_IPHONE_SIMULATOR && \
136 		IPHONE_SIMULATOR_HOST_MIN_VERSION_REQUIRED < 1090)
137 #define _dispatch_contention_usleep(u) _dispatch_thread_switch(MACH_PORT_NULL, \
138 		SWITCH_OPTION_DISPATCH_CONTENTION, (u))
139 #else
140 #define _dispatch_contention_usleep(u) _dispatch_thread_switch(MACH_PORT_NULL, \
141 		SWITCH_OPTION_WAIT, (((u)-1)/1000)+1)
142 #endif
143 #else
144 #define _dispatch_contention_usleep(u) usleep((u))
145 #endif // HAVE_MACH
146 
147 #pragma mark -
148 #pragma mark _dispatch_thread_switch
149 
150 #if HAVE_MACH
151 #define _dispatch_thread_switch(thread_name, option, option_time) \
152 		thread_switch((thread_name), (option), (option_time))
153 
154 #endif // HAVE_MACH
155 
156 #endif // __DISPATCH_SHIMS_YIELD__
157