char *__kmp_env_get(char const *name) { char *result = NULL; #if KMP_OS_UNIX char const *value = getenv(name); if (value != NULL) { size_t len = KMP_STRLEN(value) + 1; result = (char *)KMP_INTERNAL_MALLOC(len); if (result == NULL) { KMP_FATAL(MemoryAllocFailed); } KMP_STRNCPY_S(result, len, value, len); } #elif KMP_OS_WINDOWS /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the act of loading a DLL on Windows* OS makes any user-set environment variables (i.e. with putenv()) unavailable. getenv() apparently gets a clean copy of the env variables as they existed at the start of the run. JH 12/23/2002 */ DWORD rc; rc = GetEnvironmentVariable(name, NULL, 0); if (!rc) { DWORD error = GetLastError(); if (error != ERROR_ENVVAR_NOT_FOUND) { __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null); } // Variable is not found, it's ok, just continue. } else { DWORD len = rc; result = (char *)KMP_INTERNAL_MALLOC(len); if (result == NULL) { KMP_FATAL(MemoryAllocFailed); } rc = GetEnvironmentVariable(name, result, len); if (!rc) { // GetEnvironmentVariable() may return 0 if variable is empty. // In such a case GetLastError() returns ERROR_SUCCESS. DWORD error = GetLastError(); if (error != ERROR_SUCCESS) { // Unexpected error. The variable should be in the environment, // and buffer should be large enough. __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null); KMP_INTERNAL_FREE((void *)result); result = NULL; } } } #else #error Unknown or unsupported OS. #endif return result; } // func __kmp_env_get
void * __kmpc_threadprivate(ident_t *loc, kmp_int32 global_tid, void *data, size_t size) { void *ret; struct private_common *tn; KC_TRACE( 10, ("__kmpc_threadprivate: T#%d called\n", global_tid ) ); #ifdef USE_CHECKS_COMMON if (! __kmp_init_serial) KMP_FATAL( RTLNotInitialized ); #endif /* USE_CHECKS_COMMON */ if ( ! __kmp_threads[global_tid] -> th.th_root -> r.r_active && ! __kmp_foreign_tp ) { /* The parallel address will NEVER overlap with the data_address */ /* dkp: 3rd arg to kmp_threadprivate_insert_private_data() is the data_address; use data_address = data */ KC_TRACE( 20, ("__kmpc_threadprivate: T#%d inserting private data\n", global_tid ) ); kmp_threadprivate_insert_private_data( global_tid, data, data, size ); ret = data; } else { KC_TRACE( 50, ("__kmpc_threadprivate: T#%d try to find private data at address %p\n", global_tid, data ) ); tn = __kmp_threadprivate_find_task_common( __kmp_threads[ global_tid ]->th.th_pri_common, global_tid, data ); if ( tn ) { KC_TRACE( 20, ("__kmpc_threadprivate: T#%d found data\n", global_tid ) ); #ifdef USE_CHECKS_COMMON if ((size_t) size > tn->cmn_size) { KC_TRACE( 10, ( "THREADPRIVATE: %p (%" KMP_UINTPTR_SPEC " ,%" KMP_UINTPTR_SPEC ")\n", data, size, tn->cmn_size ) ); KMP_FATAL( TPCommonBlocksInconsist ); } #endif /* USE_CHECKS_COMMON */ } else { /* The parallel address will NEVER overlap with the data_address */ /* dkp: 3rd arg to kmp_threadprivate_insert() is the data_address; use data_address = data */ KC_TRACE( 20, ("__kmpc_threadprivate: T#%d inserting data\n", global_tid ) ); tn = kmp_threadprivate_insert( global_tid, data, data, size ); } ret = tn->par_addr; } KC_TRACE( 10, ("__kmpc_threadprivate: T#%d exiting; return value = %p\n", global_tid, ret ) ); return ret; }
char * __kmp_str_format( // Allocated string. char const * format, // Format string. ... // Other parameters. ) { va_list args; int size = 512; char * buffer = NULL; int rc; // Allocate buffer. buffer = (char *) KMP_INTERNAL_MALLOC( size ); if ( buffer == NULL ) { KMP_FATAL( MemoryAllocFailed ); }; // if for ( ; ; ) { // Try to format string. va_start( args, format ); rc = vsnprintf( buffer, size, format, args ); va_end( args ); // No errors, string has been formatted. if ( rc >= 0 && rc < size ) { break; }; // if // Error occured, buffer is too small. if ( rc >= 0 ) { // C99-conforming implementation of vsnprintf returns required buffer size. size = rc + 1; } else { // Older implementations just return -1. size = size * 2; }; // if // Enlarge buffer and try again. buffer = (char *) KMP_INTERNAL_REALLOC( buffer, size ); if ( buffer == NULL ) { KMP_FATAL( MemoryAllocFailed ); }; // if }; // forever return buffer; } // func __kmp_str_format
static inline void *allocate(size_t size) { void *ptr = KMP_INTERNAL_MALLOC(size); if (ptr == NULL) { KMP_FATAL(MemoryAllocFailed); } return ptr; } // allocate
void __kmp_str_buf_reserve( kmp_str_buf_t * buffer, int size ) { KMP_STR_BUF_INVARIANT( buffer ); KMP_DEBUG_ASSERT( size >= 0 ); if ( buffer->size < size ) { // Calculate buffer size. do { buffer->size *= 2; } while ( buffer->size < size ); // Enlarge buffer. if ( buffer->str == & buffer->bulk[ 0 ] ) { buffer->str = (char *) KMP_INTERNAL_MALLOC( buffer->size ); if ( buffer->str == NULL ) { KMP_FATAL( MemoryAllocFailed ); }; // if memcpy( buffer->str, buffer->bulk, buffer->used + 1 ); } else { buffer->str = (char *) KMP_INTERNAL_REALLOC( buffer->str, buffer->size ); if ( buffer->str == NULL ) { KMP_FATAL( MemoryAllocFailed ); }; // if }; // if }; // if KMP_DEBUG_ASSERT( buffer->size > 0 ); KMP_DEBUG_ASSERT( buffer->size >= size ); KMP_STR_BUF_INVARIANT( buffer ); } // __kmp_str_buf_reserve
void __kmp_str_buf_detach( kmp_str_buf_t * buffer ) { KMP_STR_BUF_INVARIANT( buffer ); // If internal bulk is used, allocate memory and copy it. if ( buffer->size <= sizeof( buffer->bulk ) ) { buffer->str = (char *) KMP_INTERNAL_MALLOC( buffer->size ); if ( buffer->str == NULL ) { KMP_FATAL( MemoryAllocFailed ); }; // if memcpy( buffer->str, buffer->bulk, buffer->used + 1 ); }; // if } // __kmp_str_buf_detach
static char * sys_error( int err ) { char * message = NULL; #if KMP_OS_WINDOWS LPVOID buffer = NULL; int len; DWORD rc; rc = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language. (LPTSTR) & buffer, 0, NULL ); if ( rc > 0 ) { // Message formatted. Copy it (so we can free it later with normal free(). message = __kmp_str_format( "%s", (char *) buffer ); len = ___strip_crs( message ); // Delete carriage returns if any. // Strip trailing newlines. while ( len > 0 && message[ len - 1 ] == '\n' ) { -- len; }; // while message[ len ] = 0; } else { // FormatMessage() failed to format system error message. GetLastError() would give us // error code, which we would convert to message... this it dangerous recursion, which // cannot clarify original error, so we will not even start it. }; // if if ( buffer != NULL ) { LocalFree( buffer ); }; // if #else // Non-Windows* OS: Linux* OS or OS X* /* There are 2 incompatible versions of strerror_r: char * strerror_r( int, char *, size_t ); // GNU version int strerror_r( int, char *, size_t ); // XSI version */ #if defined(__GLIBC__) && defined(_GNU_SOURCE) // GNU version of strerror_r. char buffer[ 2048 ]; char * const err_msg = strerror_r( err, buffer, sizeof( buffer ) ); // Do not eliminate this assignment to temporary variable, otherwise compiler would // not issue warning if strerror_r() returns `int' instead of expected `char *'. message = __kmp_str_format( "%s", err_msg ); #else // OS X*, FreeBSD* etc. // XSI version of strerror_r. int size = 2048; // TODO: Add checking result of malloc(). char * buffer = (char *) KMP_INTERNAL_MALLOC( size ); int rc; if (buffer == NULL) { KMP_FATAL(MemoryAllocFailed); } rc = strerror_r( err, buffer, size ); if ( rc == -1 ) { rc = errno; // XSI version sets errno. }; // if while ( rc == ERANGE ) { // ERANGE means the buffer is too small. KMP_INTERNAL_FREE( buffer ); size *= 2; buffer = (char *) KMP_INTERNAL_MALLOC( size ); if (buffer == NULL) { KMP_FATAL(MemoryAllocFailed); } rc = strerror_r( err, buffer, size ); if ( rc == -1 ) { rc = errno; // XSI version sets errno. }; // if }; // while if ( rc == 0 ) { message = buffer; } else { // Buffer is unused. Free it. KMP_INTERNAL_FREE( buffer ); }; // if #endif #endif /* KMP_OS_WINDOWS */ if ( message == NULL ) { // TODO: I18n this message. message = __kmp_str_format( "%s", "(No system error message available)" ); }; // if return message; } // sys_error
struct private_common * kmp_threadprivate_insert( int gtid, void *pc_addr, void *data_addr, size_t pc_size ) { struct private_common *tn, **tt; struct shared_common *d_tn; /* +++++++++ START OF CRITICAL SECTION +++++++++ */ __kmp_acquire_lock( & __kmp_global_lock, gtid ); tn = (struct private_common *) __kmp_allocate( sizeof (struct private_common) ); tn->gbl_addr = pc_addr; d_tn = __kmp_find_shared_task_common( &__kmp_threadprivate_d_table, gtid, pc_addr ); /* Only the MASTER data table exists. */ if (d_tn != 0) { /* This threadprivate variable has already been seen. */ if ( d_tn->pod_init == 0 && d_tn->obj_init == 0 ) { d_tn->cmn_size = pc_size; if (d_tn->is_vec) { if (d_tn->ct.ctorv != 0) { /* Construct from scratch so no prototype exists */ d_tn->obj_init = 0; } else if (d_tn->cct.cctorv != 0) { /* Now data initialize the prototype since it was previously registered */ d_tn->obj_init = (void *) __kmp_allocate( d_tn->cmn_size ); (void) (*d_tn->cct.cctorv) (d_tn->obj_init, pc_addr, d_tn->vec_len); } else { d_tn->pod_init = __kmp_init_common_data( data_addr, d_tn->cmn_size ); } } else { if (d_tn->ct.ctor != 0) { /* Construct from scratch so no prototype exists */ d_tn->obj_init = 0; } else if (d_tn->cct.cctor != 0) { /* Now data initialize the prototype since it was previously registered */ d_tn->obj_init = (void *) __kmp_allocate( d_tn->cmn_size ); (void) (*d_tn->cct.cctor) (d_tn->obj_init, pc_addr); } else { d_tn->pod_init = __kmp_init_common_data( data_addr, d_tn->cmn_size ); } } } } else { struct shared_common **lnk_tn; d_tn = (struct shared_common *) __kmp_allocate( sizeof( struct shared_common ) ); d_tn->gbl_addr = pc_addr; d_tn->cmn_size = pc_size; d_tn->pod_init = __kmp_init_common_data( data_addr, pc_size ); /* d_tn->obj_init = 0; // AC: commented out because __kmp_allocate zeroes the memory d_tn->ct.ctor = 0; d_tn->cct.cctor = 0; d_tn->dt.dtor = 0; d_tn->is_vec = FALSE; d_tn->vec_len = 0L; */ lnk_tn = &(__kmp_threadprivate_d_table.data[ KMP_HASH(pc_addr) ]); d_tn->next = *lnk_tn; *lnk_tn = d_tn; } tn->cmn_size = d_tn->cmn_size; if ( (__kmp_foreign_tp) ? (KMP_INITIAL_GTID (gtid)) : (KMP_UBER_GTID (gtid)) ) { tn->par_addr = (void *) pc_addr; } else { tn->par_addr = (void *) __kmp_allocate( tn->cmn_size ); } __kmp_release_lock( & __kmp_global_lock, gtid ); /* +++++++++ END OF CRITICAL SECTION +++++++++ */ #ifdef USE_CHECKS_COMMON if (pc_size > d_tn->cmn_size) { KC_TRACE( 10, ( "__kmp_threadprivate_insert: THREADPRIVATE: %p (%" KMP_UINTPTR_SPEC " ,%" KMP_UINTPTR_SPEC ")\n", pc_addr, pc_size, d_tn->cmn_size ) ); KMP_FATAL( TPCommonBlocksInconsist ); } #endif /* USE_CHECKS_COMMON */ tt = &(__kmp_threads[ gtid ]->th.th_pri_common->data[ KMP_HASH(pc_addr) ]); #ifdef KMP_TASK_COMMON_DEBUG if (*tt != 0) { KC_TRACE( 10, ( "__kmp_threadprivate_insert: WARNING! thread#%d: collision on %p\n", gtid, pc_addr ) ); } #endif tn->next = *tt; *tt = tn; #ifdef KMP_TASK_COMMON_DEBUG KC_TRACE( 10, ( "__kmp_threadprivate_insert: thread#%d, inserted node %p on list\n", gtid, pc_addr ) ); dump_list( ); #endif /* Link the node into a simple list */ tn->link = __kmp_threads[ gtid ]->th.th_pri_head; __kmp_threads[ gtid ]->th.th_pri_head = tn; #ifdef BUILD_TV __kmp_tv_threadprivate_store( __kmp_threads[ gtid ], tn->gbl_addr, tn->par_addr ); #endif if( (__kmp_foreign_tp) ? (KMP_INITIAL_GTID (gtid)) : (KMP_UBER_GTID (gtid)) ) return tn; /* * if C++ object with copy constructor, use it; * else if C++ object with constructor, use it for the non-master copies only; * else use pod_init and memcpy * * C++ constructors need to be called once for each non-master thread on allocate * C++ copy constructors need to be called once for each thread on allocate */ /* * C++ object with constructors/destructors; * don't call constructors for master thread though */ if (d_tn->is_vec) { if ( d_tn->ct.ctorv != 0) { (void) (*d_tn->ct.ctorv) (tn->par_addr, d_tn->vec_len); } else if (d_tn->cct.cctorv != 0) { (void) (*d_tn->cct.cctorv) (tn->par_addr, d_tn->obj_init, d_tn->vec_len); } else if (tn->par_addr != tn->gbl_addr) { __kmp_copy_common_data( tn->par_addr, d_tn->pod_init ); } } else { if ( d_tn->ct.ctor != 0 ) { (void) (*d_tn->ct.ctor) (tn->par_addr); } else if (d_tn->cct.cctor != 0) { (void) (*d_tn->cct.cctor) (tn->par_addr, d_tn->obj_init); } else if (tn->par_addr != tn->gbl_addr) { __kmp_copy_common_data( tn->par_addr, d_tn->pod_init ); } } /* !BUILD_OPENMP_C if (tn->par_addr != tn->gbl_addr) __kmp_copy_common_data( tn->par_addr, d_tn->pod_init ); */ return tn; }