]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgomp/oacc-init.c
Empty libgomp for nvptx
[thirdparty/gcc.git] / libgomp / oacc-init.c
CommitLineData
41dbbb37
TS
1/* OpenACC Runtime initialization routines
2
3 Copyright (C) 2013-2015 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"
32eaed93 32#include "plugin/plugin-host.h"
41dbbb37
TS
33#include <assert.h>
34#include <stdlib.h>
35#include <strings.h>
36#include <stdbool.h>
37#include <string.h>
38
d2463960
JB
39/* This lock is used to protect access to cached_base_dev, dispatchers and
40 the (abstract) initialisation state of attached offloading devices. */
41
41dbbb37
TS
42static gomp_mutex_t acc_device_lock;
43
d93bdab5
JB
44/* A cached version of the dispatcher for the global "current" accelerator type,
45 e.g. used as the default when creating new host threads. This is the
46 device-type equivalent of goacc_device_num (which specifies which device to
47 use out of potentially several of the same type). If there are several
48 devices of a given type, this points at the first one. */
49
50static struct gomp_device_descr *cached_base_dev = NULL;
41dbbb37
TS
51
52#if defined HAVE_TLS || defined USE_EMUTLS
53__thread struct goacc_thread *goacc_tls_data;
54#else
55pthread_key_t goacc_tls_key;
56#endif
57static pthread_key_t goacc_cleanup_key;
58
41dbbb37
TS
59static struct goacc_thread *goacc_threads;
60static gomp_mutex_t goacc_thread_lock;
61
62/* An array of dispatchers for device types, indexed by the type. This array
63 only references "base" devices, and other instances of the same type are
64 found by simply indexing from each such device (which are stored linearly,
65 grouped by device in target.c:devices). */
66static struct gomp_device_descr *dispatchers[_ACC_device_hwm] = { 0 };
67
68attribute_hidden void
69goacc_register (struct gomp_device_descr *disp)
70{
71 /* Only register the 0th device here. */
72 if (disp->target_id != 0)
73 return;
74
75 gomp_mutex_lock (&acc_device_lock);
76
77 assert (acc_device_type (disp->type) != acc_device_none
78 && acc_device_type (disp->type) != acc_device_default
79 && acc_device_type (disp->type) != acc_device_not_host);
80 assert (!dispatchers[disp->type]);
81 dispatchers[disp->type] = disp;
82
83 gomp_mutex_unlock (&acc_device_lock);
84}
85
86/* OpenACC names some things a little differently. */
87
88static const char *
89get_openacc_name (const char *name)
90{
91 if (strcmp (name, "nvptx") == 0)
92 return "nvidia";
93 else
94 return name;
95}
96
d93bdab5
JB
97static const char *
98name_of_acc_device_t (enum acc_device_t type)
99{
100 switch (type)
101 {
102 case acc_device_none: return "none";
103 case acc_device_default: return "default";
104 case acc_device_host: return "host";
105 case acc_device_host_nonshm: return "host_nonshm";
106 case acc_device_not_host: return "not_host";
107 case acc_device_nvidia: return "nvidia";
108 default: gomp_fatal ("unknown device type %u", (unsigned) type);
109 }
110}
111
9fb5fd44
JB
112/* ACC_DEVICE_LOCK must be held before calling this function. If FAIL_IS_ERROR
113 is true, this function raises an error if there are no devices of type D,
114 otherwise it returns NULL in that case. */
d2463960 115
41dbbb37 116static struct gomp_device_descr *
9fb5fd44 117resolve_device (acc_device_t d, bool fail_is_error)
41dbbb37
TS
118{
119 acc_device_t d_arg = d;
120
121 switch (d)
122 {
123 case acc_device_default:
124 {
125 if (goacc_device_type)
126 {
127 /* Lookup the named device. */
128 while (++d != _ACC_device_hwm)
129 if (dispatchers[d]
130 && !strcasecmp (goacc_device_type,
131 get_openacc_name (dispatchers[d]->name))
132 && dispatchers[d]->get_num_devices_func () > 0)
133 goto found;
134
9fb5fd44
JB
135 if (fail_is_error)
136 {
137 gomp_mutex_unlock (&acc_device_lock);
138 gomp_fatal ("device type %s not supported", goacc_device_type);
139 }
140 else
141 return NULL;
41dbbb37
TS
142 }
143
144 /* No default device specified, so start scanning for any non-host
145 device that is available. */
146 d = acc_device_not_host;
147 }
148 /* FALLTHROUGH */
149
150 case acc_device_not_host:
151 /* Find the first available device after acc_device_not_host. */
152 while (++d != _ACC_device_hwm)
153 if (dispatchers[d] && dispatchers[d]->get_num_devices_func () > 0)
154 goto found;
155 if (d_arg == acc_device_default)
156 {
157 d = acc_device_host;
158 goto found;
159 }
9fb5fd44
JB
160 if (fail_is_error)
161 {
162 gomp_mutex_unlock (&acc_device_lock);
163 gomp_fatal ("no device found");
164 }
165 else
166 return NULL;
41dbbb37
TS
167 break;
168
169 case acc_device_host:
170 break;
171
172 default:
173 if (d > _ACC_device_hwm)
9fb5fd44
JB
174 {
175 if (fail_is_error)
176 goto unsupported_device;
177 else
178 return NULL;
179 }
41dbbb37
TS
180 break;
181 }
182 found:
183
184 assert (d != acc_device_none
185 && d != acc_device_default
186 && d != acc_device_not_host);
187
9fb5fd44
JB
188 if (dispatchers[d] == NULL && fail_is_error)
189 {
190 unsupported_device:
191 gomp_mutex_unlock (&acc_device_lock);
192 gomp_fatal ("device type %s not supported", name_of_acc_device_t (d));
193 }
194
41dbbb37
TS
195 return dispatchers[d];
196}
197
9fb5fd44
JB
198/* Emit a suitable error if no device of a particular type is available, or
199 the given device number is out-of-range. */
200static void
201acc_dev_num_out_of_range (acc_device_t d, int ord, int ndevs)
202{
203 if (ndevs == 0)
204 gomp_fatal ("no devices of type %s available", name_of_acc_device_t (d));
205 else
206 gomp_fatal ("device %u out of range", ord);
207}
208
41dbbb37
TS
209/* This is called when plugins have been initialized, and serves to call
210 (indirectly) the target's device_init hook. Calling multiple times without
9fb5fd44 211 an intervening acc_shutdown_1 call is an error. ACC_DEVICE_LOCK must be
d2463960 212 held before calling this function. */
41dbbb37
TS
213
214static struct gomp_device_descr *
215acc_init_1 (acc_device_t d)
216{
d93bdab5
JB
217 struct gomp_device_descr *base_dev, *acc_dev;
218 int ndevs;
41dbbb37 219
9fb5fd44 220 base_dev = resolve_device (d, true);
d93bdab5
JB
221
222 ndevs = base_dev->get_num_devices_func ();
223
9fb5fd44
JB
224 if (ndevs <= 0 || goacc_device_num >= ndevs)
225 acc_dev_num_out_of_range (d, goacc_device_num, ndevs);
41dbbb37 226
d93bdab5 227 acc_dev = &base_dev[goacc_device_num];
41dbbb37 228
d2463960 229 gomp_mutex_lock (&acc_dev->lock);
41dbbb37 230 if (acc_dev->is_initialized)
d2463960
JB
231 {
232 gomp_mutex_unlock (&acc_dev->lock);
233 gomp_fatal ("device already active");
234 }
41dbbb37 235
41dbbb37 236 gomp_init_device (acc_dev);
d2463960 237 gomp_mutex_unlock (&acc_dev->lock);
41dbbb37 238
d93bdab5
JB
239 return base_dev;
240}
241
9fb5fd44 242/* ACC_DEVICE_LOCK must be held before calling this function. */
d2463960 243
d93bdab5
JB
244static void
245acc_shutdown_1 (acc_device_t d)
246{
247 struct gomp_device_descr *base_dev;
248 struct goacc_thread *walk;
249 int ndevs, i;
250 bool devices_active = false;
251
252 /* Get the base device for this device type. */
9fb5fd44 253 base_dev = resolve_device (d, true);
d93bdab5 254
22be2349
NS
255 ndevs = base_dev->get_num_devices_func ();
256
257 /* Unload all the devices of this type that have been opened. */
258 for (i = 0; i < ndevs; i++)
259 {
260 struct gomp_device_descr *acc_dev = &base_dev[i];
261
262 gomp_mutex_lock (&acc_dev->lock);
263 gomp_unload_device (acc_dev);
264 gomp_mutex_unlock (&acc_dev->lock);
265 }
266
d93bdab5
JB
267 gomp_mutex_lock (&goacc_thread_lock);
268
269 /* Free target-specific TLS data and close all devices. */
270 for (walk = goacc_threads; walk != NULL; walk = walk->next)
271 {
272 if (walk->target_tls)
273 base_dev->openacc.destroy_thread_data_func (walk->target_tls);
274
275 walk->target_tls = NULL;
276
277 /* This would mean the user is shutting down OpenACC in the middle of an
278 "acc data" pragma. Likely not intentional. */
279 if (walk->mapped_data)
e38fdba4
JB
280 {
281 gomp_mutex_unlock (&goacc_thread_lock);
282 gomp_fatal ("shutdown in 'acc data' region");
283 }
d93bdab5
JB
284
285 /* Similarly, if this happens then user code has done something weird. */
286 if (walk->saved_bound_dev)
e38fdba4
JB
287 {
288 gomp_mutex_unlock (&goacc_thread_lock);
289 gomp_fatal ("shutdown during host fallback");
290 }
d93bdab5
JB
291
292 if (walk->dev)
293 {
294 gomp_mutex_lock (&walk->dev->lock);
295 gomp_free_memmap (&walk->dev->mem_map);
296 gomp_mutex_unlock (&walk->dev->lock);
297
298 walk->dev = NULL;
299 walk->base_dev = NULL;
300 }
301 }
302
303 gomp_mutex_unlock (&goacc_thread_lock);
304
d93bdab5
JB
305
306 /* Close all the devices of this type that have been opened. */
307 for (i = 0; i < ndevs; i++)
308 {
309 struct gomp_device_descr *acc_dev = &base_dev[i];
d2463960 310 gomp_mutex_lock (&acc_dev->lock);
d93bdab5
JB
311 if (acc_dev->is_initialized)
312 {
313 devices_active = true;
314 gomp_fini_device (acc_dev);
315 }
d2463960 316 gomp_mutex_unlock (&acc_dev->lock);
d93bdab5
JB
317 }
318
319 if (!devices_active)
320 gomp_fatal ("no device initialized");
41dbbb37
TS
321}
322
323static struct goacc_thread *
324goacc_new_thread (void)
325{
326 struct goacc_thread *thr = gomp_malloc (sizeof (struct gomp_thread));
327
328#if defined HAVE_TLS || defined USE_EMUTLS
329 goacc_tls_data = thr;
330#else
331 pthread_setspecific (goacc_tls_key, thr);
332#endif
333
334 pthread_setspecific (goacc_cleanup_key, thr);
335
336 gomp_mutex_lock (&goacc_thread_lock);
337 thr->next = goacc_threads;
338 goacc_threads = thr;
339 gomp_mutex_unlock (&goacc_thread_lock);
340
341 return thr;
342}
343
344static void
345goacc_destroy_thread (void *data)
346{
347 struct goacc_thread *thr = data, *walk, *prev;
348
349 gomp_mutex_lock (&goacc_thread_lock);
350
351 if (thr)
352 {
d93bdab5
JB
353 struct gomp_device_descr *acc_dev = thr->dev;
354
355 if (acc_dev && thr->target_tls)
41dbbb37 356 {
d93bdab5 357 acc_dev->openacc.destroy_thread_data_func (thr->target_tls);
41dbbb37
TS
358 thr->target_tls = NULL;
359 }
360
361 assert (!thr->mapped_data);
362
363 /* Remove from thread list. */
364 for (prev = NULL, walk = goacc_threads; walk;
365 prev = walk, walk = walk->next)
366 if (walk == thr)
367 {
368 if (prev == NULL)
369 goacc_threads = walk->next;
370 else
371 prev->next = walk->next;
372
373 free (thr);
374
375 break;
376 }
377
378 assert (walk);
379 }
380
381 gomp_mutex_unlock (&goacc_thread_lock);
382}
383
d93bdab5
JB
384/* Use the ORD'th device instance for the current host thread (or -1 for the
385 current global default). The device (and the runtime) must be initialised
386 before calling this function. */
41dbbb37 387
d93bdab5
JB
388void
389goacc_attach_host_thread_to_device (int ord)
41dbbb37
TS
390{
391 struct goacc_thread *thr = goacc_thread ();
d93bdab5
JB
392 struct gomp_device_descr *acc_dev = NULL, *base_dev = NULL;
393 int num_devices;
394
395 if (thr && thr->dev && (thr->dev->target_id == ord || ord < 0))
396 return;
397
41dbbb37
TS
398 if (ord < 0)
399 ord = goacc_device_num;
d93bdab5
JB
400
401 /* Decide which type of device to use. If the current thread has a device
402 type already (e.g. set by acc_set_device_type), use that, else use the
403 global default. */
404 if (thr && thr->base_dev)
405 base_dev = thr->base_dev;
406 else
407 {
408 assert (cached_base_dev);
409 base_dev = cached_base_dev;
410 }
411
412 num_devices = base_dev->get_num_devices_func ();
413 if (num_devices <= 0 || ord >= num_devices)
9fb5fd44
JB
414 acc_dev_num_out_of_range (acc_device_type (base_dev->type), ord,
415 num_devices);
d93bdab5 416
41dbbb37
TS
417 if (!thr)
418 thr = goacc_new_thread ();
d93bdab5
JB
419
420 thr->base_dev = base_dev;
421 thr->dev = acc_dev = &base_dev[ord];
41dbbb37
TS
422 thr->saved_bound_dev = NULL;
423 thr->mapped_data = NULL;
d93bdab5 424
41dbbb37 425 thr->target_tls
d93bdab5
JB
426 = acc_dev->openacc.create_thread_data_func (ord);
427
41dbbb37 428 acc_dev->openacc.async_set_async_func (acc_async_sync);
41dbbb37
TS
429}
430
431/* OpenACC 2.0a (3.2.12, 3.2.13) doesn't specify whether the serialization of
432 init/shutdown is per-process or per-thread. We choose per-process. */
433
434void
435acc_init (acc_device_t d)
436{
d93bdab5 437 if (!cached_base_dev)
41dbbb37
TS
438 gomp_init_targets_once ();
439
440 gomp_mutex_lock (&acc_device_lock);
441
d93bdab5 442 cached_base_dev = acc_init_1 (d);
41dbbb37
TS
443
444 gomp_mutex_unlock (&acc_device_lock);
d93bdab5
JB
445
446 goacc_attach_host_thread_to_device (-1);
41dbbb37
TS
447}
448
449ialias (acc_init)
450
41dbbb37
TS
451void
452acc_shutdown (acc_device_t d)
453{
454 gomp_mutex_lock (&acc_device_lock);
455
456 acc_shutdown_1 (d);
457
458 gomp_mutex_unlock (&acc_device_lock);
459}
460
461ialias (acc_shutdown)
462
41dbbb37
TS
463int
464acc_get_num_devices (acc_device_t d)
465{
466 int n = 0;
d93bdab5 467 struct gomp_device_descr *acc_dev;
41dbbb37
TS
468
469 if (d == acc_device_none)
470 return 0;
471
d93bdab5 472 gomp_init_targets_once ();
41dbbb37 473
d2463960 474 gomp_mutex_lock (&acc_device_lock);
9fb5fd44 475 acc_dev = resolve_device (d, false);
d2463960
JB
476 gomp_mutex_unlock (&acc_device_lock);
477
41dbbb37
TS
478 if (!acc_dev)
479 return 0;
480
481 n = acc_dev->get_num_devices_func ();
482 if (n < 0)
483 n = 0;
484
485 return n;
486}
487
488ialias (acc_get_num_devices)
489
d93bdab5
JB
490/* Set the device type for the current thread only (using the current global
491 default device number), initialising that device if necessary. Also set the
492 default device type for new threads to D. */
493
41dbbb37
TS
494void
495acc_set_device_type (acc_device_t d)
496{
d93bdab5
JB
497 struct gomp_device_descr *base_dev, *acc_dev;
498 struct goacc_thread *thr = goacc_thread ();
499
500 gomp_mutex_lock (&acc_device_lock);
501
502 if (!cached_base_dev)
503 gomp_init_targets_once ();
504
9fb5fd44 505 cached_base_dev = base_dev = resolve_device (d, true);
d93bdab5
JB
506 acc_dev = &base_dev[goacc_device_num];
507
d2463960 508 gomp_mutex_lock (&acc_dev->lock);
d93bdab5
JB
509 if (!acc_dev->is_initialized)
510 gomp_init_device (acc_dev);
d2463960 511 gomp_mutex_unlock (&acc_dev->lock);
d93bdab5
JB
512
513 gomp_mutex_unlock (&acc_device_lock);
514
515 /* We're changing device type: invalidate the current thread's dev and
516 base_dev pointers. */
517 if (thr && thr->base_dev != base_dev)
518 {
519 thr->base_dev = thr->dev = NULL;
520 if (thr->mapped_data)
521 gomp_fatal ("acc_set_device_type in 'acc data' region");
522 }
523
524 goacc_attach_host_thread_to_device (-1);
41dbbb37
TS
525}
526
527ialias (acc_set_device_type)
528
529acc_device_t
530acc_get_device_type (void)
531{
532 acc_device_t res = acc_device_none;
d93bdab5
JB
533 struct gomp_device_descr *dev;
534 struct goacc_thread *thr = goacc_thread ();
41dbbb37 535
d93bdab5
JB
536 if (thr && thr->base_dev)
537 res = acc_device_type (thr->base_dev->type);
41dbbb37
TS
538 else
539 {
540 gomp_init_targets_once ();
541
d2463960 542 gomp_mutex_lock (&acc_device_lock);
9fb5fd44 543 dev = resolve_device (acc_device_default, true);
d2463960 544 gomp_mutex_unlock (&acc_device_lock);
41dbbb37
TS
545 res = acc_device_type (dev->type);
546 }
547
548 assert (res != acc_device_default
549 && res != acc_device_not_host);
550
551 return res;
552}
553
554ialias (acc_get_device_type)
555
556int
557acc_get_device_num (acc_device_t d)
558{
559 const struct gomp_device_descr *dev;
d93bdab5 560 struct goacc_thread *thr = goacc_thread ();
41dbbb37
TS
561
562 if (d >= _ACC_device_hwm)
9fb5fd44 563 gomp_fatal ("unknown device type %u", (unsigned) d);
41dbbb37 564
d93bdab5 565 if (!cached_base_dev)
41dbbb37
TS
566 gomp_init_targets_once ();
567
d2463960 568 gomp_mutex_lock (&acc_device_lock);
9fb5fd44 569 dev = resolve_device (d, true);
d2463960 570 gomp_mutex_unlock (&acc_device_lock);
41dbbb37 571
d93bdab5
JB
572 if (thr && thr->base_dev == dev && thr->dev)
573 return thr->dev->target_id;
41dbbb37 574
d93bdab5 575 return goacc_device_num;
41dbbb37
TS
576}
577
578ialias (acc_get_device_num)
579
580void
d93bdab5 581acc_set_device_num (int ord, acc_device_t d)
41dbbb37 582{
d93bdab5 583 struct gomp_device_descr *base_dev, *acc_dev;
41dbbb37
TS
584 int num_devices;
585
d93bdab5 586 if (!cached_base_dev)
41dbbb37
TS
587 gomp_init_targets_once ();
588
d93bdab5
JB
589 if (ord < 0)
590 ord = goacc_device_num;
41dbbb37 591
d93bdab5
JB
592 if ((int) d == 0)
593 /* Set whatever device is being used by the current host thread to use
594 device instance ORD. It's unclear if this is supposed to affect other
595 host threads too (OpenACC 2.0 (3.2.4) acc_set_device_num). */
596 goacc_attach_host_thread_to_device (ord);
41dbbb37
TS
597 else
598 {
41dbbb37
TS
599 gomp_mutex_lock (&acc_device_lock);
600
9fb5fd44 601 cached_base_dev = base_dev = resolve_device (d, true);
41dbbb37
TS
602
603 num_devices = base_dev->get_num_devices_func ();
604
9fb5fd44
JB
605 if (num_devices <= 0 || ord >= num_devices)
606 acc_dev_num_out_of_range (d, ord, num_devices);
41dbbb37 607
d93bdab5 608 acc_dev = &base_dev[ord];
41dbbb37 609
d2463960 610 gomp_mutex_lock (&acc_dev->lock);
d93bdab5
JB
611 if (!acc_dev->is_initialized)
612 gomp_init_device (acc_dev);
d2463960 613 gomp_mutex_unlock (&acc_dev->lock);
41dbbb37
TS
614
615 gomp_mutex_unlock (&acc_device_lock);
d93bdab5
JB
616
617 goacc_attach_host_thread_to_device (ord);
41dbbb37 618 }
d93bdab5
JB
619
620 goacc_device_num = ord;
41dbbb37
TS
621}
622
623ialias (acc_set_device_num)
624
625int
626acc_on_device (acc_device_t dev)
627{
32eaed93
JB
628 struct goacc_thread *thr = goacc_thread ();
629
630 /* We only want to appear to be the "host_nonshm" plugin from "offloaded"
631 code -- i.e. within a parallel region. Test a flag set by the
632 openacc_parallel hook of the host_nonshm plugin to determine that. */
633 if (acc_get_device_type () == acc_device_host_nonshm
634 && thr && thr->target_tls
635 && ((struct nonshm_thread *)thr->target_tls)->nonshm_exec)
41dbbb37
TS
636 return dev == acc_device_host_nonshm || dev == acc_device_not_host;
637
32eaed93
JB
638 /* For OpenACC, libgomp is only built for the host, so this is sufficient. */
639 return dev == acc_device_host || dev == acc_device_none;
41dbbb37
TS
640}
641
642ialias (acc_on_device)
643
644attribute_hidden void
645goacc_runtime_initialize (void)
646{
647 gomp_mutex_init (&acc_device_lock);
648
649#if !(defined HAVE_TLS || defined USE_EMUTLS)
650 pthread_key_create (&goacc_tls_key, NULL);
651#endif
652
653 pthread_key_create (&goacc_cleanup_key, goacc_destroy_thread);
654
d93bdab5 655 cached_base_dev = NULL;
41dbbb37
TS
656
657 goacc_threads = NULL;
658 gomp_mutex_init (&goacc_thread_lock);
659}
660
661/* Compiler helper functions */
662
663attribute_hidden void
664goacc_save_and_set_bind (acc_device_t d)
665{
666 struct goacc_thread *thr = goacc_thread ();
667
668 assert (!thr->saved_bound_dev);
669
670 thr->saved_bound_dev = thr->dev;
671 thr->dev = dispatchers[d];
672}
673
674attribute_hidden void
675goacc_restore_bind (void)
676{
677 struct goacc_thread *thr = goacc_thread ();
678
679 thr->dev = thr->saved_bound_dev;
680 thr->saved_bound_dev = NULL;
681}
682
683/* This is called from any OpenACC support function that may need to implicitly
d93bdab5
JB
684 initialize the libgomp runtime, either globally or from a new host thread.
685 On exit "goacc_thread" will return a valid & populated thread block. */
41dbbb37
TS
686
687attribute_hidden void
688goacc_lazy_initialize (void)
689{
690 struct goacc_thread *thr = goacc_thread ();
691
692 if (thr && thr->dev)
693 return;
694
d93bdab5
JB
695 if (!cached_base_dev)
696 acc_init (acc_device_default);
41dbbb37 697 else
d93bdab5 698 goacc_attach_host_thread_to_device (-1);
41dbbb37 699}