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