re PR fortran/88376 (ICE in is_illegal_recursion, at fortran/resolve.c:1689)
[official-gcc.git] / libgomp / oacc-mem.c
blob26e1a7545dfd939d811128ec8f290d50861e1353
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
8 (libgomp).
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.
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.
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/>. */
29 #include "openacc.h"
30 #include "config.h"
31 #include "libgomp.h"
32 #include "gomp-constants.h"
33 #include "oacc-int.h"
34 #include <stdint.h>
35 #include <string.h>
36 #include <assert.h>
38 /* Return block containing [H->S), or NULL if not contained. The device lock
39 for DEV must be locked on entry, and remains locked on exit. */
41 static splay_tree_key
42 lookup_host (struct gomp_device_descr *dev, void *h, size_t s)
44 struct splay_tree_key_s node;
45 splay_tree_key key;
47 node.host_start = (uintptr_t) h;
48 node.host_end = (uintptr_t) h + s;
50 key = splay_tree_lookup (&dev->mem_map, &node);
52 return key;
55 /* Return block containing [D->S), or NULL if not contained.
56 The list isn't ordered by device address, so we have to iterate
57 over the whole array. This is not expected to be a common
58 operation. The device lock associated with TGT must be locked on entry, and
59 remains locked on exit. */
61 static splay_tree_key
62 lookup_dev (struct target_mem_desc *tgt, void *d, size_t s)
64 int i;
65 struct target_mem_desc *t;
67 if (!tgt)
68 return NULL;
70 for (t = tgt; t != NULL; t = t->prev)
72 if (t->tgt_start <= (uintptr_t) d && t->tgt_end >= (uintptr_t) d + s)
73 break;
76 if (!t)
77 return NULL;
79 for (i = 0; i < t->list_count; i++)
81 void * offset;
83 splay_tree_key k = &t->array[i].key;
84 offset = d - t->tgt_start + k->tgt_offset;
86 if (k->host_start + offset <= (void *) k->host_end)
87 return k;
90 return NULL;
93 /* OpenACC is silent on how memory exhaustion is indicated. We return
94 NULL. */
96 void *
97 acc_malloc (size_t s)
99 if (!s)
100 return NULL;
102 goacc_lazy_initialize ();
104 struct goacc_thread *thr = goacc_thread ();
106 assert (thr->dev);
108 if (thr->dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
109 return malloc (s);
111 return thr->dev->alloc_func (thr->dev->target_id, s);
114 /* OpenACC 2.0a (3.2.16) doesn't specify what to do in the event
115 the device address is mapped. We choose to check if it mapped,
116 and if it is, to unmap it. */
117 void
118 acc_free (void *d)
120 splay_tree_key k;
122 if (!d)
123 return;
125 struct goacc_thread *thr = goacc_thread ();
127 assert (thr && thr->dev);
129 struct gomp_device_descr *acc_dev = thr->dev;
131 if (acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
132 return free (d);
134 gomp_mutex_lock (&acc_dev->lock);
136 /* We don't have to call lazy open here, as the ptr value must have
137 been returned by acc_malloc. It's not permitted to pass NULL in
138 (unless you got that null from acc_malloc). */
139 if ((k = lookup_dev (acc_dev->openacc.data_environ, d, 1)))
141 void *offset;
143 offset = d - k->tgt->tgt_start + k->tgt_offset;
145 gomp_mutex_unlock (&acc_dev->lock);
147 acc_unmap_data ((void *)(k->host_start + offset));
149 else
150 gomp_mutex_unlock (&acc_dev->lock);
152 if (!acc_dev->free_func (acc_dev->target_id, d))
153 gomp_fatal ("error in freeing device memory in %s", __FUNCTION__);
156 static void
157 memcpy_tofrom_device (bool from, void *d, void *h, size_t s, int async,
158 const char *libfnname)
160 /* No need to call lazy open here, as the device pointer must have
161 been obtained from a routine that did that. */
162 struct goacc_thread *thr = goacc_thread ();
164 assert (thr && thr->dev);
166 if (thr->dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
168 if (from)
169 memmove (h, d, s);
170 else
171 memmove (d, h, s);
172 return;
175 if (async > acc_async_sync)
176 thr->dev->openacc.async_set_async_func (async);
178 bool ret = (from
179 ? thr->dev->dev2host_func (thr->dev->target_id, h, d, s)
180 : thr->dev->host2dev_func (thr->dev->target_id, d, h, s));
182 if (async > acc_async_sync)
183 thr->dev->openacc.async_set_async_func (acc_async_sync);
185 if (!ret)
186 gomp_fatal ("error in %s", libfnname);
189 void
190 acc_memcpy_to_device (void *d, void *h, size_t s)
192 memcpy_tofrom_device (false, d, h, s, acc_async_sync, __FUNCTION__);
195 void
196 acc_memcpy_to_device_async (void *d, void *h, size_t s, int async)
198 memcpy_tofrom_device (false, d, h, s, async, __FUNCTION__);
201 void
202 acc_memcpy_from_device (void *h, void *d, size_t s)
204 memcpy_tofrom_device (true, d, h, s, acc_async_sync, __FUNCTION__);
207 void
208 acc_memcpy_from_device_async (void *h, void *d, size_t s, int async)
210 memcpy_tofrom_device (true, d, h, s, async, __FUNCTION__);
213 /* Return the device pointer that corresponds to host data H. Or NULL
214 if no mapping. */
216 void *
217 acc_deviceptr (void *h)
219 splay_tree_key n;
220 void *d;
221 void *offset;
223 goacc_lazy_initialize ();
225 struct goacc_thread *thr = goacc_thread ();
226 struct gomp_device_descr *dev = thr->dev;
228 if (thr->dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
229 return h;
231 gomp_mutex_lock (&dev->lock);
233 n = lookup_host (dev, h, 1);
235 if (!n)
237 gomp_mutex_unlock (&dev->lock);
238 return NULL;
241 offset = h - n->host_start;
243 d = n->tgt->tgt_start + n->tgt_offset + offset;
245 gomp_mutex_unlock (&dev->lock);
247 return d;
250 /* Return the host pointer that corresponds to device data D. Or NULL
251 if no mapping. */
253 void *
254 acc_hostptr (void *d)
256 splay_tree_key n;
257 void *h;
258 void *offset;
260 goacc_lazy_initialize ();
262 struct goacc_thread *thr = goacc_thread ();
263 struct gomp_device_descr *acc_dev = thr->dev;
265 if (thr->dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
266 return d;
268 gomp_mutex_lock (&acc_dev->lock);
270 n = lookup_dev (acc_dev->openacc.data_environ, d, 1);
272 if (!n)
274 gomp_mutex_unlock (&acc_dev->lock);
275 return NULL;
278 offset = d - n->tgt->tgt_start + n->tgt_offset;
280 h = n->host_start + offset;
282 gomp_mutex_unlock (&acc_dev->lock);
284 return h;
287 /* Return 1 if host data [H,+S] is present on the device. */
290 acc_is_present (void *h, size_t s)
292 splay_tree_key n;
294 if (!s || !h)
295 return 0;
297 goacc_lazy_initialize ();
299 struct goacc_thread *thr = goacc_thread ();
300 struct gomp_device_descr *acc_dev = thr->dev;
302 if (thr->dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
303 return h != NULL;
305 gomp_mutex_lock (&acc_dev->lock);
307 n = lookup_host (acc_dev, h, s);
309 if (n && ((uintptr_t)h < n->host_start
310 || (uintptr_t)h + s > n->host_end
311 || s > n->host_end - n->host_start))
312 n = NULL;
314 gomp_mutex_unlock (&acc_dev->lock);
316 return n != NULL;
319 /* Create a mapping for host [H,+S] -> device [D,+S] */
321 void
322 acc_map_data (void *h, void *d, size_t s)
324 struct target_mem_desc *tgt = NULL;
325 size_t mapnum = 1;
326 void *hostaddrs = h;
327 void *devaddrs = d;
328 size_t sizes = s;
329 unsigned short kinds = GOMP_MAP_ALLOC;
331 goacc_lazy_initialize ();
333 struct goacc_thread *thr = goacc_thread ();
334 struct gomp_device_descr *acc_dev = thr->dev;
336 if (acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
338 if (d != h)
339 gomp_fatal ("cannot map data on shared-memory system");
341 else
343 struct goacc_thread *thr = goacc_thread ();
345 if (!d || !h || !s)
346 gomp_fatal ("[%p,+%d]->[%p,+%d] is a bad map",
347 (void *)h, (int)s, (void *)d, (int)s);
349 gomp_mutex_lock (&acc_dev->lock);
351 if (lookup_host (acc_dev, h, s))
353 gomp_mutex_unlock (&acc_dev->lock);
354 gomp_fatal ("host address [%p, +%d] is already mapped", (void *)h,
355 (int)s);
358 if (lookup_dev (thr->dev->openacc.data_environ, d, s))
360 gomp_mutex_unlock (&acc_dev->lock);
361 gomp_fatal ("device address [%p, +%d] is already mapped", (void *)d,
362 (int)s);
365 gomp_mutex_unlock (&acc_dev->lock);
367 tgt = gomp_map_vars (acc_dev, mapnum, &hostaddrs, &devaddrs, &sizes,
368 &kinds, true, GOMP_MAP_VARS_OPENACC);
369 tgt->list[0].key->refcount = REFCOUNT_INFINITY;
372 gomp_mutex_lock (&acc_dev->lock);
373 tgt->prev = acc_dev->openacc.data_environ;
374 acc_dev->openacc.data_environ = tgt;
375 gomp_mutex_unlock (&acc_dev->lock);
378 void
379 acc_unmap_data (void *h)
381 struct goacc_thread *thr = goacc_thread ();
382 struct gomp_device_descr *acc_dev = thr->dev;
384 /* No need to call lazy open, as the address must have been mapped. */
386 /* This is a no-op on shared-memory targets. */
387 if (acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
388 return;
390 size_t host_size;
392 gomp_mutex_lock (&acc_dev->lock);
394 splay_tree_key n = lookup_host (acc_dev, h, 1);
395 struct target_mem_desc *t;
397 if (!n)
399 gomp_mutex_unlock (&acc_dev->lock);
400 gomp_fatal ("%p is not a mapped block", (void *)h);
403 host_size = n->host_end - n->host_start;
405 if (n->host_start != (uintptr_t) h)
407 gomp_mutex_unlock (&acc_dev->lock);
408 gomp_fatal ("[%p,%d] surrounds %p",
409 (void *) n->host_start, (int) host_size, (void *) h);
412 /* Mark for removal. */
413 n->refcount = 1;
415 t = n->tgt;
417 if (t->refcount == 2)
419 struct target_mem_desc *tp;
421 /* This is the last reference, so pull the descriptor off the
422 chain. This avoids gomp_unmap_vars via gomp_unmap_tgt from
423 freeing the device memory. */
424 t->tgt_end = 0;
425 t->to_free = 0;
427 for (tp = NULL, t = acc_dev->openacc.data_environ; t != NULL;
428 tp = t, t = t->prev)
429 if (n->tgt == t)
431 if (tp)
432 tp->prev = t->prev;
433 else
434 acc_dev->openacc.data_environ = t->prev;
436 break;
440 gomp_mutex_unlock (&acc_dev->lock);
442 gomp_unmap_vars (t, true);
445 #define FLAG_PRESENT (1 << 0)
446 #define FLAG_CREATE (1 << 1)
447 #define FLAG_COPY (1 << 2)
449 static void *
450 present_create_copy (unsigned f, void *h, size_t s, int async)
452 void *d;
453 splay_tree_key n;
455 if (!h || !s)
456 gomp_fatal ("[%p,+%d] is a bad range", (void *)h, (int)s);
458 goacc_lazy_initialize ();
460 struct goacc_thread *thr = goacc_thread ();
461 struct gomp_device_descr *acc_dev = thr->dev;
463 if (acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
464 return h;
466 gomp_mutex_lock (&acc_dev->lock);
468 n = lookup_host (acc_dev, h, s);
469 if (n)
471 /* Present. */
472 d = (void *) (n->tgt->tgt_start + n->tgt_offset);
474 if (!(f & FLAG_PRESENT))
476 gomp_mutex_unlock (&acc_dev->lock);
477 gomp_fatal ("[%p,+%d] already mapped to [%p,+%d]",
478 (void *)h, (int)s, (void *)d, (int)s);
480 if ((h + s) > (void *)n->host_end)
482 gomp_mutex_unlock (&acc_dev->lock);
483 gomp_fatal ("[%p,+%d] not mapped", (void *)h, (int)s);
486 if (n->refcount != REFCOUNT_INFINITY)
488 n->refcount++;
489 n->dynamic_refcount++;
491 gomp_mutex_unlock (&acc_dev->lock);
493 else if (!(f & FLAG_CREATE))
495 gomp_mutex_unlock (&acc_dev->lock);
496 gomp_fatal ("[%p,+%d] not mapped", (void *)h, (int)s);
498 else
500 struct target_mem_desc *tgt;
501 size_t mapnum = 1;
502 unsigned short kinds;
503 void *hostaddrs = h;
505 if (f & FLAG_COPY)
506 kinds = GOMP_MAP_TO;
507 else
508 kinds = GOMP_MAP_ALLOC;
510 gomp_mutex_unlock (&acc_dev->lock);
512 if (async > acc_async_sync)
513 acc_dev->openacc.async_set_async_func (async);
515 tgt = gomp_map_vars (acc_dev, mapnum, &hostaddrs, NULL, &s, &kinds, true,
516 GOMP_MAP_VARS_OPENACC);
517 /* Initialize dynamic refcount. */
518 tgt->list[0].key->dynamic_refcount = 1;
520 if (async > acc_async_sync)
521 acc_dev->openacc.async_set_async_func (acc_async_sync);
523 gomp_mutex_lock (&acc_dev->lock);
525 d = tgt->to_free;
526 tgt->prev = acc_dev->openacc.data_environ;
527 acc_dev->openacc.data_environ = tgt;
529 gomp_mutex_unlock (&acc_dev->lock);
532 return d;
535 void *
536 acc_create (void *h, size_t s)
538 return present_create_copy (FLAG_PRESENT | FLAG_CREATE, h, s, acc_async_sync);
541 void
542 acc_create_async (void *h, size_t s, int async)
544 present_create_copy (FLAG_PRESENT | FLAG_CREATE, h, s, async);
547 /* acc_present_or_create used to be what acc_create is now. */
548 /* acc_pcreate is acc_present_or_create by a different name. */
549 #ifdef HAVE_ATTRIBUTE_ALIAS
550 strong_alias (acc_create, acc_present_or_create)
551 strong_alias (acc_create, acc_pcreate)
552 #else
553 void *
554 acc_present_or_create (void *h, size_t s)
556 return acc_create (h, s);
559 void *
560 acc_pcreate (void *h, size_t s)
562 return acc_create (h, s);
564 #endif
566 void *
567 acc_copyin (void *h, size_t s)
569 return present_create_copy (FLAG_PRESENT | FLAG_CREATE | FLAG_COPY, h, s,
570 acc_async_sync);
573 void
574 acc_copyin_async (void *h, size_t s, int async)
576 present_create_copy (FLAG_PRESENT | FLAG_CREATE | FLAG_COPY, h, s, async);
579 /* acc_present_or_copyin used to be what acc_copyin is now. */
580 /* acc_pcopyin is acc_present_or_copyin by a different name. */
581 #ifdef HAVE_ATTRIBUTE_ALIAS
582 strong_alias (acc_copyin, acc_present_or_copyin)
583 strong_alias (acc_copyin, acc_pcopyin)
584 #else
585 void *
586 acc_present_or_copyin (void *h, size_t s)
588 return acc_copyin (h, s);
591 void *
592 acc_pcopyin (void *h, size_t s)
594 return acc_copyin (h, s);
596 #endif
598 #define FLAG_COPYOUT (1 << 0)
599 #define FLAG_FINALIZE (1 << 1)
601 static void
602 delete_copyout (unsigned f, void *h, size_t s, int async, const char *libfnname)
604 size_t host_size;
605 splay_tree_key n;
606 void *d;
607 struct goacc_thread *thr = goacc_thread ();
608 struct gomp_device_descr *acc_dev = thr->dev;
610 if (acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
611 return;
613 gomp_mutex_lock (&acc_dev->lock);
615 n = lookup_host (acc_dev, h, s);
617 /* No need to call lazy open, as the data must already have been
618 mapped. */
620 if (!n)
622 gomp_mutex_unlock (&acc_dev->lock);
623 gomp_fatal ("[%p,%d] is not mapped", (void *)h, (int)s);
626 d = (void *) (n->tgt->tgt_start + n->tgt_offset
627 + (uintptr_t) h - n->host_start);
629 host_size = n->host_end - n->host_start;
631 if (n->host_start != (uintptr_t) h || host_size != s)
633 gomp_mutex_unlock (&acc_dev->lock);
634 gomp_fatal ("[%p,%d] surrounds2 [%p,+%d]",
635 (void *) n->host_start, (int) host_size, (void *) h, (int) s);
638 if (n->refcount == REFCOUNT_INFINITY)
640 n->refcount = 0;
641 n->dynamic_refcount = 0;
643 if (n->refcount < n->dynamic_refcount)
645 gomp_mutex_unlock (&acc_dev->lock);
646 gomp_fatal ("Dynamic reference counting assert fail\n");
649 if (f & FLAG_FINALIZE)
651 n->refcount -= n->dynamic_refcount;
652 n->dynamic_refcount = 0;
654 else if (n->dynamic_refcount)
656 n->dynamic_refcount--;
657 n->refcount--;
660 if (n->refcount == 0)
662 if (n->tgt->refcount == 2)
664 struct target_mem_desc *tp, *t;
665 for (tp = NULL, t = acc_dev->openacc.data_environ; t != NULL;
666 tp = t, t = t->prev)
667 if (n->tgt == t)
669 if (tp)
670 tp->prev = t->prev;
671 else
672 acc_dev->openacc.data_environ = t->prev;
673 break;
677 if (f & FLAG_COPYOUT)
679 if (async > acc_async_sync)
680 acc_dev->openacc.async_set_async_func (async);
681 acc_dev->dev2host_func (acc_dev->target_id, h, d, s);
682 if (async > acc_async_sync)
683 acc_dev->openacc.async_set_async_func (acc_async_sync);
686 gomp_remove_var (acc_dev, n);
689 gomp_mutex_unlock (&acc_dev->lock);
692 void
693 acc_delete (void *h , size_t s)
695 delete_copyout (0, h, s, acc_async_sync, __FUNCTION__);
698 void
699 acc_delete_async (void *h , size_t s, int async)
701 delete_copyout (0, h, s, async, __FUNCTION__);
704 void
705 acc_delete_finalize (void *h , size_t s)
707 delete_copyout (FLAG_FINALIZE, h, s, acc_async_sync, __FUNCTION__);
710 void
711 acc_delete_finalize_async (void *h , size_t s, int async)
713 delete_copyout (FLAG_FINALIZE, h, s, async, __FUNCTION__);
716 void
717 acc_copyout (void *h, size_t s)
719 delete_copyout (FLAG_COPYOUT, h, s, acc_async_sync, __FUNCTION__);
722 void
723 acc_copyout_async (void *h, size_t s, int async)
725 delete_copyout (FLAG_COPYOUT, h, s, async, __FUNCTION__);
728 void
729 acc_copyout_finalize (void *h, size_t s)
731 delete_copyout (FLAG_COPYOUT | FLAG_FINALIZE, h, s, acc_async_sync,
732 __FUNCTION__);
735 void
736 acc_copyout_finalize_async (void *h, size_t s, int async)
738 delete_copyout (FLAG_COPYOUT | FLAG_FINALIZE, h, s, async, __FUNCTION__);
741 static void
742 update_dev_host (int is_dev, void *h, size_t s, int async)
744 splay_tree_key n;
745 void *d;
747 goacc_lazy_initialize ();
749 struct goacc_thread *thr = goacc_thread ();
750 struct gomp_device_descr *acc_dev = thr->dev;
752 if (acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
753 return;
755 gomp_mutex_lock (&acc_dev->lock);
757 n = lookup_host (acc_dev, h, s);
759 if (!n)
761 gomp_mutex_unlock (&acc_dev->lock);
762 gomp_fatal ("[%p,%d] is not mapped", h, (int)s);
765 d = (void *) (n->tgt->tgt_start + n->tgt_offset
766 + (uintptr_t) h - n->host_start);
768 if (async > acc_async_sync)
769 acc_dev->openacc.async_set_async_func (async);
771 if (is_dev)
772 acc_dev->host2dev_func (acc_dev->target_id, d, h, s);
773 else
774 acc_dev->dev2host_func (acc_dev->target_id, h, d, s);
776 if (async > acc_async_sync)
777 acc_dev->openacc.async_set_async_func (acc_async_sync);
779 gomp_mutex_unlock (&acc_dev->lock);
782 void
783 acc_update_device (void *h, size_t s)
785 update_dev_host (1, h, s, acc_async_sync);
788 void
789 acc_update_device_async (void *h, size_t s, int async)
791 update_dev_host (1, h, s, async);
794 void
795 acc_update_self (void *h, size_t s)
797 update_dev_host (0, h, s, acc_async_sync);
800 void
801 acc_update_self_async (void *h, size_t s, int async)
803 update_dev_host (0, h, s, async);
806 void
807 gomp_acc_insert_pointer (size_t mapnum, void **hostaddrs, size_t *sizes,
808 void *kinds)
810 struct target_mem_desc *tgt;
811 struct goacc_thread *thr = goacc_thread ();
812 struct gomp_device_descr *acc_dev = thr->dev;
814 if (acc_is_present (*hostaddrs, *sizes))
816 splay_tree_key n;
817 gomp_mutex_lock (&acc_dev->lock);
818 n = lookup_host (acc_dev, *hostaddrs, *sizes);
819 gomp_mutex_unlock (&acc_dev->lock);
821 tgt = n->tgt;
822 for (size_t i = 0; i < tgt->list_count; i++)
823 if (tgt->list[i].key == n)
825 for (size_t j = 0; j < mapnum; j++)
826 if (i + j < tgt->list_count && tgt->list[i + j].key)
828 tgt->list[i + j].key->refcount++;
829 tgt->list[i + j].key->dynamic_refcount++;
831 return;
833 /* Should not reach here. */
834 gomp_fatal ("Dynamic refcount incrementing failed for pointer/pset");
837 gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__);
838 tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs,
839 NULL, sizes, kinds, true, GOMP_MAP_VARS_OPENACC);
840 gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__);
842 /* Initialize dynamic refcount. */
843 tgt->list[0].key->dynamic_refcount = 1;
845 gomp_mutex_lock (&acc_dev->lock);
846 tgt->prev = acc_dev->openacc.data_environ;
847 acc_dev->openacc.data_environ = tgt;
848 gomp_mutex_unlock (&acc_dev->lock);
851 void
852 gomp_acc_remove_pointer (void *h, size_t s, bool force_copyfrom, int async,
853 int finalize, int mapnum)
855 struct goacc_thread *thr = goacc_thread ();
856 struct gomp_device_descr *acc_dev = thr->dev;
857 splay_tree_key n;
858 struct target_mem_desc *t;
859 int minrefs = (mapnum == 1) ? 2 : 3;
861 if (!acc_is_present (h, s))
862 return;
864 gomp_mutex_lock (&acc_dev->lock);
866 n = lookup_host (acc_dev, h, 1);
868 if (!n)
870 gomp_mutex_unlock (&acc_dev->lock);
871 gomp_fatal ("%p is not a mapped block", (void *)h);
874 gomp_debug (0, " %s: restore mappings\n", __FUNCTION__);
876 t = n->tgt;
878 if (n->refcount < n->dynamic_refcount)
880 gomp_mutex_unlock (&acc_dev->lock);
881 gomp_fatal ("Dynamic reference counting assert fail\n");
884 if (finalize)
886 n->refcount -= n->dynamic_refcount;
887 n->dynamic_refcount = 0;
889 else if (n->dynamic_refcount)
891 n->dynamic_refcount--;
892 n->refcount--;
895 gomp_mutex_unlock (&acc_dev->lock);
897 if (n->refcount == 0)
899 if (t->refcount == minrefs)
901 /* This is the last reference, so pull the descriptor off the
902 chain. This prevents gomp_unmap_vars via gomp_unmap_tgt from
903 freeing the device memory. */
904 struct target_mem_desc *tp;
905 for (tp = NULL, t = acc_dev->openacc.data_environ; t != NULL;
906 tp = t, t = t->prev)
908 if (n->tgt == t)
910 if (tp)
911 tp->prev = t->prev;
912 else
913 acc_dev->openacc.data_environ = t->prev;
914 break;
919 /* Set refcount to 1 to allow gomp_unmap_vars to unmap it. */
920 n->refcount = 1;
921 t->refcount = minrefs;
922 for (size_t i = 0; i < t->list_count; i++)
923 if (t->list[i].key == n)
925 t->list[i].copy_from = force_copyfrom ? 1 : 0;
926 break;
929 /* If running synchronously, unmap immediately. */
930 if (async < acc_async_noval)
931 gomp_unmap_vars (t, true);
932 else
933 t->device_descr->openacc.register_async_cleanup_func (t, async);
936 gomp_mutex_unlock (&acc_dev->lock);
938 gomp_debug (0, " %s: mappings restored\n", __FUNCTION__);