gcc/ChangeLog:
[official-gcc.git] / libcilkrts / runtime / sysdep-unix.c
blob0b99008b82bcce44560e5ade365eb09d7d53d9ba
1 /*
2 * sysdep-unix.c
4 *************************************************************************
6 * Copyright (C) 2010-2016, Intel Corporation
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 * * Neither the name of Intel Corporation nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
33 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
36 * *********************************************************************
38 * PLEASE NOTE: This file is a downstream copy of a file mainitained in
39 * a repository at cilkplus.org. Changes made to this file that are not
40 * submitted through the contribution process detailed at
41 * http://www.cilkplus.org/submit-cilk-contribution will be lost the next
42 * time that a new version is released. Changes only submitted to the
43 * GNU compiler collection or posted to the git repository at
44 * https://bitbucket.org/intelcilkruntime/intel-cilk-runtime.git are
45 * not tracked.
47 * We welcome your contributions to this open source project. Thank you
48 * for your assistance in helping us improve Cilk Plus.
50 **************************************************************************
53 #include "sysdep.h"
54 #include "os.h"
55 #include "bug.h"
56 #include "local_state.h"
57 #include "signal_node.h"
58 #include "full_frame.h"
59 #include "jmpbuf.h"
60 #include "cilk_malloc.h"
61 #include "reducer_impl.h"
62 #include "metacall_impl.h"
65 // On x86 processors (but not MIC processors), the compiler generated code to
66 // save the FP state (rounding mode and the like) before calling setjmp. We
67 // will need to restore that state when we resume.
68 #ifndef __MIC__
69 # if defined(__i386__) || defined(__x86_64)
70 # define RESTORE_X86_FP_STATE
71 # endif // defined(__i386__) || defined(__x86_64)
72 #endif // __MIC__
74 // contains notification macros for VTune.
75 #include "cilk-ittnotify.h"
77 #include <stddef.h>
79 #ifdef __CYGWIN__
80 // On Cygwin, string.h doesnt declare strcasecmp if __STRICT_ANSI__ is defined
81 # undef __STRICT_ANSI__
82 #endif
84 #include <string.h>
85 #include <pthread.h>
86 #include <unistd.h>
87 #include "declare-alloca.h"
89 #ifdef __linux__
90 # include <sys/resource.h>
91 # include <sys/sysinfo.h>
92 #endif
94 #ifdef __FreeBSD__
95 # include <sys/resource.h>
96 // BSD does not define MAP_ANONYMOUS, but *does* define MAP_ANON. Aren't standards great!
97 # define MAP_ANONYMOUS MAP_ANON
98 #endif
100 #ifdef __VXWORKS__
101 # include <vxWorks.h>
102 # include <vxCpuLib.h>
103 #endif
105 struct global_sysdep_state
107 pthread_t *threads; ///< Array of pthreads for system workers
108 size_t pthread_t_size; ///< for cilk_db
111 static void internal_enforce_global_visibility();
114 COMMON_SYSDEP
115 void __cilkrts_init_worker_sysdep(struct __cilkrts_worker *w)
117 ITT_SYNC_CREATE(w, "Scheduler");
120 COMMON_SYSDEP
121 void __cilkrts_destroy_worker_sysdep(struct __cilkrts_worker *w)
125 COMMON_SYSDEP
126 void __cilkrts_init_global_sysdep(global_state_t *g)
128 internal_enforce_global_visibility();
130 __cilkrts_init_tls_variables();
132 CILK_ASSERT(g->total_workers >= g->P - 1);
133 g->sysdep = __cilkrts_malloc(sizeof (struct global_sysdep_state));
134 CILK_ASSERT(g->sysdep);
135 g->sysdep->pthread_t_size = sizeof (pthread_t);
137 // TBD: Should this value be g->total_workers, or g->P?
138 // Need to check what we are using this field for.
139 g->sysdep->threads = __cilkrts_malloc(sizeof(pthread_t) * g->total_workers);
140 CILK_ASSERT(g->sysdep->threads);
142 return;
145 COMMON_SYSDEP
146 void __cilkrts_destroy_global_sysdep(global_state_t *g)
148 if (g->sysdep->threads)
149 __cilkrts_free(g->sysdep->threads);
150 __cilkrts_free(g->sysdep);
153 /*************************************************************
154 Creation of worker threads:
155 *************************************************************/
157 static void internal_run_scheduler_with_exceptions(__cilkrts_worker *w)
159 /* We assume the stack grows down. */
160 char var;
161 __cilkrts_cilkscreen_establish_c_stack(&var - 1000000, &var);
163 __cilkrts_run_scheduler_with_exceptions(w);
169 * scheduler_thread_proc_for_system_worker
171 * Thread start function called when we start a new worker.
174 NON_COMMON void* scheduler_thread_proc_for_system_worker(void *arg)
176 /*int status;*/
177 __cilkrts_worker *w = (__cilkrts_worker *)arg;
179 #ifdef __INTEL_COMPILER
180 #ifdef USE_ITTNOTIFY
181 // Name the threads for Advisor. They don't want a worker number.
182 __itt_thread_set_name("Cilk Worker");
183 #endif // defined USE_ITTNOTIFY
184 #endif // defined __INTEL_COMPILER
186 /* Worker startup is serialized
187 status = pthread_mutex_lock(&__cilkrts_global_mutex);
188 CILK_ASSERT(status == 0);*/
189 CILK_ASSERT(w->l->type == WORKER_SYSTEM);
190 /*status = pthread_mutex_unlock(&__cilkrts_global_mutex);
191 CILK_ASSERT(status == 0);*/
193 __cilkrts_set_tls_worker(w);
195 START_INTERVAL(w, INTERVAL_IN_SCHEDULER);
196 START_INTERVAL(w, INTERVAL_IN_RUNTIME);
197 START_INTERVAL(w, INTERVAL_INIT_WORKER);
199 // Create a cilk fiber for this worker on this thread.
200 START_INTERVAL(w, INTERVAL_FIBER_ALLOCATE_FROM_THREAD) {
201 w->l->scheduling_fiber = cilk_fiber_allocate_from_thread();
202 cilk_fiber_set_owner(w->l->scheduling_fiber, w);
203 } STOP_INTERVAL(w, INTERVAL_FIBER_ALLOCATE_FROM_THREAD);
205 STOP_INTERVAL(w, INTERVAL_INIT_WORKER);
207 internal_run_scheduler_with_exceptions(w);
209 START_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE_FROM_THREAD) {
210 // Deallocate the scheduling fiber. This operation reverses the
211 // effect cilk_fiber_allocate_from_thread() and must be done in this
212 // thread before it exits.
213 int ref_count = cilk_fiber_deallocate_from_thread(w->l->scheduling_fiber);
214 // Scheduling fibers should never have extra references to them.
215 // We only get extra references into fibers because of Windows
216 // exceptions.
217 CILK_ASSERT(0 == ref_count);
218 w->l->scheduling_fiber = NULL;
219 } STOP_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE_FROM_THREAD);
221 STOP_INTERVAL(w, INTERVAL_IN_RUNTIME);
222 STOP_INTERVAL(w, INTERVAL_IN_SCHEDULER);
223 return 0;
227 * We are exporting a function with this name to Inspector?
228 * What a confusing name...
230 * This function is exported so Piersol's stack trace displays
231 * reasonable information.
233 void* __cilkrts_worker_stub(void* arg)
235 return scheduler_thread_proc_for_system_worker(arg);
238 // /* Return the lesser of the argument and the operating system
239 // limit on the number of workers (threads) that may or ought
240 // to be created. */
241 // int sysdep_thread_limit(int n, int physical_cpus)
242 // {
243 // /* On Linux thread creation fails somewhere short of the
244 // number of available processes. */
245 // struct rlimit lim;
247 // if (n > 256 + 2 * physical_cpus)
248 // n = 256 + 2 * physical_cpus;
250 // if (getrlimit(RLIMIT_NPROC, &lim) == 0 && lim.rlim_cur != RLIM_INFINITY)
251 // {
252 // /* If the limit reads 0 or absurdly small, ignore it. */
253 // unsigned int maxproc = (lim.rlim_cur * 3 + 3) / 4;
254 // if (maxproc > 8 + 2 * physical_cpus && maxproc < n)
255 // n = maxproc;
256 // }
257 // return n;
258 // }
262 static void write_version_file (global_state_t *, int);
264 /* Create n worker threads from base..top-1
266 static void create_threads(global_state_t *g, int base, int top)
268 // TBD(11/30/12): We want to insert code providing the option of
269 // pinning system workers to cores.
270 for (int i = base; i < top; i++) {
271 int status = pthread_create(&g->sysdep->threads[i],
272 NULL,
273 scheduler_thread_proc_for_system_worker,
274 g->workers[i]);
275 if (status != 0)
276 __cilkrts_bug("Cilk runtime error: thread creation (%d) failed: %d\n", i, status);
280 #if PARALLEL_THREAD_CREATE
281 static int volatile threads_created = 0;
283 // Create approximately half of the worker threads, and then become a worker
284 // ourselves.
285 static void * create_threads_and_work (void * arg)
287 global_state_t *g = ((__cilkrts_worker *)arg)->g;
289 create_threads(g, g->P/2, g->P-1);
290 // Let the initial thread know that we're done.
291 threads_created = 1;
293 // Ideally this turns into a tail call that wipes out this stack frame.
294 return scheduler_thread_proc_for_system_worker(arg);
296 #endif
297 void __cilkrts_start_workers(global_state_t *g, int n)
299 g->workers_running = 1;
300 g->work_done = 0;
302 if (!g->sysdep->threads)
303 return;
305 // Do we actually have any threads to create?
306 if (n > 0)
308 #if PARALLEL_THREAD_CREATE
309 int status;
310 // We create (a rounded up) half of the threads, thread one creates the rest
311 int half_threads = (n+1)/2;
313 // Create the first thread passing a different thread function, so that it creates threads itself
314 status = pthread_create(&g->sysdep->threads[0], NULL, create_threads_and_work, g->workers[0]);
316 if (status != 0)
317 __cilkrts_bug("Cilk runtime error: thread creation (0) failed: %d\n", status);
319 // Then the rest of the ones we have to create
320 create_threads(g, 1, half_threads);
322 // Now wait for the first created thread to tell us it's created all of its threads.
323 // We could maybe drop this a bit lower and overlap with write_version_file.
324 while (!threads_created)
325 __cilkrts_yield();
326 #else
327 // Simply create all the threads linearly here.
328 create_threads(g, 0, n);
329 #endif
331 // write the version information to a file if the environment is configured
332 // for it (the function makes the check).
333 write_version_file(g, n);
336 return;
339 void __cilkrts_stop_workers(global_state_t *g)
341 int i;
343 // Tell the workers to give up
345 g->work_done = 1;
347 if (g->workers_running == 0)
348 return;
350 if (!g->sysdep->threads)
351 return;
353 /* Make them all runnable. */
354 if (g->P > 1) {
355 CILK_ASSERT(g->workers[0]->l->signal_node);
356 signal_node_msg(g->workers[0]->l->signal_node, 1);
359 for (i = 0; i < g->P - 1; ++i) {
360 int sc_status;
361 void *th_status;
363 sc_status = pthread_join(g->sysdep->threads[i], &th_status);
364 if (sc_status != 0)
365 __cilkrts_bug("Cilk runtime error: thread join (%d) failed: %d\n", i, sc_status);
368 g->workers_running = 0;
371 return;
376 * @brief Returns the stack address for resuming execution of sf.
378 * This method takes in the top of the stack to use, and then returns
379 * a properly aligned address for resuming execution of sf.
381 * @param sf - The stack frame we want to resume executing.
382 * @param stack_base - The top of the stack we want to execute sf on.
385 static char* get_sp_for_executing_sf(char* stack_base,
386 full_frame *ff,
387 __cilkrts_stack_frame *sf)
389 // The original calculation that had been done to correct the stack
390 // pointer when resuming execution.
392 // But this code was never getting called in the eng branch anyway...
394 // TBD(11/30/12): This logic needs to be revisited to make sure that
395 // we are doing the proper calculation in reserving space for outgoing
396 // arguments on all platforms and architectures.
397 #if 0
398 /* Preserve outgoing argument space and stack alignment on steal.
399 Outgoing argument space is bounded by the difference between
400 stack and frame pointers. Some user code is known to rely on
401 16 byte alignment. Maintain 32 byte alignment for future
402 compatibility. */
403 #define SMASK 31 /* 32 byte alignment */
404 if (sf) {
405 char *fp = FP(sf), *sp = SP(sf);
406 int fp_align = (int)(size_t)fp & SMASK;
407 ptrdiff_t space = fp - sp;
409 fprintf(stderr, "Here: fp = %p, sp = %p\n", fp, sp);
410 char *top_aligned = (char *)((((size_t)stack_base - SMASK) & ~(size_t)SMASK) | fp_align);
411 /* Don't allocate an unreasonable amount of stack space. */
413 fprintf(stderr, "Here: stack_base = %p, top_aligned=%p, space=%ld\n",
414 stack_base, top_aligned, space);
415 if (space < 32)
416 space = 32 + (space & SMASK);
417 else if (space > 40 * 1024)
418 space = 40 * 1024 + (space & SMASK);
420 return top_aligned - space;
422 #endif
424 #define PERFORM_FRAME_SIZE_CALCULATION 0
426 char* new_stack_base = stack_base - 256;
428 #if PERFORM_FRAME_SIZE_CALCULATION
429 // If there is a frame size saved, then use that as the
430 // correction instead of 256.
431 if (ff->frame_size > 0) {
432 if (ff->frame_size < 40*1024) {
433 new_stack_base = stack_base - ff->frame_size;
435 else {
436 // If for some reason, our frame size calculation is giving us
437 // a number which is bigger than about 10 pages, then
438 // there is likely something wrong here? Don't allocate
439 // an unreasonable amount of space.
440 new_stack_base = stack_base - 40*1024;
443 #endif
445 // Whatever correction we choose, align the final stack top.
446 // This alignment seems to be necessary in particular on 32-bit
447 // Linux, and possibly Mac. (Is 32-byte alignment is sufficient?)
448 /* 256-byte alignment. Why not? */
449 const uintptr_t align_mask = ~(256 -1);
450 new_stack_base = (char*)((size_t)new_stack_base & align_mask);
451 return new_stack_base;
454 char* sysdep_reset_jump_buffers_for_resume(cilk_fiber* fiber,
455 full_frame *ff,
456 __cilkrts_stack_frame *sf)
458 #if FIBER_DEBUG >= 4
459 fprintf(stderr, "ThreadId=%p (fiber_proc_to_resume), Fiber %p. sf = %p. ff=%p, ff->sync_sp=%p\n",
460 cilkos_get_current_thread_id(),
461 fiber,
463 ff, ff->sync_sp);
464 #endif
466 CILK_ASSERT(fiber);
467 void* sp = (void*)get_sp_for_executing_sf(cilk_fiber_get_stack_base(fiber), ff, sf);
468 SP(sf) = CILK_ADJUST_SP(sp);
470 /* Debugging: make sure stack is accessible. */
471 ((volatile char *)sp)[-1];
473 // Adjust the saved_sp to account for the SP we're about to run. This will
474 // allow us to track fluctations in the stack
475 #if FIBER_DEBUG >= 4
476 fprintf(stderr, "ThreadId=%p, about to take stack ff=%p, sp=%p, sync_sp=%p\n",
477 cilkos_get_current_thread_id(),
480 ff->sync_sp);
481 #endif
482 __cilkrts_take_stack(ff, sp);
483 return sp;
487 NORETURN sysdep_longjmp_to_sf(char* new_sp,
488 __cilkrts_stack_frame *sf,
489 full_frame *ff_for_exceptions /* UNUSED on Unix */)
491 #if FIBER_DEBUG >= 3
492 fprintf(stderr,
493 "ThreadId=%p. resume user code, sf=%p, new_sp = %p, original SP(sf) = %p, FP(sf) = %p\n",
494 cilkos_get_current_thread_id(), sf, new_sp, SP(sf), FP(sf));
495 #endif
497 // Set the stack pointer.
498 SP(sf) = CILK_ADJUST_SP(new_sp);
500 #ifdef RESTORE_X86_FP_STATE
501 if (CILK_FRAME_VERSION_VALUE(sf->flags) >= 1) {
502 // Restore the floating point state that was set in this frame at the
503 // last spawn.
505 // This feature is only available in ABI 1 or later frames, and only
506 // needed on IA64 or Intel64 processors.
507 restore_x86_fp_state(sf);
509 #endif
511 CILK_LONGJMP(sf->ctx);
515 #include <stddef.h>
516 #include <stdlib.h>
517 #include <string.h>
518 #include <sys/mman.h>
519 #include <errno.h>
522 void __cilkrts_make_unrunnable_sysdep(__cilkrts_worker *w,
523 full_frame *ff,
524 __cilkrts_stack_frame *sf,
525 int is_loot,
526 const char *why)
528 (void)w; /* unused */
529 sf->except_data = 0;
531 if (is_loot)
533 if (ff->frame_size == 0)
534 ff->frame_size = __cilkrts_get_frame_size(sf);
536 // Null loot's sp for debugging purposes (so we'll know it's not valid)
537 SP(sf) = 0;
541 /*************************************************************
542 Version information:
543 *************************************************************/
545 #ifndef _WRS_KERNEL
546 #include <dlfcn.h>
547 #endif
548 #include "internal/cilk_version.h"
549 #include <stdio.h>
550 #ifndef _WRS_KERNEL
551 #include <sys/utsname.h>
552 #endif
554 #ifdef __VXWORKS__
555 #include <version.h>
556 #endif
558 /* (Non-static) dummy function is used by get_runtime_path() to find the path
559 * to the .so containing the Cilk runtime.
561 void dummy_function() { }
564 * Return a string with the path to the Cilk runtime, or "unknown" if the path
565 * cannot be determined.
567 static const char *get_runtime_path ()
569 // dladdr is a glibc extension. If it's available, use it to find the path
570 // for libcilkrts.so
571 #if HAVE_DLADDR
572 Dl_info info;
573 if (0 != dladdr(dummy_function, &info))
574 return info.dli_fname;
575 #endif
577 // If dladdr isn't available, or dladdr failed, we can't know the path for
578 // the shared object
579 return "unknown";
582 #ifdef _WRS_KERNEL
583 #include <version.h>
584 #include <sysLib.h>
585 #endif
586 /* if the environment variable, CILK_VERSION, is defined, writes the version
587 * information to the specified file.
588 * g is the global state that was just created, and n is the number of workers
589 * that were made (or requested from RML) for it.
591 static void write_version_file (global_state_t *g, int n)
593 const char *env; // environment variable.
594 char buf[256]; // print buffer.
595 time_t t;
596 FILE *fp;
597 #ifndef _WRS_KERNEL
598 struct utsname sys_info;
599 #endif
600 int err; // error code from system calls.
602 // if CILK_VERSION is not set, or if the file cannot be opened, fail
603 // silently. Otherwise open the file for writing (or use stderr or stdout
604 // if the user specifies).
605 if (NULL == (env = getenv("CILK_VERSION"))) return;
606 if (0 == strcasecmp(env, "stderr")) fp = stderr;
607 else if (0 == strcasecmp(env, "stdout")) fp = stdout;
608 else if (NULL == (fp = fopen(env, "w"))) return;
610 // get a string for the current time. E.g.,
611 // Cilk runtime initialized: Thu Jun 10 13:28:00 2010
612 t = time(NULL);
613 strftime(buf, 256, "%a %b %d %H:%M:%S %Y", localtime(&t));
614 fprintf(fp, "Cilk runtime initialized: %s\n", buf);
616 // Print runtime info. E.g.,
617 // Cilk runtime information
618 // ========================
619 // Cilk version: 2.0.0 Build 9184
620 // Built by willtor on host willtor-desktop
621 // Compilation date: Thu Jun 10 13:27:42 2010
622 // Compiled with ICC V99.9.9, ICC build date: 20100610
624 fprintf(fp, "\nCilk runtime information\n");
625 fprintf(fp, "========================\n");
626 fprintf(fp, "Cilk version: %d.%d.%d Build %d\n",
627 VERSION_MAJOR,
628 VERSION_MINOR,
629 VERSION_REV,
630 VERSION_BUILD);
631 #ifdef __VXWORKS__
632 char * vxWorksVer = VXWORKS_VERSION;
633 fprintf(fp, "Cross compiled for %s\n",vxWorksVer);
634 // user and host not avalible if VxWorks cross compiled on windows build host
635 #else
637 // User and host are not available for GCC builds
638 #ifdef BUILD_USER
639 fprintf(fp, "Built by "BUILD_USER" on host "BUILD_HOST"\n");
640 #endif // BUILD_USER
641 #endif // __VXWORKS__
643 // GCC has requested that this be removed for GCC builds
644 #ifdef BUILD_USER
645 fprintf(fp, "Compilation date: "__DATE__" "__TIME__"\n");
646 #endif // BUILD_USER
648 #ifdef __INTEL_COMPILER
649 // Compiled by the Intel C/C++ compiler.
650 fprintf(fp, "Compiled with ICC V%d.%d.%d, ICC build date: %d\n",
651 __INTEL_COMPILER / 100,
652 (__INTEL_COMPILER / 10) % 10,
653 __INTEL_COMPILER % 10,
654 __INTEL_COMPILER_BUILD_DATE);
655 #else
656 // Compiled by GCC.
657 fprintf(fp, "Compiled with GCC V%d.%d.%d\n",
658 __GNUC__,
659 __GNUC_MINOR__,
660 __GNUC_PATCHLEVEL__);
661 #endif // defined __INTEL_COMPILER
663 // Print system info. E.g.,
664 // System information
665 // ==================
666 // Cilk runtime path: /opt/icc/64/lib/libcilkrts.so.5
667 // System OS: Linux, release 2.6.28-19-generic
668 // System architecture: x86_64
670 fprintf(fp, "\nSystem information\n");
671 fprintf(fp, "==================\n");
672 fprintf(fp, "Cilk runtime path: %s\n", get_runtime_path());
673 #ifndef _WRS_KERNEL
674 err = uname(&sys_info);
675 fprintf(fp, "System OS: %s, release %s\n",
676 err < 0 ? "unknown" : sys_info.sysname,
677 err < 0 ? "?" : sys_info.release);
678 fprintf(fp, "System architecture: %s\n",
679 err < 0 ? "unknown" : sys_info.machine);
680 #else
681 fprintf(fp, "System OS: %s, release %s\n",
682 "VxWorks", RUNTIME_NAME RUNTIME_VERSION);
683 fprintf(fp, "System architecture: %s\n",
684 sysModel());
685 #endif
687 // Print thread info. E.g.,
688 // Thread information
689 // ==================
690 // System cores: 8
691 // Cilk workers requested: 8
693 fprintf(fp, "\nThread information\n");
694 fprintf(fp, "==================\n");
695 #ifdef __VXWORKS__
696 fprintf(fp, "System cores: %d\n", (int)__builtin_popcount(vxCpuEnabledGet()));
697 #else
698 fprintf(fp, "System cores: %d\n", (int)sysconf(_SC_NPROCESSORS_ONLN));
699 #endif
700 fprintf(fp, "Cilk workers requested: %d\n", n);
702 if (fp != stderr && fp != stdout) fclose(fp);
703 else fflush(fp); // flush the handle buffer if it is stdout or stderr.
708 * __cilkrts_establish_c_stack
710 * Tell Cilkscreen about the user stack bounds.
712 * Note that the Cilk V1 runtime only included the portion of the stack from
713 * the entry into Cilk, down. We don't appear to be able to find that, but
714 * I think this will be sufficient.
717 void __cilkrts_establish_c_stack(void)
719 /* FIXME: Not implemented. */
721 /* TBD: Do we need this */
723 void __cilkrts_cilkscreen_establish_c_stack(char *begin, char *end);
725 size_t r;
726 MEMORY_BASIC_INFORMATION mbi;
728 r = VirtualQuery (&mbi,
729 &mbi,
730 sizeof(mbi));
732 __cilkrts_cilkscreen_establish_c_stack((char *)mbi.BaseAddress,
733 (char *)mbi.BaseAddress + mbi.RegionSize);
739 * internal_enforce_global_visibility
741 * Ensure global visibility of public symbols, for proper Cilk-TBB interop.
743 * If Cilk runtime is loaded dynamically, its symbols might remain unavailable
744 * for global search with dladdr; that might prevent TBB from finding Cilk
745 * in the process address space and initiating the interop protocol.
746 * The workaround is for the library to open itself with RTLD_GLOBAL flag.
749 static __attribute__((noinline))
750 void internal_enforce_global_visibility()
752 #ifndef __VXWORKS__
753 void* handle = dlopen( get_runtime_path(), RTLD_GLOBAL|RTLD_LAZY );
755 /* For proper reference counting, close the handle immediately. */
756 if( handle) dlclose(handle);
757 #endif
761 Local Variables: **
762 c-file-style:"bsd" **
763 c-basic-offset:4 **
764 indent-tabs-mode:nil **
765 End: **