libgfortran: Fix up the autoreconf warnings
[official-gcc.git] / libgomp / oacc-init.c
blob17ddf137fcc4434d7d7738ca657a9fcd7465a3d7
1 /* OpenACC Runtime initialization routines
3 Copyright (C) 2013-2024 Free Software Foundation, Inc.
5 Contributed by Mentor Embedded.
7 This file is part of the GNU Offloading and Multi Processing Library
8 (libgomp).
10 Libgomp is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3, or (at your option)
13 any later version.
15 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 more details.
20 Under Section 7 of GPL version 3, you are granted additional
21 permissions described in the GCC Runtime Library Exception, version
22 3.1, as published by the Free Software Foundation.
24 You should have received a copy of the GNU General Public License and
25 a copy of the GCC Runtime Library Exception along with this program;
26 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
27 <http://www.gnu.org/licenses/>. */
29 #include "libgomp.h"
30 #include "oacc-int.h"
31 #include "openacc.h"
32 #include <assert.h>
33 #include <stdlib.h>
34 #include <strings.h>
35 #include <stdbool.h>
36 #include <string.h>
38 /* This lock is used to protect access to cached_base_dev, dispatchers and
39 the (abstract) initialisation state of attached offloading devices. */
41 static gomp_mutex_t acc_device_lock;
43 static gomp_mutex_t acc_init_state_lock;
44 static enum { uninitialized, initializing, initialized } acc_init_state
45 = uninitialized;
46 static pthread_t acc_init_thread;
48 /* A cached version of the dispatcher for the global "current" accelerator type,
49 e.g. used as the default when creating new host threads. This is the
50 device-type equivalent of goacc_device_num (which specifies which device to
51 use out of potentially several of the same type). If there are several
52 devices of a given type, this points at the first one. */
54 static struct gomp_device_descr *cached_base_dev = NULL;
56 #if defined HAVE_TLS || defined USE_EMUTLS
57 __thread struct goacc_thread *goacc_tls_data;
58 #else
59 pthread_key_t goacc_tls_key;
60 #endif
61 static pthread_key_t goacc_cleanup_key;
63 static struct goacc_thread *goacc_threads;
64 static gomp_mutex_t goacc_thread_lock;
66 /* An array of dispatchers for device types, indexed by the type. This array
67 only references "base" devices, and other instances of the same type are
68 found by simply indexing from each such device (which are stored linearly,
69 grouped by device in target.c:devices). */
70 static struct gomp_device_descr *dispatchers[_ACC_device_hwm] = { 0 };
72 attribute_hidden void
73 goacc_register (struct gomp_device_descr *disp)
75 /* Only register the 0th device here. */
76 if (disp->target_id != 0)
77 return;
79 gomp_mutex_lock (&acc_device_lock);
81 assert (acc_device_type (disp->type) != acc_device_none
82 && acc_device_type (disp->type) != acc_device_default
83 && acc_device_type (disp->type) != acc_device_not_host);
84 assert (!dispatchers[disp->type]);
85 dispatchers[disp->type] = disp;
87 gomp_mutex_unlock (&acc_device_lock);
90 static bool
91 known_device_type_p (acc_device_t d)
93 return d >= 0 && d < _ACC_device_hwm;
96 static void
97 unknown_device_type_error (acc_device_t invalid_type)
99 gomp_fatal ("unknown device type %u", invalid_type);
102 /* OpenACC names some things a little differently. */
104 static const char *
105 get_openacc_name (const char *name)
107 if (strcmp (name, "gcn") == 0)
108 return "radeon";
109 else if (strcmp (name, "nvptx") == 0)
110 return "nvidia";
111 else
112 return name;
115 static const char *
116 name_of_acc_device_t (enum acc_device_t type)
118 switch (type)
120 case acc_device_none: return "none";
121 case acc_device_default: return "default";
122 case acc_device_host: return "host";
123 case acc_device_not_host: return "not_host";
124 case acc_device_nvidia: return "nvidia";
125 case acc_device_radeon: return "radeon";
126 default: unknown_device_type_error (type);
128 __builtin_unreachable ();
131 /* ACC_DEVICE_LOCK must be held before calling this function. If FAIL_IS_ERROR
132 is true, this function raises an error if there are no devices of type D,
133 otherwise it returns NULL in that case. */
135 static struct gomp_device_descr *
136 resolve_device (acc_device_t d, bool fail_is_error)
138 acc_device_t d_arg = d;
140 switch (d)
142 case acc_device_default:
144 if (goacc_device_type)
146 /* Lookup the named device. */
147 while (known_device_type_p (++d))
148 if (dispatchers[d]
149 && !strcasecmp (goacc_device_type,
150 get_openacc_name (dispatchers[d]->name))
151 && dispatchers[d]->get_num_devices_func (0) > 0)
152 goto found;
154 if (fail_is_error)
156 gomp_mutex_unlock (&acc_device_lock);
157 gomp_fatal ("device type %s not supported", goacc_device_type);
159 else
160 return NULL;
163 /* No default device specified, so start scanning for any non-host
164 device that is available. */
165 d = acc_device_not_host;
167 /* FALLTHROUGH */
169 case acc_device_not_host:
170 /* Find the first available device after acc_device_not_host. */
171 while (known_device_type_p (++d))
172 if (dispatchers[d] && dispatchers[d]->get_num_devices_func (0) > 0)
173 goto found;
174 if (d_arg == acc_device_default)
176 d = acc_device_host;
177 goto found;
179 if (fail_is_error)
181 gomp_mutex_unlock (&acc_device_lock);
182 gomp_fatal ("no device found");
184 else
185 return NULL;
186 break;
188 case acc_device_host:
189 break;
191 default:
192 if (!known_device_type_p (d))
194 if (fail_is_error)
195 goto unsupported_device;
196 else
197 return NULL;
199 break;
201 found:
203 assert (d != acc_device_none
204 && d != acc_device_default
205 && d != acc_device_not_host);
207 if (dispatchers[d] == NULL && fail_is_error)
209 unsupported_device:
210 gomp_mutex_unlock (&acc_device_lock);
211 gomp_fatal ("device type %s not supported", name_of_acc_device_t (d));
214 return dispatchers[d];
217 /* Emit a suitable error if no device of a particular type is available, or
218 the given device number is out-of-range. */
219 static void
220 acc_dev_num_out_of_range (acc_device_t d, int ord, int ndevs)
222 if (ndevs == 0)
223 gomp_fatal ("no devices of type %s available", name_of_acc_device_t (d));
224 else
225 gomp_fatal ("device %u out of range", ord);
228 /* This is called when plugins have been initialized, and serves to call
229 (indirectly) the target's device_init hook. Calling multiple times without
230 an intervening acc_shutdown_1 call is an error. ACC_DEVICE_LOCK must be
231 held before calling this function. */
233 static struct gomp_device_descr *
234 acc_init_1 (acc_device_t d, acc_construct_t parent_construct, int implicit)
236 gomp_mutex_lock (&acc_init_state_lock);
237 acc_init_state = initializing;
238 acc_init_thread = pthread_self ();
239 gomp_mutex_unlock (&acc_init_state_lock);
241 bool check_not_nested_p;
242 if (implicit)
244 /* In the implicit case, there should (TODO: must?) already be something
245 have been set up for an outer construct. */
246 check_not_nested_p = false;
248 else
250 check_not_nested_p = true;
251 /* TODO: should we set 'thr->prof_info' etc. in this case ('acc_init')?
252 The problem is, that we don't have 'thr' yet? (So,
253 'check_not_nested_p = true' also is pointless actually.) */
255 bool profiling_p = GOACC_PROFILING_DISPATCH_P (check_not_nested_p);
257 acc_prof_info prof_info;
258 if (profiling_p)
260 prof_info.event_type = acc_ev_device_init_start;
261 prof_info.valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
262 prof_info.version = _ACC_PROF_INFO_VERSION;
263 prof_info.device_type = d;
264 prof_info.device_number = goacc_device_num;
265 prof_info.thread_id = -1;
266 prof_info.async = acc_async_sync;
267 prof_info.async_queue = prof_info.async;
268 prof_info.src_file = NULL;
269 prof_info.func_name = NULL;
270 prof_info.line_no = -1;
271 prof_info.end_line_no = -1;
272 prof_info.func_line_no = -1;
273 prof_info.func_end_line_no = -1;
275 acc_event_info device_init_event_info;
276 if (profiling_p)
278 device_init_event_info.other_event.event_type = prof_info.event_type;
279 device_init_event_info.other_event.valid_bytes
280 = _ACC_OTHER_EVENT_INFO_VALID_BYTES;
281 device_init_event_info.other_event.parent_construct = parent_construct;
282 device_init_event_info.other_event.implicit = implicit;
283 device_init_event_info.other_event.tool_info = NULL;
285 acc_api_info api_info;
286 if (profiling_p)
288 api_info.device_api = acc_device_api_none;
289 api_info.valid_bytes = _ACC_API_INFO_VALID_BYTES;
290 api_info.device_type = prof_info.device_type;
291 api_info.vendor = -1;
292 api_info.device_handle = NULL;
293 api_info.context_handle = NULL;
294 api_info.async_handle = NULL;
297 if (profiling_p)
298 goacc_profiling_dispatch (&prof_info, &device_init_event_info, &api_info);
300 struct gomp_device_descr *base_dev, *acc_dev;
301 int ndevs;
303 base_dev = resolve_device (d, true);
305 ndevs = base_dev->get_num_devices_func (0);
307 if (ndevs <= 0 || goacc_device_num >= ndevs)
308 acc_dev_num_out_of_range (d, goacc_device_num, ndevs);
310 acc_dev = &base_dev[goacc_device_num];
312 gomp_mutex_lock (&acc_dev->lock);
313 if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
315 gomp_mutex_unlock (&acc_dev->lock);
316 gomp_fatal ("device already active");
319 gomp_init_device (acc_dev);
320 gomp_mutex_unlock (&acc_dev->lock);
322 if (profiling_p)
324 prof_info.event_type = acc_ev_device_init_end;
325 device_init_event_info.other_event.event_type = prof_info.event_type;
326 goacc_profiling_dispatch (&prof_info, &device_init_event_info,
327 &api_info);
330 /* We're setting 'initialized' *after* 'goacc_profiling_dispatch', so that a
331 nested 'acc_get_device_type' called from a profiling callback still sees
332 'initializing', so that we don't deadlock when it then again tries to lock
333 'goacc_prof_lock'. See also the discussion in 'acc_get_device_type'. */
334 gomp_mutex_lock (&acc_init_state_lock);
335 acc_init_state = initialized;
336 gomp_mutex_unlock (&acc_init_state_lock);
338 return base_dev;
341 /* ACC_DEVICE_LOCK must be held before calling this function. */
343 static void
344 acc_shutdown_1 (acc_device_t d)
346 struct gomp_device_descr *base_dev;
347 struct goacc_thread *walk;
348 int ndevs, i;
349 bool devices_active = false;
351 /* Get the base device for this device type. */
352 base_dev = resolve_device (d, true);
354 ndevs = base_dev->get_num_devices_func (0);
356 /* Unload all the devices of this type that have been opened. */
357 for (i = 0; i < ndevs; i++)
359 struct gomp_device_descr *acc_dev = &base_dev[i];
361 gomp_mutex_lock (&acc_dev->lock);
362 gomp_unload_device (acc_dev);
363 gomp_mutex_unlock (&acc_dev->lock);
366 gomp_mutex_lock (&goacc_thread_lock);
368 /* Free target-specific TLS data and close all devices. */
369 for (walk = goacc_threads; walk != NULL; walk = walk->next)
371 if (walk->target_tls)
372 base_dev->openacc.destroy_thread_data_func (walk->target_tls);
374 walk->target_tls = NULL;
376 /* This would mean the user is shutting down OpenACC in the middle of an
377 "acc data" pragma. Likely not intentional. */
378 if (walk->mapped_data)
380 gomp_mutex_unlock (&goacc_thread_lock);
381 gomp_fatal ("shutdown in 'acc data' region");
384 /* Similarly, if this happens then user code has done something weird. */
385 if (walk->saved_bound_dev)
387 gomp_mutex_unlock (&goacc_thread_lock);
388 gomp_fatal ("shutdown during host fallback");
391 if (walk->dev)
393 gomp_mutex_lock (&walk->dev->lock);
395 while (walk->dev->mem_map.root)
397 splay_tree_key k = &walk->dev->mem_map.root->key;
398 if (k->aux)
399 k->aux->link_key = NULL;
400 gomp_remove_var (walk->dev, k);
403 gomp_mutex_unlock (&walk->dev->lock);
405 walk->dev = NULL;
406 walk->base_dev = NULL;
410 gomp_mutex_unlock (&goacc_thread_lock);
412 /* Close all the devices of this type that have been opened. */
413 bool ret = true;
414 for (i = 0; i < ndevs; i++)
416 struct gomp_device_descr *acc_dev = &base_dev[i];
417 gomp_mutex_lock (&acc_dev->lock);
418 if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
420 devices_active = true;
421 ret &= gomp_fini_device (acc_dev);
422 acc_dev->state = GOMP_DEVICE_UNINITIALIZED;
424 gomp_mutex_unlock (&acc_dev->lock);
427 if (!ret)
428 gomp_fatal ("device finalization failed");
430 if (!devices_active)
431 gomp_fatal ("no device initialized");
434 static struct goacc_thread *
435 goacc_new_thread (void)
437 struct goacc_thread *thr = gomp_malloc (sizeof (struct goacc_thread));
439 #if defined HAVE_TLS || defined USE_EMUTLS
440 goacc_tls_data = thr;
441 #else
442 pthread_setspecific (goacc_tls_key, thr);
443 #endif
445 pthread_setspecific (goacc_cleanup_key, thr);
447 gomp_mutex_lock (&goacc_thread_lock);
448 thr->next = goacc_threads;
449 goacc_threads = thr;
450 gomp_mutex_unlock (&goacc_thread_lock);
452 return thr;
455 static void
456 goacc_destroy_thread (void *data)
458 struct goacc_thread *thr = data, *walk, *prev;
460 gomp_mutex_lock (&goacc_thread_lock);
462 if (thr)
464 struct gomp_device_descr *acc_dev = thr->dev;
466 if (acc_dev && thr->target_tls)
468 acc_dev->openacc.destroy_thread_data_func (thr->target_tls);
469 thr->target_tls = NULL;
472 assert (!thr->mapped_data);
474 /* Remove from thread list. */
475 for (prev = NULL, walk = goacc_threads; walk;
476 prev = walk, walk = walk->next)
477 if (walk == thr)
479 if (prev == NULL)
480 goacc_threads = walk->next;
481 else
482 prev->next = walk->next;
484 free (thr);
486 break;
489 assert (walk);
492 gomp_mutex_unlock (&goacc_thread_lock);
495 /* Use the ORD'th device instance for the current host thread (or -1 for the
496 current global default). The device (and the runtime) must be initialised
497 before calling this function. */
499 void
500 goacc_attach_host_thread_to_device (int ord)
502 struct goacc_thread *thr = goacc_thread ();
503 struct gomp_device_descr *acc_dev = NULL, *base_dev = NULL;
504 int num_devices;
506 if (thr && thr->dev && (thr->dev->target_id == ord || ord < 0))
507 return;
509 if (ord < 0)
510 ord = goacc_device_num;
512 /* Decide which type of device to use. If the current thread has a device
513 type already (e.g. set by acc_set_device_type), use that, else use the
514 global default. */
515 if (thr && thr->base_dev)
516 base_dev = thr->base_dev;
517 else
519 assert (cached_base_dev);
520 base_dev = cached_base_dev;
523 num_devices = base_dev->get_num_devices_func (0);
524 if (num_devices <= 0 || ord >= num_devices)
525 acc_dev_num_out_of_range (acc_device_type (base_dev->type), ord,
526 num_devices);
528 if (!thr)
529 thr = goacc_new_thread ();
531 thr->base_dev = base_dev;
532 thr->dev = acc_dev = &base_dev[ord];
533 thr->saved_bound_dev = NULL;
534 thr->mapped_data = NULL;
535 thr->prof_info = NULL;
536 thr->api_info = NULL;
537 /* Initially, all callbacks for all events are enabled. */
538 thr->prof_callbacks_enabled = true;
540 thr->target_tls
541 = acc_dev->openacc.create_thread_data_func (ord);
544 /* OpenACC 2.0a (3.2.12, 3.2.13) doesn't specify whether the serialization of
545 init/shutdown is per-process or per-thread. We choose per-process. */
547 void
548 acc_init (acc_device_t d)
550 if (!known_device_type_p (d))
551 unknown_device_type_error (d);
553 gomp_init_targets_once ();
555 gomp_mutex_lock (&acc_device_lock);
556 cached_base_dev = acc_init_1 (d, acc_construct_runtime_api, 0);
557 gomp_mutex_unlock (&acc_device_lock);
559 goacc_attach_host_thread_to_device (-1);
562 ialias (acc_init)
564 void
565 acc_shutdown (acc_device_t d)
567 if (!known_device_type_p (d))
568 unknown_device_type_error (d);
570 gomp_init_targets_once ();
572 gomp_mutex_lock (&acc_device_lock);
574 acc_shutdown_1 (d);
576 gomp_mutex_unlock (&acc_device_lock);
579 ialias (acc_shutdown)
582 acc_get_num_devices (acc_device_t d)
584 if (!known_device_type_p (d))
585 unknown_device_type_error (d);
587 int n = 0;
588 struct gomp_device_descr *acc_dev;
590 if (d == acc_device_none)
591 return 0;
593 gomp_init_targets_once ();
595 gomp_mutex_lock (&acc_device_lock);
596 acc_dev = resolve_device (d, false);
597 gomp_mutex_unlock (&acc_device_lock);
599 if (!acc_dev)
600 return 0;
602 n = acc_dev->get_num_devices_func (0);
603 if (n < 0)
604 n = 0;
606 return n;
609 ialias (acc_get_num_devices)
611 /* Set the device type for the current thread only (using the current global
612 default device number), initialising that device if necessary. Also set the
613 default device type for new threads to D. */
615 void
616 acc_set_device_type (acc_device_t d)
618 if (!known_device_type_p (d))
619 unknown_device_type_error (d);
621 struct gomp_device_descr *base_dev, *acc_dev;
622 struct goacc_thread *thr = goacc_thread ();
624 acc_prof_info prof_info;
625 acc_api_info api_info;
626 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
627 if (profiling_p)
628 prof_info.device_type = d;
630 gomp_init_targets_once ();
632 gomp_mutex_lock (&acc_device_lock);
634 cached_base_dev = base_dev = resolve_device (d, true);
635 acc_dev = &base_dev[goacc_device_num];
637 gomp_mutex_lock (&acc_dev->lock);
638 if (acc_dev->state == GOMP_DEVICE_UNINITIALIZED)
639 gomp_init_device (acc_dev);
640 gomp_mutex_unlock (&acc_dev->lock);
642 gomp_mutex_unlock (&acc_device_lock);
644 /* We're changing device type: invalidate the current thread's dev and
645 base_dev pointers. */
646 if (thr && thr->base_dev != base_dev)
648 thr->base_dev = thr->dev = NULL;
649 if (thr->mapped_data)
650 gomp_fatal ("acc_set_device_type in 'acc data' region");
653 goacc_attach_host_thread_to_device (-1);
655 if (profiling_p)
657 thr->prof_info = NULL;
658 thr->api_info = NULL;
662 ialias (acc_set_device_type)
664 static bool
665 self_initializing_p (void)
667 bool res;
668 gomp_mutex_lock (&acc_init_state_lock);
669 res = (acc_init_state == initializing
670 && pthread_equal (acc_init_thread, pthread_self ()));
671 gomp_mutex_unlock (&acc_init_state_lock);
672 return res;
675 acc_device_t
676 acc_get_device_type (void)
678 acc_device_t res = acc_device_none;
679 struct gomp_device_descr *dev;
680 struct goacc_thread *thr = goacc_thread ();
682 if (thr && thr->base_dev)
683 res = acc_device_type (thr->base_dev->type);
684 else if (self_initializing_p ())
685 /* The Cuda libaccinj64.so version 9.0+ calls acc_get_device_type during the
686 acc_ev_device_init_start event callback, which is dispatched during
687 acc_init_1. Trying to lock acc_device_lock during such a call (as we do
688 in the else clause below), will result in deadlock, since the lock has
689 already been taken by the acc_init_1 caller. We work around this problem
690 by using the acc_get_device_type property "If the device type has not yet
691 been selected, the value acc_device_none may be returned". */
693 else
695 acc_prof_info prof_info;
696 acc_api_info api_info;
697 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
699 gomp_init_targets_once ();
701 gomp_mutex_lock (&acc_device_lock);
702 dev = resolve_device (acc_device_default, true);
703 gomp_mutex_unlock (&acc_device_lock);
704 res = acc_device_type (dev->type);
706 if (profiling_p)
708 thr->prof_info = NULL;
709 thr->api_info = NULL;
713 assert (res != acc_device_default
714 && res != acc_device_not_host
715 && res != acc_device_current);
717 return res;
720 ialias (acc_get_device_type)
723 acc_get_device_num (acc_device_t d)
725 if (!known_device_type_p (d))
726 unknown_device_type_error (d);
728 const struct gomp_device_descr *dev;
729 struct goacc_thread *thr = goacc_thread ();
731 acc_prof_info prof_info;
732 acc_api_info api_info;
733 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
734 if (profiling_p)
735 prof_info.device_type = d;
737 gomp_init_targets_once ();
739 gomp_mutex_lock (&acc_device_lock);
740 dev = resolve_device (d, true);
741 gomp_mutex_unlock (&acc_device_lock);
743 if (profiling_p)
745 thr->prof_info = NULL;
746 thr->api_info = NULL;
749 if (thr && thr->base_dev == dev && thr->dev)
750 return thr->dev->target_id;
752 return goacc_device_num;
755 ialias (acc_get_device_num)
757 void
758 acc_set_device_num (int ord, acc_device_t d)
760 if (!known_device_type_p (d))
761 unknown_device_type_error (d);
763 struct gomp_device_descr *base_dev, *acc_dev;
764 int num_devices;
766 gomp_init_targets_once ();
768 if (ord < 0)
769 ord = goacc_device_num;
771 if ((int) d == 0)
772 /* Set whatever device is being used by the current host thread to use
773 device instance ORD. It's unclear if this is supposed to affect other
774 host threads too (OpenACC 2.0 (3.2.4) acc_set_device_num). */
775 goacc_attach_host_thread_to_device (ord);
776 else
778 gomp_mutex_lock (&acc_device_lock);
780 cached_base_dev = base_dev = resolve_device (d, true);
782 num_devices = base_dev->get_num_devices_func (0);
784 if (num_devices <= 0 || ord >= num_devices)
785 acc_dev_num_out_of_range (d, ord, num_devices);
787 acc_dev = &base_dev[ord];
789 gomp_mutex_lock (&acc_dev->lock);
790 if (acc_dev->state == GOMP_DEVICE_UNINITIALIZED)
791 gomp_init_device (acc_dev);
792 gomp_mutex_unlock (&acc_dev->lock);
794 gomp_mutex_unlock (&acc_device_lock);
796 goacc_attach_host_thread_to_device (ord);
799 goacc_device_num = ord;
802 ialias (acc_set_device_num)
804 static union goacc_property_value
805 get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
807 goacc_lazy_initialize ();
808 struct goacc_thread *thr = goacc_thread ();
810 if (d == acc_device_current && thr && thr->dev)
811 return thr->dev->openacc.get_property_func (thr->dev->target_id, prop);
813 gomp_mutex_lock (&acc_device_lock);
815 struct gomp_device_descr *dev = resolve_device (d, true);
817 int num_devices = dev->get_num_devices_func (0);
819 if (num_devices <= 0 || ord >= num_devices)
820 acc_dev_num_out_of_range (d, ord, num_devices);
822 dev += ord;
824 gomp_mutex_lock (&dev->lock);
825 if (dev->state == GOMP_DEVICE_UNINITIALIZED)
826 gomp_init_device (dev);
827 gomp_mutex_unlock (&dev->lock);
829 gomp_mutex_unlock (&acc_device_lock);
831 assert (dev);
833 return dev->openacc.get_property_func (dev->target_id, prop);
836 size_t
837 acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
839 if (!known_device_type_p (d))
840 unknown_device_type_error(d);
842 if (prop & GOACC_PROPERTY_STRING_MASK)
843 return 0;
844 else
845 return get_property_any (ord, d, prop).val;
848 ialias (acc_get_property)
850 const char *
851 acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
853 if (!known_device_type_p (d))
854 unknown_device_type_error(d);
856 if (prop & GOACC_PROPERTY_STRING_MASK)
857 return get_property_any (ord, d, prop).ptr;
858 else
859 return NULL;
862 ialias (acc_get_property_string)
864 /* For -O and higher, the compiler always attempts to expand acc_on_device, but
865 if the user disables the builtin, or calls it via a pointer, we'll need this
866 version.
868 Compile this with optimization, so that the compiler expands
869 this, rather than generating infinitely recursive code.
871 The function just forwards its argument to __builtin_acc_on_device. It does
872 not verify that the argument is a valid acc_device_t enumeration value. */
874 int __attribute__ ((__optimize__ ("O2")))
875 acc_on_device (acc_device_t dev)
877 return __builtin_acc_on_device (dev);
880 ialias (acc_on_device)
882 attribute_hidden void
883 goacc_runtime_initialize (void)
885 gomp_mutex_init (&acc_device_lock);
887 #if !(defined HAVE_TLS || defined USE_EMUTLS)
888 pthread_key_create (&goacc_tls_key, NULL);
889 #endif
891 pthread_key_create (&goacc_cleanup_key, goacc_destroy_thread);
893 cached_base_dev = NULL;
895 goacc_threads = NULL;
896 gomp_mutex_init (&goacc_thread_lock);
898 /* Initialize and register the 'host' device type. */
899 goacc_host_init ();
902 static void __attribute__((destructor))
903 goacc_runtime_deinitialize (void)
905 #if !(defined HAVE_TLS || defined USE_EMUTLS)
906 pthread_key_delete (goacc_tls_key);
907 #endif
908 pthread_key_delete (goacc_cleanup_key);
911 /* Compiler helper functions */
913 attribute_hidden void
914 goacc_save_and_set_bind (acc_device_t d)
916 struct goacc_thread *thr = goacc_thread ();
918 assert (!thr->saved_bound_dev);
920 thr->saved_bound_dev = thr->dev;
921 thr->dev = dispatchers[d];
924 attribute_hidden void
925 goacc_restore_bind (void)
927 struct goacc_thread *thr = goacc_thread ();
929 thr->dev = thr->saved_bound_dev;
930 thr->saved_bound_dev = NULL;
933 /* This is called from any OpenACC support function that may need to implicitly
934 initialize the libgomp runtime, either globally or from a new host thread.
935 On exit "goacc_thread" will return a valid & populated thread block. */
937 attribute_hidden void
938 goacc_lazy_initialize (void)
940 struct goacc_thread *thr = goacc_thread ();
942 if (thr && thr->dev)
943 return;
945 gomp_init_targets_once ();
947 gomp_mutex_lock (&acc_device_lock);
948 if (!cached_base_dev)
949 cached_base_dev = acc_init_1 (acc_device_default,
950 acc_construct_parallel, 1);
951 gomp_mutex_unlock (&acc_device_lock);
953 goacc_attach_host_thread_to_device (-1);