static void * __upc_start_pthread (void *arg) { upc_startup_args_p startup_args = arg; int thread_id = startup_args->thread_id; upc_info_p u = __upc_info; int *status_ptr; if (!u) __upc_fatal ("UPC runtime not initialized"); /* MYTHREAD is located in thread local storage */ MYTHREAD = thread_id; __upc_affinity_set (u, thread_id); /* Perform per thread initialization. */ __upc_per_thread_init (u); /* Initialize random number generator seed. Note: C99 requires an initial seed value of 1, per 7.20.2.2. */ __upc_srand (1); status_ptr = &u->thread_info[thread_id].exit_status; __upc_barrier (GUPCR_RUNTIME_BARRIER_ID); __upc_pupc_init (&startup_args->argc, &startup_args->argv); *status_ptr = GUPCR_MAIN (startup_args->argc, startup_args->argv); p_startx (GASP_UPC_COLLECTIVE_EXIT, *status_ptr); p_endx (GASP_UPC_COLLECTIVE_EXIT, *status_ptr); return status_ptr; }
/* upc_global_exit - exit program with given status, terminate all other threads. The implementation imposes a restriction on exit return codes. If the return code has bit 7 (0x80) set, then the exit code will be interpreted as the code passed to upc_global_exit() and the monitor program will cancel all other executing threads. */ void upc_global_exit (int status) { upc_info_p u = __upc_info; if (!u) __upc_fatal ("UPC runtime not initialized"); exit ((THREADS > 1) ? ((status & 0x7f) | 0x80) : status); }
void __upc_exit (int status) { upc_info_p u = __upc_info; int *status_ptr; int thread_id = MYTHREAD; if (!u) __upc_fatal ("UPC runtime not initialized"); __upc_barrier (GUPCR_RUNTIME_BARRIER_ID); status_ptr = &u->thread_info[thread_id].exit_status; *status_ptr = status; pthread_exit (status_ptr); }
/* Calls to exit() are rewritten into calls to __upc_exit() by #define in <gcc-upc.h>. Simply perform a upc_barrier and then exit the process. Monitor_threads() will pick up the returned status code. */ void __upc_exit (int status) { upc_info_p u = __upc_info; if (!u) __upc_fatal ("UPC runtime not initialized"); __upc_acquire_lock (&u->lock); fflush (0); fsync (1); fsync (2); __upc_release_lock (&u->lock); __upc_barrier (GUPCR_RUNTIME_BARRIER_ID); exit (status); }
void __upc_affinity_set (upc_info_p u, int thread_id) { const upc_thread_info_p tinfo = &u->thread_info[thread_id]; switch (u->sched_policy) { case GUPCR_SCHED_POLICY_CPU: case GUPCR_SCHED_POLICY_CPU_STRICT: { const int sched_affinity = tinfo->sched_affinity; cpu_set_t set; CPU_ZERO (&set); CPU_SET (sched_affinity, &set); if (sched_setaffinity (0, sizeof (set), &set)) { __upc_fatal ("Scheduling cannot be set"); } } break; case GUPCR_SCHED_POLICY_NODE: __upc_numa_sched_set (u, thread_id); break; default: /* auto - no scheduling support */ break; } /* set memory policy only if we are not AUTO scheduling */ if ((u->sched_policy != GUPCR_SCHED_POLICY_AUTO) && (u->mem_policy != GUPCR_MEM_POLICY_AUTO)) __upc_numa_memory_affinity_set (u, thread_id); #ifdef DEBUG_AFFINITY printf ("affinity: %d (%s,%s) scheduling (%d,%d)\n", thread_id, upc_sched_policy_to_string (u->sched_policy), upc_mem_policy_to_string (u->mem_policy), tinfo->sched_affinity, tinfo->mem_affinity); #endif /* DEBUG_AFFINITY */ }
/** * GLIBC backtrace. * * Show backtrace by using the GLIBC backtrace functionality. * Backtrace is improved with the source file/line numbers if * libbfd is available. * * By default backtrace lines are sent to the 'stderr' file * descriptor. However, an environment variable * UPC_BACKTRACEFILE can be used to redirect the backtrace * to an actual file and it is used as a simple prefix for * the backtrace file. For example, if it is set to "/tmp/trace-upc", * the actual trace file is going to be "/tmp/trace-upc-PID.MYTHREAD". * If empty environment variable is provided, a simple "trace" prefix * is used. * */ void __upc_backtrace (void) { void *strace[GUPCR_BT_DEPTH_CNT]; size_t size,i; char **strace_str; char *file_env; int under_upc_main = 1; FILE *traceout = stderr; upc_info_p u = __upc_info; if (!u) __upc_fatal ("UPC runtime not initialized"); file_env = getenv (GUPCR_BACKTRACE_FILE_ENV); if (file_env) { int len = strlen (file_env); char *tracefile = malloc (len + 128); if (!tracefile) __upc_fatal ("UPC backtrace cannot allocate file name memory"); if (len) strcpy (tracefile, file_env); else { strcpy (tracefile, "backtrace"); len = 9; } len = snprintf (&tracefile[len], 128, ".%d", MYTHREAD); traceout = fopen (tracefile, "w"); if (!traceout) __upc_fatal ("Cannot open file for backtrace log"); free (tracefile); } else fprintf (traceout, "Thread %d backtrace:\n", MYTHREAD); /* Use "backtrace" functionality of glibc. */ size = backtrace (strace, GUPCR_BT_DEPTH_CNT); # if HAVE_LIBBFD strace_str = backtrace_src_symbols (strace, size, __upc_abs_execname); # else strace_str = backtrace_symbols (strace, size); # endif for (i = GUPCR_BT_SKIP_FRAME_CNT; i < size; i++) { if (under_upc_main) { fprintf (traceout, "[%4d][%lld] %s\n", MYTHREAD, (long long int) (i - GUPCR_BT_SKIP_FRAME_CNT), strace_str[i]); /* Extra info for the barrier. */ if ( strstr( strace_str[i], "__upc_wait")) { fprintf (traceout, "[%4d] BARRIER ID: %d\n", MYTHREAD, __upc_barrier_id); } } if (under_upc_main && strstr (strace_str[i], "upc_main")) under_upc_main = 0; } fflush (traceout); if (file_env) fclose (traceout); }
/* Check for UPC runtime calls from OMP threads. */ void __upc_omp_check (void) { if (__upc_omp_master_id != pthread_self ()) __upc_fatal ("UPC runtime calls are allowed only from UPC threads");; }