|  | /* | 
|  | * sysdep-unix.c | 
|  | * | 
|  | ************************************************************************* | 
|  | * | 
|  | *  @copyright | 
|  | *  Copyright (C) 2010-2013, Intel Corporation | 
|  | *  All rights reserved. | 
|  | * | 
|  | *  @copyright | 
|  | *  Redistribution and use in source and binary forms, with or without | 
|  | *  modification, are permitted provided that the following conditions | 
|  | *  are met: | 
|  | * | 
|  | *    * Redistributions of source code must retain the above copyright | 
|  | *      notice, this list of conditions and the following disclaimer. | 
|  | *    * Redistributions in binary form must reproduce the above copyright | 
|  | *      notice, this list of conditions and the following disclaimer in | 
|  | *      the documentation and/or other materials provided with the | 
|  | *      distribution. | 
|  | *    * Neither the name of Intel Corporation nor the names of its | 
|  | *      contributors may be used to endorse or promote products derived | 
|  | *      from this software without specific prior written permission. | 
|  | * | 
|  | *  @copyright | 
|  | *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 
|  | *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 
|  | *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | 
|  | *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 
|  | *  AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
|  | *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY | 
|  | *  WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 
|  | *  POSSIBILITY OF SUCH DAMAGE. | 
|  | * | 
|  | ************************************************************************** | 
|  | */ | 
|  |  | 
|  | #ifdef __linux__ | 
|  | // define _GNU_SOURCE before *any* #include. | 
|  | // Even <stdint.h> will break later #includes if this macro is not | 
|  | // already defined when it is #included. | 
|  | #   define _GNU_SOURCE | 
|  | #endif | 
|  |  | 
|  | #include "sysdep.h" | 
|  | #include "os.h" | 
|  | #include "bug.h" | 
|  | #include "local_state.h" | 
|  | #include "signal_node.h" | 
|  | #include "full_frame.h" | 
|  | #include "jmpbuf.h" | 
|  | #include "cilk_malloc.h" | 
|  | #include "reducer_impl.h" | 
|  | #include "metacall_impl.h" | 
|  |  | 
|  |  | 
|  | // On x86 processors (but not MIC processors), the compiler generated code to | 
|  | // save the FP state (rounding mode and the like) before calling setjmp.  We | 
|  | // will need to restore that state when we resume. | 
|  | #ifndef __MIC__ | 
|  | # if defined(__i386__) || defined(__x86_64) | 
|  | #   define RESTORE_X86_FP_STATE | 
|  | # endif // defined(__i386__) || defined(__x86_64) | 
|  | #endif  // __MIC__ | 
|  |  | 
|  | // contains notification macros for VTune. | 
|  | #include "cilk-ittnotify.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #ifdef __CYGWIN__ | 
|  | // On Cygwin, string.h doesnt declare strcasecmp if __STRICT_ANSI__ is defined | 
|  | #   undef __STRICT_ANSI__ | 
|  | #endif | 
|  |  | 
|  | #include <string.h> | 
|  | #include <pthread.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | #if defined HAVE_ALLOCA_H | 
|  | # include <alloca.h> | 
|  | #elif defined __GNUC__ | 
|  | # define alloca __builtin_alloca | 
|  | #elif defined _AIX | 
|  | # define alloca __alloca | 
|  | #else | 
|  | # include <stddef.h> | 
|  | # ifdef  __cplusplus | 
|  | extern "C" | 
|  | # endif | 
|  | void *alloca (size_t); | 
|  | #endif | 
|  |  | 
|  | #ifdef __APPLE__ | 
|  | //#   include <scheduler.h>  // Angle brackets include Apple's scheduler.h, not ours. | 
|  | #endif | 
|  |  | 
|  | #ifdef __linux__ | 
|  | #   include <sys/resource.h> | 
|  | #   include <sys/sysinfo.h> | 
|  | #endif | 
|  |  | 
|  | #ifdef __FreeBSD__ | 
|  | #   include <sys/resource.h> | 
|  | // BSD does not define MAP_ANONYMOUS, but *does* define MAP_ANON. Aren't standards great! | 
|  | #   define MAP_ANONYMOUS MAP_ANON | 
|  | #endif | 
|  |  | 
|  | #ifdef  __VXWORKS__ | 
|  | #   include <vxWorks.h> | 
|  | #   include <vxCpuLib.h> | 
|  | #endif | 
|  |  | 
|  | struct global_sysdep_state | 
|  | { | 
|  | pthread_t *threads;    ///< Array of pthreads for system workers | 
|  | size_t pthread_t_size; ///< for cilk_db | 
|  | }; | 
|  |  | 
|  | static void internal_enforce_global_visibility(); | 
|  |  | 
|  |  | 
|  | COMMON_SYSDEP | 
|  | void __cilkrts_init_worker_sysdep(struct __cilkrts_worker *w) | 
|  | { | 
|  | ITT_SYNC_CREATE(w, "Scheduler"); | 
|  | } | 
|  |  | 
|  | COMMON_SYSDEP | 
|  | void __cilkrts_destroy_worker_sysdep(struct __cilkrts_worker *w) | 
|  | { | 
|  | } | 
|  |  | 
|  | COMMON_SYSDEP | 
|  | void __cilkrts_init_global_sysdep(global_state_t *g) | 
|  | { | 
|  | internal_enforce_global_visibility(); | 
|  |  | 
|  | __cilkrts_init_tls_variables(); | 
|  |  | 
|  | CILK_ASSERT(g->total_workers >= g->P - 1); | 
|  | g->sysdep = __cilkrts_malloc(sizeof (struct global_sysdep_state)); | 
|  | CILK_ASSERT(g->sysdep); | 
|  | g->sysdep->pthread_t_size = sizeof (pthread_t); | 
|  |  | 
|  | // TBD: Should this value be g->total_workers, or g->P? | 
|  | //      Need to check what we are using this field for. | 
|  | g->sysdep->threads = __cilkrts_malloc(sizeof(pthread_t) * g->total_workers); | 
|  | CILK_ASSERT(g->sysdep->threads); | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | COMMON_SYSDEP | 
|  | void __cilkrts_destroy_global_sysdep(global_state_t *g) | 
|  | { | 
|  | if (g->sysdep->threads) | 
|  | __cilkrts_free(g->sysdep->threads); | 
|  | __cilkrts_free(g->sysdep); | 
|  | } | 
|  |  | 
|  | /************************************************************* | 
|  | Creation of worker threads: | 
|  | *************************************************************/ | 
|  |  | 
|  | static void internal_run_scheduler_with_exceptions(__cilkrts_worker *w) | 
|  | { | 
|  | /* We assume the stack grows down. */ | 
|  | char var; | 
|  | __cilkrts_cilkscreen_establish_c_stack(&var - 1000000, &var); | 
|  |  | 
|  | __cilkrts_run_scheduler_with_exceptions(w); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /* | 
|  | * scheduler_thread_proc_for_system_worker | 
|  | * | 
|  | * Thread start function called when we start a new worker. | 
|  | * | 
|  | */ | 
|  | NON_COMMON void* scheduler_thread_proc_for_system_worker(void *arg) | 
|  | { | 
|  | /*int status;*/ | 
|  | __cilkrts_worker *w = (__cilkrts_worker *)arg; | 
|  |  | 
|  | #ifdef __INTEL_COMPILER | 
|  | #ifdef USE_ITTNOTIFY | 
|  | // Name the threads for Advisor.  They don't want a worker number. | 
|  | __itt_thread_set_name("Cilk Worker"); | 
|  | #endif // defined USE_ITTNOTIFY | 
|  | #endif // defined __INTEL_COMPILER | 
|  |  | 
|  | /* Worker startup is serialized | 
|  | status = pthread_mutex_lock(&__cilkrts_global_mutex); | 
|  | CILK_ASSERT(status == 0);*/ | 
|  | CILK_ASSERT(w->l->type == WORKER_SYSTEM); | 
|  | /*status = pthread_mutex_unlock(&__cilkrts_global_mutex); | 
|  | CILK_ASSERT(status == 0);*/ | 
|  |  | 
|  | __cilkrts_set_tls_worker(w); | 
|  |  | 
|  | // Create a cilk fiber for this worker on this thread. | 
|  | START_INTERVAL(w, INTERVAL_FIBER_ALLOCATE_FROM_THREAD) { | 
|  | w->l->scheduling_fiber = cilk_fiber_allocate_from_thread(); | 
|  | cilk_fiber_set_owner(w->l->scheduling_fiber, w); | 
|  | } STOP_INTERVAL(w, INTERVAL_FIBER_ALLOCATE_FROM_THREAD); | 
|  |  | 
|  | internal_run_scheduler_with_exceptions(w); | 
|  |  | 
|  | START_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE_FROM_THREAD) { | 
|  | // Deallocate the scheduling fiber.  This operation reverses the | 
|  | // effect cilk_fiber_allocate_from_thread() and must be done in this | 
|  | // thread before it exits. | 
|  | int ref_count = cilk_fiber_deallocate_from_thread(w->l->scheduling_fiber); | 
|  | // Scheduling fibers should never have extra references to them. | 
|  | // We only get extra references into fibers because of Windows | 
|  | // exceptions. | 
|  | CILK_ASSERT(0 == ref_count); | 
|  | w->l->scheduling_fiber = NULL; | 
|  | } STOP_INTERVAL(w, INTERVAL_FIBER_DEALLOCATE_FROM_THREAD); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * __cilkrts_user_worker_scheduling_stub | 
|  | * | 
|  | * Routine for the scheduling fiber created for an imported user | 
|  | * worker thread.  This method is analogous to | 
|  | * scheduler_thread_proc_for_system_worker. | 
|  | * | 
|  | */ | 
|  | void __cilkrts_user_worker_scheduling_stub(cilk_fiber* fiber, void* null_arg) | 
|  | { | 
|  | __cilkrts_worker *w = __cilkrts_get_tls_worker(); | 
|  |  | 
|  | // Sanity check. | 
|  | CILK_ASSERT(WORKER_USER == w->l->type); | 
|  |  | 
|  | // Enter the scheduling loop on the user worker. | 
|  | // This function will never return. | 
|  | __cilkrts_run_scheduler_with_exceptions(w); | 
|  |  | 
|  | // A WORKER_USER, at some point, will resume on the original stack and leave | 
|  | // Cilk.  Under no circumstances do we ever exit off of the bottom of this | 
|  | // stack. | 
|  | CILK_ASSERT(0); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * We are exporting a function with this name to Inspector? | 
|  | * What a confusing name... | 
|  | * | 
|  | * This function is exported so Piersol's stack trace displays | 
|  | * reasonable information. | 
|  | */ | 
|  | void* __cilkrts_worker_stub(void* arg) | 
|  | { | 
|  | return scheduler_thread_proc_for_system_worker(arg); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | // /* Return the lesser of the argument and the operating system | 
|  | //    limit on the number of workers (threads) that may or ought | 
|  | //    to be created. */ | 
|  | // int sysdep_thread_limit(int n, int physical_cpus) | 
|  | // { | 
|  | //     /* On Linux thread creation fails somewhere short of the | 
|  | //        number of available processes. */ | 
|  | //     struct rlimit lim; | 
|  |  | 
|  | //     if (n > 256 + 2 * physical_cpus) | 
|  | //         n = 256 + 2 * physical_cpus; | 
|  |  | 
|  | //     if (getrlimit(RLIMIT_NPROC, &lim) == 0 && lim.rlim_cur != RLIM_INFINITY) | 
|  | //     { | 
|  | //         /* If the limit reads 0 or absurdly small, ignore it. */ | 
|  | //         unsigned int maxproc = (lim.rlim_cur * 3 + 3) / 4; | 
|  | //         if (maxproc > 8 + 2 * physical_cpus && maxproc < n) | 
|  | //             n = maxproc; | 
|  | //     } | 
|  | //     return n; | 
|  | // } | 
|  |  | 
|  |  | 
|  |  | 
|  | static void write_version_file (global_state_t *, int); | 
|  |  | 
|  | /* Create n worker threads from base..top-1 | 
|  | */ | 
|  | static void create_threads(global_state_t *g, int base, int top) | 
|  | { | 
|  | // TBD(11/30/12): We want to insert code providing the option of | 
|  | // pinning system workers to cores. | 
|  | for (int i = base; i < top; i++) { | 
|  | int status = pthread_create(&g->sysdep->threads[i], | 
|  | NULL, | 
|  | scheduler_thread_proc_for_system_worker, | 
|  | g->workers[i]); | 
|  | if (status != 0) | 
|  | __cilkrts_bug("Cilk runtime error: thread creation (%d) failed: %d\n", i, status); | 
|  | } | 
|  | } | 
|  |  | 
|  | #if PARALLEL_THREAD_CREATE | 
|  | static int volatile threads_created = 0; | 
|  |  | 
|  | // Create approximately half of the worker threads, and then become a worker | 
|  | // ourselves. | 
|  | static void * create_threads_and_work (void * arg) | 
|  | { | 
|  | global_state_t *g = ((__cilkrts_worker *)arg)->g; | 
|  |  | 
|  | create_threads(g, g->P/2, g->P-1); | 
|  | // Let the initial thread know that we're done. | 
|  | threads_created = 1; | 
|  |  | 
|  | // Ideally this turns into a tail call that wipes out this stack frame. | 
|  | return scheduler_thread_proc_for_system_worker(arg); | 
|  | } | 
|  | #endif | 
|  | void __cilkrts_start_workers(global_state_t *g, int n) | 
|  | { | 
|  | g->workers_running = 1; | 
|  | g->work_done = 0; | 
|  |  | 
|  | if (!g->sysdep->threads) | 
|  | return; | 
|  |  | 
|  | // Do we actually have any threads to create? | 
|  | if (n > 0) | 
|  | { | 
|  | #if PARALLEL_THREAD_CREATE | 
|  | int status; | 
|  | // We create (a rounded up) half of the threads, thread one creates the rest | 
|  | int half_threads = (n+1)/2; | 
|  |  | 
|  | // Create the first thread passing a different thread function, so that it creates threads itself | 
|  | status = pthread_create(&g->sysdep->threads[0], NULL, create_threads_and_work, g->workers[0]); | 
|  |  | 
|  | if (status != 0) | 
|  | __cilkrts_bug("Cilk runtime error: thread creation (0) failed: %d\n", status); | 
|  |  | 
|  | // Then the rest of the ones we have to create | 
|  | create_threads(g, 1, half_threads); | 
|  |  | 
|  | // Now wait for the first created thread to tell us it's created all of its threads. | 
|  | // We could maybe drop this a bit lower and overlap with write_version_file. | 
|  | while (!threads_created) | 
|  | __cilkrts_yield(); | 
|  | #else | 
|  | // Simply create all the threads linearly here. | 
|  | create_threads(g, 0, n); | 
|  | #endif | 
|  | } | 
|  | // write the version information to a file if the environment is configured | 
|  | // for it (the function makes the check). | 
|  | write_version_file(g, n); | 
|  |  | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | void __cilkrts_stop_workers(global_state_t *g) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | // Tell the workers to give up | 
|  |  | 
|  | g->work_done = 1; | 
|  |  | 
|  | if (g->workers_running == 0) | 
|  | return; | 
|  |  | 
|  | if (!g->sysdep->threads) | 
|  | return; | 
|  |  | 
|  | /* Make them all runnable. */ | 
|  | if (g->P > 1) { | 
|  | CILK_ASSERT(g->workers[0]->l->signal_node); | 
|  | signal_node_msg(g->workers[0]->l->signal_node, 1); | 
|  | } | 
|  |  | 
|  | for (i = 0; i < g->P - 1; ++i) { | 
|  | int sc_status; | 
|  | void *th_status; | 
|  |  | 
|  | sc_status = pthread_join(g->sysdep->threads[i], &th_status); | 
|  | if (sc_status != 0) | 
|  | __cilkrts_bug("Cilk runtime error: thread join (%d) failed: %d\n", i, sc_status); | 
|  | } | 
|  |  | 
|  | g->workers_running = 0; | 
|  |  | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * @brief Returns the stack address for resuming execution of sf. | 
|  | * | 
|  | * This method takes in the top of the stack to use, and then returns | 
|  | * a properly aligned address for resuming execution of sf. | 
|  | * | 
|  | *  @param sf           -   The stack frame we want to resume executing. | 
|  | *  @param stack_base   -   The top of the stack we want to execute sf on. | 
|  | * | 
|  | */ | 
|  | static char* get_sp_for_executing_sf(char* stack_base, | 
|  | full_frame *ff, | 
|  | __cilkrts_stack_frame *sf) | 
|  | { | 
|  | // The original calculation that had been done to correct the stack | 
|  | // pointer when resuming execution. | 
|  | // | 
|  | // But this code was never getting called in the eng branch anyway... | 
|  | // | 
|  | // TBD(11/30/12): This logic needs to be revisited to make sure that | 
|  | // we are doing the proper calculation in reserving space for outgoing | 
|  | // arguments on all platforms and architectures. | 
|  | #if 0 | 
|  | /* Preserve outgoing argument space and stack alignment on steal. | 
|  | Outgoing argument space is bounded by the difference between | 
|  | stack and frame pointers.  Some user code is known to rely on | 
|  | 16 byte alignment.  Maintain 32 byte alignment for future | 
|  | compatibility. */ | 
|  | #define SMASK 31 /* 32 byte alignment */ | 
|  | if (sf) { | 
|  | char *fp = FP(sf), *sp = SP(sf); | 
|  | int fp_align = (int)(size_t)fp & SMASK; | 
|  | ptrdiff_t space = fp - sp; | 
|  |  | 
|  | fprintf(stderr, "Here: fp = %p, sp = %p\n", fp, sp); | 
|  | char *top_aligned = (char *)((((size_t)stack_base - SMASK) & ~(size_t)SMASK) | fp_align); | 
|  | /* Don't allocate an unreasonable amount of stack space. */ | 
|  |  | 
|  | fprintf(stderr, "Here: stack_base = %p, top_aligned=%p, space=%ld\n", | 
|  | stack_base, top_aligned, space); | 
|  | if (space < 32) | 
|  | space = 32 + (space & SMASK); | 
|  | else if (space > 40 * 1024) | 
|  | space = 40 * 1024 + (space & SMASK); | 
|  |  | 
|  | return top_aligned - space; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #define PERFORM_FRAME_SIZE_CALCULATION 0 | 
|  |  | 
|  | char* new_stack_base = stack_base - 256; | 
|  |  | 
|  | #if PERFORM_FRAME_SIZE_CALCULATION | 
|  | // If there is a frame size saved, then use that as the | 
|  | // correction instead of 256. | 
|  | if (ff->frame_size > 0) { | 
|  | if (ff->frame_size < 40*1024) { | 
|  | new_stack_base = stack_base - ff->frame_size; | 
|  | } | 
|  | else { | 
|  | // If for some reason, our frame size calculation is giving us | 
|  | // a number which is bigger than about 10 pages, then | 
|  | // there is likely something wrong here?  Don't allocate | 
|  | // an unreasonable amount of space. | 
|  | new_stack_base = stack_base - 40*1024; | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  | // Whatever correction we choose, align the final stack top. | 
|  | // This alignment seems to be necessary in particular on 32-bit | 
|  | // Linux, and possibly Mac. (Is 32-byte alignment is sufficient?) | 
|  | /* 256-byte alignment. Why not? */ | 
|  | const uintptr_t align_mask = ~(256 -1); | 
|  | new_stack_base = (char*)((size_t)new_stack_base & align_mask); | 
|  | return new_stack_base; | 
|  | } | 
|  |  | 
|  | char* sysdep_reset_jump_buffers_for_resume(cilk_fiber* fiber, | 
|  | full_frame *ff, | 
|  | __cilkrts_stack_frame *sf) | 
|  | { | 
|  | #if FIBER_DEBUG >= 4 | 
|  | fprintf(stderr, "ThreadId=%p (fiber_proc_to_resume), Fiber %p.  sf = %p. ff=%p, ff->sync_sp=%p\n", | 
|  | cilkos_get_current_thread_id(), | 
|  | fiber, | 
|  | sf, | 
|  | ff, ff->sync_sp); | 
|  | #endif | 
|  |  | 
|  | CILK_ASSERT(fiber); | 
|  | void* sp = (void*)get_sp_for_executing_sf(cilk_fiber_get_stack_base(fiber), ff, sf); | 
|  | SP(sf) = sp; | 
|  |  | 
|  | /* Debugging: make sure stack is accessible. */ | 
|  | ((volatile char *)sp)[-1]; | 
|  |  | 
|  | // Adjust the saved_sp to account for the SP we're about to run.  This will | 
|  | // allow us to track fluctations in the stack | 
|  | #if FIBER_DEBUG >= 4 | 
|  | fprintf(stderr, "ThreadId=%p, about to take stack ff=%p, sp=%p, sync_sp=%p\n", | 
|  | cilkos_get_current_thread_id(), | 
|  | ff, | 
|  | sp, | 
|  | ff->sync_sp); | 
|  | #endif | 
|  | __cilkrts_take_stack(ff, sp); | 
|  | return sp; | 
|  | } | 
|  |  | 
|  |  | 
|  | NORETURN sysdep_longjmp_to_sf(char* new_sp, | 
|  | __cilkrts_stack_frame *sf, | 
|  | full_frame *ff_for_exceptions /* UNUSED on Unix */) | 
|  | { | 
|  | #if FIBER_DEBUG >= 3 | 
|  | fprintf(stderr, | 
|  | "ThreadId=%p. resume user code, sf=%p, new_sp = %p, original SP(sf) = %p, FP(sf) = %p\n", | 
|  | cilkos_get_current_thread_id(), sf, new_sp, SP(sf), FP(sf)); | 
|  | #endif | 
|  |  | 
|  | // Set the stack pointer. | 
|  | SP(sf) = new_sp; | 
|  |  | 
|  | #ifdef RESTORE_X86_FP_STATE | 
|  | if (CILK_FRAME_VERSION_VALUE(sf->flags) >= 1) { | 
|  | // Restore the floating point state that was set in this frame at the | 
|  | // last spawn. | 
|  | // | 
|  | // This feature is only available in ABI 1 or later frames, and only | 
|  | // needed on IA64 or Intel64 processors. | 
|  | restore_x86_fp_state(sf); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | CILK_LONGJMP(sf->ctx); | 
|  | } | 
|  |  | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <sys/mman.h> | 
|  | #include <errno.h> | 
|  |  | 
|  |  | 
|  | void __cilkrts_make_unrunnable_sysdep(__cilkrts_worker *w, | 
|  | full_frame *ff, | 
|  | __cilkrts_stack_frame *sf, | 
|  | int is_loot, | 
|  | const char *why) | 
|  | { | 
|  | (void)w; /* unused */ | 
|  | sf->except_data = 0; | 
|  |  | 
|  | if (is_loot) | 
|  | { | 
|  | if (ff->frame_size == 0) | 
|  | ff->frame_size = __cilkrts_get_frame_size(sf); | 
|  |  | 
|  | // Null loot's sp for debugging purposes (so we'll know it's not valid) | 
|  | SP(sf) = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * __cilkrts_sysdep_is_worker_thread_id | 
|  | * | 
|  | * Returns true if the thread ID specified matches the thread ID we saved | 
|  | * for a worker. | 
|  | */ | 
|  |  | 
|  | int __cilkrts_sysdep_is_worker_thread_id(global_state_t *g, | 
|  | int i, | 
|  | void *thread_id) | 
|  | { | 
|  | #if defined( __linux__) || defined(__VXWORKS__) | 
|  | pthread_t tid = *(pthread_t *)thread_id; | 
|  | if (i < 0 || i > g->total_workers) | 
|  | return 0; | 
|  | return g->sysdep->threads[i] == tid; | 
|  | #else | 
|  | // Needs to be implemented | 
|  | return 0; | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | /************************************************************* | 
|  | Version information: | 
|  | *************************************************************/ | 
|  |  | 
|  | #include <dlfcn.h> | 
|  | #include "internal/cilk_version.h" | 
|  | #include <stdio.h> | 
|  | #include <sys/utsname.h> | 
|  |  | 
|  | #ifdef __VXWORKS__ | 
|  | #include <version.h> | 
|  | # endif | 
|  |  | 
|  | /* (Non-static) dummy function is used by get_runtime_path() to find the path | 
|  | * to the .so containing the Cilk runtime. | 
|  | */ | 
|  | void dummy_function() { } | 
|  |  | 
|  | /* return a string with the path to the Cilk runtime, or "unknown" if the path | 
|  | * cannot be determined. | 
|  | */ | 
|  | static const char *get_runtime_path () | 
|  | { | 
|  | #ifdef __CYGWIN__ | 
|  | // Cygwin doesn't support dladdr, which sucks | 
|  | return "unknown"; | 
|  | #else | 
|  | Dl_info info; | 
|  | if (0 == dladdr(dummy_function, &info)) return "unknown"; | 
|  | return info.dli_fname; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* if the environment variable, CILK_VERSION, is defined, writes the version | 
|  | * information to the specified file. | 
|  | * g is the global state that was just created, and n is the number of workers | 
|  | * that were made (or requested from RML) for it. | 
|  | */ | 
|  | static void write_version_file (global_state_t *g, int n) | 
|  | { | 
|  | const char *env;      // environment variable. | 
|  | char buf[256];        // print buffer. | 
|  | time_t t; | 
|  | FILE *fp; | 
|  | struct utsname sys_info; | 
|  | int err;              // error code from system calls. | 
|  |  | 
|  | // if CILK_VERSION is not set, or if the file cannot be opened, fail | 
|  | // silently.  Otherwise open the file for writing (or use stderr or stdout | 
|  | // if the user specifies). | 
|  | if (NULL == (env = getenv("CILK_VERSION"))) return; | 
|  | if (0 == strcasecmp(env, "stderr"))         fp = stderr; | 
|  | else if (0 == strcasecmp(env, "stdout"))    fp = stdout; | 
|  | else if (NULL == (fp = fopen(env, "w")))    return; | 
|  |  | 
|  | // get a string for the current time.  E.g., | 
|  | // Cilk runtime initialized: Thu Jun 10 13:28:00 2010 | 
|  | t = time(NULL); | 
|  | strftime(buf, 256, "%a %b %d %H:%M:%S %Y", localtime(&t)); | 
|  | fprintf(fp, "Cilk runtime initialized: %s\n", buf); | 
|  |  | 
|  | // Print runtime info.  E.g., | 
|  | // Cilk runtime information | 
|  | // ======================== | 
|  | // Cilk version: 2.0.0 Build 9184 | 
|  | // Built by willtor on host willtor-desktop | 
|  | // Compilation date: Thu Jun 10 13:27:42 2010 | 
|  | // Compiled with ICC V99.9.9, ICC build date: 20100610 | 
|  |  | 
|  | fprintf(fp, "\nCilk runtime information\n"); | 
|  | fprintf(fp, "========================\n"); | 
|  | fprintf(fp, "Cilk version: %d.%d.%d Build %d\n", | 
|  | VERSION_MAJOR, | 
|  | VERSION_MINOR, | 
|  | VERSION_REV, | 
|  | VERSION_BUILD); | 
|  | #ifdef __VXWORKS__ | 
|  | char * vxWorksVer = VXWORKS_VERSION; | 
|  | fprintf(fp, "Cross compiled for %s\n",vxWorksVer); | 
|  | // user and host not avalible if VxWorks cross compiled on windows build host | 
|  | #else | 
|  |  | 
|  | // User and host are not available for GCC builds | 
|  | #ifdef BUILD_USER | 
|  | fprintf(fp, "Built by "BUILD_USER" on host "BUILD_HOST"\n"); | 
|  | #endif // BUILD_USER | 
|  | #endif // __VXWORKS__ | 
|  |  | 
|  | // GCC has requested that this be removed for GCC builds | 
|  | #ifdef BUILD_USER | 
|  | fprintf(fp, "Compilation date: "__DATE__" "__TIME__"\n"); | 
|  | #endif // BUILD_USER | 
|  |  | 
|  | #ifdef __INTEL_COMPILER | 
|  | // Compiled by the Intel C/C++ compiler. | 
|  | fprintf(fp, "Compiled with ICC V%d.%d.%d, ICC build date: %d\n", | 
|  | __INTEL_COMPILER / 100, | 
|  | (__INTEL_COMPILER / 10) % 10, | 
|  | __INTEL_COMPILER % 10, | 
|  | __INTEL_COMPILER_BUILD_DATE); | 
|  | #else | 
|  | // Compiled by GCC. | 
|  | fprintf(fp, "Compiled with GCC V%d.%d.%d\n", | 
|  | __GNUC__, | 
|  | __GNUC_MINOR__, | 
|  | __GNUC_PATCHLEVEL__); | 
|  | #endif // defined __INTEL_COMPILER | 
|  |  | 
|  | // Print system info.  E.g., | 
|  | // System information | 
|  | // ================== | 
|  | // Cilk runtime path: /opt/icc/64/lib/libcilkrts.so.5 | 
|  | // System OS: Linux, release 2.6.28-19-generic | 
|  | // System architecture: x86_64 | 
|  |  | 
|  | err = uname(&sys_info); | 
|  | fprintf(fp, "\nSystem information\n"); | 
|  | fprintf(fp, "==================\n"); | 
|  | fprintf(fp, "Cilk runtime path: %s\n", get_runtime_path()); | 
|  | fprintf(fp, "System OS: %s, release %s\n", | 
|  | err < 0 ? "unknown" : sys_info.sysname, | 
|  | err < 0 ? "?" : sys_info.release); | 
|  | fprintf(fp, "System architecture: %s\n", | 
|  | err < 0 ? "unknown" : sys_info.machine); | 
|  |  | 
|  | // Print thread info.  E.g., | 
|  | // Thread information | 
|  | // ================== | 
|  | // System cores: 8 | 
|  | // Cilk workers requested: 8 | 
|  | // Thread creator: Private | 
|  |  | 
|  | fprintf(fp, "\nThread information\n"); | 
|  | fprintf(fp, "==================\n"); | 
|  | #ifdef __VXWORKS__ | 
|  | fprintf(fp, "System cores: %d\n", (int)__builtin_popcount(vxCpuEnabledGet())); | 
|  | #else | 
|  | fprintf(fp, "System cores: %d\n", (int)sysconf(_SC_NPROCESSORS_ONLN)); | 
|  | #endif | 
|  | fprintf(fp, "Cilk workers requested: %d\n", n); | 
|  | #if (PARALLEL_THREAD_CREATE) | 
|  | fprintf(fp, "Thread creator: Private (parallel)\n"); | 
|  | #else | 
|  | fprintf(fp, "Thread creator: Private\n"); | 
|  | #endif | 
|  |  | 
|  | if (fp != stderr && fp != stdout) fclose(fp); | 
|  | else fflush(fp); // flush the handle buffer if it is stdout or stderr. | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * __cilkrts_establish_c_stack | 
|  | * | 
|  | * Tell Cilkscreen about the user stack bounds. | 
|  | * | 
|  | * Note that the Cilk V1 runtime only included the portion of the stack from | 
|  | * the entry into Cilk, down.  We don't appear to be able to find that, but | 
|  | * I think this will be sufficient. | 
|  | */ | 
|  |  | 
|  | void __cilkrts_establish_c_stack(void) | 
|  | { | 
|  | /* FIXME: Not implemented. */ | 
|  |  | 
|  | /* TBD: Do we need this */ | 
|  | /* | 
|  | void __cilkrts_cilkscreen_establish_c_stack(char *begin, char *end); | 
|  |  | 
|  | size_t r; | 
|  | MEMORY_BASIC_INFORMATION mbi; | 
|  |  | 
|  | r = VirtualQuery (&mbi, | 
|  | &mbi, | 
|  | sizeof(mbi)); | 
|  |  | 
|  | __cilkrts_cilkscreen_establish_c_stack((char *)mbi.BaseAddress, | 
|  | (char *)mbi.BaseAddress + mbi.RegionSize); | 
|  | */ | 
|  | } | 
|  |  | 
|  |  | 
|  | /* | 
|  | * internal_enforce_global_visibility | 
|  | * | 
|  | * Ensure global visibility of public symbols, for proper Cilk-TBB interop. | 
|  | * | 
|  | * If Cilk runtime is loaded dynamically, its symbols might remain unavailable | 
|  | * for global search with dladdr; that might prevent TBB from finding Cilk | 
|  | * in the process address space and initiating the interop protocol. | 
|  | * The workaround is for the library to open itself with RTLD_GLOBAL flag. | 
|  | */ | 
|  |  | 
|  | static __attribute__((noinline)) | 
|  | void internal_enforce_global_visibility() | 
|  | { | 
|  | void* handle = dlopen( get_runtime_path(), RTLD_GLOBAL|RTLD_LAZY ); | 
|  |  | 
|  | /* For proper reference counting, close the handle immediately. */ | 
|  | if( handle) dlclose(handle); | 
|  | } | 
|  |  | 
|  | /* | 
|  | Local Variables: ** | 
|  | c-file-style:"bsd" ** | 
|  | c-basic-offset:4 ** | 
|  | indent-tabs-mode:nil ** | 
|  | End: ** | 
|  | */ |