ada: Allow use of writable parameters inside function with side-effects
[official-gcc.git] / libgomp / affinity-fmt.c
blob91bc340d68a95fb1ea6a3ddad26760e52f3483da
1 /* Copyright (C) 2018-2024 Free Software Foundation, Inc.
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
4 This file is part of the GNU Offloading and Multi Processing Library
5 (libgomp).
7 Libgomp is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 #include "libgomp.h"
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #ifdef HAVE_INTTYPES_H
34 # include <inttypes.h> /* For PRIx64. */
35 #endif
36 #ifdef HAVE_UNAME
37 #include <sys/utsname.h>
38 #endif
40 ialias_redirect (omp_get_team_num)
41 ialias_redirect (omp_get_num_teams)
43 bool
44 gomp_print_string (const char *str, size_t len)
46 return fwrite (str, 1, len, stderr) != len;
49 void
50 gomp_set_affinity_format (const char *format, size_t len)
52 if (len < gomp_affinity_format_len)
53 memcpy (gomp_affinity_format_var, format, len);
54 else
56 char *p;
57 if (gomp_affinity_format_len)
58 p = gomp_realloc (gomp_affinity_format_var, len + 1);
59 else
60 p = gomp_malloc (len + 1);
61 memcpy (p, format, len);
62 gomp_affinity_format_var = p;
63 gomp_affinity_format_len = len + 1;
65 gomp_affinity_format_var[len] = '\0';
68 void
69 omp_set_affinity_format (const char *format)
71 gomp_set_affinity_format (format, strlen (format));
74 size_t
75 omp_get_affinity_format (char *buffer, size_t size)
77 size_t len = strlen (gomp_affinity_format_var);
78 if (size)
80 if (len < size)
81 memcpy (buffer, gomp_affinity_format_var, len + 1);
82 else
84 memcpy (buffer, gomp_affinity_format_var, size - 1);
85 buffer[size - 1] = '\0';
88 return len;
91 void
92 gomp_display_string (char *buffer, size_t size, size_t *ret,
93 const char *str, size_t len)
95 size_t r = *ret;
96 if (size && r < size)
98 size_t l = len;
99 if (size - r < len)
100 l = size - r;
101 memcpy (buffer + r, str, l);
103 *ret += len;
104 if (__builtin_expect (r > *ret, 0))
105 gomp_fatal ("overflow in omp_capture_affinity");
108 static void
109 gomp_display_repeat (char *buffer, size_t size, size_t *ret,
110 char c, size_t len)
112 size_t r = *ret;
113 if (size && r < size)
115 size_t l = len;
116 if (size - r < len)
117 l = size - r;
118 memset (buffer + r, c, l);
120 *ret += len;
121 if (__builtin_expect (r > *ret, 0))
122 gomp_fatal ("overflow in omp_capture_affinity");
125 static void
126 gomp_display_num (char *buffer, size_t size, size_t *ret,
127 bool zero, bool right, size_t sz, char *buf)
129 size_t l = strlen (buf);
130 if (sz == (size_t) -1 || l >= sz)
132 gomp_display_string (buffer, size, ret, buf, l);
133 return;
135 if (zero)
137 if (buf[0] == '-')
138 gomp_display_string (buffer, size, ret, buf, 1);
139 else if (buf[0] == '0' && buf[1] == 'x')
140 gomp_display_string (buffer, size, ret, buf, 2);
141 gomp_display_repeat (buffer, size, ret, '0', sz - l);
142 if (buf[0] == '-')
143 gomp_display_string (buffer, size, ret, buf + 1, l - 1);
144 else if (buf[0] == '0' && buf[1] == 'x')
145 gomp_display_string (buffer, size, ret, buf + 2, l - 2);
146 else
147 gomp_display_string (buffer, size, ret, buf, l);
149 else if (right)
151 gomp_display_repeat (buffer, size, ret, ' ', sz - l);
152 gomp_display_string (buffer, size, ret, buf, l);
154 else
156 gomp_display_string (buffer, size, ret, buf, l);
157 gomp_display_repeat (buffer, size, ret, ' ', sz - l);
161 static void
162 gomp_display_int (char *buffer, size_t size, size_t *ret,
163 bool zero, bool right, size_t sz, int num)
165 char buf[3 * sizeof (int) + 2];
166 sprintf (buf, "%d", num);
167 gomp_display_num (buffer, size, ret, zero, right, sz, buf);
170 static void
171 gomp_display_string_len (char *buffer, size_t size, size_t *ret,
172 bool right, size_t sz, char *str, size_t len)
174 if (sz == (size_t) -1 || len >= sz)
176 gomp_display_string (buffer, size, ret, str, len);
177 return;
180 if (right)
182 gomp_display_repeat (buffer, size, ret, ' ', sz - len);
183 gomp_display_string (buffer, size, ret, str, len);
185 else
187 gomp_display_string (buffer, size, ret, str, len);
188 gomp_display_repeat (buffer, size, ret, ' ', sz - len);
192 static void
193 gomp_display_hostname (char *buffer, size_t size, size_t *ret,
194 bool right, size_t sz)
196 #ifdef HAVE_GETHOSTNAME
198 char buf[256];
199 char *b = buf;
200 size_t len = 256;
203 b[len - 1] = '\0';
204 if (gethostname (b, len - 1) == 0)
206 size_t l = strlen (b);
207 if (l < len - 1)
209 gomp_display_string_len (buffer, size, ret,
210 right, sz, b, l);
211 if (b != buf)
212 free (b);
213 return;
216 if (len == 1048576)
217 break;
218 len = len * 2;
219 if (len == 512)
220 b = gomp_malloc (len);
221 else
222 b = gomp_realloc (b, len);
224 while (1);
225 if (b != buf)
226 free (b);
228 #endif
229 #ifdef HAVE_UNAME
231 struct utsname buf;
232 if (uname (&buf) == 0)
234 gomp_display_string_len (buffer, size, ret, right, sz,
235 buf.nodename, strlen (buf.nodename));
236 return;
239 #endif
240 gomp_display_string_len (buffer, size, ret, right, sz, "node", 4);
243 struct affinity_types_struct {
244 char long_str[18];
245 char long_len;
246 char short_c; };
248 static struct affinity_types_struct affinity_types[] =
250 #define AFFINITY_TYPE(l, s) \
251 { #l, sizeof (#l) - 1, s }
252 AFFINITY_TYPE (team_num, 't'),
253 AFFINITY_TYPE (num_teams, 'T'),
254 AFFINITY_TYPE (nesting_level, 'L'),
255 AFFINITY_TYPE (thread_num, 'n'),
256 AFFINITY_TYPE (num_threads, 'N'),
257 AFFINITY_TYPE (ancestor_tnum, 'a'),
258 AFFINITY_TYPE (host, 'H'),
259 AFFINITY_TYPE (process_id, 'P'),
260 AFFINITY_TYPE (native_thread_id, 'i'),
261 AFFINITY_TYPE (thread_affinity, 'A')
262 #undef AFFINITY_TYPE
265 size_t
266 gomp_display_affinity (char *buffer, size_t size,
267 const char *format, gomp_thread_handle handle,
268 struct gomp_team_state *ts, unsigned int place)
270 size_t ret = 0;
273 const char *p = strchr (format, '%');
274 bool zero = false;
275 bool right = false;
276 size_t sz = -1;
277 char c;
278 int val;
279 if (p == NULL)
280 p = strchr (format, '\0');
281 if (p != format)
282 gomp_display_string (buffer, size, &ret,
283 format, p - format);
284 if (*p == '\0')
285 break;
286 p++;
287 if (*p == '%')
289 gomp_display_string (buffer, size, &ret, "%", 1);
290 format = p + 1;
291 continue;
293 if (*p == '0')
295 zero = true;
296 p++;
297 if (*p != '.')
298 gomp_fatal ("leading zero not followed by dot in affinity format");
300 if (*p == '.')
302 right = true;
303 p++;
305 if (*p >= '1' && *p <= '9')
307 char *end;
308 sz = strtoul (p, &end, 10);
309 p = end;
311 else if (zero || right)
312 gomp_fatal ("leading zero or right justification in affinity format "
313 "requires size");
314 c = *p;
315 if (c == '{')
317 int i;
318 for (i = 0;
319 i < sizeof (affinity_types) / sizeof (affinity_types[0]); ++i)
320 if (strncmp (p + 1, affinity_types[i].long_str,
321 affinity_types[i].long_len) == 0
322 && p[affinity_types[i].long_len + 1] == '}')
324 c = affinity_types[i].short_c;
325 p += affinity_types[i].long_len + 1;
326 break;
328 if (c == '{')
330 char *q = strchr (p + 1, '}');
331 if (q)
332 gomp_fatal ("unsupported long type name '%.*s' in affinity "
333 "format", (int) (q - (p + 1)), p + 1);
334 else
335 gomp_fatal ("unterminated long type name '%s' in affinity "
336 "format", p + 1);
339 switch (c)
341 case 't':
342 val = omp_get_team_num ();
343 goto do_int;
344 case 'T':
345 val = omp_get_num_teams ();
346 goto do_int;
347 case 'L':
348 val = ts->level;
349 goto do_int;
350 case 'n':
351 val = ts->team_id;
352 goto do_int;
353 case 'N':
354 val = ts->team ? ts->team->nthreads : 1;
355 goto do_int;
356 case 'a':
357 val = ts->team ? ts->team->prev_ts.team_id : -1;
358 goto do_int;
359 case 'H':
360 gomp_display_hostname (buffer, size, &ret, right, sz);
361 break;
362 case 'P':
363 #ifdef HAVE_GETPID
364 val = getpid ();
365 #else
366 val = 0;
367 #endif
368 goto do_int;
369 case 'i':
370 #if defined(LIBGOMP_USE_PTHREADS) && defined(__GNUC__)
372 char buf[3 * (sizeof (handle) + sizeof (uintptr_t) + sizeof (int))
373 + 4];
374 /* This macro returns expr unmodified for integral or pointer
375 types and 0 for anything else (e.g. aggregates). */
376 #define gomp_nonaggregate(expr) \
377 __builtin_choose_expr (__builtin_classify_type (expr) == 1 \
378 || __builtin_classify_type (expr) == 5, expr, 0)
379 /* This macro returns expr unmodified for integral types,
380 (uintptr_t) (expr) for pointer types and 0 for anything else
381 (e.g. aggregates). */
382 #define gomp_integral(expr) \
383 __builtin_choose_expr (__builtin_classify_type (expr) == 5, \
384 (uintptr_t) gomp_nonaggregate (expr), \
385 gomp_nonaggregate (expr))
387 if (sizeof (gomp_integral (handle)) == sizeof (unsigned long))
388 sprintf (buf, "0x%lx", (unsigned long) gomp_integral (handle));
389 #if defined (HAVE_INTTYPES_H) && defined (PRIx64)
390 else if (sizeof (gomp_integral (handle)) == sizeof (uint64_t))
391 sprintf (buf, "0x%" PRIx64, (uint64_t) gomp_integral (handle));
392 #else
393 else if (sizeof (gomp_integral (handle))
394 == sizeof (unsigned long long))
395 sprintf (buf, "0x%llx",
396 (unsigned long long) gomp_integral (handle));
397 #endif
398 else
399 sprintf (buf, "0x%x", (unsigned int) gomp_integral (handle));
400 gomp_display_num (buffer, size, &ret, zero, right, sz, buf);
401 break;
403 #else
404 val = 0;
405 goto do_int;
406 #endif
407 case 'A':
408 if (sz == (size_t) -1)
409 gomp_display_affinity_place (buffer, size, &ret,
410 place - 1);
411 else if (right)
413 size_t len = 0;
414 gomp_display_affinity_place (NULL, 0, &len, place - 1);
415 if (len < sz)
416 gomp_display_repeat (buffer, size, &ret, ' ', sz - len);
417 gomp_display_affinity_place (buffer, size, &ret, place - 1);
419 else
421 size_t start = ret;
422 gomp_display_affinity_place (buffer, size, &ret, place - 1);
423 if (ret - start < sz)
424 gomp_display_repeat (buffer, size, &ret, ' ', sz - (ret - start));
426 break;
427 do_int:
428 gomp_display_int (buffer, size, &ret, zero, right, sz, val);
429 break;
430 default:
431 gomp_fatal ("unsupported type %c in affinity format", c);
433 format = p + 1;
435 while (1);
436 return ret;
439 size_t
440 omp_capture_affinity (char *buffer, size_t size, const char *format)
442 struct gomp_thread *thr = gomp_thread ();
443 size_t ret
444 = gomp_display_affinity (buffer, size,
445 format && *format
446 ? format : gomp_affinity_format_var,
447 gomp_thread_self (), &thr->ts, thr->place);
448 if (size)
450 if (ret >= size)
451 buffer[size - 1] = '\0';
452 else
453 buffer[ret] = '\0';
455 return ret;
457 ialias (omp_capture_affinity)
459 void
460 omp_display_affinity (const char *format)
462 char buf[512];
463 char *b;
464 size_t ret = ialias_call (omp_capture_affinity) (buf, sizeof buf, format);
465 if (ret < sizeof buf)
467 buf[ret] = '\n';
468 gomp_print_string (buf, ret + 1);
469 return;
471 b = gomp_malloc (ret + 1);
472 ialias_call (omp_capture_affinity) (b, ret + 1, format);
473 b[ret] = '\n';
474 gomp_print_string (b, ret + 1);
475 free (b);
478 void
479 gomp_display_affinity_thread (gomp_thread_handle handle,
480 struct gomp_team_state *ts, unsigned int place)
482 char buf[512];
483 char *b;
484 size_t ret = gomp_display_affinity (buf, sizeof buf, gomp_affinity_format_var,
485 handle, ts, place);
486 if (ret < sizeof buf)
488 buf[ret] = '\n';
489 gomp_print_string (buf, ret + 1);
490 return;
492 b = gomp_malloc (ret + 1);
493 gomp_display_affinity (b, ret + 1, gomp_affinity_format_var,
494 handle, ts, place);
495 b[ret] = '\n';
496 gomp_print_string (b, ret + 1);
497 free (b);