Hi! While the standard talks about list form of nthreads-var everywhere, given that omp_set_num_threads only affects the first element of the list, only the first element is also used everywhere but during parallel creation of new implicit tasks, I think this patch is equivalent to it.
Regtested on x86_64-linux, committed to gomp-3_1-branch. 2011-03-07 Jakub Jelinek <ja...@redhat.com> * libgomp.h (gomp_nthreads_var_list, gomp_nthreads_var_list_len): New externs. * env.c (gomp_nthreads_var_list, gomp_nthreads_var_list_len): New variables. (parse_unsigned_long_list): New function. (initialize_env): Use it for OMP_NUM_THREADS. * team.c (gomp_team_start): Override new task's nthreads_var icv if list form OMP_NUM_THREADS has been used and it has value for the new nesting level. --- libgomp/libgomp.h.jj 2011-02-24 14:11:10.000000000 +0100 +++ libgomp/libgomp.h 2011-03-07 15:57:44.000000000 +0100 @@ -226,6 +226,7 @@ extern gomp_mutex_t gomp_remaining_threa extern unsigned long gomp_max_active_levels_var; extern unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var; extern unsigned long gomp_available_cpus, gomp_managed_threads; +extern unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len; enum gomp_task_kind { --- libgomp/env.c.jj 2011-02-24 14:11:10.000000000 +0100 +++ libgomp/env.c 2011-03-07 16:14:03.000000000 +0100 @@ -67,6 +67,7 @@ gomp_mutex_t gomp_remaining_threads_lock #endif unsigned long gomp_available_cpus = 1, gomp_managed_threads = 1; unsigned long long gomp_spin_count_var, gomp_throttled_spin_count_var; +unsigned long *gomp_nthreads_var_list, gomp_nthreads_var_list_len; /* Parse the OMP_SCHEDULE environment variable. */ @@ -178,6 +179,95 @@ parse_unsigned_long (const char *name, u return false; } +/* Parse an unsigned long list environment variable. Return true if one was + present and it was successfully parsed. */ + +static bool +parse_unsigned_long_list (const char *name, unsigned long *p1stvalue, + unsigned long **pvalues, + unsigned long *pnvalues) +{ + char *env, *end; + unsigned long value, *values = NULL; + + env = getenv (name); + if (env == NULL) + return false; + + while (isspace ((unsigned char) *env)) + ++env; + if (*env == '\0') + goto invalid; + + errno = 0; + value = strtoul (env, &end, 10); + if (errno || (long) value <= 0) + goto invalid; + + while (isspace ((unsigned char) *end)) + ++end; + if (*end != '\0') + { + if (*end == ',') + { + unsigned long nvalues = 0, nalloced = 0; + + do + { + env = end + 1; + if (nvalues == nalloced) + { + unsigned long *n; + nalloced = nalloced ? nalloced * 2 : 16; + n = realloc (values, nalloced * sizeof (unsigned long)); + if (n == NULL) + { + free (values); + gomp_error ("Out of memory while trying to parse" + " environment variable %s", name); + return false; + } + values = n; + if (nvalues == 0) + values[nvalues++] = value; + } + + while (isspace ((unsigned char) *env)) + ++env; + if (*env == '\0') + goto invalid; + + errno = 0; + value = strtoul (env, &end, 10); + if (errno || (long) value <= 0) + goto invalid; + + values[nvalues++] = value; + while (isspace ((unsigned char) *end)) + ++end; + if (*end == '\0') + break; + if (*end != ',') + goto invalid; + } + while (1); + *p1stvalue = values[0]; + *pvalues = values; + *pnvalues = nvalues; + return true; + } + goto invalid; + } + + *p1stvalue = value; + return true; + + invalid: + free (values); + gomp_error ("Invalid value for environment variable %s", name); + return false; +} + /* Parse the OMP_STACKSIZE environment varible. Return true if one was present and it was successfully parsed. */ @@ -492,8 +582,10 @@ initialize_env (void) #endif gomp_init_num_threads (); gomp_available_cpus = gomp_global_icv.nthreads_var; - if (!parse_unsigned_long ("OMP_NUM_THREADS", &gomp_global_icv.nthreads_var, - false)) + if (!parse_unsigned_long_list ("OMP_NUM_THREADS", + &gomp_global_icv.nthreads_var, + &gomp_nthreads_var_list, + &gomp_nthreads_var_list_len)) gomp_global_icv.nthreads_var = gomp_available_cpus; if (parse_affinity ()) gomp_init_affinity (); --- libgomp/team.c.jj 2011-02-24 14:11:10.000000000 +0100 +++ libgomp/team.c 2011-03-07 16:13:23.000000000 +0100 @@ -260,6 +260,7 @@ gomp_team_start (void (*fn) (void *), vo struct gomp_thread_pool *pool; unsigned i, n, old_threads_used = 0; pthread_attr_t thread_attr, *attr; + unsigned long nthreads_var; thr = gomp_thread (); nested = thr->ts.team != NULL; @@ -289,7 +290,12 @@ gomp_team_start (void (*fn) (void *), vo #endif thr->ts.static_trip = 0; thr->task = &team->implicit_task[0]; + nthreads_var = icv->nthreads_var; + if (__builtin_expect (gomp_nthreads_var_list != NULL, 0) + && thr->ts.level < gomp_nthreads_var_list_len) + nthreads_var = gomp_nthreads_var_list[thr->ts.level]; gomp_init_task (thr->task, task, icv); + team->implicit_task[0].icv.nthreads_var = nthreads_var; if (nthreads == 1) return; @@ -342,6 +348,7 @@ gomp_team_start (void (*fn) (void *), vo nthr->ts.static_trip = 0; nthr->task = &team->implicit_task[i]; gomp_init_task (nthr->task, task, icv); + team->implicit_task[i].icv.nthreads_var = nthreads_var; nthr->fn = fn; nthr->data = data; team->ordered_release[i] = &nthr->release; @@ -413,6 +420,7 @@ gomp_team_start (void (*fn) (void *), vo start_data->ts.static_trip = 0; start_data->task = &team->implicit_task[i]; gomp_init_task (start_data->task, task, icv); + team->implicit_task[i].icv.nthreads_var = nthreads_var; start_data->thread_pool = pool; start_data->nested = nested; Jakub