1/* OpenACC Runtime initialization routines
2
3   Copyright (C) 2013-2020 Free Software Foundation, Inc.
4
5   Contributed by Mentor Embedded.
6
7   This file is part of the GNU Offloading and Multi Processing Library
8   (libgomp).
9
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.
14
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.
19
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.
23
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/>.  */
28
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>
37
38/* This lock is used to protect access to cached_base_dev, dispatchers and
39   the (abstract) initialisation state of attached offloading devices.  */
40
41static gomp_mutex_t acc_device_lock;
42
43static gomp_mutex_t acc_init_state_lock;
44static enum { uninitialized, initializing, initialized } acc_init_state
45  = uninitialized;
46static pthread_t acc_init_thread;
47
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.  */
53
54static struct gomp_device_descr *cached_base_dev = NULL;
55
56#if defined HAVE_TLS || defined USE_EMUTLS
57__thread struct goacc_thread *goacc_tls_data;
58#else
59pthread_key_t goacc_tls_key;
60#endif
61static pthread_key_t goacc_cleanup_key;
62
63static struct goacc_thread *goacc_threads;
64static gomp_mutex_t goacc_thread_lock;
65
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).  */
70static struct gomp_device_descr *dispatchers[_ACC_device_hwm] = { 0 };
71
72attribute_hidden void
73goacc_register (struct gomp_device_descr *disp)
74{
75  /* Only register the 0th device here.  */
76  if (disp->target_id != 0)
77    return;
78
79  gomp_mutex_lock (&acc_device_lock);
80
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;
86
87  gomp_mutex_unlock (&acc_device_lock);
88}
89
90static bool
91known_device_type_p (acc_device_t d)
92{
93  return d >= 0 && d < _ACC_device_hwm;
94}
95
96static void
97unknown_device_type_error (acc_device_t invalid_type)
98{
99  gomp_fatal ("unknown device type %u", invalid_type);
100}
101
102/* OpenACC names some things a little differently.  */
103
104static const char *
105get_openacc_name (const char *name)
106{
107  if (strcmp (name, "gcn") == 0)
108    return "radeon";
109  else if (strcmp (name, "nvptx") == 0)
110    return "nvidia";
111  else
112    return name;
113}
114
115static const char *
116name_of_acc_device_t (enum acc_device_t type)
117{
118  switch (type)
119    {
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);
127    }
128  __builtin_unreachable ();
129}
130
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.  */
134
135static struct gomp_device_descr *
136resolve_device (acc_device_t d, bool fail_is_error)
137{
138  acc_device_t d_arg = d;
139
140  switch (d)
141    {
142    case acc_device_default:
143      {
144	if (goacc_device_type)
145	  {
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)
152		goto found;
153
154	    if (fail_is_error)
155	      {
156		gomp_mutex_unlock (&acc_device_lock);
157		gomp_fatal ("device type %s not supported", goacc_device_type);
158	      }
159	    else
160	      return NULL;
161	  }
162
163	/* No default device specified, so start scanning for any non-host
164	   device that is available.  */
165	d = acc_device_not_host;
166      }
167      /* FALLTHROUGH */
168
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)
173	  goto found;
174      if (d_arg == acc_device_default)
175	{
176	  d = acc_device_host;
177	  goto found;
178	}
179      if (fail_is_error)
180        {
181	  gomp_mutex_unlock (&acc_device_lock);
182	  gomp_fatal ("no device found");
183	}
184      else
185        return NULL;
186      break;
187
188    case acc_device_host:
189      break;
190
191    default:
192      if (!known_device_type_p (d))
193	{
194	  if (fail_is_error)
195	    goto unsupported_device;
196	  else
197	    return NULL;
198	}
199      break;
200    }
201 found:
202
203  assert (d != acc_device_none
204	  && d != acc_device_default
205	  && d != acc_device_not_host);
206
207  if (dispatchers[d] == NULL && fail_is_error)
208    {
209    unsupported_device:
210      gomp_mutex_unlock (&acc_device_lock);
211      gomp_fatal ("device type %s not supported", name_of_acc_device_t (d));
212    }
213
214  return dispatchers[d];
215}
216
217/* Emit a suitable error if no device of a particular type is available, or
218   the given device number is out-of-range.  */
219static void
220acc_dev_num_out_of_range (acc_device_t d, int ord, int ndevs)
221{
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);
226}
227
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.  */
232
233static struct gomp_device_descr *
234acc_init_1 (acc_device_t d, acc_construct_t parent_construct, int implicit)
235{
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);
240
241  bool check_not_nested_p;
242  if (implicit)
243    {
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;
247    }
248  else
249    {
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.)  */
254    }
255  bool profiling_p = GOACC_PROFILING_DISPATCH_P (check_not_nested_p);
256
257  acc_prof_info prof_info;
258  if (profiling_p)
259    {
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;
274    }
275  acc_event_info device_init_event_info;
276  if (profiling_p)
277    {
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;
284    }
285  acc_api_info api_info;
286  if (profiling_p)
287    {
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;
295    }
296
297  if (profiling_p)
298    goacc_profiling_dispatch (&prof_info, &device_init_event_info, &api_info);
299
300  struct gomp_device_descr *base_dev, *acc_dev;
301  int ndevs;
302
303  base_dev = resolve_device (d, true);
304
305  ndevs = base_dev->get_num_devices_func ();
306
307  if (ndevs <= 0 || goacc_device_num >= ndevs)
308    acc_dev_num_out_of_range (d, goacc_device_num, ndevs);
309
310  acc_dev = &base_dev[goacc_device_num];
311
312  gomp_mutex_lock (&acc_dev->lock);
313  if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
314    {
315      gomp_mutex_unlock (&acc_dev->lock);
316      gomp_fatal ("device already active");
317    }
318
319  gomp_init_device (acc_dev);
320  gomp_mutex_unlock (&acc_dev->lock);
321
322  if (profiling_p)
323    {
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);
328    }
329
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);
337
338  return base_dev;
339}
340
341/* ACC_DEVICE_LOCK must be held before calling this function.  */
342
343static void
344acc_shutdown_1 (acc_device_t d)
345{
346  struct gomp_device_descr *base_dev;
347  struct goacc_thread *walk;
348  int ndevs, i;
349  bool devices_active = false;
350
351  /* Get the base device for this device type.  */
352  base_dev = resolve_device (d, true);
353
354  ndevs = base_dev->get_num_devices_func ();
355
356  /* Unload all the devices of this type that have been opened.  */
357  for (i = 0; i < ndevs; i++)
358    {
359      struct gomp_device_descr *acc_dev = &base_dev[i];
360
361      gomp_mutex_lock (&acc_dev->lock);
362      gomp_unload_device (acc_dev);
363      gomp_mutex_unlock (&acc_dev->lock);
364    }
365
366  gomp_mutex_lock (&goacc_thread_lock);
367
368  /* Free target-specific TLS data and close all devices.  */
369  for (walk = goacc_threads; walk != NULL; walk = walk->next)
370    {
371      if (walk->target_tls)
372	base_dev->openacc.destroy_thread_data_func (walk->target_tls);
373
374      walk->target_tls = NULL;
375
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)
379	{
380	  gomp_mutex_unlock (&goacc_thread_lock);
381	  gomp_fatal ("shutdown in 'acc data' region");
382	}
383
384      /* Similarly, if this happens then user code has done something weird.  */
385      if (walk->saved_bound_dev)
386	{
387	  gomp_mutex_unlock (&goacc_thread_lock);
388	  gomp_fatal ("shutdown during host fallback");
389	}
390
391      if (walk->dev)
392	{
393	  gomp_mutex_lock (&walk->dev->lock);
394
395	  while (walk->dev->mem_map.root)
396	    {
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);
401	    }
402
403	  gomp_mutex_unlock (&walk->dev->lock);
404
405	  walk->dev = NULL;
406	  walk->base_dev = NULL;
407	}
408    }
409
410  gomp_mutex_unlock (&goacc_thread_lock);
411
412  /* Close all the devices of this type that have been opened.  */
413  bool ret = true;
414  for (i = 0; i < ndevs; i++)
415    {
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)
419        {
420	  devices_active = true;
421	  ret &= gomp_fini_device (acc_dev);
422	  acc_dev->state = GOMP_DEVICE_UNINITIALIZED;
423	}
424      gomp_mutex_unlock (&acc_dev->lock);
425    }
426
427  if (!ret)
428    gomp_fatal ("device finalization failed");
429
430  if (!devices_active)
431    gomp_fatal ("no device initialized");
432}
433
434static struct goacc_thread *
435goacc_new_thread (void)
436{
437  struct goacc_thread *thr = gomp_malloc (sizeof (struct goacc_thread));
438
439#if defined HAVE_TLS || defined USE_EMUTLS
440  goacc_tls_data = thr;
441#else
442  pthread_setspecific (goacc_tls_key, thr);
443#endif
444
445  pthread_setspecific (goacc_cleanup_key, thr);
446
447  gomp_mutex_lock (&goacc_thread_lock);
448  thr->next = goacc_threads;
449  goacc_threads = thr;
450  gomp_mutex_unlock (&goacc_thread_lock);
451
452  return thr;
453}
454
455static void
456goacc_destroy_thread (void *data)
457{
458  struct goacc_thread *thr = data, *walk, *prev;
459
460  gomp_mutex_lock (&goacc_thread_lock);
461
462  if (thr)
463    {
464      struct gomp_device_descr *acc_dev = thr->dev;
465
466      if (acc_dev && thr->target_tls)
467	{
468	  acc_dev->openacc.destroy_thread_data_func (thr->target_tls);
469	  thr->target_tls = NULL;
470	}
471
472      assert (!thr->mapped_data);
473
474      /* Remove from thread list.  */
475      for (prev = NULL, walk = goacc_threads; walk;
476	   prev = walk, walk = walk->next)
477	if (walk == thr)
478	  {
479	    if (prev == NULL)
480	      goacc_threads = walk->next;
481	    else
482	      prev->next = walk->next;
483
484	    free (thr);
485
486	    break;
487	  }
488
489      assert (walk);
490    }
491
492  gomp_mutex_unlock (&goacc_thread_lock);
493}
494
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.  */
498
499void
500goacc_attach_host_thread_to_device (int ord)
501{
502  struct goacc_thread *thr = goacc_thread ();
503  struct gomp_device_descr *acc_dev = NULL, *base_dev = NULL;
504  int num_devices;
505
506  if (thr && thr->dev && (thr->dev->target_id == ord || ord < 0))
507    return;
508
509  if (ord < 0)
510    ord = goacc_device_num;
511
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
518    {
519      assert (cached_base_dev);
520      base_dev = cached_base_dev;
521    }
522
523  num_devices = base_dev->get_num_devices_func ();
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);
527
528  if (!thr)
529    thr = goacc_new_thread ();
530
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;
539
540  thr->target_tls
541    = acc_dev->openacc.create_thread_data_func (ord);
542}
543
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.  */
546
547void
548acc_init (acc_device_t d)
549{
550  if (!known_device_type_p (d))
551    unknown_device_type_error (d);
552
553  gomp_init_targets_once ();
554
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);
558
559  goacc_attach_host_thread_to_device (-1);
560}
561
562ialias (acc_init)
563
564void
565acc_shutdown (acc_device_t d)
566{
567  if (!known_device_type_p (d))
568    unknown_device_type_error (d);
569
570  gomp_init_targets_once ();
571
572  gomp_mutex_lock (&acc_device_lock);
573
574  acc_shutdown_1 (d);
575
576  gomp_mutex_unlock (&acc_device_lock);
577}
578
579ialias (acc_shutdown)
580
581int
582acc_get_num_devices (acc_device_t d)
583{
584  if (!known_device_type_p (d))
585    unknown_device_type_error (d);
586
587  int n = 0;
588  struct gomp_device_descr *acc_dev;
589
590  if (d == acc_device_none)
591    return 0;
592
593  gomp_init_targets_once ();
594
595  gomp_mutex_lock (&acc_device_lock);
596  acc_dev = resolve_device (d, false);
597  gomp_mutex_unlock (&acc_device_lock);
598
599  if (!acc_dev)
600    return 0;
601
602  n = acc_dev->get_num_devices_func ();
603  if (n < 0)
604    n = 0;
605
606  return n;
607}
608
609ialias (acc_get_num_devices)
610
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.  */
614
615void
616acc_set_device_type (acc_device_t d)
617{
618  if (!known_device_type_p (d))
619    unknown_device_type_error (d);
620
621  struct gomp_device_descr *base_dev, *acc_dev;
622  struct goacc_thread *thr = goacc_thread ();
623
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;
629
630  gomp_init_targets_once ();
631
632  gomp_mutex_lock (&acc_device_lock);
633
634  cached_base_dev = base_dev = resolve_device (d, true);
635  acc_dev = &base_dev[goacc_device_num];
636
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);
641
642  gomp_mutex_unlock (&acc_device_lock);
643
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)
647    {
648      thr->base_dev = thr->dev = NULL;
649      if (thr->mapped_data)
650        gomp_fatal ("acc_set_device_type in 'acc data' region");
651    }
652
653  goacc_attach_host_thread_to_device (-1);
654
655  if (profiling_p)
656    {
657      thr->prof_info = NULL;
658      thr->api_info = NULL;
659    }
660}
661
662ialias (acc_set_device_type)
663
664static bool
665self_initializing_p (void)
666{
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;
673}
674
675acc_device_t
676acc_get_device_type (void)
677{
678  acc_device_t res = acc_device_none;
679  struct gomp_device_descr *dev;
680  struct goacc_thread *thr = goacc_thread ();
681
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".  */
692    ;
693  else
694    {
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);
698
699      gomp_init_targets_once ();
700
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);
705
706      if (profiling_p)
707	{
708	  thr->prof_info = NULL;
709	  thr->api_info = NULL;
710	}
711    }
712
713  assert (res != acc_device_default
714	  && res != acc_device_not_host
715	  && res != acc_device_current);
716
717  return res;
718}
719
720ialias (acc_get_device_type)
721
722int
723acc_get_device_num (acc_device_t d)
724{
725  if (!known_device_type_p (d))
726    unknown_device_type_error (d);
727
728  const struct gomp_device_descr *dev;
729  struct goacc_thread *thr = goacc_thread ();
730
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;
736
737  gomp_init_targets_once ();
738
739  gomp_mutex_lock (&acc_device_lock);
740  dev = resolve_device (d, true);
741  gomp_mutex_unlock (&acc_device_lock);
742
743  if (profiling_p)
744    {
745      thr->prof_info = NULL;
746      thr->api_info = NULL;
747    }
748
749  if (thr && thr->base_dev == dev && thr->dev)
750    return thr->dev->target_id;
751
752  return goacc_device_num;
753}
754
755ialias (acc_get_device_num)
756
757void
758acc_set_device_num (int ord, acc_device_t d)
759{
760  if (!known_device_type_p (d))
761    unknown_device_type_error (d);
762
763  struct gomp_device_descr *base_dev, *acc_dev;
764  int num_devices;
765
766  gomp_init_targets_once ();
767
768  if (ord < 0)
769    ord = goacc_device_num;
770
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
777    {
778      gomp_mutex_lock (&acc_device_lock);
779
780      cached_base_dev = base_dev = resolve_device (d, true);
781
782      num_devices = base_dev->get_num_devices_func ();
783
784      if (num_devices <= 0 || ord >= num_devices)
785        acc_dev_num_out_of_range (d, ord, num_devices);
786
787      acc_dev = &base_dev[ord];
788
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);
793
794      gomp_mutex_unlock (&acc_device_lock);
795
796      goacc_attach_host_thread_to_device (ord);
797    }
798
799  goacc_device_num = ord;
800}
801
802ialias (acc_set_device_num)
803
804static union goacc_property_value
805get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
806{
807  goacc_lazy_initialize ();
808  struct goacc_thread *thr = goacc_thread ();
809
810  if (d == acc_device_current && thr && thr->dev)
811    return thr->dev->openacc.get_property_func (thr->dev->target_id, prop);
812
813  gomp_mutex_lock (&acc_device_lock);
814
815  struct gomp_device_descr *dev = resolve_device (d, true);
816
817  int num_devices = dev->get_num_devices_func ();
818
819  if (num_devices <= 0 || ord >= num_devices)
820    acc_dev_num_out_of_range (d, ord, num_devices);
821
822  dev += ord;
823
824  gomp_mutex_lock (&dev->lock);
825  if (dev->state == GOMP_DEVICE_UNINITIALIZED)
826    gomp_init_device (dev);
827  gomp_mutex_unlock (&dev->lock);
828
829  gomp_mutex_unlock (&acc_device_lock);
830
831  assert (dev);
832
833  return dev->openacc.get_property_func (dev->target_id, prop);
834}
835
836size_t
837acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
838{
839  if (!known_device_type_p (d))
840    unknown_device_type_error(d);
841
842  if (prop & GOACC_PROPERTY_STRING_MASK)
843    return 0;
844  else
845    return get_property_any (ord, d, prop).val;
846}
847
848ialias (acc_get_property)
849
850const char *
851acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
852{
853  if (!known_device_type_p (d))
854    unknown_device_type_error(d);
855
856  if (prop & GOACC_PROPERTY_STRING_MASK)
857    return get_property_any (ord, d, prop).ptr;
858  else
859    return NULL;
860}
861
862ialias (acc_get_property_string)
863
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.
867
868   Compile this with optimization, so that the compiler expands
869   this, rather than generating infinitely recursive code.
870
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.  */
873
874int __attribute__ ((__optimize__ ("O2")))
875acc_on_device (acc_device_t dev)
876{
877  return __builtin_acc_on_device (dev);
878}
879
880ialias (acc_on_device)
881
882attribute_hidden void
883goacc_runtime_initialize (void)
884{
885  gomp_mutex_init (&acc_device_lock);
886
887#if !(defined HAVE_TLS || defined USE_EMUTLS)
888  pthread_key_create (&goacc_tls_key, NULL);
889#endif
890
891  pthread_key_create (&goacc_cleanup_key, goacc_destroy_thread);
892
893  cached_base_dev = NULL;
894
895  goacc_threads = NULL;
896  gomp_mutex_init (&goacc_thread_lock);
897
898  /* Initialize and register the 'host' device type.  */
899  goacc_host_init ();
900}
901
902static void __attribute__((destructor))
903goacc_runtime_deinitialize (void)
904{
905#if !(defined HAVE_TLS || defined USE_EMUTLS)
906  pthread_key_delete (goacc_tls_key);
907#endif
908  pthread_key_delete (goacc_cleanup_key);
909}
910
911/* Compiler helper functions */
912
913attribute_hidden void
914goacc_save_and_set_bind (acc_device_t d)
915{
916  struct goacc_thread *thr = goacc_thread ();
917
918  assert (!thr->saved_bound_dev);
919
920  thr->saved_bound_dev = thr->dev;
921  thr->dev = dispatchers[d];
922}
923
924attribute_hidden void
925goacc_restore_bind (void)
926{
927  struct goacc_thread *thr = goacc_thread ();
928
929  thr->dev = thr->saved_bound_dev;
930  thr->saved_bound_dev = NULL;
931}
932
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.  */
936
937attribute_hidden void
938goacc_lazy_initialize (void)
939{
940  struct goacc_thread *thr = goacc_thread ();
941
942  if (thr && thr->dev)
943    return;
944
945  gomp_init_targets_once ();
946
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);
952
953  goacc_attach_host_thread_to_device (-1);
954}
955