SURFEX v8.1
General documentation of Surfex
env.c
Go to the documentation of this file.
1 
2 /* env.c */
3 
4 /* Implement Fortran-callable ec_getenv and ec_putenv,
5  since not all environments have getenv & putenv,
6  but Unix/C library always have them */
7 
8 /* Author: Sami Saarinen, ECMWF, 15-Mar-2006 */
9 
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <signal.h>
15 #include <sys/types.h>
16 #include <sys/time.h>
17 #include <unistd.h>
18 #include <limits.h>
19 #include <errno.h>
20 #include "privpub.h"
21 
22 extern char **environ; /* Global Unix var */
23 static int numenv = 0;
24 
25 void
27 { /* Returns the number of environment variables currently active */
28  int j=0;
29  if (environ) {
30  for (; environ[j]; j++) { }
31  }
32  if (n) *n = j;
33  numenv = j; /* Not thread-safe */
34 }
35 
36 
37 void
38 ec_numenv(int *n)
39 {
40  ec_numenv_(n);
41 }
42 
43 
44 void
45 ec_overwrite_env_(int *do_overwrite)
46 {
47  if (do_overwrite) {
48  char *env = getenv("EC_OVERWRITE_ENV");
49  if (env) {
50  *do_overwrite = atoi(env);
51  }
52  else {
53  *do_overwrite = 0;
54  }
55  }
56 }
57 
58 
59 void
60 ec_overwrite_env(int *do_overwrite)
61 {
62  ec_overwrite_env_(do_overwrite);
63 }
64 
65 
66 void
67 ec_strenv_(const int *i,
68  char *value,
69  /* Hidden arguments */
70  const int valuelen)
71 { /* Returns (*i)'th environment number;
72  Note: "Fortran", not "C" range between [1..numenv] */
73  int j = (i && environ) ? (*i) : 0;
74  memset(value, ' ', valuelen);
75  if (j >= 1 && j <= numenv) {
76  char *p = environ[--j];
77  if (p) {
78  int len = strlen(p);
79  if (valuelen < len) len = valuelen;
80  memcpy(value,p,len);
81  }
82  }
83 }
84 
85 
86 void
87 ec_strenv(const int *i,
88  char *value,
89  /* Hidden arguments */
90  const int valuelen)
91 {
92  ec_strenv_(i, value, valuelen);
93 }
94 
95 
96 void
97 ec_getenv_(const char *s,
98  char *value,
99  /* Hidden arguments */
100  int slen,
101  const int valuelen)
102 {
103  char *env = NULL;
104  char *p = malloc(slen+1);
105  if (!p) {
106  fprintf(stderr,"ec_getenv_(): Unable to allocate %d bytes of memory\n", slen+1);
107  ABOR1("ec_getenv_(): Unable to allocate memory");
108  }
109  memcpy(p,s,slen);
110  p[slen]='\0';
111  memset(value, ' ', valuelen);
112  env = getenv(p);
113  if (env) {
114  int len = strlen(env);
115  if (valuelen < len) len = valuelen;
116  memcpy(value,env,len);
117  }
118  free(p);
119 }
120 
121 
122 void
123 ec_getenv(const char *s,
124  char *value,
125  /* Hidden arguments */
126  int slen,
127  const int valuelen)
128 {
129  ec_getenv_(s, value, slen, valuelen);
130 }
131 
132 
133 void
134 ec_putenv_(const char *s,
135  /* Hidden argument */
136  int slen)
137 {
138  const char *x = &s[slen-1];
139  /* strip trailing blanks first */
140  while (slen > 0 && *x == ' ') { --slen; --x; }
141  /* now go ahead */
142  if (slen > 0) {
143  char *p = malloc(slen+1);
144  if (!p) {
145  fprintf(stderr,"ec_putenv_(): Unable to allocate %d bytes of memory\n", slen+1);
146  ABOR1("ec_putenv_(): Unable to allocate memory");
147  }
148  memcpy(p,s,slen);
149  p[slen]='\0';
150  putenv(p);
151  /* Cannot free(p); , since putenv() uses this memory area for good ;-( */
152  }
153 }
154 
155 
156 void
157 ec_putenv(const char *s,
158  /* Hidden argument */
159  int slen)
160 {
161  ec_putenv_(s,slen);
162 }
163 
164 
165 void
167  /* Hidden argument */
168  int slen)
169 {
170  const char *x = &s[slen-1];
171  /* strip trailing blanks first */
172  while (slen > 0 && *x == ' ') { --slen; --x; }
173  /* now go ahead */
174  if (slen > 0) {
175  char *eq = NULL;
176  char *p = malloc(slen+1);
177  if (!p) {
178  fprintf(stderr,"ec_putenv_nooverwrite_(): Unable to allocate %d bytes of memory\n", slen+1);
179  ABOR1("ec_putenv_nooverwrite_(): Unable to allocate memory");
180  }
181  memcpy(p,s,slen);
182  p[slen]='\0';
183  eq = strchr(p,'=');
184  if (eq) {
185  char *env = NULL;
186  *eq = '\0';
187  env = getenv(p);
188  if (env) {
189  /* Already found ==> do not overwrite */
190  free(p);
191  return;
192  }
193  else {
194  /* Reset '=' back and continue with putenv() */
195  *eq = '=';
196  }
197  }
198  putenv(p);
199  /* Cannot free(p); , since putenv() uses this memory area for good ;-( */
200  }
201 }
202 
203 
204 void
205 ec_putenv_nooverwrite(const char *s,
206  /* Hidden argument */
207  int slen)
208 {
209  ec_putenv_nooverwrite_(s,slen);
210 }
211 
212 
213 unsigned int
214 ec_sleep_(const int *nsec)
215 {
216  return sleep((nsec && *nsec > 0) ? *nsec : 0);
217 }
218 
219 
220 unsigned int
221 ec_sleep(const int *nsec)
222 {
223  return ec_sleep_(nsec);
224 }
225 
226 
227 /* Microsecond-sleep, by S.Saarinen, 25-jan-2008 */
228 
229 void /* Global, C-callable, too */
230 ec_microsleep(int usecs) {
231  if (usecs > 0) {
232  struct timeval t;
233  t.tv_sec = usecs/1000000;
234  t.tv_usec = usecs%1000000;
235  (void) select(0, NULL, NULL, NULL, &t);
236  }
237 }
238 
239 
240 void
241 ec_usleep_(const int *usecs)
242 {
243  if (usecs && *usecs > 0) ec_microsleep(*usecs);
244 }
245 
246 
247 void
248 ec_usleep(const int *usecs)
249 {
250  ec_usleep_(usecs);
251 }
252 
253 /* ec_gethostname, by S.Saarinen, 30-sep-2016 */
254 
255 #ifndef DARWIN
256 
257 void ec_gethostname_(char a[],
258  /* Hidden argument */
259  int alen)
260 {
261  char s[HOST_NAME_MAX];
262  memset(a,' ',alen);
263  if (gethostname(s,sizeof(s)) == 0) {
264  int len = strlen(s);
265  if (len > alen) len = alen;
266  memcpy(a,s,len);
267  }
268 }
269 
270 void ec_gethostname(char a[],
271  /* Hidden argument */
272  int alen)
273 {
274  ec_gethostname_(a,alen);
275 }
276 
277 #endif
278 
279 #if defined(__GNUC__)
280 
281 /* pthread_attr_init() interception to reset guard region size
282  between thread stacks, by S.Saarinen, 30-sep-2016 */
283 
284 #include <pthread.h>
285 #include <dlfcn.h>
286 #include <sys/types.h>
287 #include <sys/syscall.h>
288 
289 #if defined(RTLD_NEXT)
290 #define PTR_LIBC RTLD_NEXT
291 #else
292 #define PTR_LIBC ((void*) -1L)
293 #endif
294 
295 #ifndef SYS_gettid
296 #define SYS_gettid __NR_gettid
297 #endif
298 
299 static pid_t gettid() {
300  pid_t tid = syscall(SYS_gettid);
301  return tid;
302 }
303 
304 static int GetMe()
305 {
306  int me = -1; /* MPI task id >= 0 && <= NPES - 1 */
307  /* Trying to figure out MPI task id since are potentially doing this *before* MPI_Init*() */
308  char *env_procid = getenv("ALPS_APP_PE");
309  if (!env_procid) env_procid = getenv("EC_FARM_ID");
310  if (!env_procid) env_procid = getenv("PMI_RANK");
311  if (!env_procid) env_procid = getenv("OMPI_COMM_WORLD_RANK");
312  if (env_procid) me = atoi(env_procid);
313  return me;
314 }
315 
316 static int (*ptr_pthread_attr_init)(pthread_attr_t *attr) = NULL;
317 int pthread_attr_init(pthread_attr_t *attr)
318 {
319  int rc;
320  static int done = 0;
321  FILE *fp = NULL;
322  int me = GetMe();
323  pid_t pid = getpid();
324  pid_t tid = gettid();
325  int master = (pid == tid) ? 1 : 0;
326  if (!ptr_pthread_attr_init) {
327  ptr_pthread_attr_init = (int (*)(pthread_attr_t *a))dlsym(PTR_LIBC, "pthread_attr_init");
328  if (!ptr_pthread_attr_init) {
329  fprintf(stderr,"***Error: Dynamic linking to pthread_attr_init() failed : errno = %d\n",errno);
330  abort();
331  }
332  /* We intend to output only from MPI-task 0, master thread */
333  if (!done && me == 0 && master) fp = stderr;
334  done = 1;
335  }
336  rc = ptr_pthread_attr_init(attr);
337  {
338  char *env_gs = getenv("THREAD_GUARDSIZE");
339  if (env_gs) {
340  int pgsize = getpagesize();
341  size_t guardsize = atoll(env_gs);
342  if (strchr(env_gs,'G')) guardsize *= 1073741824; /* hence, in GiB */
343  else if (strchr(env_gs,'M')) guardsize *= 1048576; /* hence, in MiB */
344  else if (strchr(env_gs,'K')) guardsize *= 1024; /* hence, in KiB */
345  guardsize = RNDUP(guardsize,pgsize);
346  if (fp) fprintf(fp,
347  "[%s@%s:%d] [pid=%ld:tid=%ld]: Requesting guard region size between thread stacks : %lld bytes (%s PAGESIZE = %d)\n",
348  __FUNCTION__,__FILE__,__LINE__,
349  (long int)pid,(long int)tid,
350  (long long int)guardsize,
351  (guardsize > pgsize) ? ">" : "<=",
352  pgsize);
353  if (guardsize > pgsize) { /* Now we do bother */
354  char *env_omp = getenv("OMP_STACKSIZE");
355  size_t omp_stacksize = env_omp ? atoll(env_omp) : 0;
356  size_t stacksize = 0;
357 #ifdef SFX_OMP
358  int iret = pthread_attr_getstacksize(attr,&stacksize);
359 #else
360  int iret = 0;
361 #endif
362  if (env_omp) {
363  if (strchr(env_omp,'G')) omp_stacksize *= 1073741824; /* hence, in GiB */
364  else if (strchr(env_omp,'M')) omp_stacksize *= 1048576; /* hence, in MiB */
365  else if (strchr(env_omp,'K')) omp_stacksize *= 1024; /* hence, in KiB */
366  }
367  if (fp) fprintf(fp,
368  "[%s@%s:%d] [pid=%ld:tid=%ld]: Stack size(s) : %lld bytes (def), %lld bytes (OMP) : [iret=%d]\n",
369  __FUNCTION__,__FILE__,__LINE__,
370  (long int)pid,(long int)tid,
371  (long long int)stacksize,
372  (long long int)omp_stacksize,
373  iret);
374  if (iret == 0 && omp_stacksize > guardsize) {
375 #ifdef SFX_OMP
376  iret = pthread_attr_setguardsize(attr,guardsize);
377  (void) pthread_attr_getguardsize(attr,&guardsize);
378 #endif
379  if (fp) fprintf(fp,
380  "[%s@%s:%d] [pid=%ld:tid=%ld]: Guard region size now : %lld bytes : [iret=%d]\n",
381  __FUNCTION__,__FILE__,__LINE__,
382  (long int)pid,(long int)tid,
383  (long long int)guardsize,iret);
384  }
385  }
386  }
387  }
388  if (fp) fflush(fp);
389  return rc;
390 }
391 
392 #if 0
393 /* Opting out for now */
394 static void MemInfoBeforeMain() __attribute__((constructor));
395 static void MemInfoBeforeMain()
396 {
397  static int done = 0;
398  int me = GetMe();
399  if (!done && me == 0) {
400  extern void meminfo_(const int *, const int *);
401  const int kout = 0;
402  const int kstep = -1;
403  pid_t pid = getpid();
404  pid_t tid = gettid();
405  int master = (pid == tid) ? 1 : 0;
406  if (me == 0 && master) meminfo_(&kout, &kstep); /* utilities/ec_cray_meminfo.F90 */
407  done = 1;
408  }
409 }
410 #endif
411 
412 #endif /* defined(__GNUC__) */
void ec_microsleep(int usecs)
Definition: env.c:230
static int GetMe()
Definition: env.c:304
void ec_gethostname_(char a[], int alen)
Definition: env.c:257
void ec_usleep_(const int *usecs)
Definition: env.c:241
void ec_strenv(const int *i, char *value, const int valuelen)
Definition: env.c:87
ERROR in a
Definition: ecsort_shared.h:90
void ec_putenv(const char *s, int slen)
Definition: env.c:157
static void MemInfoBeforeMain()
Definition: env.c:394
void ec_getenv(const char *s, char *value, int slen, const int valuelen)
Definition: env.c:123
void ec_gethostname(char a[], int alen)
Definition: env.c:270
integer(kind=jpim) iret
Definition: distio_mix.F90:26
void ec_putenv_nooverwrite_(const char *s, int slen)
Definition: env.c:166
FILE * fp
Definition: opfla_perfmon.c:24
void ec_putenv_(const char *s, int slen)
Definition: env.c:134
char ** environ
unsigned int ec_sleep(const int *nsec)
Definition: env.c:221
void ec_usleep(const int *usecs)
Definition: env.c:248
ERROR in n
Definition: ecsort_shared.h:90
void ec_overwrite_env(int *do_overwrite)
Definition: env.c:60
void ec_overwrite_env_(int *do_overwrite)
Definition: env.c:45
int pthread_attr_init(pthread_attr_t *attr)
Definition: env.c:317
void ec_numenv_(int *n)
Definition: env.c:26
static pid_t gettid()
Definition: env.c:299
void __attribute__((constructor))
Definition: memory_hook.c:50
void ec_numenv(int *n)
Definition: env.c:38
unsigned int ec_sleep_(const int *nsec)
Definition: env.c:214
static int(* ptr_pthread_attr_init)(pthread_attr_t *attr)
Definition: env.c:316
void ec_strenv_(const int *i, char *value, const int valuelen)
Definition: env.c:67
void ec_getenv_(const char *s, char *value, int slen, const int valuelen)
Definition: env.c:97
pid_t pid
Definition: opfla_perfmon.c:22
void ec_putenv_nooverwrite(const char *s, int slen)
Definition: env.c:205
static int numenv
Definition: env.c:23