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
;
132 struct goacc_thread
*thr
= goacc_thread ();
134 assert (thr
&& thr
->dev
);
136 struct gomp_device_descr
*acc_dev
= thr
->dev
;
138 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
141 acc_prof_info prof_info
;
142 acc_api_info api_info
;
143 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
145 gomp_mutex_lock (&acc_dev
->lock
);
147 /* We don't have to call lazy open here, as the ptr value must have
148 been returned by acc_malloc. It's not permitted to pass NULL in
149 (unless you got that null from acc_malloc). */
150 if ((k
= lookup_dev (acc_dev
->openacc
.data_environ
, d
, 1)))
152 void *offset
= d
- k
->tgt
->tgt_start
+ k
->tgt_offset
;
153 void *h
= k
->host_start
+ offset
;
154 size_t h_size
= k
->host_end
- k
->host_start
;
155 gomp_mutex_unlock (&acc_dev
->lock
);
156 /* PR92503 "[OpenACC] Behavior of 'acc_free' if the memory space is still
157 used in a mapping". */
158 gomp_fatal ("refusing to free device memory space at %p that is still"
159 " mapped at [%p,+%d]",
163 gomp_mutex_unlock (&acc_dev
->lock
);
165 if (!acc_dev
->free_func (acc_dev
->target_id
, d
))
166 gomp_fatal ("error in freeing device memory in %s", __FUNCTION__
);
170 thr
->prof_info
= NULL
;
171 thr
->api_info
= NULL
;
176 memcpy_tofrom_device (bool from
, void *d
, void *h
, size_t s
, int async
,
177 const char *libfnname
)
179 /* No need to call lazy open here, as the device pointer must have
180 been obtained from a routine that did that. */
181 struct goacc_thread
*thr
= goacc_thread ();
183 assert (thr
&& thr
->dev
);
185 if (thr
->dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
194 acc_prof_info prof_info
;
195 acc_api_info api_info
;
196 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
199 prof_info
.async
= async
;
200 prof_info
.async_queue
= prof_info
.async
;
203 goacc_aq aq
= get_goacc_asyncqueue (async
);
205 gomp_copy_dev2host (thr
->dev
, aq
, h
, d
, s
);
207 gomp_copy_host2dev (thr
->dev
, aq
, d
, h
, s
, /* TODO: cbuf? */ NULL
);
211 thr
->prof_info
= NULL
;
212 thr
->api_info
= NULL
;
217 acc_memcpy_to_device (void *d
, void *h
, size_t s
)
219 memcpy_tofrom_device (false, d
, h
, s
, acc_async_sync
, __FUNCTION__
);
223 acc_memcpy_to_device_async (void *d
, void *h
, size_t s
, int async
)
225 memcpy_tofrom_device (false, d
, h
, s
, async
, __FUNCTION__
);
229 acc_memcpy_from_device (void *h
, void *d
, size_t s
)
231 memcpy_tofrom_device (true, d
, h
, s
, acc_async_sync
, __FUNCTION__
);
235 acc_memcpy_from_device_async (void *h
, void *d
, size_t s
, int async
)
237 memcpy_tofrom_device (true, d
, h
, s
, async
, __FUNCTION__
);
240 /* Return the device pointer that corresponds to host data H. Or NULL
244 acc_deviceptr (void *h
)
250 goacc_lazy_initialize ();
252 struct goacc_thread
*thr
= goacc_thread ();
253 struct gomp_device_descr
*dev
= thr
->dev
;
255 if (thr
->dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
258 /* In the following, no OpenACC Profiling Interface events can possibly be
261 gomp_mutex_lock (&dev
->lock
);
263 n
= lookup_host (dev
, h
, 1);
267 gomp_mutex_unlock (&dev
->lock
);
271 offset
= h
- n
->host_start
;
273 d
= n
->tgt
->tgt_start
+ n
->tgt_offset
+ offset
;
275 gomp_mutex_unlock (&dev
->lock
);
280 /* Return the host pointer that corresponds to device data D. Or NULL
284 acc_hostptr (void *d
)
290 goacc_lazy_initialize ();
292 struct goacc_thread
*thr
= goacc_thread ();
293 struct gomp_device_descr
*acc_dev
= thr
->dev
;
295 if (thr
->dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
298 /* In the following, no OpenACC Profiling Interface events can possibly be
301 gomp_mutex_lock (&acc_dev
->lock
);
303 n
= lookup_dev (acc_dev
->openacc
.data_environ
, d
, 1);
307 gomp_mutex_unlock (&acc_dev
->lock
);
311 offset
= d
- n
->tgt
->tgt_start
+ n
->tgt_offset
;
313 h
= n
->host_start
+ offset
;
315 gomp_mutex_unlock (&acc_dev
->lock
);
320 /* Return 1 if host data [H,+S] is present on the device. */
323 acc_is_present (void *h
, size_t s
)
330 goacc_lazy_initialize ();
332 struct goacc_thread
*thr
= goacc_thread ();
333 struct gomp_device_descr
*acc_dev
= thr
->dev
;
335 if (thr
->dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
338 /* In the following, no OpenACC Profiling Interface events can possibly be
341 gomp_mutex_lock (&acc_dev
->lock
);
343 n
= lookup_host (acc_dev
, h
, s
);
345 if (n
&& ((uintptr_t)h
< n
->host_start
346 || (uintptr_t)h
+ s
> n
->host_end
347 || s
> n
->host_end
- n
->host_start
))
350 gomp_mutex_unlock (&acc_dev
->lock
);
355 /* Create a mapping for host [H,+S] -> device [D,+S] */
358 acc_map_data (void *h
, void *d
, size_t s
)
360 struct target_mem_desc
*tgt
= NULL
;
365 unsigned short kinds
= GOMP_MAP_ALLOC
;
367 goacc_lazy_initialize ();
369 struct goacc_thread
*thr
= goacc_thread ();
370 struct gomp_device_descr
*acc_dev
= thr
->dev
;
372 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
375 gomp_fatal ("cannot map data on shared-memory system");
379 struct goacc_thread
*thr
= goacc_thread ();
382 gomp_fatal ("[%p,+%d]->[%p,+%d] is a bad map",
383 (void *)h
, (int)s
, (void *)d
, (int)s
);
385 acc_prof_info prof_info
;
386 acc_api_info api_info
;
387 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
389 gomp_mutex_lock (&acc_dev
->lock
);
391 if (lookup_host (acc_dev
, h
, s
))
393 gomp_mutex_unlock (&acc_dev
->lock
);
394 gomp_fatal ("host address [%p, +%d] is already mapped", (void *)h
,
398 if (lookup_dev (thr
->dev
->openacc
.data_environ
, d
, s
))
400 gomp_mutex_unlock (&acc_dev
->lock
);
401 gomp_fatal ("device address [%p, +%d] is already mapped", (void *)d
,
405 gomp_mutex_unlock (&acc_dev
->lock
);
407 tgt
= gomp_map_vars (acc_dev
, mapnum
, &hostaddrs
, &devaddrs
, &sizes
,
408 &kinds
, true, GOMP_MAP_VARS_OPENACC
);
409 splay_tree_key n
= tgt
->list
[0].key
;
410 assert (n
->refcount
== 1);
411 assert (n
->dynamic_refcount
== 0);
412 /* Special reference counting behavior. */
413 n
->refcount
= REFCOUNT_INFINITY
;
417 thr
->prof_info
= NULL
;
418 thr
->api_info
= NULL
;
422 gomp_mutex_lock (&acc_dev
->lock
);
423 tgt
->prev
= acc_dev
->openacc
.data_environ
;
424 acc_dev
->openacc
.data_environ
= tgt
;
425 gomp_mutex_unlock (&acc_dev
->lock
);
429 acc_unmap_data (void *h
)
431 struct goacc_thread
*thr
= goacc_thread ();
432 struct gomp_device_descr
*acc_dev
= thr
->dev
;
434 /* No need to call lazy open, as the address must have been mapped. */
436 /* This is a no-op on shared-memory targets. */
437 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
440 acc_prof_info prof_info
;
441 acc_api_info api_info
;
442 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
446 gomp_mutex_lock (&acc_dev
->lock
);
448 splay_tree_key n
= lookup_host (acc_dev
, h
, 1);
449 struct target_mem_desc
*t
;
453 gomp_mutex_unlock (&acc_dev
->lock
);
454 gomp_fatal ("%p is not a mapped block", (void *)h
);
457 host_size
= n
->host_end
- n
->host_start
;
459 if (n
->host_start
!= (uintptr_t) h
)
461 gomp_mutex_unlock (&acc_dev
->lock
);
462 gomp_fatal ("[%p,%d] surrounds %p",
463 (void *) n
->host_start
, (int) host_size
, (void *) h
);
465 /* TODO This currently doesn't catch 'REFCOUNT_INFINITY' usage different from
466 'acc_map_data'. Maybe 'dynamic_refcount' can be used for disambiguating
467 the different 'REFCOUNT_INFINITY' cases, or simply separate
468 'REFCOUNT_INFINITY' values per different usage ('REFCOUNT_ACC_MAP_DATA'
470 else if (n
->refcount
!= REFCOUNT_INFINITY
)
472 gomp_mutex_unlock (&acc_dev
->lock
);
473 gomp_fatal ("refusing to unmap block [%p,+%d] that has not been mapped"
474 " by 'acc_map_data'",
475 (void *) h
, (int) host_size
);
478 /* Mark for removal. */
483 if (t
->refcount
== 2)
485 struct target_mem_desc
*tp
;
487 /* This is the last reference, so pull the descriptor off the
488 chain. This avoids gomp_unmap_vars via gomp_unmap_tgt from
489 freeing the device memory. */
493 for (tp
= NULL
, t
= acc_dev
->openacc
.data_environ
; t
!= NULL
;
500 acc_dev
->openacc
.data_environ
= t
->prev
;
506 gomp_mutex_unlock (&acc_dev
->lock
);
508 gomp_unmap_vars (t
, true);
512 thr
->prof_info
= NULL
;
513 thr
->api_info
= NULL
;
517 #define FLAG_PRESENT (1 << 0)
518 #define FLAG_CREATE (1 << 1)
519 #define FLAG_COPY (1 << 2)
522 present_create_copy (unsigned f
, void *h
, size_t s
, int async
)
528 gomp_fatal ("[%p,+%d] is a bad range", (void *)h
, (int)s
);
530 goacc_lazy_initialize ();
532 struct goacc_thread
*thr
= goacc_thread ();
533 struct gomp_device_descr
*acc_dev
= thr
->dev
;
535 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
538 acc_prof_info prof_info
;
539 acc_api_info api_info
;
540 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
543 prof_info
.async
= async
;
544 prof_info
.async_queue
= prof_info
.async
;
547 gomp_mutex_lock (&acc_dev
->lock
);
549 n
= lookup_host (acc_dev
, h
, s
);
553 d
= (void *) (n
->tgt
->tgt_start
+ n
->tgt_offset
+ h
- n
->host_start
);
555 if (!(f
& FLAG_PRESENT
))
557 gomp_mutex_unlock (&acc_dev
->lock
);
558 gomp_fatal ("[%p,+%d] already mapped to [%p,+%d]",
559 (void *)h
, (int)s
, (void *)d
, (int)s
);
561 if ((h
+ s
) > (void *)n
->host_end
)
563 gomp_mutex_unlock (&acc_dev
->lock
);
564 gomp_fatal ("[%p,+%d] not mapped", (void *)h
, (int)s
);
567 if (n
->refcount
!= REFCOUNT_INFINITY
)
570 n
->dynamic_refcount
++;
572 gomp_mutex_unlock (&acc_dev
->lock
);
574 else if (!(f
& FLAG_CREATE
))
576 gomp_mutex_unlock (&acc_dev
->lock
);
577 gomp_fatal ("[%p,+%d] not mapped", (void *)h
, (int)s
);
581 struct target_mem_desc
*tgt
;
583 unsigned short kinds
;
589 kinds
= GOMP_MAP_ALLOC
;
591 gomp_mutex_unlock (&acc_dev
->lock
);
593 goacc_aq aq
= get_goacc_asyncqueue (async
);
595 tgt
= gomp_map_vars_async (acc_dev
, aq
, mapnum
, &hostaddrs
, NULL
, &s
,
596 &kinds
, true, GOMP_MAP_VARS_OPENACC
);
597 /* Initialize dynamic refcount. */
598 tgt
->list
[0].key
->dynamic_refcount
= 1;
600 gomp_mutex_lock (&acc_dev
->lock
);
603 tgt
->prev
= acc_dev
->openacc
.data_environ
;
604 acc_dev
->openacc
.data_environ
= tgt
;
606 gomp_mutex_unlock (&acc_dev
->lock
);
611 thr
->prof_info
= NULL
;
612 thr
->api_info
= NULL
;
619 acc_create (void *h
, size_t s
)
621 return present_create_copy (FLAG_PRESENT
| FLAG_CREATE
, h
, s
, acc_async_sync
);
625 acc_create_async (void *h
, size_t s
, int async
)
627 present_create_copy (FLAG_PRESENT
| FLAG_CREATE
, h
, s
, async
);
630 /* acc_present_or_create used to be what acc_create is now. */
631 /* acc_pcreate is acc_present_or_create by a different name. */
632 #ifdef HAVE_ATTRIBUTE_ALIAS
633 strong_alias (acc_create
, acc_present_or_create
)
634 strong_alias (acc_create
, acc_pcreate
)
637 acc_present_or_create (void *h
, size_t s
)
639 return acc_create (h
, s
);
643 acc_pcreate (void *h
, size_t s
)
645 return acc_create (h
, s
);
650 acc_copyin (void *h
, size_t s
)
652 return present_create_copy (FLAG_PRESENT
| FLAG_CREATE
| FLAG_COPY
, h
, s
,
657 acc_copyin_async (void *h
, size_t s
, int async
)
659 present_create_copy (FLAG_PRESENT
| FLAG_CREATE
| FLAG_COPY
, h
, s
, async
);
662 /* acc_present_or_copyin used to be what acc_copyin is now. */
663 /* acc_pcopyin is acc_present_or_copyin by a different name. */
664 #ifdef HAVE_ATTRIBUTE_ALIAS
665 strong_alias (acc_copyin
, acc_present_or_copyin
)
666 strong_alias (acc_copyin
, acc_pcopyin
)
669 acc_present_or_copyin (void *h
, size_t s
)
671 return acc_copyin (h
, s
);
675 acc_pcopyin (void *h
, size_t s
)
677 return acc_copyin (h
, s
);
681 #define FLAG_COPYOUT (1 << 0)
682 #define FLAG_FINALIZE (1 << 1)
685 delete_copyout (unsigned f
, void *h
, size_t s
, int async
, const char *libfnname
)
689 struct goacc_thread
*thr
= goacc_thread ();
690 struct gomp_device_descr
*acc_dev
= thr
->dev
;
692 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
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
);
700 prof_info
.async
= async
;
701 prof_info
.async_queue
= prof_info
.async
;
704 gomp_mutex_lock (&acc_dev
->lock
);
706 n
= lookup_host (acc_dev
, h
, s
);
708 /* No need to call lazy open, as the data must already have been
713 gomp_mutex_unlock (&acc_dev
->lock
);
714 gomp_fatal ("[%p,%d] is not mapped", (void *)h
, (int)s
);
717 d
= (void *) (n
->tgt
->tgt_start
+ n
->tgt_offset
718 + (uintptr_t) h
- n
->host_start
);
720 if ((uintptr_t) h
< n
->host_start
|| (uintptr_t) h
+ s
> n
->host_end
)
722 size_t host_size
= n
->host_end
- n
->host_start
;
723 gomp_mutex_unlock (&acc_dev
->lock
);
724 gomp_fatal ("[%p,+%d] outside mapped block [%p,+%d]",
725 (void *) h
, (int) s
, (void *) n
->host_start
, (int) host_size
);
728 if (n
->refcount
== REFCOUNT_INFINITY
)
731 n
->dynamic_refcount
= 0;
733 if (n
->refcount
< n
->dynamic_refcount
)
735 gomp_mutex_unlock (&acc_dev
->lock
);
736 gomp_fatal ("Dynamic reference counting assert fail\n");
739 if (f
& FLAG_FINALIZE
)
741 n
->refcount
-= n
->dynamic_refcount
;
742 n
->dynamic_refcount
= 0;
744 else if (n
->dynamic_refcount
)
746 n
->dynamic_refcount
--;
750 if (n
->refcount
== 0)
752 if (n
->tgt
->refcount
== 2)
754 struct target_mem_desc
*tp
, *t
;
755 for (tp
= NULL
, t
= acc_dev
->openacc
.data_environ
; t
!= NULL
;
762 acc_dev
->openacc
.data_environ
= t
->prev
;
767 if (f
& FLAG_COPYOUT
)
769 goacc_aq aq
= get_goacc_asyncqueue (async
);
770 gomp_copy_dev2host (acc_dev
, aq
, h
, d
, s
);
772 gomp_remove_var (acc_dev
, n
);
775 gomp_mutex_unlock (&acc_dev
->lock
);
779 thr
->prof_info
= NULL
;
780 thr
->api_info
= NULL
;
785 acc_delete (void *h
, size_t s
)
787 delete_copyout (0, h
, s
, acc_async_sync
, __FUNCTION__
);
791 acc_delete_async (void *h
, size_t s
, int async
)
793 delete_copyout (0, h
, s
, async
, __FUNCTION__
);
797 acc_delete_finalize (void *h
, size_t s
)
799 delete_copyout (FLAG_FINALIZE
, h
, s
, acc_async_sync
, __FUNCTION__
);
803 acc_delete_finalize_async (void *h
, size_t s
, int async
)
805 delete_copyout (FLAG_FINALIZE
, h
, s
, async
, __FUNCTION__
);
809 acc_copyout (void *h
, size_t s
)
811 delete_copyout (FLAG_COPYOUT
, h
, s
, acc_async_sync
, __FUNCTION__
);
815 acc_copyout_async (void *h
, size_t s
, int async
)
817 delete_copyout (FLAG_COPYOUT
, h
, s
, async
, __FUNCTION__
);
821 acc_copyout_finalize (void *h
, size_t s
)
823 delete_copyout (FLAG_COPYOUT
| FLAG_FINALIZE
, h
, s
, acc_async_sync
,
828 acc_copyout_finalize_async (void *h
, size_t s
, int async
)
830 delete_copyout (FLAG_COPYOUT
| FLAG_FINALIZE
, h
, s
, async
, __FUNCTION__
);
834 update_dev_host (int is_dev
, void *h
, size_t s
, int async
)
839 goacc_lazy_initialize ();
841 struct goacc_thread
*thr
= goacc_thread ();
842 struct gomp_device_descr
*acc_dev
= thr
->dev
;
844 if (acc_dev
->capabilities
& GOMP_OFFLOAD_CAP_SHARED_MEM
)
847 /* Fortran optional arguments that are non-present result in a
848 NULL host address here. This can safely be ignored as it is
849 not possible to 'update' a non-present optional argument. */
853 acc_prof_info prof_info
;
854 acc_api_info api_info
;
855 bool profiling_p
= GOACC_PROFILING_SETUP_P (thr
, &prof_info
, &api_info
);
858 prof_info
.async
= async
;
859 prof_info
.async_queue
= prof_info
.async
;
862 gomp_mutex_lock (&acc_dev
->lock
);
864 n
= lookup_host (acc_dev
, h
, s
);
868 gomp_mutex_unlock (&acc_dev
->lock
);
869 gomp_fatal ("[%p,%d] is not mapped", h
, (int)s
);
872 d
= (void *) (n
->tgt
->tgt_start
+ n
->tgt_offset
873 + (uintptr_t) h
- n
->host_start
);
875 goacc_aq aq
= get_goacc_asyncqueue (async
);
878 gomp_copy_host2dev (acc_dev
, aq
, d
, h
, s
, /* TODO: cbuf? */ NULL
);
880 gomp_copy_dev2host (acc_dev
, aq
, h
, d
, s
);
882 gomp_mutex_unlock (&acc_dev
->lock
);
886 thr
->prof_info
= NULL
;
887 thr
->api_info
= NULL
;
892 acc_update_device (void *h
, size_t s
)
894 update_dev_host (1, h
, s
, acc_async_sync
);
898 acc_update_device_async (void *h
, size_t s
, int async
)
900 update_dev_host (1, h
, s
, async
);
904 acc_update_self (void *h
, size_t s
)
906 update_dev_host (0, h
, s
, acc_async_sync
);
910 acc_update_self_async (void *h
, size_t s
, int async
)
912 update_dev_host (0, h
, s
, async
);
916 gomp_acc_insert_pointer (size_t mapnum
, void **hostaddrs
, size_t *sizes
,
917 void *kinds
, int async
)
919 struct target_mem_desc
*tgt
;
920 struct goacc_thread
*thr
= goacc_thread ();
921 struct gomp_device_descr
*acc_dev
= thr
->dev
;
923 if (*hostaddrs
== NULL
)
926 if (acc_is_present (*hostaddrs
, *sizes
))
929 gomp_mutex_lock (&acc_dev
->lock
);
930 n
= lookup_host (acc_dev
, *hostaddrs
, *sizes
);
931 gomp_mutex_unlock (&acc_dev
->lock
);
934 for (size_t i
= 0; i
< tgt
->list_count
; i
++)
935 if (tgt
->list
[i
].key
== n
)
937 for (size_t j
= 0; j
< mapnum
; j
++)
938 if (i
+ j
< tgt
->list_count
&& tgt
->list
[i
+ j
].key
)
940 tgt
->list
[i
+ j
].key
->refcount
++;
941 tgt
->list
[i
+ j
].key
->dynamic_refcount
++;
945 /* Should not reach here. */
946 gomp_fatal ("Dynamic refcount incrementing failed for pointer/pset");
949 gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__
);
950 goacc_aq aq
= get_goacc_asyncqueue (async
);
951 tgt
= gomp_map_vars_async (acc_dev
, aq
, mapnum
, hostaddrs
,
952 NULL
, sizes
, kinds
, true, GOMP_MAP_VARS_OPENACC
);
953 gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__
);
955 /* Initialize dynamic refcount. */
956 tgt
->list
[0].key
->dynamic_refcount
= 1;
958 gomp_mutex_lock (&acc_dev
->lock
);
959 tgt
->prev
= acc_dev
->openacc
.data_environ
;
960 acc_dev
->openacc
.data_environ
= tgt
;
961 gomp_mutex_unlock (&acc_dev
->lock
);
965 gomp_acc_remove_pointer (void *h
, size_t s
, bool force_copyfrom
, int async
,
966 int finalize
, int mapnum
)
968 struct goacc_thread
*thr
= goacc_thread ();
969 struct gomp_device_descr
*acc_dev
= thr
->dev
;
971 struct target_mem_desc
*t
;
972 int minrefs
= (mapnum
== 1) ? 2 : 3;
974 if (!acc_is_present (h
, s
))
977 gomp_mutex_lock (&acc_dev
->lock
);
979 n
= lookup_host (acc_dev
, h
, 1);
983 gomp_mutex_unlock (&acc_dev
->lock
);
984 gomp_fatal ("%p is not a mapped block", (void *)h
);
987 gomp_debug (0, " %s: restore mappings\n", __FUNCTION__
);
991 if (n
->refcount
< n
->dynamic_refcount
)
993 gomp_mutex_unlock (&acc_dev
->lock
);
994 gomp_fatal ("Dynamic reference counting assert fail\n");
999 n
->refcount
-= n
->dynamic_refcount
;
1000 n
->dynamic_refcount
= 0;
1002 else if (n
->dynamic_refcount
)
1004 n
->dynamic_refcount
--;
1008 gomp_mutex_unlock (&acc_dev
->lock
);
1010 if (n
->refcount
== 0)
1012 if (t
->refcount
== minrefs
)
1014 /* This is the last reference, so pull the descriptor off the
1015 chain. This prevents gomp_unmap_vars via gomp_unmap_tgt from
1016 freeing the device memory. */
1017 struct target_mem_desc
*tp
;
1018 for (tp
= NULL
, t
= acc_dev
->openacc
.data_environ
; t
!= NULL
;
1019 tp
= t
, t
= t
->prev
)
1026 acc_dev
->openacc
.data_environ
= t
->prev
;
1032 /* Set refcount to 1 to allow gomp_unmap_vars to unmap it. */
1034 t
->refcount
= minrefs
;
1035 for (size_t i
= 0; i
< t
->list_count
; i
++)
1036 if (t
->list
[i
].key
== n
)
1038 t
->list
[i
].copy_from
= force_copyfrom
? 1 : 0;
1042 /* If running synchronously, unmap immediately. */
1043 if (async
< acc_async_noval
)
1044 gomp_unmap_vars (t
, true);
1047 goacc_aq aq
= get_goacc_asyncqueue (async
);
1048 gomp_unmap_vars_async (t
, true, aq
);
1052 gomp_mutex_unlock (&acc_dev
->lock
);
1054 gomp_debug (0, " %s: mappings restored\n", __FUNCTION__
);