[RS6000] PR72802 part 2, reload ICE
[official-gcc.git] / libcilkrts / runtime / cilk_fiber-unix.cpp
blobd59bfcae4cb561f0d021aa84b8b68e14cab676f9
1 /* cilk_fiber-unix.cpp -*-C++-*-
3 *************************************************************************
5 * Copyright (C) 2012-2016, Intel Corporation
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * * Neither the name of Intel Corporation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
32 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
35 * *********************************************************************
37 * PLEASE NOTE: This file is a downstream copy of a file mainitained in
38 * a repository at cilkplus.org. Changes made to this file that are not
39 * submitted through the contribution process detailed at
40 * http://www.cilkplus.org/submit-cilk-contribution will be lost the next
41 * time that a new version is released. Changes only submitted to the
42 * GNU compiler collection or posted to the git repository at
43 * https://bitbucket.org/intelcilkruntime/intel-cilk-runtime.git are
44 * not tracked.
46 * We welcome your contributions to this open source project. Thank you
47 * for your assistance in helping us improve Cilk Plus.
48 **************************************************************************/
50 #include "cilk_fiber-unix.h"
51 #include "cilk_malloc.h"
52 #include "bug.h"
53 #include "os.h"
55 #include <cstdio>
56 #include <cstdlib>
58 #include <errno.h>
59 #include <sys/mman.h>
60 #include <unistd.h>
61 #include "declare-alloca.h"
63 // MAP_ANON is deprecated on Linux, but seems to be required on Mac...
64 #ifndef MAP_ANONYMOUS
65 # define MAP_ANONYMOUS MAP_ANON
66 #endif
68 // MAP_STACK and MAP_GROWSDOWN have no affect in Linux as of 2014-04-04, but
69 // could be very useful in future versions. If they are not defined, then set
70 // them to zero (no bits set).
71 #ifndef MAP_STACK
72 # define MAP_STACK 0
73 #endif
74 #ifndef MAP_GROWSDOWN
75 # define MAP_GROWSDOWN 0
76 #endif
78 // Magic number for sanity checking fiber structure
79 const unsigned magic_number = 0x5afef00d;
81 // Page size for stacks
82 #ifdef _WRS_KERNEL
83 long cilk_fiber_sysdep::s_page_size = 4096;
84 #else
85 long cilk_fiber_sysdep::s_page_size = sysconf(_SC_PAGESIZE);
86 #endif
88 cilk_fiber_sysdep::cilk_fiber_sysdep(std::size_t stack_size)
89 : cilk_fiber(stack_size)
90 , m_magic(magic_number)
92 // Set m_stack and m_stack_base.
93 make_stack(stack_size);
95 // Get high-address of stack, with 32-bytes of spare space, and rounded
96 // down to the nearest 32-byte boundary.
97 const uintptr_t align_mask = 32 - 1;
98 m_stack_base -= ((std::size_t) m_stack_base) & align_mask;
101 cilk_fiber_sysdep::cilk_fiber_sysdep(from_thread_t)
102 : cilk_fiber()
103 , m_magic(magic_number)
105 this->set_allocated_from_thread(true);
107 // Dummy stack data for thread-main fiber
108 m_stack = NULL;
109 m_stack_base = NULL;
112 void cilk_fiber_sysdep::convert_fiber_back_to_thread()
114 // Does nothing on Linux.
117 cilk_fiber_sysdep::~cilk_fiber_sysdep()
119 CILK_ASSERT(magic_number == m_magic);
120 if (!this->is_allocated_from_thread())
121 free_stack();
124 #if SUPPORT_GET_CURRENT_FIBER
125 cilk_fiber_sysdep* cilk_fiber_sysdep::get_current_fiber_sysdep()
127 return cilkos_get_tls_cilk_fiber();
129 #endif
131 // Jump to resume other fiber. We may or may not come back.
132 inline void cilk_fiber_sysdep::resume_other_sysdep(cilk_fiber_sysdep* other)
134 if (other->is_resumable()) {
135 other->set_resumable(false);
136 // Resume by longjmp'ing to the place where we suspended.
137 CILK_LONGJMP(other->m_resume_jmpbuf);
139 else {
140 // Otherwise, we've never ran this fiber before. Start the
141 // proc method.
142 other->run();
146 void cilk_fiber_sysdep::suspend_self_and_resume_other_sysdep(cilk_fiber_sysdep* other)
148 #if SUPPORT_GET_CURRENT_FIBER
149 cilkos_set_tls_cilk_fiber(other);
150 #endif
151 CILK_ASSERT(this->is_resumable());
154 // Jump to the other fiber. We expect to come back.
155 if (! CILK_SETJMP(m_resume_jmpbuf)) {
156 resume_other_sysdep(other);
159 // Return here when another fiber resumes me.
160 // If the fiber that switched to me wants to be deallocated, do it now.
161 do_post_switch_actions();
164 NORETURN cilk_fiber_sysdep::jump_to_resume_other_sysdep(cilk_fiber_sysdep* other)
166 #if SUPPORT_GET_CURRENT_FIBER
167 cilkos_set_tls_cilk_fiber(other);
168 #endif
169 CILK_ASSERT(!this->is_resumable());
171 // Jump to the other fiber. But we are never coming back because
172 // this fiber is being reset.
173 resume_other_sysdep(other);
175 // We should never come back here...
176 __cilkrts_bug("Should not get here");
179 // GCC doesn't allow us to call __builtin_longjmp in the same function that
180 // calls __builtin_setjmp, so create a new function to house the call to
181 // __builtin_longjmp
182 static void __attribute__((noinline))
183 do_cilk_longjmp(__CILK_JUMP_BUFFER jmpbuf)
185 CILK_LONGJMP(jmpbuf);
188 NORETURN cilk_fiber_sysdep::run()
190 // Only fibers created from a pool have a proc method to run and execute.
191 CILK_ASSERT(m_start_proc);
192 CILK_ASSERT(!this->is_allocated_from_thread());
193 CILK_ASSERT(!this->is_resumable());
195 // TBD: This setjmp/longjmp pair simply changes the stack pointer.
196 // We could probably replace this code with some assembly.
197 if (! CILK_SETJMP(m_resume_jmpbuf))
199 // Calculate the size of the current stack frame (i.e., this
200 // run() function.
201 size_t frame_size = (size_t)JMPBUF_FP(m_resume_jmpbuf) - (size_t)JMPBUF_SP(m_resume_jmpbuf);
203 // Macs require 16-byte alignment. Do it always because it just
204 // doesn't matter
205 if (frame_size & (16-1))
206 frame_size += 16 - (frame_size & (16-1));
208 // Assert that we are getting a reasonable frame size out of
209 // it. If this run() function is using more than 4096 bytes
210 // of space for its local variables / any state that spills to
211 // registers, something is probably *very* wrong here...
213 // 4096 bytes just happens to be a number that seems "large
214 // enough" --- for an example GCC 32-bit compilation, the
215 // frame size was 48 bytes.
216 CILK_ASSERT(frame_size < 4096);
218 // Change stack pointer to fiber stack. Offset the
219 // calculation by the frame size, so that we've allocated
220 // enough extra space from the top of the stack we are
221 // switching to for any temporaries required for this run()
222 // function.
223 JMPBUF_SP(m_resume_jmpbuf) = m_stack_base - frame_size;
225 // GCC doesn't allow us to call __builtin_longjmp in the same function
226 // that calls __builtin_setjmp, so it's been moved into it's own
227 // function that cannot be inlined.
228 do_cilk_longjmp(m_resume_jmpbuf);
231 // Note: our resetting of the stack pointer is valid only if the
232 // compiler has not saved any temporaries onto the stack for this
233 // function before the longjmp that we still care about at this
234 // point.
236 // Verify that 1) 'this' is still valid and 2) '*this' has not been
237 // corrupted.
238 CILK_ASSERT(magic_number == m_magic);
240 // If the fiber that switched to me wants to be deallocated, do it now.
241 do_post_switch_actions();
243 // Now call the user proc on the new stack
244 m_start_proc(this);
246 // alloca() to force generation of frame pointer. The argument to alloca
247 // is contrived to prevent the compiler from optimizing it away. This
248 // code should never actually be executed.
249 int* dummy = (int*) alloca((sizeof(int) + (std::size_t) m_start_proc) & 0x1);
250 *dummy = 0xface;
252 // User proc should never return.
253 __cilkrts_bug("Should not get here");
256 void cilk_fiber_sysdep::make_stack(size_t stack_size)
258 char* p;
259 // We've already validated that the stack size is page-aligned and
260 // is a reasonable value. No need to do any extra rounding here.
261 size_t rounded_stack_size = stack_size;
263 // Normally, we have already validated that the stack size is
264 // aligned to 4K. In the rare case that pages are huge though, we
265 // need to do some extra checks.
266 if (rounded_stack_size < 3 * (size_t)s_page_size) {
267 // If the specified stack size is too small, round up to 3
268 // pages. We need at least 2 extra for the guard pages.
269 rounded_stack_size = 3 * (size_t)s_page_size;
271 else {
272 // Otherwise, the stack size is large enough, but might not be
273 // a multiple of page size. Round up to nearest multiple of
274 // s_page_size, just to be safe.
275 size_t remainder = rounded_stack_size % s_page_size;
276 if (remainder) {
277 rounded_stack_size += s_page_size - remainder;
281 p = (char*)mmap(0, rounded_stack_size,
282 PROT_READ|PROT_WRITE,
283 MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK|MAP_GROWSDOWN,
284 -1, 0);
285 if (MAP_FAILED == p) {
286 // For whatever reason (probably ran out of memory), mmap() failed.
287 // There is no stack to return, so the program loses parallelism.
288 m_stack = NULL;
289 m_stack_base = NULL;
290 return;
293 // mprotect guard pages.
294 mprotect(p + rounded_stack_size - s_page_size, s_page_size, PROT_NONE);
295 mprotect(p, s_page_size, PROT_NONE);
297 m_stack = p;
298 m_stack_base = p + rounded_stack_size - s_page_size;
302 void cilk_fiber_sysdep::free_stack()
304 if (m_stack) {
305 size_t rounded_stack_size = m_stack_base - m_stack + s_page_size;
306 if (munmap(m_stack, rounded_stack_size) < 0)
307 __cilkrts_bug("Cilk: stack munmap failed error %d\n", errno);
311 /* End cilk_fiber-unix.cpp */