1 /* OpenACC Runtime initialization routines
3 Copyright (C) 2013-2019 Free Software Foundation, Inc.
5 Contributed by Mentor Embedded.
7 This file is part of the GNU Offloading and Multi Processing Library
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)
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
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/>. */
31 #include "gomp-constants.h"
36 /* Return block containing [H->S), or NULL if not contained. The device lock
37 for DEV must be locked on entry, and remains locked on exit. */
40 lookup_host (struct gomp_device_descr
*dev
, void *h
, size_t s
)
42 struct splay_tree_key_s node
;
45 node
.host_start
= (uintptr_t) h
;
46 node
.host_end
= (uintptr_t) h
+ s
;
48 key
= splay_tree_lookup (&dev
->mem_map
, &node
);
53 /* Return block containing [D->S), or NULL if not contained.
54 The list isn't ordered by device address, so we have to iterate
55 over the whole array. This is not expected to be a common
56 operation. The device lock associated with TGT must be locked on entry, and
57 remains locked on exit. */
60 lookup_dev (struct target_mem_desc
*tgt
, void *d
, size_t s
)
63 struct target_mem_desc
*t
;
68 for (t
= tgt
; t
!= NULL
; t
= t
->prev
)
70 if (t
->tgt_start
<= (uintptr_t) d
&& t
->tgt_end
>= (uintptr_t) d
+ s
)
77 for (i
= 0; i
< t
->list_count
; i
++)
81 splay_tree_key k
= &t
->array
[i
].key
;
82 offset
= d
- t
->tgt_start
+ k
->tgt_offset
;
84 if (k
->host_start
+ offset
<= (void *) k
->host_end
)
91 /* OpenACC is silent on how memory exhaustion is indicated. We return
100 goacc_lazy_initialize ();
102 struct goacc_thread
*thr
= goacc_thread ();
106 if (thr
->dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
109 acc_prof_info prof_info
;
110 acc_api_info api_info
;
111 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
113 void *res
= thr
->dev
->alloc_func (thr
->dev
->target_id
, s
);
117 thr
->prof_info
= NULL
;
118 thr
->api_info
= NULL
;
124 /* OpenACC 2.0a (3.2.16) doesn't specify what to do in the event
125 the device address is mapped. We choose to check if it mapped,
126 and if it is, to unmap it. */
135 struct goacc_thread
*thr
= goacc_thread ();
137 assert (thr
&& thr
->dev
);
139 struct gomp_device_descr
*acc_dev
= thr
->dev
;
141 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
144 acc_prof_info prof_info
;
145 acc_api_info api_info
;
146 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
148 gomp_mutex_lock (&acc_dev
->lock
);
150 /* We don't have to call lazy open here, as the ptr value must have
151 been returned by acc_malloc. It's not permitted to pass NULL in
152 (unless you got that null from acc_malloc). */
153 if ((k
= lookup_dev (acc_dev
->openacc
.data_environ
, d
, 1)))
157 offset
= d
- k
->tgt
->tgt_start
+ k
->tgt_offset
;
159 gomp_mutex_unlock (&acc_dev
->lock
);
161 acc_unmap_data ((void *)(k
->host_start
+ offset
));
164 gomp_mutex_unlock (&acc_dev
->lock
);
166 if (!acc_dev
->free_func (acc_dev
->target_id
, d
))
167 gomp_fatal ("error in freeing device memory in %s", __FUNCTION__
);
171 thr
->prof_info
= NULL
;
172 thr
->api_info
= NULL
;
177 memcpy_tofrom_device (bool from
, void *d
, void *h
, size_t s
, int async
,
178 const char *libfnname
)
180 /* No need to call lazy open here, as the device pointer must have
181 been obtained from a routine that did that. */
182 struct goacc_thread
*thr
= goacc_thread ();
184 assert (thr
&& thr
->dev
);
186 if (thr
->dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
195 acc_prof_info prof_info
;
196 acc_api_info api_info
;
197 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
200 prof_info
.async
= async
;
201 prof_info
.async_queue
= prof_info
.async
;
204 goacc_aq aq
= get_goacc_asyncqueue (async
);
206 gomp_copy_dev2host (thr
->dev
, aq
, h
, d
, s
);
208 gomp_copy_host2dev (thr
->dev
, aq
, d
, h
, s
, /* TODO: cbuf? */ NULL
);
212 thr
->prof_info
= NULL
;
213 thr
->api_info
= NULL
;
218 acc_memcpy_to_device (void *d
, void *h
, size_t s
)
220 memcpy_tofrom_device (false, d
, h
, s
, acc_async_sync
, __FUNCTION__
);
224 acc_memcpy_to_device_async (void *d
, void *h
, size_t s
, int async
)
226 memcpy_tofrom_device (false, d
, h
, s
, async
, __FUNCTION__
);
230 acc_memcpy_from_device (void *h
, void *d
, size_t s
)
232 memcpy_tofrom_device (true, d
, h
, s
, acc_async_sync
, __FUNCTION__
);
236 acc_memcpy_from_device_async (void *h
, void *d
, size_t s
, int async
)
238 memcpy_tofrom_device (true, d
, h
, s
, async
, __FUNCTION__
);
241 /* Return the device pointer that corresponds to host data H. Or NULL
245 acc_deviceptr (void *h
)
251 goacc_lazy_initialize ();
253 struct goacc_thread
*thr
= goacc_thread ();
254 struct gomp_device_descr
*dev
= thr
->dev
;
256 if (thr
->dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
259 /* In the following, no OpenACC Profiling Interface events can possibly be
262 gomp_mutex_lock (&dev
->lock
);
264 n
= lookup_host (dev
, h
, 1);
268 gomp_mutex_unlock (&dev
->lock
);
272 offset
= h
- n
->host_start
;
274 d
= n
->tgt
->tgt_start
+ n
->tgt_offset
+ offset
;
276 gomp_mutex_unlock (&dev
->lock
);
281 /* Return the host pointer that corresponds to device data D. Or NULL
285 acc_hostptr (void *d
)
291 goacc_lazy_initialize ();
293 struct goacc_thread
*thr
= goacc_thread ();
294 struct gomp_device_descr
*acc_dev
= thr
->dev
;
296 if (thr
->dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
299 /* In the following, no OpenACC Profiling Interface events can possibly be
302 gomp_mutex_lock (&acc_dev
->lock
);
304 n
= lookup_dev (acc_dev
->openacc
.data_environ
, d
, 1);
308 gomp_mutex_unlock (&acc_dev
->lock
);
312 offset
= d
- n
->tgt
->tgt_start
+ n
->tgt_offset
;
314 h
= n
->host_start
+ offset
;
316 gomp_mutex_unlock (&acc_dev
->lock
);
321 /* Return 1 if host data [H,+S] is present on the device. */
324 acc_is_present (void *h
, size_t s
)
331 goacc_lazy_initialize ();
333 struct goacc_thread
*thr
= goacc_thread ();
334 struct gomp_device_descr
*acc_dev
= thr
->dev
;
336 if (thr
->dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
339 /* In the following, no OpenACC Profiling Interface events can possibly be
342 gomp_mutex_lock (&acc_dev
->lock
);
344 n
= lookup_host (acc_dev
, h
, s
);
346 if (n
&& ((uintptr_t)h
< n
->host_start
347 || (uintptr_t)h
+ s
> n
->host_end
348 || s
> n
->host_end
- n
->host_start
))
351 gomp_mutex_unlock (&acc_dev
->lock
);
356 /* Create a mapping for host [H,+S] -> device [D,+S] */
359 acc_map_data (void *h
, void *d
, size_t s
)
361 struct target_mem_desc
*tgt
= NULL
;
366 unsigned short kinds
= GOMP_MAP_ALLOC
;
368 goacc_lazy_initialize ();
370 struct goacc_thread
*thr
= goacc_thread ();
371 struct gomp_device_descr
*acc_dev
= thr
->dev
;
373 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
376 gomp_fatal ("cannot map data on shared-memory system");
380 struct goacc_thread
*thr
= goacc_thread ();
383 gomp_fatal ("[%p,+%d]->[%p,+%d] is a bad map",
384 (void *)h
, (int)s
, (void *)d
, (int)s
);
386 acc_prof_info prof_info
;
387 acc_api_info api_info
;
388 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
390 gomp_mutex_lock (&acc_dev
->lock
);
392 if (lookup_host (acc_dev
, h
, s
))
394 gomp_mutex_unlock (&acc_dev
->lock
);
395 gomp_fatal ("host address [%p, +%d] is already mapped", (void *)h
,
399 if (lookup_dev (thr
->dev
->openacc
.data_environ
, d
, s
))
401 gomp_mutex_unlock (&acc_dev
->lock
);
402 gomp_fatal ("device address [%p, +%d] is already mapped", (void *)d
,
406 gomp_mutex_unlock (&acc_dev
->lock
);
408 tgt
= gomp_map_vars (acc_dev
, mapnum
, &hostaddrs
, &devaddrs
, &sizes
,
409 &kinds
, true, GOMP_MAP_VARS_OPENACC
);
410 splay_tree_key n
= tgt
->list
[0].key
;
411 assert (n
->refcount
== 1);
412 assert (n
->dynamic_refcount
== 0);
413 /* Special reference counting behavior. */
414 n
->refcount
= REFCOUNT_INFINITY
;
418 thr
->prof_info
= NULL
;
419 thr
->api_info
= NULL
;
423 gomp_mutex_lock (&acc_dev
->lock
);
424 tgt
->prev
= acc_dev
->openacc
.data_environ
;
425 acc_dev
->openacc
.data_environ
= tgt
;
426 gomp_mutex_unlock (&acc_dev
->lock
);
430 acc_unmap_data (void *h
)
432 struct goacc_thread
*thr
= goacc_thread ();
433 struct gomp_device_descr
*acc_dev
= thr
->dev
;
435 /* No need to call lazy open, as the address must have been mapped. */
437 /* This is a no-op on shared-memory targets. */
438 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
441 acc_prof_info prof_info
;
442 acc_api_info api_info
;
443 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
447 gomp_mutex_lock (&acc_dev
->lock
);
449 splay_tree_key n
= lookup_host (acc_dev
, h
, 1);
450 struct target_mem_desc
*t
;
454 gomp_mutex_unlock (&acc_dev
->lock
);
455 gomp_fatal ("%p is not a mapped block", (void *)h
);
458 host_size
= n
->host_end
- n
->host_start
;
460 if (n
->host_start
!= (uintptr_t) h
)
462 gomp_mutex_unlock (&acc_dev
->lock
);
463 gomp_fatal ("[%p,%d] surrounds %p",
464 (void *) n
->host_start
, (int) host_size
, (void *) h
);
466 /* TODO This currently doesn't catch 'REFCOUNT_INFINITY' usage different from
467 'acc_map_data'. Maybe 'dynamic_refcount' can be used for disambiguating
468 the different 'REFCOUNT_INFINITY' cases, or simply separate
469 'REFCOUNT_INFINITY' values per different usage ('REFCOUNT_ACC_MAP_DATA'
471 else if (n
->refcount
!= REFCOUNT_INFINITY
)
473 gomp_mutex_unlock (&acc_dev
->lock
);
474 gomp_fatal ("refusing to unmap block [%p,+%d] that has not been mapped"
475 " by 'acc_map_data'",
476 (void *) h
, (int) host_size
);
479 /* Mark for removal. */
484 if (t
->refcount
== 2)
486 struct target_mem_desc
*tp
;
488 /* This is the last reference, so pull the descriptor off the
489 chain. This avoids gomp_unmap_vars via gomp_unmap_tgt from
490 freeing the device memory. */
494 for (tp
= NULL
, t
= acc_dev
->openacc
.data_environ
; t
!= NULL
;
501 acc_dev
->openacc
.data_environ
= t
->prev
;
507 gomp_mutex_unlock (&acc_dev
->lock
);
509 gomp_unmap_vars (t
, true);
513 thr
->prof_info
= NULL
;
514 thr
->api_info
= NULL
;
518 #define FLAG_PRESENT (1 << 0)
519 #define FLAG_CREATE (1 << 1)
520 #define FLAG_COPY (1 << 2)
523 present_create_copy (unsigned f
, void *h
, size_t s
, int async
)
529 gomp_fatal ("[%p,+%d] is a bad range", (void *)h
, (int)s
);
531 goacc_lazy_initialize ();
533 struct goacc_thread
*thr
= goacc_thread ();
534 struct gomp_device_descr
*acc_dev
= thr
->dev
;
536 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
539 acc_prof_info prof_info
;
540 acc_api_info api_info
;
541 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
544 prof_info
.async
= async
;
545 prof_info
.async_queue
= prof_info
.async
;
548 gomp_mutex_lock (&acc_dev
->lock
);
550 n
= lookup_host (acc_dev
, h
, s
);
554 d
= (void *) (n
->tgt
->tgt_start
+ n
->tgt_offset
+ h
- n
->host_start
);
556 if (!(f
& FLAG_PRESENT
))
558 gomp_mutex_unlock (&acc_dev
->lock
);
559 gomp_fatal ("[%p,+%d] already mapped to [%p,+%d]",
560 (void *)h
, (int)s
, (void *)d
, (int)s
);
562 if ((h
+ s
) > (void *)n
->host_end
)
564 gomp_mutex_unlock (&acc_dev
->lock
);
565 gomp_fatal ("[%p,+%d] not mapped", (void *)h
, (int)s
);
568 if (n
->refcount
!= REFCOUNT_INFINITY
)
571 n
->dynamic_refcount
++;
573 gomp_mutex_unlock (&acc_dev
->lock
);
575 else if (!(f
& FLAG_CREATE
))
577 gomp_mutex_unlock (&acc_dev
->lock
);
578 gomp_fatal ("[%p,+%d] not mapped", (void *)h
, (int)s
);
582 struct target_mem_desc
*tgt
;
584 unsigned short kinds
;
590 kinds
= GOMP_MAP_ALLOC
;
592 gomp_mutex_unlock (&acc_dev
->lock
);
594 goacc_aq aq
= get_goacc_asyncqueue (async
);
596 tgt
= gomp_map_vars_async (acc_dev
, aq
, mapnum
, &hostaddrs
, NULL
, &s
,
597 &kinds
, true, GOMP_MAP_VARS_OPENACC
);
598 /* Initialize dynamic refcount. */
599 tgt
->list
[0].key
->dynamic_refcount
= 1;
601 gomp_mutex_lock (&acc_dev
->lock
);
604 tgt
->prev
= acc_dev
->openacc
.data_environ
;
605 acc_dev
->openacc
.data_environ
= tgt
;
607 gomp_mutex_unlock (&acc_dev
->lock
);
612 thr
->prof_info
= NULL
;
613 thr
->api_info
= NULL
;
620 acc_create (void *h
, size_t s
)
622 return present_create_copy (FLAG_PRESENT
| FLAG_CREATE
, h
, s
, acc_async_sync
);
626 acc_create_async (void *h
, size_t s
, int async
)
628 present_create_copy (FLAG_PRESENT
| FLAG_CREATE
, h
, s
, async
);
631 /* acc_present_or_create used to be what acc_create is now. */
632 /* acc_pcreate is acc_present_or_create by a different name. */
633 #ifdef HAVE_ATTRIBUTE_ALIAS
634 strong_alias (acc_create
, acc_present_or_create
)
635 strong_alias (acc_create
, acc_pcreate
)
638 acc_present_or_create (void *h
, size_t s
)
640 return acc_create (h
, s
);
644 acc_pcreate (void *h
, size_t s
)
646 return acc_create (h
, s
);
651 acc_copyin (void *h
, size_t s
)
653 return present_create_copy (FLAG_PRESENT
| FLAG_CREATE
| FLAG_COPY
, h
, s
,
658 acc_copyin_async (void *h
, size_t s
, int async
)
660 present_create_copy (FLAG_PRESENT
| FLAG_CREATE
| FLAG_COPY
, h
, s
, async
);
663 /* acc_present_or_copyin used to be what acc_copyin is now. */
664 /* acc_pcopyin is acc_present_or_copyin by a different name. */
665 #ifdef HAVE_ATTRIBUTE_ALIAS
666 strong_alias (acc_copyin
, acc_present_or_copyin
)
667 strong_alias (acc_copyin
, acc_pcopyin
)
670 acc_present_or_copyin (void *h
, size_t s
)
672 return acc_copyin (h
, s
);
676 acc_pcopyin (void *h
, size_t s
)
678 return acc_copyin (h
, s
);
682 #define FLAG_COPYOUT (1 << 0)
683 #define FLAG_FINALIZE (1 << 1)
686 delete_copyout (unsigned f
, void *h
, size_t s
, int async
, const char *libfnname
)
690 struct goacc_thread
*thr
= goacc_thread ();
691 struct gomp_device_descr
*acc_dev
= thr
->dev
;
693 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
696 acc_prof_info prof_info
;
697 acc_api_info api_info
;
698 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
701 prof_info
.async
= async
;
702 prof_info
.async_queue
= prof_info
.async
;
705 gomp_mutex_lock (&acc_dev
->lock
);
707 n
= lookup_host (acc_dev
, h
, s
);
709 /* No need to call lazy open, as the data must already have been
714 gomp_mutex_unlock (&acc_dev
->lock
);
715 gomp_fatal ("[%p,%d] is not mapped", (void *)h
, (int)s
);
718 d
= (void *) (n
->tgt
->tgt_start
+ n
->tgt_offset
719 + (uintptr_t) h
- n
->host_start
);
721 if ((uintptr_t) h
< n
->host_start
|| (uintptr_t) h
+ s
> n
->host_end
)
723 size_t host_size
= n
->host_end
- n
->host_start
;
724 gomp_mutex_unlock (&acc_dev
->lock
);
725 gomp_fatal ("[%p,+%d] outside mapped block [%p,+%d]",
726 (void *) h
, (int) s
, (void *) n
->host_start
, (int) host_size
);
729 if (n
->refcount
== REFCOUNT_INFINITY
)
732 n
->dynamic_refcount
= 0;
734 if (n
->refcount
< n
->dynamic_refcount
)
736 gomp_mutex_unlock (&acc_dev
->lock
);
737 gomp_fatal ("Dynamic reference counting assert fail\n");
740 if (f
& FLAG_FINALIZE
)
742 n
->refcount
-= n
->dynamic_refcount
;
743 n
->dynamic_refcount
= 0;
745 else if (n
->dynamic_refcount
)
747 n
->dynamic_refcount
--;
751 if (n
->refcount
== 0)
753 if (n
->tgt
->refcount
== 2)
755 struct target_mem_desc
*tp
, *t
;
756 for (tp
= NULL
, t
= acc_dev
->openacc
.data_environ
; t
!= NULL
;
763 acc_dev
->openacc
.data_environ
= t
->prev
;
768 if (f
& FLAG_COPYOUT
)
770 goacc_aq aq
= get_goacc_asyncqueue (async
);
771 gomp_copy_dev2host (acc_dev
, aq
, h
, d
, s
);
773 gomp_remove_var (acc_dev
, n
);
776 gomp_mutex_unlock (&acc_dev
->lock
);
780 thr
->prof_info
= NULL
;
781 thr
->api_info
= NULL
;
786 acc_delete (void *h
, size_t s
)
788 delete_copyout (0, h
, s
, acc_async_sync
, __FUNCTION__
);
792 acc_delete_async (void *h
, size_t s
, int async
)
794 delete_copyout (0, h
, s
, async
, __FUNCTION__
);
798 acc_delete_finalize (void *h
, size_t s
)
800 delete_copyout (FLAG_FINALIZE
, h
, s
, acc_async_sync
, __FUNCTION__
);
804 acc_delete_finalize_async (void *h
, size_t s
, int async
)
806 delete_copyout (FLAG_FINALIZE
, h
, s
, async
, __FUNCTION__
);
810 acc_copyout (void *h
, size_t s
)
812 delete_copyout (FLAG_COPYOUT
, h
, s
, acc_async_sync
, __FUNCTION__
);
816 acc_copyout_async (void *h
, size_t s
, int async
)
818 delete_copyout (FLAG_COPYOUT
, h
, s
, async
, __FUNCTION__
);
822 acc_copyout_finalize (void *h
, size_t s
)
824 delete_copyout (FLAG_COPYOUT
| FLAG_FINALIZE
, h
, s
, acc_async_sync
,
829 acc_copyout_finalize_async (void *h
, size_t s
, int async
)
831 delete_copyout (FLAG_COPYOUT
| FLAG_FINALIZE
, h
, s
, async
, __FUNCTION__
);
835 update_dev_host (int is_dev
, void *h
, size_t s
, int async
)
840 goacc_lazy_initialize ();
842 struct goacc_thread
*thr
= goacc_thread ();
843 struct gomp_device_descr
*acc_dev
= thr
->dev
;
845 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
848 /* Fortran optional arguments that are non-present result in a
849 NULL host address here. This can safely be ignored as it is
850 not possible to 'update' a non-present optional argument. */
854 acc_prof_info prof_info
;
855 acc_api_info api_info
;
856 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
859 prof_info
.async
= async
;
860 prof_info
.async_queue
= prof_info
.async
;
863 gomp_mutex_lock (&acc_dev
->lock
);
865 n
= lookup_host (acc_dev
, h
, s
);
869 gomp_mutex_unlock (&acc_dev
->lock
);
870 gomp_fatal ("[%p,%d] is not mapped", h
, (int)s
);
873 d
= (void *) (n
->tgt
->tgt_start
+ n
->tgt_offset
874 + (uintptr_t) h
- n
->host_start
);
876 goacc_aq aq
= get_goacc_asyncqueue (async
);
879 gomp_copy_host2dev (acc_dev
, aq
, d
, h
, s
, /* TODO: cbuf? */ NULL
);
881 gomp_copy_dev2host (acc_dev
, aq
, h
, d
, s
);
883 gomp_mutex_unlock (&acc_dev
->lock
);
887 thr
->prof_info
= NULL
;
888 thr
->api_info
= NULL
;
893 acc_update_device (void *h
, size_t s
)
895 update_dev_host (1, h
, s
, acc_async_sync
);
899 acc_update_device_async (void *h
, size_t s
, int async
)
901 update_dev_host (1, h
, s
, async
);
905 acc_update_self (void *h
, size_t s
)
907 update_dev_host (0, h
, s
, acc_async_sync
);
911 acc_update_self_async (void *h
, size_t s
, int async
)
913 update_dev_host (0, h
, s
, async
);
917 gomp_acc_insert_pointer (size_t mapnum
, void **hostaddrs
, size_t *sizes
,
918 void *kinds
, int async
)
920 struct target_mem_desc
*tgt
;
921 struct goacc_thread
*thr
= goacc_thread ();
922 struct gomp_device_descr
*acc_dev
= thr
->dev
;
924 if (*hostaddrs
== NULL
)
927 if (acc_is_present (*hostaddrs
, *sizes
))
930 gomp_mutex_lock (&acc_dev
->lock
);
931 n
= lookup_host (acc_dev
, *hostaddrs
, *sizes
);
932 gomp_mutex_unlock (&acc_dev
->lock
);
935 for (size_t i
= 0; i
< tgt
->list_count
; i
++)
936 if (tgt
->list
[i
].key
== n
)
938 for (size_t j
= 0; j
< mapnum
; j
++)
939 if (i
+ j
< tgt
->list_count
&& tgt
->list
[i
+ j
].key
)
941 tgt
->list
[i
+ j
].key
->refcount
++;
942 tgt
->list
[i
+ j
].key
->dynamic_refcount
++;
946 /* Should not reach here. */
947 gomp_fatal ("Dynamic refcount incrementing failed for pointer/pset");
950 gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__
);
951 goacc_aq aq
= get_goacc_asyncqueue (async
);
952 tgt
= gomp_map_vars_async (acc_dev
, aq
, mapnum
, hostaddrs
,
953 NULL
, sizes
, kinds
, true, GOMP_MAP_VARS_OPENACC
);
954 gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__
);
956 /* Initialize dynamic refcount. */
957 tgt
->list
[0].key
->dynamic_refcount
= 1;
959 gomp_mutex_lock (&acc_dev
->lock
);
960 tgt
->prev
= acc_dev
->openacc
.data_environ
;
961 acc_dev
->openacc
.data_environ
= tgt
;
962 gomp_mutex_unlock (&acc_dev
->lock
);
966 gomp_acc_remove_pointer (void *h
, size_t s
, bool force_copyfrom
, int async
,
967 int finalize
, int mapnum
)
969 struct goacc_thread
*thr
= goacc_thread ();
970 struct gomp_device_descr
*acc_dev
= thr
->dev
;
972 struct target_mem_desc
*t
;
973 int minrefs
= (mapnum
== 1) ? 2 : 3;
975 if (!acc_is_present (h
, s
))
978 gomp_mutex_lock (&acc_dev
->lock
);
980 n
= lookup_host (acc_dev
, h
, 1);
984 gomp_mutex_unlock (&acc_dev
->lock
);
985 gomp_fatal ("%p is not a mapped block", (void *)h
);
988 gomp_debug (0, " %s: restore mappings\n", __FUNCTION__
);
992 if (n
->refcount
< n
->dynamic_refcount
)
994 gomp_mutex_unlock (&acc_dev
->lock
);
995 gomp_fatal ("Dynamic reference counting assert fail\n");
1000 n
->refcount
-= n
->dynamic_refcount
;
1001 n
->dynamic_refcount
= 0;
1003 else if (n
->dynamic_refcount
)
1005 n
->dynamic_refcount
--;
1009 gomp_mutex_unlock (&acc_dev
->lock
);
1011 if (n
->refcount
== 0)
1013 if (t
->refcount
== minrefs
)
1015 /* This is the last reference, so pull the descriptor off the
1016 chain. This prevents gomp_unmap_vars via gomp_unmap_tgt from
1017 freeing the device memory. */
1018 struct target_mem_desc
*tp
;
1019 for (tp
= NULL
, t
= acc_dev
->openacc
.data_environ
; t
!= NULL
;
1020 tp
= t
, t
= t
->prev
)
1027 acc_dev
->openacc
.data_environ
= t
->prev
;
1033 /* Set refcount to 1 to allow gomp_unmap_vars to unmap it. */
1035 t
->refcount
= minrefs
;
1036 for (size_t i
= 0; i
< t
->list_count
; i
++)
1037 if (t
->list
[i
].key
== n
)
1039 t
->list
[i
].copy_from
= force_copyfrom
? 1 : 0;
1043 /* If running synchronously, unmap immediately. */
1044 if (async
< acc_async_noval
)
1045 gomp_unmap_vars (t
, true);
1048 goacc_aq aq
= get_goacc_asyncqueue (async
);
1049 gomp_unmap_vars_async (t
, true, aq
);
1053 gomp_mutex_unlock (&acc_dev
->lock
);
1055 gomp_debug (0, " %s: mappings restored\n", __FUNCTION__
);