c-common.h (get_dump_info): Declare.
[gcc.git] / libcilkrts / runtime / sysdep-unix.c
1 /*
2 * sysdep-unix.c
3 *
4 *************************************************************************
5 *
6 * @copyright
7 * Copyright (C) 2010-2013, Intel Corporation
8 * All rights reserved.
9 *
10 * @copyright
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in
19 * the documentation and/or other materials provided with the
20 * distribution.
21 * * Neither the name of Intel Corporation nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * @copyright
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
33 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
34 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
36 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 *
39 **************************************************************************
40 */
41
42 #ifdef __linux__
43 // define _GNU_SOURCE before *any* #include.
44 // Even <stdint.h> will break later #includes if this macro is not
45 // already defined when it is #included.
46 # define _GNU_SOURCE
47 #endif
48
49 #include "sysdep.h"
50 #include "os.h"
51 #include "bug.h"
52 #include "local_state.h"
53 #include "signal_node.h"
54 #include "full_frame.h"
55 #include "jmpbuf.h"
56 #include "cilk_malloc.h"
57 #include "reducer_impl.h"
58 #include "metacall_impl.h"
59
60
61 // On x86 processors (but not MIC processors), the compiler generated code to
62 // save the FP state (rounding mode and the like) before calling setjmp. We
63 // will need to restore that state when we resume.
64 #ifndef __MIC__
65 # if defined(__i386__) || defined(__x86_64)
66 # define RESTORE_X86_FP_STATE
67 # endif // defined(__i386__) || defined(__x86_64)
68 #endif // __MIC__
69
70 // contains notification macros for VTune.
71 #include "cilk-ittnotify.h"
72
73 #include <stddef.h>
74
75 #ifdef __CYGWIN__
76 // On Cygwin, string.h doesnt declare strcasecmp if __STRICT_ANSI__ is defined
77 # undef __STRICT_ANSI__
78 #endif
79
80 #include <string.h>
81 #include <pthread.h>
82 #include <unistd.h>
83
84 #if defined HAVE_ALLOCA_H
85 # include <alloca.h>
86 #elif defined __GNUC__
87 # define alloca __builtin_alloca
88 #elif defined _AIX
89 # define alloca __alloca
90 #else
91 # include <stddef.h>
92 # ifdef __cplusplus
93 extern "C"
94 # endif
95 void *alloca (size_t);
96 #endif
97
98 #ifdef __APPLE__
99 //# include <scheduler.h> // Angle brackets include Apple's scheduler.h, not ours.
100 #endif
101
102 #ifdef __linux__
103 # include <sys/resource.h>
104 # include <sys/sysinfo.h>
105 #endif
106
107 #ifdef __FreeBSD__
108 # include <sys/resource.h>
109 // BSD does not define MAP_ANONYMOUS, but *does* define MAP_ANON. Aren't standards great!
110 # define MAP_ANONYMOUS MAP_ANON
111 #endif
112
113 #ifdef __VXWORKS__
114 # include <vxWorks.h>
115 # include <vxCpuLib.h>
116 #endif
117
118 struct global_sysdep_state
119 {
120 pthread_t *threads; ///< Array of pthreads for system workers
121 size_t pthread_t_size; ///< for cilk_db
122 };
123
124 static void internal_enforce_global_visibility();
125
126
127 COMMON_SYSDEP
128 void __cilkrts_init_worker_sysdep(struct __cilkrts_worker *w)
129 {
130 ITT_SYNC_CREATE(w, "Scheduler");
131 }
132
133 COMMON_SYSDEP
134 void __cilkrts_destroy_worker_sysdep(struct __cilkrts_worker *w)
135 {
136 }
137
138 COMMON_SYSDEP
139 void __cilkrts_init_global_sysdep(global_state_t *g)
140 {
141 internal_enforce_global_visibility();
142
143 __cilkrts_init_tls_variables();
144
145 CILK_ASSERT(g->total_workers >= g->P - 1);
146 g->sysdep = __cilkrts_malloc(sizeof (struct global_sysdep_state));
147 CILK_ASSERT(g->sysdep);
148 g->sysdep->pthread_t_size = sizeof (pthread_t);
149
150 // TBD: Should this value be g->total_workers, or g->P?
151 // Need to check what we are using this field for.
152 g->sysdep->threads = __cilkrts_malloc(sizeof(pthread_t) * g->total_workers);
153 CILK_ASSERT(g->sysdep->threads);
154
155 return;
156 }
157
158 COMMON_SYSDEP
159 void __cilkrts_destroy_global_sysdep(global_state_t *g)
160 {
161 if (g->sysdep->threads)
162 __cilkrts_free(g->sysdep->threads);
163 __cilkrts_free(g->sysdep);
164 }
165
166 /*************************************************************
167 Creation of worker threads:
168 *************************************************************/
169
170 static void internal_run_scheduler_with_exceptions(__cilkrts_worker *w)
171 {
172 /* We assume the stack grows down. */
173 char var;
174 __cilkrts_cilkscreen_establish_c_stack(&var - 1000000, &var);
175
176 __cilkrts_run_scheduler_with_exceptions(w);
177 }
178
179
180
181 /*
182 * scheduler_thread_proc_for_system_worker
183 *
184 * Thread start function called when we start a new worker.
185 *
186 */
187 NON_COMMON void* scheduler_thread_proc_for_system_worker(void *arg)
188 {
189 /*int status;*/
190 __cilkrts_worker *w = (__cilkrts_worker *)arg;
191
192 #ifdef __INTEL_COMPILER
193 #ifdef USE_ITTNOTIFY
194 // Name the threads for Advisor. They don't want a worker number.
195 __itt_thread_set_name("Cilk Worker");
196 #endif // defined USE_ITTNOTIFY
197 #endif // defined __INTEL_COMPILER
198
199 /* Worker startup is serialized
200 status = pthread_mutex_lock(&__cilkrts_global_mutex);
201 CILK_ASSERT(status == 0);*/
202 CILK_ASSERT(w->l->type == WORKER_SYSTEM);
203 /*status = pthread_mutex_unlock(&__cilkrts_global_mutex);
204 CILK_ASSERT(status == 0);*/
205
206 __cilkrts_set_tls_worker(w);
207
208 // Create a cilk fiber for this worker on this thread.
209 START_INTERVAL(w, INTERVAL_FIBER_ALLOCATE_FROM_THREAD) {
210 w->l->scheduling_fiber = cilk_fiber_allocate_from_thread();
211 cilk_fiber_set_owner(w->l->scheduling_fiber, w);
212 } STOP_INTERVAL(w, INTERVAL_FIBER_ALLOCATE_FROM_THREAD);
213
214 internal_run_scheduler_with_exceptions(w);
215
216 START_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE_FROM_THREAD) {
217 // Deallocate the scheduling fiber. This operation reverses the
218 // effect cilk_fiber_allocate_from_thread() and must be done in this
219 // thread before it exits.
220 int ref_count = cilk_fiber_deallocate_from_thread(w->l->scheduling_fiber);
221 // Scheduling fibers should never have extra references to them.
222 // We only get extra references into fibers because of Windows
223 // exceptions.
224 CILK_ASSERT(0 == ref_count);
225 w->l->scheduling_fiber = NULL;
226 } STOP_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE_FROM_THREAD);
227
228 return 0;
229 }
230
231
232 /*
233 * __cilkrts_user_worker_scheduling_stub
234 *
235 * Routine for the scheduling fiber created for an imported user
236 * worker thread. This method is analogous to
237 * scheduler_thread_proc_for_system_worker.
238 *
239 */
240 void __cilkrts_user_worker_scheduling_stub(cilk_fiber* fiber, void* null_arg)
241 {
242 __cilkrts_worker *w = __cilkrts_get_tls_worker();
243
244 // Sanity check.
245 CILK_ASSERT(WORKER_USER == w->l->type);
246
247 // Enter the scheduling loop on the user worker.
248 // This function will never return.
249 __cilkrts_run_scheduler_with_exceptions(w);
250
251 // A WORKER_USER, at some point, will resume on the original stack and leave
252 // Cilk. Under no circumstances do we ever exit off of the bottom of this
253 // stack.
254 CILK_ASSERT(0);
255 }
256
257 /**
258 * We are exporting a function with this name to Inspector?
259 * What a confusing name...
260 *
261 * This function is exported so Piersol's stack trace displays
262 * reasonable information.
263 */
264 void* __cilkrts_worker_stub(void* arg)
265 {
266 return scheduler_thread_proc_for_system_worker(arg);
267 }
268
269
270
271 // /* Return the lesser of the argument and the operating system
272 // limit on the number of workers (threads) that may or ought
273 // to be created. */
274 // int sysdep_thread_limit(int n, int physical_cpus)
275 // {
276 // /* On Linux thread creation fails somewhere short of the
277 // number of available processes. */
278 // struct rlimit lim;
279
280 // if (n > 256 + 2 * physical_cpus)
281 // n = 256 + 2 * physical_cpus;
282
283 // if (getrlimit(RLIMIT_NPROC, &lim) == 0 && lim.rlim_cur != RLIM_INFINITY)
284 // {
285 // /* If the limit reads 0 or absurdly small, ignore it. */
286 // unsigned int maxproc = (lim.rlim_cur * 3 + 3) / 4;
287 // if (maxproc > 8 + 2 * physical_cpus && maxproc < n)
288 // n = maxproc;
289 // }
290 // return n;
291 // }
292
293
294
295 static void write_version_file (global_state_t *, int);
296
297 /* Create n worker threads from base..top-1
298 */
299 static void create_threads(global_state_t *g, int base, int top)
300 {
301 // TBD(11/30/12): We want to insert code providing the option of
302 // pinning system workers to cores.
303 for (int i = base; i < top; i++) {
304 int status = pthread_create(&g->sysdep->threads[i],
305 NULL,
306 scheduler_thread_proc_for_system_worker,
307 g->workers[i]);
308 if (status != 0)
309 __cilkrts_bug("Cilk runtime error: thread creation (%d) failed: %d\n", i, status);
310 }
311 }
312
313 #if PARALLEL_THREAD_CREATE
314 static int volatile threads_created = 0;
315
316 // Create approximately half of the worker threads, and then become a worker
317 // ourselves.
318 static void * create_threads_and_work (void * arg)
319 {
320 global_state_t *g = ((__cilkrts_worker *)arg)->g;
321
322 create_threads(g, g->P/2, g->P-1);
323 // Let the initial thread know that we're done.
324 threads_created = 1;
325
326 // Ideally this turns into a tail call that wipes out this stack frame.
327 return scheduler_thread_proc_for_system_worker(arg);
328 }
329 #endif
330 void __cilkrts_start_workers(global_state_t *g, int n)
331 {
332 g->workers_running = 1;
333 g->work_done = 0;
334
335 if (!g->sysdep->threads)
336 return;
337
338 // Do we actually have any threads to create?
339 if (n > 0)
340 {
341 #if PARALLEL_THREAD_CREATE
342 int status;
343 // We create (a rounded up) half of the threads, thread one creates the rest
344 int half_threads = (n+1)/2;
345
346 // Create the first thread passing a different thread function, so that it creates threads itself
347 status = pthread_create(&g->sysdep->threads[0], NULL, create_threads_and_work, g->workers[0]);
348
349 if (status != 0)
350 __cilkrts_bug("Cilk runtime error: thread creation (0) failed: %d\n", status);
351
352 // Then the rest of the ones we have to create
353 create_threads(g, 1, half_threads);
354
355 // Now wait for the first created thread to tell us it's created all of its threads.
356 // We could maybe drop this a bit lower and overlap with write_version_file.
357 while (!threads_created)
358 __cilkrts_yield();
359 #else
360 // Simply create all the threads linearly here.
361 create_threads(g, 0, n);
362 #endif
363 }
364 // write the version information to a file if the environment is configured
365 // for it (the function makes the check).
366 write_version_file(g, n);
367
368
369 return;
370 }
371
372 void __cilkrts_stop_workers(global_state_t *g)
373 {
374 int i;
375
376 // Tell the workers to give up
377
378 g->work_done = 1;
379
380 if (g->workers_running == 0)
381 return;
382
383 if (!g->sysdep->threads)
384 return;
385
386 /* Make them all runnable. */
387 if (g->P > 1) {
388 CILK_ASSERT(g->workers[0]->l->signal_node);
389 signal_node_msg(g->workers[0]->l->signal_node, 1);
390 }
391
392 for (i = 0; i < g->P - 1; ++i) {
393 int sc_status;
394 void *th_status;
395
396 sc_status = pthread_join(g->sysdep->threads[i], &th_status);
397 if (sc_status != 0)
398 __cilkrts_bug("Cilk runtime error: thread join (%d) failed: %d\n", i, sc_status);
399 }
400
401 g->workers_running = 0;
402
403
404 return;
405 }
406
407
408 /*
409 * @brief Returns the stack address for resuming execution of sf.
410 *
411 * This method takes in the top of the stack to use, and then returns
412 * a properly aligned address for resuming execution of sf.
413 *
414 * @param sf - The stack frame we want to resume executing.
415 * @param stack_base - The top of the stack we want to execute sf on.
416 *
417 */
418 static char* get_sp_for_executing_sf(char* stack_base,
419 full_frame *ff,
420 __cilkrts_stack_frame *sf)
421 {
422 // The original calculation that had been done to correct the stack
423 // pointer when resuming execution.
424 //
425 // But this code was never getting called in the eng branch anyway...
426 //
427 // TBD(11/30/12): This logic needs to be revisited to make sure that
428 // we are doing the proper calculation in reserving space for outgoing
429 // arguments on all platforms and architectures.
430 #if 0
431 /* Preserve outgoing argument space and stack alignment on steal.
432 Outgoing argument space is bounded by the difference between
433 stack and frame pointers. Some user code is known to rely on
434 16 byte alignment. Maintain 32 byte alignment for future
435 compatibility. */
436 #define SMASK 31 /* 32 byte alignment */
437 if (sf) {
438 char *fp = FP(sf), *sp = SP(sf);
439 int fp_align = (int)(size_t)fp & SMASK;
440 ptrdiff_t space = fp - sp;
441
442 fprintf(stderr, "Here: fp = %p, sp = %p\n", fp, sp);
443 char *top_aligned = (char *)((((size_t)stack_base - SMASK) & ~(size_t)SMASK) | fp_align);
444 /* Don't allocate an unreasonable amount of stack space. */
445
446 fprintf(stderr, "Here: stack_base = %p, top_aligned=%p, space=%ld\n",
447 stack_base, top_aligned, space);
448 if (space < 32)
449 space = 32 + (space & SMASK);
450 else if (space > 40 * 1024)
451 space = 40 * 1024 + (space & SMASK);
452
453 return top_aligned - space;
454 }
455 #endif
456
457 #define PERFORM_FRAME_SIZE_CALCULATION 0
458
459 char* new_stack_base = stack_base - 256;
460
461 #if PERFORM_FRAME_SIZE_CALCULATION
462 // If there is a frame size saved, then use that as the
463 // correction instead of 256.
464 if (ff->frame_size > 0) {
465 if (ff->frame_size < 40*1024) {
466 new_stack_base = stack_base - ff->frame_size;
467 }
468 else {
469 // If for some reason, our frame size calculation is giving us
470 // a number which is bigger than about 10 pages, then
471 // there is likely something wrong here? Don't allocate
472 // an unreasonable amount of space.
473 new_stack_base = stack_base - 40*1024;
474 }
475 }
476 #endif
477
478 // Whatever correction we choose, align the final stack top.
479 // This alignment seems to be necessary in particular on 32-bit
480 // Linux, and possibly Mac. (Is 32-byte alignment is sufficient?)
481 /* 256-byte alignment. Why not? */
482 const uintptr_t align_mask = ~(256 -1);
483 new_stack_base = (char*)((size_t)new_stack_base & align_mask);
484 return new_stack_base;
485 }
486
487 char* sysdep_reset_jump_buffers_for_resume(cilk_fiber* fiber,
488 full_frame *ff,
489 __cilkrts_stack_frame *sf)
490 {
491 #if FIBER_DEBUG >= 4
492 fprintf(stderr, "ThreadId=%p (fiber_proc_to_resume), Fiber %p. sf = %p. ff=%p, ff->sync_sp=%p\n",
493 cilkos_get_current_thread_id(),
494 fiber,
495 sf,
496 ff, ff->sync_sp);
497 #endif
498
499 CILK_ASSERT(fiber);
500 void* sp = (void*)get_sp_for_executing_sf(cilk_fiber_get_stack_base(fiber), ff, sf);
501 SP(sf) = sp;
502
503 /* Debugging: make sure stack is accessible. */
504 ((volatile char *)sp)[-1];
505
506 // Adjust the saved_sp to account for the SP we're about to run. This will
507 // allow us to track fluctations in the stack
508 #if FIBER_DEBUG >= 4
509 fprintf(stderr, "ThreadId=%p, about to take stack ff=%p, sp=%p, sync_sp=%p\n",
510 cilkos_get_current_thread_id(),
511 ff,
512 sp,
513 ff->sync_sp);
514 #endif
515 __cilkrts_take_stack(ff, sp);
516 return sp;
517 }
518
519
520 NORETURN sysdep_longjmp_to_sf(char* new_sp,
521 __cilkrts_stack_frame *sf,
522 full_frame *ff_for_exceptions /* UNUSED on Unix */)
523 {
524 #if FIBER_DEBUG >= 3
525 fprintf(stderr,
526 "ThreadId=%p. resume user code, sf=%p, new_sp = %p, original SP(sf) = %p, FP(sf) = %p\n",
527 cilkos_get_current_thread_id(), sf, new_sp, SP(sf), FP(sf));
528 #endif
529
530 // Set the stack pointer.
531 SP(sf) = new_sp;
532
533 #ifdef RESTORE_X86_FP_STATE
534 if (CILK_FRAME_VERSION_VALUE(sf->flags) >= 1) {
535 // Restore the floating point state that was set in this frame at the
536 // last spawn.
537 //
538 // This feature is only available in ABI 1 or later frames, and only
539 // needed on IA64 or Intel64 processors.
540 restore_x86_fp_state(sf);
541 }
542 #endif
543
544 CILK_LONGJMP(sf->ctx);
545 }
546
547
548 #include <stddef.h>
549 #include <stdlib.h>
550 #include <string.h>
551 #include <sys/mman.h>
552 #include <errno.h>
553
554
555 void __cilkrts_make_unrunnable_sysdep(__cilkrts_worker *w,
556 full_frame *ff,
557 __cilkrts_stack_frame *sf,
558 int is_loot,
559 const char *why)
560 {
561 (void)w; /* unused */
562 sf->except_data = 0;
563
564 if (is_loot)
565 {
566 if (ff->frame_size == 0)
567 ff->frame_size = __cilkrts_get_frame_size(sf);
568
569 // Null loot's sp for debugging purposes (so we'll know it's not valid)
570 SP(sf) = 0;
571 }
572 }
573
574 /*
575 * __cilkrts_sysdep_is_worker_thread_id
576 *
577 * Returns true if the thread ID specified matches the thread ID we saved
578 * for a worker.
579 */
580
581 int __cilkrts_sysdep_is_worker_thread_id(global_state_t *g,
582 int i,
583 void *thread_id)
584 {
585 #if defined( __linux__) || defined(__VXWORKS__)
586 pthread_t tid = *(pthread_t *)thread_id;
587 if (i < 0 || i > g->total_workers)
588 return 0;
589 return g->sysdep->threads[i] == tid;
590 #else
591 // Needs to be implemented
592 return 0;
593 #endif
594 }
595
596
597
598
599 /*************************************************************
600 Version information:
601 *************************************************************/
602
603 #include <dlfcn.h>
604 #include "internal/cilk_version.h"
605 #include <stdio.h>
606 #include <sys/utsname.h>
607
608 #ifdef __VXWORKS__
609 #include <version.h>
610 # endif
611
612 /* (Non-static) dummy function is used by get_runtime_path() to find the path
613 * to the .so containing the Cilk runtime.
614 */
615 void dummy_function() { }
616
617 /* return a string with the path to the Cilk runtime, or "unknown" if the path
618 * cannot be determined.
619 */
620 static const char *get_runtime_path ()
621 {
622 #ifdef __CYGWIN__
623 // Cygwin doesn't support dladdr, which sucks
624 return "unknown";
625 #else
626 Dl_info info;
627 if (0 == dladdr(dummy_function, &info)) return "unknown";
628 return info.dli_fname;
629 #endif
630 }
631
632 /* if the environment variable, CILK_VERSION, is defined, writes the version
633 * information to the specified file.
634 * g is the global state that was just created, and n is the number of workers
635 * that were made (or requested from RML) for it.
636 */
637 static void write_version_file (global_state_t *g, int n)
638 {
639 const char *env; // environment variable.
640 char buf[256]; // print buffer.
641 time_t t;
642 FILE *fp;
643 struct utsname sys_info;
644 int err; // error code from system calls.
645
646 // if CILK_VERSION is not set, or if the file cannot be opened, fail
647 // silently. Otherwise open the file for writing (or use stderr or stdout
648 // if the user specifies).
649 if (NULL == (env = getenv("CILK_VERSION"))) return;
650 if (0 == strcasecmp(env, "stderr")) fp = stderr;
651 else if (0 == strcasecmp(env, "stdout")) fp = stdout;
652 else if (NULL == (fp = fopen(env, "w"))) return;
653
654 // get a string for the current time. E.g.,
655 // Cilk runtime initialized: Thu Jun 10 13:28:00 2010
656 t = time(NULL);
657 strftime(buf, 256, "%a %b %d %H:%M:%S %Y", localtime(&t));
658 fprintf(fp, "Cilk runtime initialized: %s\n", buf);
659
660 // Print runtime info. E.g.,
661 // Cilk runtime information
662 // ========================
663 // Cilk version: 2.0.0 Build 9184
664 // Built by willtor on host willtor-desktop
665 // Compilation date: Thu Jun 10 13:27:42 2010
666 // Compiled with ICC V99.9.9, ICC build date: 20100610
667
668 fprintf(fp, "\nCilk runtime information\n");
669 fprintf(fp, "========================\n");
670 fprintf(fp, "Cilk version: %d.%d.%d Build %d\n",
671 VERSION_MAJOR,
672 VERSION_MINOR,
673 VERSION_REV,
674 VERSION_BUILD);
675 #ifdef __VXWORKS__
676 char * vxWorksVer = VXWORKS_VERSION;
677 fprintf(fp, "Cross compiled for %s\n",vxWorksVer);
678 // user and host not avalible if VxWorks cross compiled on windows build host
679 #else
680
681 // User and host are not available for GCC builds
682 #ifdef BUILD_USER
683 fprintf(fp, "Built by "BUILD_USER" on host "BUILD_HOST"\n");
684 #endif // BUILD_USER
685 #endif // __VXWORKS__
686
687 // GCC has requested that this be removed for GCC builds
688 #ifdef BUILD_USER
689 fprintf(fp, "Compilation date: "__DATE__" "__TIME__"\n");
690 #endif // BUILD_USER
691
692 #ifdef __INTEL_COMPILER
693 // Compiled by the Intel C/C++ compiler.
694 fprintf(fp, "Compiled with ICC V%d.%d.%d, ICC build date: %d\n",
695 __INTEL_COMPILER / 100,
696 (__INTEL_COMPILER / 10) % 10,
697 __INTEL_COMPILER % 10,
698 __INTEL_COMPILER_BUILD_DATE);
699 #else
700 // Compiled by GCC.
701 fprintf(fp, "Compiled with GCC V%d.%d.%d\n",
702 __GNUC__,
703 __GNUC_MINOR__,
704 __GNUC_PATCHLEVEL__);
705 #endif // defined __INTEL_COMPILER
706
707 // Print system info. E.g.,
708 // System information
709 // ==================
710 // Cilk runtime path: /opt/icc/64/lib/libcilkrts.so.5
711 // System OS: Linux, release 2.6.28-19-generic
712 // System architecture: x86_64
713
714 err = uname(&sys_info);
715 fprintf(fp, "\nSystem information\n");
716 fprintf(fp, "==================\n");
717 fprintf(fp, "Cilk runtime path: %s\n", get_runtime_path());
718 fprintf(fp, "System OS: %s, release %s\n",
719 err < 0 ? "unknown" : sys_info.sysname,
720 err < 0 ? "?" : sys_info.release);
721 fprintf(fp, "System architecture: %s\n",
722 err < 0 ? "unknown" : sys_info.machine);
723
724 // Print thread info. E.g.,
725 // Thread information
726 // ==================
727 // System cores: 8
728 // Cilk workers requested: 8
729 // Thread creator: Private
730
731 fprintf(fp, "\nThread information\n");
732 fprintf(fp, "==================\n");
733 #ifdef __VXWORKS__
734 fprintf(fp, "System cores: %d\n", (int)__builtin_popcount(vxCpuEnabledGet()));
735 #else
736 fprintf(fp, "System cores: %d\n", (int)sysconf(_SC_NPROCESSORS_ONLN));
737 #endif
738 fprintf(fp, "Cilk workers requested: %d\n", n);
739 #if (PARALLEL_THREAD_CREATE)
740 fprintf(fp, "Thread creator: Private (parallel)\n");
741 #else
742 fprintf(fp, "Thread creator: Private\n");
743 #endif
744
745 if (fp != stderr && fp != stdout) fclose(fp);
746 else fflush(fp); // flush the handle buffer if it is stdout or stderr.
747 }
748
749
750 /*
751 * __cilkrts_establish_c_stack
752 *
753 * Tell Cilkscreen about the user stack bounds.
754 *
755 * Note that the Cilk V1 runtime only included the portion of the stack from
756 * the entry into Cilk, down. We don't appear to be able to find that, but
757 * I think this will be sufficient.
758 */
759
760 void __cilkrts_establish_c_stack(void)
761 {
762 /* FIXME: Not implemented. */
763
764 /* TBD: Do we need this */
765 /*
766 void __cilkrts_cilkscreen_establish_c_stack(char *begin, char *end);
767
768 size_t r;
769 MEMORY_BASIC_INFORMATION mbi;
770
771 r = VirtualQuery (&mbi,
772 &mbi,
773 sizeof(mbi));
774
775 __cilkrts_cilkscreen_establish_c_stack((char *)mbi.BaseAddress,
776 (char *)mbi.BaseAddress + mbi.RegionSize);
777 */
778 }
779
780
781 /*
782 * internal_enforce_global_visibility
783 *
784 * Ensure global visibility of public symbols, for proper Cilk-TBB interop.
785 *
786 * If Cilk runtime is loaded dynamically, its symbols might remain unavailable
787 * for global search with dladdr; that might prevent TBB from finding Cilk
788 * in the process address space and initiating the interop protocol.
789 * The workaround is for the library to open itself with RTLD_GLOBAL flag.
790 */
791
792 static __attribute__((noinline))
793 void internal_enforce_global_visibility()
794 {
795 void* handle = dlopen( get_runtime_path(), RTLD_GLOBAL|RTLD_LAZY );
796
797 /* For proper reference counting, close the handle immediately. */
798 if( handle) dlclose(handle);
799 }
800
801 /*
802 Local Variables: **
803 c-file-style:"bsd" **
804 c-basic-offset:4 **
805 indent-tabs-mode:nil **
806 End: **
807 */