Home ⌂Doc Index ◂Up ▴
Intel(R) Threading Building Blocks Doxygen Documentation  version 4.2.3
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>
22 namespace tbb {
23 namespace 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 
52 namespace tbb {
53 namespace internal {
54  struct coroutine_type {
56  ucontext_t my_context;
57  void* my_stack;
58  size_t my_stack_size;
59  };
60 }}
61 #endif // _WIN32
62 
63 namespace tbb {
64 namespace 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 
72 class co_context {
73  enum co_state {
78  };
81 
82 public:
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);
95  if (my_state == co_suspended)
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
114  void* get_stack_limit() {
115  return my_coroutine.my_stack;
116  }
117 #endif
118 };
119 
120 // Defined in scheduler.h
121 #if _WIN32
122 void __stdcall co_local_wait_for_all(void*);
123 #else
124 void co_local_wait_for_all(void*);
125 #endif
126 
127 #if _WIN32
128 inline 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 
134 inline void current_coroutine(coroutine_type& c) {
135  c = IsThreadAFiber() ? GetCurrentFiber() :
136  ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH);
137  __TBB_ASSERT(c, NULL);
138 }
139 
140 inline 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 
148 inline void destroy_coroutine(coroutine_type& c) {
149  __TBB_ASSERT(c, NULL);
150  DeleteFiber(c);
151 }
152 #else // !_WIN32
153 
154 inline 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 
189 inline 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 
void co_local_wait_for_all(void *)
#define MAP_ANONYMOUS
Definition: co_context.h:49
void destroy_coroutine(coroutine_type &c)
Definition: co_context.h:194
co_context(size_t stack_size, void *arg)
Definition: co_context.h:83
coroutine_type my_coroutine
Definition: co_context.h:79
#define MAP_STACK
Definition: co_context.h:45
void swap_coroutine(coroutine_type &prev_coroutine, coroutine_type &new_coroutine)
Definition: co_context.h:189
#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
void create_coroutine(coroutine_type &c, size_t stack_size, void *arg)
Definition: co_context.h:154
static size_t default_page_size()
Definition: governor.h:89
void current_coroutine(coroutine_type &c)
Definition: co_context.h:184
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:165
void resume(co_context &target)
Definition: co_context.h:100
The graph class.

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.