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 tgt
->list
[0].key
->refcount
= REFCOUNT_INFINITY
;
414 thr
->prof_info
= NULL
;
415 thr
->api_info
= NULL
;
419 gomp_mutex_lock (&acc_dev
->lock
);
420 tgt
->prev
= acc_dev
->openacc
.data_environ
;
421 acc_dev
->openacc
.data_environ
= tgt
;
422 gomp_mutex_unlock (&acc_dev
->lock
);
426 acc_unmap_data (void *h
)
428 struct goacc_thread
*thr
= goacc_thread ();
429 struct gomp_device_descr
*acc_dev
= thr
->dev
;
431 /* No need to call lazy open, as the address must have been mapped. */
433 /* This is a no-op on shared-memory targets. */
434 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
437 acc_prof_info prof_info
;
438 acc_api_info api_info
;
439 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
443 gomp_mutex_lock (&acc_dev
->lock
);
445 splay_tree_key n
= lookup_host (acc_dev
, h
, 1);
446 struct target_mem_desc
*t
;
450 gomp_mutex_unlock (&acc_dev
->lock
);
451 gomp_fatal ("%p is not a mapped block", (void *)h
);
454 host_size
= n
->host_end
- n
->host_start
;
456 if (n
->host_start
!= (uintptr_t) h
)
458 gomp_mutex_unlock (&acc_dev
->lock
);
459 gomp_fatal ("[%p,%d] surrounds %p",
460 (void *) n
->host_start
, (int) host_size
, (void *) h
);
463 /* Mark for removal. */
468 if (t
->refcount
== 2)
470 struct target_mem_desc
*tp
;
472 /* This is the last reference, so pull the descriptor off the
473 chain. This avoids gomp_unmap_vars via gomp_unmap_tgt from
474 freeing the device memory. */
478 for (tp
= NULL
, t
= acc_dev
->openacc
.data_environ
; t
!= NULL
;
485 acc_dev
->openacc
.data_environ
= t
->prev
;
491 gomp_mutex_unlock (&acc_dev
->lock
);
493 gomp_unmap_vars (t
, true);
497 thr
->prof_info
= NULL
;
498 thr
->api_info
= NULL
;
502 #define FLAG_PRESENT (1 << 0)
503 #define FLAG_CREATE (1 << 1)
504 #define FLAG_COPY (1 << 2)
507 present_create_copy (unsigned f
, void *h
, size_t s
, int async
)
513 gomp_fatal ("[%p,+%d] is a bad range", (void *)h
, (int)s
);
515 goacc_lazy_initialize ();
517 struct goacc_thread
*thr
= goacc_thread ();
518 struct gomp_device_descr
*acc_dev
= thr
->dev
;
520 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
523 acc_prof_info prof_info
;
524 acc_api_info api_info
;
525 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
528 prof_info
.async
= async
;
529 prof_info
.async_queue
= prof_info
.async
;
532 gomp_mutex_lock (&acc_dev
->lock
);
534 n
= lookup_host (acc_dev
, h
, s
);
538 d
= (void *) (n
->tgt
->tgt_start
+ n
->tgt_offset
+ h
- n
->host_start
);
540 if (!(f
& FLAG_PRESENT
))
542 gomp_mutex_unlock (&acc_dev
->lock
);
543 gomp_fatal ("[%p,+%d] already mapped to [%p,+%d]",
544 (void *)h
, (int)s
, (void *)d
, (int)s
);
546 if ((h
+ s
) > (void *)n
->host_end
)
548 gomp_mutex_unlock (&acc_dev
->lock
);
549 gomp_fatal ("[%p,+%d] not mapped", (void *)h
, (int)s
);
552 if (n
->refcount
!= REFCOUNT_INFINITY
)
555 n
->dynamic_refcount
++;
557 gomp_mutex_unlock (&acc_dev
->lock
);
559 else if (!(f
& FLAG_CREATE
))
561 gomp_mutex_unlock (&acc_dev
->lock
);
562 gomp_fatal ("[%p,+%d] not mapped", (void *)h
, (int)s
);
566 struct target_mem_desc
*tgt
;
568 unsigned short kinds
;
574 kinds
= GOMP_MAP_ALLOC
;
576 gomp_mutex_unlock (&acc_dev
->lock
);
578 goacc_aq aq
= get_goacc_asyncqueue (async
);
580 tgt
= gomp_map_vars_async (acc_dev
, aq
, mapnum
, &hostaddrs
, NULL
, &s
,
581 &kinds
, true, GOMP_MAP_VARS_OPENACC
);
582 /* Initialize dynamic refcount. */
583 tgt
->list
[0].key
->dynamic_refcount
= 1;
585 gomp_mutex_lock (&acc_dev
->lock
);
588 tgt
->prev
= acc_dev
->openacc
.data_environ
;
589 acc_dev
->openacc
.data_environ
= tgt
;
591 gomp_mutex_unlock (&acc_dev
->lock
);
596 thr
->prof_info
= NULL
;
597 thr
->api_info
= NULL
;
604 acc_create (void *h
, size_t s
)
606 return present_create_copy (FLAG_PRESENT
| FLAG_CREATE
, h
, s
, acc_async_sync
);
610 acc_create_async (void *h
, size_t s
, int async
)
612 present_create_copy (FLAG_PRESENT
| FLAG_CREATE
, h
, s
, async
);
615 /* acc_present_or_create used to be what acc_create is now. */
616 /* acc_pcreate is acc_present_or_create by a different name. */
617 #ifdef HAVE_ATTRIBUTE_ALIAS
618 strong_alias (acc_create
, acc_present_or_create
)
619 strong_alias (acc_create
, acc_pcreate
)
622 acc_present_or_create (void *h
, size_t s
)
624 return acc_create (h
, s
);
628 acc_pcreate (void *h
, size_t s
)
630 return acc_create (h
, s
);
635 acc_copyin (void *h
, size_t s
)
637 return present_create_copy (FLAG_PRESENT
| FLAG_CREATE
| FLAG_COPY
, h
, s
,
642 acc_copyin_async (void *h
, size_t s
, int async
)
644 present_create_copy (FLAG_PRESENT
| FLAG_CREATE
| FLAG_COPY
, h
, s
, async
);
647 /* acc_present_or_copyin used to be what acc_copyin is now. */
648 /* acc_pcopyin is acc_present_or_copyin by a different name. */
649 #ifdef HAVE_ATTRIBUTE_ALIAS
650 strong_alias (acc_copyin
, acc_present_or_copyin
)
651 strong_alias (acc_copyin
, acc_pcopyin
)
654 acc_present_or_copyin (void *h
, size_t s
)
656 return acc_copyin (h
, s
);
660 acc_pcopyin (void *h
, size_t s
)
662 return acc_copyin (h
, s
);
666 #define FLAG_COPYOUT (1 << 0)
667 #define FLAG_FINALIZE (1 << 1)
670 delete_copyout (unsigned f
, void *h
, size_t s
, int async
, const char *libfnname
)
674 struct goacc_thread
*thr
= goacc_thread ();
675 struct gomp_device_descr
*acc_dev
= thr
->dev
;
677 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
680 acc_prof_info prof_info
;
681 acc_api_info api_info
;
682 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
685 prof_info
.async
= async
;
686 prof_info
.async_queue
= prof_info
.async
;
689 gomp_mutex_lock (&acc_dev
->lock
);
691 n
= lookup_host (acc_dev
, h
, s
);
693 /* No need to call lazy open, as the data must already have been
698 gomp_mutex_unlock (&acc_dev
->lock
);
699 gomp_fatal ("[%p,%d] is not mapped", (void *)h
, (int)s
);
702 d
= (void *) (n
->tgt
->tgt_start
+ n
->tgt_offset
703 + (uintptr_t) h
- n
->host_start
);
705 if ((uintptr_t) h
< n
->host_start
|| (uintptr_t) h
+ s
> n
->host_end
)
707 size_t host_size
= n
->host_end
- n
->host_start
;
708 gomp_mutex_unlock (&acc_dev
->lock
);
709 gomp_fatal ("[%p,+%d] outside mapped block [%p,+%d]",
710 (void *) h
, (int) s
, (void *) n
->host_start
, (int) host_size
);
713 if (n
->refcount
== REFCOUNT_INFINITY
)
716 n
->dynamic_refcount
= 0;
718 if (n
->refcount
< n
->dynamic_refcount
)
720 gomp_mutex_unlock (&acc_dev
->lock
);
721 gomp_fatal ("Dynamic reference counting assert fail\n");
724 if (f
& FLAG_FINALIZE
)
726 n
->refcount
-= n
->dynamic_refcount
;
727 n
->dynamic_refcount
= 0;
729 else if (n
->dynamic_refcount
)
731 n
->dynamic_refcount
--;
735 if (n
->refcount
== 0)
737 if (n
->tgt
->refcount
== 2)
739 struct target_mem_desc
*tp
, *t
;
740 for (tp
= NULL
, t
= acc_dev
->openacc
.data_environ
; t
!= NULL
;
747 acc_dev
->openacc
.data_environ
= t
->prev
;
752 if (f
& FLAG_COPYOUT
)
754 goacc_aq aq
= get_goacc_asyncqueue (async
);
755 gomp_copy_dev2host (acc_dev
, aq
, h
, d
, s
);
757 gomp_remove_var (acc_dev
, n
);
760 gomp_mutex_unlock (&acc_dev
->lock
);
764 thr
->prof_info
= NULL
;
765 thr
->api_info
= NULL
;
770 acc_delete (void *h
, size_t s
)
772 delete_copyout (0, h
, s
, acc_async_sync
, __FUNCTION__
);
776 acc_delete_async (void *h
, size_t s
, int async
)
778 delete_copyout (0, h
, s
, async
, __FUNCTION__
);
782 acc_delete_finalize (void *h
, size_t s
)
784 delete_copyout (FLAG_FINALIZE
, h
, s
, acc_async_sync
, __FUNCTION__
);
788 acc_delete_finalize_async (void *h
, size_t s
, int async
)
790 delete_copyout (FLAG_FINALIZE
, h
, s
, async
, __FUNCTION__
);
794 acc_copyout (void *h
, size_t s
)
796 delete_copyout (FLAG_COPYOUT
, h
, s
, acc_async_sync
, __FUNCTION__
);
800 acc_copyout_async (void *h
, size_t s
, int async
)
802 delete_copyout (FLAG_COPYOUT
, h
, s
, async
, __FUNCTION__
);
806 acc_copyout_finalize (void *h
, size_t s
)
808 delete_copyout (FLAG_COPYOUT
| FLAG_FINALIZE
, h
, s
, acc_async_sync
,
813 acc_copyout_finalize_async (void *h
, size_t s
, int async
)
815 delete_copyout (FLAG_COPYOUT
| FLAG_FINALIZE
, h
, s
, async
, __FUNCTION__
);
819 update_dev_host (int is_dev
, void *h
, size_t s
, int async
)
824 goacc_lazy_initialize ();
826 struct goacc_thread
*thr
= goacc_thread ();
827 struct gomp_device_descr
*acc_dev
= thr
->dev
;
829 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
832 /* Fortran optional arguments that are non-present result in a
833 NULL host address here. This can safely be ignored as it is
834 not possible to 'update' a non-present optional argument. */
838 acc_prof_info prof_info
;
839 acc_api_info api_info
;
840 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
843 prof_info
.async
= async
;
844 prof_info
.async_queue
= prof_info
.async
;
847 gomp_mutex_lock (&acc_dev
->lock
);
849 n
= lookup_host (acc_dev
, h
, s
);
853 gomp_mutex_unlock (&acc_dev
->lock
);
854 gomp_fatal ("[%p,%d] is not mapped", h
, (int)s
);
857 d
= (void *) (n
->tgt
->tgt_start
+ n
->tgt_offset
858 + (uintptr_t) h
- n
->host_start
);
860 goacc_aq aq
= get_goacc_asyncqueue (async
);
863 gomp_copy_host2dev (acc_dev
, aq
, d
, h
, s
, /* TODO: cbuf? */ NULL
);
865 gomp_copy_dev2host (acc_dev
, aq
, h
, d
, s
);
867 gomp_mutex_unlock (&acc_dev
->lock
);
871 thr
->prof_info
= NULL
;
872 thr
->api_info
= NULL
;
877 acc_update_device (void *h
, size_t s
)
879 update_dev_host (1, h
, s
, acc_async_sync
);
883 acc_update_device_async (void *h
, size_t s
, int async
)
885 update_dev_host (1, h
, s
, async
);
889 acc_update_self (void *h
, size_t s
)
891 update_dev_host (0, h
, s
, acc_async_sync
);
895 acc_update_self_async (void *h
, size_t s
, int async
)
897 update_dev_host (0, h
, s
, async
);
901 gomp_acc_insert_pointer (size_t mapnum
, void **hostaddrs
, size_t *sizes
,
902 void *kinds
, int async
)
904 struct target_mem_desc
*tgt
;
905 struct goacc_thread
*thr
= goacc_thread ();
906 struct gomp_device_descr
*acc_dev
= thr
->dev
;
908 if (*hostaddrs
== NULL
)
911 if (acc_is_present (*hostaddrs
, *sizes
))
914 gomp_mutex_lock (&acc_dev
->lock
);
915 n
= lookup_host (acc_dev
, *hostaddrs
, *sizes
);
916 gomp_mutex_unlock (&acc_dev
->lock
);
919 for (size_t i
= 0; i
< tgt
->list_count
; i
++)
920 if (tgt
->list
[i
].key
== n
)
922 for (size_t j
= 0; j
< mapnum
; j
++)
923 if (i
+ j
< tgt
->list_count
&& tgt
->list
[i
+ j
].key
)
925 tgt
->list
[i
+ j
].key
->refcount
++;
926 tgt
->list
[i
+ j
].key
->dynamic_refcount
++;
930 /* Should not reach here. */
931 gomp_fatal ("Dynamic refcount incrementing failed for pointer/pset");
934 gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__
);
935 goacc_aq aq
= get_goacc_asyncqueue (async
);
936 tgt
= gomp_map_vars_async (acc_dev
, aq
, mapnum
, hostaddrs
,
937 NULL
, sizes
, kinds
, true, GOMP_MAP_VARS_OPENACC
);
938 gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__
);
940 /* Initialize dynamic refcount. */
941 tgt
->list
[0].key
->dynamic_refcount
= 1;
943 gomp_mutex_lock (&acc_dev
->lock
);
944 tgt
->prev
= acc_dev
->openacc
.data_environ
;
945 acc_dev
->openacc
.data_environ
= tgt
;
946 gomp_mutex_unlock (&acc_dev
->lock
);
950 gomp_acc_remove_pointer (void *h
, size_t s
, bool force_copyfrom
, int async
,
951 int finalize
, int mapnum
)
953 struct goacc_thread
*thr
= goacc_thread ();
954 struct gomp_device_descr
*acc_dev
= thr
->dev
;
956 struct target_mem_desc
*t
;
957 int minrefs
= (mapnum
== 1) ? 2 : 3;
959 if (!acc_is_present (h
, s
))
962 gomp_mutex_lock (&acc_dev
->lock
);
964 n
= lookup_host (acc_dev
, h
, 1);
968 gomp_mutex_unlock (&acc_dev
->lock
);
969 gomp_fatal ("%p is not a mapped block", (void *)h
);
972 gomp_debug (0, " %s: restore mappings\n", __FUNCTION__
);
976 if (n
->refcount
< n
->dynamic_refcount
)
978 gomp_mutex_unlock (&acc_dev
->lock
);
979 gomp_fatal ("Dynamic reference counting assert fail\n");
984 n
->refcount
-= n
->dynamic_refcount
;
985 n
->dynamic_refcount
= 0;
987 else if (n
->dynamic_refcount
)
989 n
->dynamic_refcount
--;
993 gomp_mutex_unlock (&acc_dev
->lock
);
995 if (n
->refcount
== 0)
997 if (t
->refcount
== minrefs
)
999 /* This is the last reference, so pull the descriptor off the
1000 chain. This prevents gomp_unmap_vars via gomp_unmap_tgt from
1001 freeing the device memory. */
1002 struct target_mem_desc
*tp
;
1003 for (tp
= NULL
, t
= acc_dev
->openacc
.data_environ
; t
!= NULL
;
1004 tp
= t
, t
= t
->prev
)
1011 acc_dev
->openacc
.data_environ
= t
->prev
;
1017 /* Set refcount to 1 to allow gomp_unmap_vars to unmap it. */
1019 t
->refcount
= minrefs
;
1020 for (size_t i
= 0; i
< t
->list_count
; i
++)
1021 if (t
->list
[i
].key
== n
)
1023 t
->list
[i
].copy_from
= force_copyfrom
? 1 : 0;
1027 /* If running synchronously, unmap immediately. */
1028 if (async
< acc_async_noval
)
1029 gomp_unmap_vars (t
, true);
1032 goacc_aq aq
= get_goacc_asyncqueue (async
);
1033 gomp_unmap_vars_async (t
, true, aq
);
1037 gomp_mutex_unlock (&acc_dev
->lock
);
1039 gomp_debug (0, " %s: mappings restored\n", __FUNCTION__
);