Intel(R) Threading Building Blocks Doxygen Documentation version 4.2.3
Loading...
Searching...
No Matches
co_context.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2005-2020 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17#ifndef _TBB_co_context_H
18#define _TBB_co_context_H
19
20#if _WIN32
21#include <windows.h>
22namespace tbb {
23namespace internal {
24 typedef LPVOID coroutine_type;
25}}
26#else // !_WIN32
27// ucontext.h API is deprecated since macOS 10.6
28#if __APPLE__
29 #if __INTEL_COMPILER
30 #pragma warning(push)
31 #pragma warning(disable:1478)
32 #elif __clang__
33 #pragma clang diagnostic push
34 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
35 #endif
36#endif // __APPLE__
37
38#include <ucontext.h>
39#include <sys/mman.h> // mprotect
40
41#include "governor.h" // default_page_size()
42
43#ifndef MAP_STACK
44// macOS* does not define MAP_STACK
45#define MAP_STACK 0
46#endif
47#ifndef MAP_ANONYMOUS
48// macOS* defines MAP_ANON, which is deprecated in Linux*.
49#define MAP_ANONYMOUS MAP_ANON
50#endif
51
52namespace tbb {
53namespace internal {
56 ucontext_t my_context;
57 void* my_stack;
59 };
60}}
61#endif // _WIN32
62
63namespace tbb {
64namespace internal {
65
66 // Forward declaration of the coroutine API.
67 void create_coroutine(coroutine_type& c, size_t stack_size, void* arg);
68 void current_coroutine(coroutine_type& c);
69 void swap_coroutine(coroutine_type& prev_coroutine, coroutine_type& new_coroutine);
70 void destroy_coroutine(coroutine_type& c);
71
73 enum co_state {
78 };
81
82public:
83 co_context(size_t stack_size, void* arg)
85 {
86 if (arg) {
87 create_coroutine(my_coroutine, stack_size, arg);
88 } else {
90 }
91 }
92
94 __TBB_ASSERT(1 << my_state & (1 << co_suspended | 1 << co_executing), NULL);
98 }
99
100 void resume(co_context& target) {
101 // Do not create non-trivial objects on the stack of this function. They might never be destroyed.
103 __TBB_ASSERT(target.my_state == co_suspended, NULL);
104
106 target.my_state = co_executing;
107
108 // 'target' can reference an invalid object after swap_coroutine. Do not access it.
110
112 }
113#if !_WIN32
115 return my_coroutine.my_stack;
116 }
117#endif
118};
119
120// Defined in scheduler.h
121#if _WIN32
122void __stdcall co_local_wait_for_all(void*);
123#else
125#endif
126
127#if _WIN32
128inline void create_coroutine(coroutine_type& c, size_t stack_size, void* arg) {
129 __TBB_ASSERT(arg, NULL);
130 c = CreateFiber(stack_size, co_local_wait_for_all, arg);
131 __TBB_ASSERT(c, NULL);
132}
133
134inline void current_coroutine(coroutine_type& c) {
135 c = IsThreadAFiber() ? GetCurrentFiber() :
136 ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH);
137 __TBB_ASSERT(c, NULL);
138}
139
140inline void swap_coroutine(coroutine_type& prev_coroutine, coroutine_type& new_coroutine) {
141 __TBB_ASSERT(IsThreadAFiber(), NULL);
142 __TBB_ASSERT(new_coroutine, NULL);
143 prev_coroutine = GetCurrentFiber();
144 __TBB_ASSERT(prev_coroutine, NULL);
145 SwitchToFiber(new_coroutine);
146}
147
148inline void destroy_coroutine(coroutine_type& c) {
149 __TBB_ASSERT(c, NULL);
150 DeleteFiber(c);
151}
152#else // !_WIN32
153
154inline void create_coroutine(coroutine_type& c, size_t stack_size, void* arg) {
155 const size_t REG_PAGE_SIZE = governor::default_page_size();
156 const size_t page_aligned_stack_size = (stack_size + (REG_PAGE_SIZE - 1)) & ~(REG_PAGE_SIZE - 1);
157 const size_t protected_stack_size = page_aligned_stack_size + 2 * REG_PAGE_SIZE;
158
159 // Allocate the stack with protection property
160 uintptr_t stack_ptr = (uintptr_t)mmap(NULL, protected_stack_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
161 __TBB_ASSERT((void*)stack_ptr != MAP_FAILED, NULL);
162
163 // Allow read write on our stack (guarded pages are still protected)
164 int err = mprotect((void*)(stack_ptr + REG_PAGE_SIZE), page_aligned_stack_size, PROT_READ | PROT_WRITE);
165 __TBB_ASSERT_EX(!err, NULL);
166
167 // Remember the stack state
168 c.my_stack = (void*)(stack_ptr + REG_PAGE_SIZE);
169 c.my_stack_size = page_aligned_stack_size;
170
171 err = getcontext(&c.my_context);
172 __TBB_ASSERT_EX(!err, NULL);
173
174 c.my_context.uc_link = 0;
175 // cast to char* to disable FreeBSD clang-3.4.1 'incompatible type' error
176 c.my_context.uc_stack.ss_sp = (char*)c.my_stack;
177 c.my_context.uc_stack.ss_size = c.my_stack_size;
178 c.my_context.uc_stack.ss_flags = 0;
179
180 typedef void(*coroutine_func_t)();
181 makecontext(&c.my_context, (coroutine_func_t)co_local_wait_for_all, sizeof(arg) / sizeof(int), arg);
182}
183
185 int err = getcontext(&c.my_context);
186 __TBB_ASSERT_EX(!err, NULL);
187}
188
189inline void swap_coroutine(coroutine_type& prev_coroutine, coroutine_type& new_coroutine) {
190 int err = swapcontext(&prev_coroutine.my_context, &new_coroutine.my_context);
191 __TBB_ASSERT_EX(!err, NULL);
192}
193
195 const size_t REG_PAGE_SIZE = governor::default_page_size();
196 // Free stack memory with guarded pages
197 munmap((void*)((uintptr_t)c.my_stack - REG_PAGE_SIZE), c.my_stack_size + 2 * REG_PAGE_SIZE);
198 // Clear the stack state afterwards
199 c.my_stack = NULL;
200 c.my_stack_size = 0;
201}
202
203#if __APPLE__
204 #if __INTEL_COMPILER
205 #pragma warning(pop) // 1478 warning
206 #elif __clang__
207 #pragma clang diagnostic pop // "-Wdeprecated-declarations"
208 #endif
209#endif
210
211#endif // _WIN32
212
213} // namespace internal
214} // namespace tbb
215
216#endif /* _TBB_co_context_H */
217
#define __TBB_ASSERT_EX(predicate, comment)
"Extended" version is useful to suppress warnings if a variable is only used with an assert
Definition tbb_stddef.h:167
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition tbb_stddef.h:165
#define MAP_STACK
Definition co_context.h:45
#define MAP_ANONYMOUS
Definition co_context.h:49
The graph class.
void current_coroutine(coroutine_type &c)
Definition co_context.h:184
void destroy_coroutine(coroutine_type &c)
Definition co_context.h:194
void swap_coroutine(coroutine_type &prev_coroutine, coroutine_type &new_coroutine)
Definition co_context.h:189
void create_coroutine(coroutine_type &c, size_t stack_size, void *arg)
Definition co_context.h:154
void co_local_wait_for_all(void *)
void resume(co_context &target)
Definition co_context.h:100
coroutine_type my_coroutine
Definition co_context.h:79
co_context(size_t stack_size, void *arg)
Definition co_context.h:83
static size_t default_page_size()
Definition governor.h:89

Copyright © 2005-2020 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.