1 /* Copyright (C) 2013-2014 Free Software Foundation, Inc.
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
4 This file is part of the GNU OpenMP Library (libgomp).
6 Libgomp is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 /* This file contains the support of offloading. */
29 #include "libgomp_target.h"
39 static void gomp_target_init (void);
41 static pthread_once_t gomp_is_initialized
= PTHREAD_ONCE_INIT
;
43 /* Forward declaration for a node in the tree. */
44 typedef struct splay_tree_node_s
*splay_tree_node
;
45 typedef struct splay_tree_s
*splay_tree
;
46 typedef struct splay_tree_key_s
*splay_tree_key
;
48 struct target_mem_desc
{
49 /* Reference count. */
51 /* All the splay nodes allocated together. */
52 splay_tree_node array
;
53 /* Start of the target region. */
55 /* End of the targer region. */
59 /* Previous target_mem_desc. */
60 struct target_mem_desc
*prev
;
61 /* Number of items in following list. */
64 /* Corresponding target device descriptor. */
65 struct gomp_device_descr
*device_descr
;
67 /* List of splay keys to remove (or decrease refcount)
68 at the end of region. */
69 splay_tree_key list
[];
72 struct splay_tree_key_s
{
73 /* Address of the host object. */
75 /* Address immediately after the host object. */
77 /* Descriptor of the target memory. */
78 struct target_mem_desc
*tgt
;
79 /* Offset from tgt->tgt_start to the start of the target object. */
81 /* Reference count. */
83 /* True if data should be copied from device to host at the end. */
87 /* This structure describes an offload image.
88 It contains type of the target device, pointer to host table descriptor, and
89 pointer to target data. */
90 struct offload_image_descr
{
91 enum offload_target_type type
;
96 /* Array of descriptors of offload images. */
97 static struct offload_image_descr
*offload_images
;
99 /* Total number of offload images. */
100 static int num_offload_images
;
102 /* Array of descriptors for all available devices. */
103 static struct gomp_device_descr
*devices
;
105 /* Total number of available devices. */
106 static int num_devices
;
108 /* The comparison function. */
111 splay_compare (splay_tree_key x
, splay_tree_key y
)
113 if (x
->host_start
== x
->host_end
114 && y
->host_start
== y
->host_end
)
116 if (x
->host_end
<= y
->host_start
)
118 if (x
->host_start
>= y
->host_end
)
123 #include "splay-tree.h"
125 /* This structure describes accelerator device.
126 It contains ID-number of the device, its type, function handlers for
127 interaction with the device, and information about mapped memory. */
128 struct gomp_device_descr
130 /* This is the ID number of device. It could be specified in DEVICE-clause of
134 /* This is the ID number of device among devices of the same type. */
137 /* This is the TYPE of device. */
138 enum offload_target_type type
;
140 /* Set to true when device is initialized. */
143 /* Function handlers. */
144 int (*get_type_func
) (void);
145 int (*get_num_devices_func
) (void);
146 void (*register_image_func
) (void *, void *);
147 void (*init_device_func
) (int);
148 int (*get_table_func
) (int, void *);
149 void *(*alloc_func
) (int, size_t);
150 void (*free_func
) (int, void *);
151 void *(*host2dev_func
) (int, void *, const void *, size_t);
152 void *(*dev2host_func
) (int, void *, const void *, size_t);
153 void (*run_func
) (int, void *, void *);
155 /* Splay tree containing information about mapped memory regions. */
156 struct splay_tree_s dev_splay_tree
;
158 /* Mutex for operating with the splay tree and other shared structures. */
159 gomp_mutex_t dev_env_lock
;
163 gomp_get_num_devices (void)
165 (void) pthread_once (&gomp_is_initialized
, gomp_target_init
);
169 static struct gomp_device_descr
*
170 resolve_device (int device_id
)
174 struct gomp_task_icv
*icv
= gomp_icv (false);
175 device_id
= icv
->default_device_var
;
178 if (device_id
< 0 || device_id
>= gomp_get_num_devices ())
181 return &devices
[device_id
];
185 /* Handle the case where splay_tree_lookup found oldn for newn.
186 Helper function of gomp_map_vars. */
189 gomp_map_vars_existing (splay_tree_key oldn
, splay_tree_key newn
,
192 if (oldn
->host_start
> newn
->host_start
193 || oldn
->host_end
< newn
->host_end
)
194 gomp_fatal ("Trying to map into device [%p..%p) object when"
195 "[%p..%p) is already mapped",
196 (void *) newn
->host_start
, (void *) newn
->host_end
,
197 (void *) oldn
->host_start
, (void *) oldn
->host_end
);
201 static struct target_mem_desc
*
202 gomp_map_vars (struct gomp_device_descr
*devicep
, size_t mapnum
,
203 void **hostaddrs
, size_t *sizes
, unsigned char *kinds
,
206 size_t i
, tgt_align
, tgt_size
, not_found_cnt
= 0;
207 struct splay_tree_key_s cur_node
;
208 struct target_mem_desc
*tgt
209 = gomp_malloc (sizeof (*tgt
) + sizeof (tgt
->list
[0]) * mapnum
);
210 tgt
->list_count
= mapnum
;
212 tgt
->device_descr
= devicep
;
217 tgt_align
= sizeof (void *);
221 size_t align
= 4 * sizeof (void *);
223 tgt_size
= mapnum
* sizeof (void *);
226 gomp_mutex_lock (&devicep
->dev_env_lock
);
227 for (i
= 0; i
< mapnum
; i
++)
229 if (hostaddrs
[i
] == NULL
)
234 cur_node
.host_start
= (uintptr_t) hostaddrs
[i
];
235 if ((kinds
[i
] & 7) != 4)
236 cur_node
.host_end
= cur_node
.host_start
+ sizes
[i
];
238 cur_node
.host_end
= cur_node
.host_start
+ sizeof (void *);
239 splay_tree_key n
= splay_tree_lookup (&devicep
->dev_splay_tree
,
244 gomp_map_vars_existing (n
, &cur_node
, kinds
[i
]);
248 size_t align
= (size_t) 1 << (kinds
[i
] >> 3);
251 if (tgt_align
< align
)
253 tgt_size
= (tgt_size
+ align
- 1) & ~(align
- 1);
254 tgt_size
+= cur_node
.host_end
- cur_node
.host_start
;
255 if ((kinds
[i
] & 7) == 5)
258 for (j
= i
+ 1; j
< mapnum
; j
++)
259 if ((kinds
[j
] & 7) != 4)
261 else if ((uintptr_t) hostaddrs
[j
] < cur_node
.host_start
262 || ((uintptr_t) hostaddrs
[j
] + sizeof (void *)
263 > cur_node
.host_end
))
274 if (not_found_cnt
|| is_target
)
276 /* Allocate tgt_align aligned tgt_size block of memory. */
277 /* FIXME: Perhaps change interface to allocate properly aligned
279 tgt
->to_free
= devicep
->alloc_func (devicep
->target_id
,
280 tgt_size
+ tgt_align
- 1);
281 tgt
->tgt_start
= (uintptr_t) tgt
->to_free
;
282 tgt
->tgt_start
= (tgt
->tgt_start
+ tgt_align
- 1) & ~(tgt_align
- 1);
283 tgt
->tgt_end
= tgt
->tgt_start
+ tgt_size
;
294 tgt_size
= mapnum
* sizeof (void *);
299 tgt
->array
= gomp_malloc (not_found_cnt
* sizeof (*tgt
->array
));
300 splay_tree_node array
= tgt
->array
;
303 for (i
= 0; i
< mapnum
; i
++)
304 if (tgt
->list
[i
] == NULL
)
306 if (hostaddrs
[i
] == NULL
)
308 splay_tree_key k
= &array
->key
;
309 k
->host_start
= (uintptr_t) hostaddrs
[i
];
310 if ((kinds
[i
] & 7) != 4)
311 k
->host_end
= k
->host_start
+ sizes
[i
];
313 k
->host_end
= k
->host_start
+ sizeof (void *);
315 = splay_tree_lookup (&devicep
->dev_splay_tree
, k
);
319 gomp_map_vars_existing (n
, k
, kinds
[i
]);
323 size_t align
= (size_t) 1 << (kinds
[i
] >> 3);
325 tgt_size
= (tgt_size
+ align
- 1) & ~(align
- 1);
327 k
->tgt_offset
= tgt_size
;
328 tgt_size
+= k
->host_end
- k
->host_start
;
329 k
->copy_from
= false;
330 if ((kinds
[i
] & 7) == 2 || (kinds
[i
] & 7) == 3)
336 splay_tree_insert (&devicep
->dev_splay_tree
, array
);
337 switch (kinds
[i
] & 7)
344 /* FIXME: Perhaps add some smarts, like if copying
345 several adjacent fields from host to target, use some
346 host buffer to avoid sending each var individually. */
347 devicep
->host2dev_func (devicep
->target_id
,
348 (void *) (tgt
->tgt_start
350 (void *) k
->host_start
,
351 k
->host_end
- k
->host_start
);
353 case 4: /* POINTER */
355 = (uintptr_t) *(void **) k
->host_start
;
356 if (cur_node
.host_start
== (uintptr_t) NULL
)
358 cur_node
.tgt_offset
= (uintptr_t) NULL
;
359 devicep
->host2dev_func (devicep
->target_id
,
360 (void *) (tgt
->tgt_start
362 (void *) &cur_node
.tgt_offset
,
366 /* Add bias to the pointer value. */
367 cur_node
.host_start
+= sizes
[i
];
368 cur_node
.host_end
= cur_node
.host_start
+ 1;
369 n
= splay_tree_lookup (&devicep
->dev_splay_tree
,
373 /* Could be possibly zero size array section. */
375 n
= splay_tree_lookup (&devicep
->dev_splay_tree
,
379 cur_node
.host_start
--;
380 n
= splay_tree_lookup (&devicep
->dev_splay_tree
,
382 cur_node
.host_start
++;
386 gomp_fatal ("Pointer target of array section "
388 cur_node
.host_start
-= n
->host_start
;
389 cur_node
.tgt_offset
= n
->tgt
->tgt_start
+ n
->tgt_offset
390 + cur_node
.host_start
;
391 /* At this point tgt_offset is target address of the
392 array section. Now subtract bias to get what we want
393 to initialize the pointer with. */
394 cur_node
.tgt_offset
-= sizes
[i
];
395 devicep
->host2dev_func (devicep
->target_id
,
396 (void *) (tgt
->tgt_start
398 (void *) &cur_node
.tgt_offset
,
401 case 5: /* TO_PSET */
402 devicep
->host2dev_func (devicep
->target_id
,
403 (void *) (tgt
->tgt_start
405 (void *) k
->host_start
,
406 k
->host_end
- k
->host_start
);
407 for (j
= i
+ 1; j
< mapnum
; j
++)
408 if ((kinds
[j
] & 7) != 4)
410 else if ((uintptr_t) hostaddrs
[j
] < k
->host_start
411 || ((uintptr_t) hostaddrs
[j
] + sizeof (void *)
419 = (uintptr_t) *(void **) hostaddrs
[j
];
420 if (cur_node
.host_start
== (uintptr_t) NULL
)
422 cur_node
.tgt_offset
= (uintptr_t) NULL
;
423 devicep
->host2dev_func (devicep
->target_id
,
424 (void *) (tgt
->tgt_start
+ k
->tgt_offset
425 + ((uintptr_t) hostaddrs
[j
]
427 (void *) &cur_node
.tgt_offset
,
432 /* Add bias to the pointer value. */
433 cur_node
.host_start
+= sizes
[j
];
434 cur_node
.host_end
= cur_node
.host_start
+ 1;
435 n
= splay_tree_lookup (&devicep
->dev_splay_tree
,
439 /* Could be possibly zero size array section. */
441 n
= splay_tree_lookup (&devicep
->dev_splay_tree
,
445 cur_node
.host_start
--;
446 n
= splay_tree_lookup
447 (&devicep
->dev_splay_tree
, &cur_node
);
448 cur_node
.host_start
++;
452 gomp_fatal ("Pointer target of array section "
454 cur_node
.host_start
-= n
->host_start
;
455 cur_node
.tgt_offset
= n
->tgt
->tgt_start
457 + cur_node
.host_start
;
458 /* At this point tgt_offset is target address of the
459 array section. Now subtract bias to get what we
460 want to initialize the pointer with. */
461 cur_node
.tgt_offset
-= sizes
[j
];
462 devicep
->host2dev_func (devicep
->target_id
,
463 (void *) (tgt
->tgt_start
+ k
->tgt_offset
464 + ((uintptr_t) hostaddrs
[j
]
466 (void *) &cur_node
.tgt_offset
,
478 for (i
= 0; i
< mapnum
; i
++)
480 if (tgt
->list
[i
] == NULL
)
481 cur_node
.tgt_offset
= (uintptr_t) NULL
;
483 cur_node
.tgt_offset
= tgt
->list
[i
]->tgt
->tgt_start
484 + tgt
->list
[i
]->tgt_offset
;
485 devicep
->host2dev_func (devicep
->target_id
,
486 (void *) (tgt
->tgt_start
487 + i
* sizeof (void *)),
488 (void *) &cur_node
.tgt_offset
,
493 gomp_mutex_unlock (&devicep
->dev_env_lock
);
498 gomp_unmap_tgt (struct target_mem_desc
*tgt
)
500 /* Deallocate on target the tgt->tgt_start .. tgt->tgt_end region. */
502 tgt
->device_descr
->free_func (tgt
->device_descr
->target_id
, tgt
->to_free
);
509 gomp_unmap_vars (struct target_mem_desc
*tgt
)
511 struct gomp_device_descr
*devicep
= tgt
->device_descr
;
513 if (tgt
->list_count
== 0)
520 gomp_mutex_lock (&devicep
->dev_env_lock
);
521 for (i
= 0; i
< tgt
->list_count
; i
++)
522 if (tgt
->list
[i
] == NULL
)
524 else if (tgt
->list
[i
]->refcount
> 1)
525 tgt
->list
[i
]->refcount
--;
528 splay_tree_key k
= tgt
->list
[i
];
530 devicep
->dev2host_func (devicep
->target_id
, (void *) k
->host_start
,
531 (void *) (k
->tgt
->tgt_start
+ k
->tgt_offset
),
532 k
->host_end
- k
->host_start
);
533 splay_tree_remove (&devicep
->dev_splay_tree
, k
);
534 if (k
->tgt
->refcount
> 1)
537 gomp_unmap_tgt (k
->tgt
);
540 if (tgt
->refcount
> 1)
543 gomp_unmap_tgt (tgt
);
544 gomp_mutex_unlock (&devicep
->dev_env_lock
);
548 gomp_update (struct gomp_device_descr
*devicep
, size_t mapnum
,
549 void **hostaddrs
, size_t *sizes
, unsigned char *kinds
)
552 struct splay_tree_key_s cur_node
;
560 gomp_mutex_lock (&devicep
->dev_env_lock
);
561 for (i
= 0; i
< mapnum
; i
++)
564 cur_node
.host_start
= (uintptr_t) hostaddrs
[i
];
565 cur_node
.host_end
= cur_node
.host_start
+ sizes
[i
];
566 splay_tree_key n
= splay_tree_lookup (&devicep
->dev_splay_tree
,
570 if (n
->host_start
> cur_node
.host_start
571 || n
->host_end
< cur_node
.host_end
)
572 gomp_fatal ("Trying to update [%p..%p) object when"
573 "only [%p..%p) is mapped",
574 (void *) cur_node
.host_start
,
575 (void *) cur_node
.host_end
,
576 (void *) n
->host_start
,
577 (void *) n
->host_end
);
578 if ((kinds
[i
] & 7) == 1)
579 devicep
->host2dev_func (devicep
->target_id
,
580 (void *) (n
->tgt
->tgt_start
582 + cur_node
.host_start
584 (void *) cur_node
.host_start
,
585 cur_node
.host_end
- cur_node
.host_start
);
586 else if ((kinds
[i
] & 7) == 2)
587 devicep
->dev2host_func (devicep
->target_id
,
588 (void *) cur_node
.host_start
,
589 (void *) (n
->tgt
->tgt_start
591 + cur_node
.host_start
593 cur_node
.host_end
- cur_node
.host_start
);
596 gomp_fatal ("Trying to update [%p..%p) object that is not mapped",
597 (void *) cur_node
.host_start
,
598 (void *) cur_node
.host_end
);
600 gomp_mutex_unlock (&devicep
->dev_env_lock
);
603 /* This function should be called from every offload image.
604 It gets the descriptor of the host func and var tables HOST_TABLE, TYPE of
605 the target, and TARGET_DATA needed by target plugin. */
608 GOMP_offload_register (void *host_table
, enum offload_target_type target_type
,
611 offload_images
= gomp_realloc (offload_images
,
612 (num_offload_images
+ 1)
613 * sizeof (struct offload_image_descr
));
615 offload_images
[num_offload_images
].type
= target_type
;
616 offload_images
[num_offload_images
].host_table
= host_table
;
617 offload_images
[num_offload_images
].target_data
= target_data
;
619 num_offload_images
++;
622 /* This function initializes the target device, specified by DEVICEP. */
625 gomp_init_device (struct gomp_device_descr
*devicep
)
627 devicep
->init_device_func (devicep
->target_id
);
629 /* Get address mapping table for device. */
630 struct mapping_table
*table
= NULL
;
631 int num_entries
= devicep
->get_table_func (devicep
->target_id
, &table
);
633 /* Insert host-target address mapping into dev_splay_tree. */
635 for (i
= 0; i
< num_entries
; i
++)
637 struct target_mem_desc
*tgt
= gomp_malloc (sizeof (*tgt
));
639 tgt
->array
= gomp_malloc (sizeof (*tgt
->array
));
640 tgt
->tgt_start
= table
[i
].tgt_start
;
641 tgt
->tgt_end
= table
[i
].tgt_end
;
644 tgt
->device_descr
= devicep
;
645 splay_tree_node node
= tgt
->array
;
646 splay_tree_key k
= &node
->key
;
647 k
->host_start
= table
[i
].host_start
;
648 k
->host_end
= table
[i
].host_end
;
651 k
->copy_from
= false;
655 splay_tree_insert (&devicep
->dev_splay_tree
, node
);
659 devicep
->is_initialized
= true;
662 /* Called when encountering a target directive. If DEVICE
663 is -1, it means use device-var ICV. If it is -2 (or any other value
664 larger than last available hw device, use host fallback.
665 FN is address of host code, OPENMP_TARGET contains value of the
666 __OPENMP_TARGET__ symbol in the shared library or binary that invokes
667 GOMP_target. HOSTADDRS, SIZES and KINDS are arrays
668 with MAPNUM entries, with addresses of the host objects,
669 sizes of the host objects (resp. for pointer kind pointer bias
670 and assumed sizeof (void *) size) and kinds. */
673 GOMP_target (int device
, void (*fn
) (void *), const void *openmp_target
,
674 size_t mapnum
, void **hostaddrs
, size_t *sizes
,
675 unsigned char *kinds
)
677 struct gomp_device_descr
*devicep
= resolve_device (device
);
681 struct gomp_thread old_thr
, *thr
= gomp_thread ();
683 memset (thr
, '\0', sizeof (*thr
));
684 if (gomp_places_list
)
686 thr
->place
= old_thr
.place
;
687 thr
->ts
.place_partition_len
= gomp_places_list_len
;
690 gomp_free_thread (thr
);
695 gomp_mutex_lock (&devicep
->dev_env_lock
);
696 if (!devicep
->is_initialized
)
697 gomp_init_device (devicep
);
699 struct splay_tree_key_s k
;
700 k
.host_start
= (uintptr_t) fn
;
701 k
.host_end
= k
.host_start
+ 1;
702 splay_tree_key tgt_fn
= splay_tree_lookup (&devicep
->dev_splay_tree
, &k
);
704 gomp_fatal ("Target function wasn't mapped");
705 gomp_mutex_unlock (&devicep
->dev_env_lock
);
707 struct target_mem_desc
*tgt_vars
708 = gomp_map_vars (devicep
, mapnum
, hostaddrs
, sizes
, kinds
, true);
709 struct gomp_thread old_thr
, *thr
= gomp_thread ();
711 memset (thr
, '\0', sizeof (*thr
));
712 if (gomp_places_list
)
714 thr
->place
= old_thr
.place
;
715 thr
->ts
.place_partition_len
= gomp_places_list_len
;
717 devicep
->run_func (devicep
->target_id
, (void *) tgt_fn
->tgt
->tgt_start
,
718 (void *) tgt_vars
->tgt_start
);
719 gomp_free_thread (thr
);
721 gomp_unmap_vars (tgt_vars
);
725 GOMP_target_data (int device
, const void *openmp_target
, size_t mapnum
,
726 void **hostaddrs
, size_t *sizes
, unsigned char *kinds
)
728 struct gomp_device_descr
*devicep
= resolve_device (device
);
732 struct gomp_task_icv
*icv
= gomp_icv (false);
733 if (icv
->target_data
)
735 /* Even when doing a host fallback, if there are any active
736 #pragma omp target data constructs, need to remember the
737 new #pragma omp target data, otherwise GOMP_target_end_data
738 would get out of sync. */
739 struct target_mem_desc
*tgt
740 = gomp_map_vars (NULL
, 0, NULL
, NULL
, NULL
, false);
741 tgt
->prev
= icv
->target_data
;
742 icv
->target_data
= tgt
;
747 gomp_mutex_lock (&devicep
->dev_env_lock
);
748 if (!devicep
->is_initialized
)
749 gomp_init_device (devicep
);
750 gomp_mutex_unlock (&devicep
->dev_env_lock
);
752 struct target_mem_desc
*tgt
753 = gomp_map_vars (devicep
, mapnum
, hostaddrs
, sizes
, kinds
, false);
754 struct gomp_task_icv
*icv
= gomp_icv (true);
755 tgt
->prev
= icv
->target_data
;
756 icv
->target_data
= tgt
;
760 GOMP_target_end_data (void)
762 struct gomp_task_icv
*icv
= gomp_icv (false);
763 if (icv
->target_data
)
765 struct target_mem_desc
*tgt
= icv
->target_data
;
766 icv
->target_data
= tgt
->prev
;
767 gomp_unmap_vars (tgt
);
772 GOMP_target_update (int device
, const void *openmp_target
, size_t mapnum
,
773 void **hostaddrs
, size_t *sizes
, unsigned char *kinds
)
775 struct gomp_device_descr
*devicep
= resolve_device (device
);
779 gomp_mutex_lock (&devicep
->dev_env_lock
);
780 if (!devicep
->is_initialized
)
781 gomp_init_device (devicep
);
782 gomp_mutex_unlock (&devicep
->dev_env_lock
);
784 gomp_update (devicep
, mapnum
, hostaddrs
, sizes
, kinds
);
788 GOMP_teams (unsigned int num_teams
, unsigned int thread_limit
)
792 struct gomp_task_icv
*icv
= gomp_icv (true);
793 icv
->thread_limit_var
794 = thread_limit
> INT_MAX
? UINT_MAX
: thread_limit
;
799 #ifdef PLUGIN_SUPPORT
801 /* This function tries to load a plugin for DEVICE. Name of plugin is passed
803 The handles of the found functions are stored in the corresponding fields
804 of DEVICE. The function returns TRUE on success and FALSE otherwise. */
807 gomp_load_plugin_for_device (struct gomp_device_descr
*device
,
808 const char *plugin_name
)
810 void *plugin_handle
= dlopen (plugin_name
, RTLD_LAZY
);
814 /* Check if all required functions are available in the plugin and store
819 device->f##_func = dlsym (plugin_handle, "GOMP_OFFLOAD_"#f); \
820 if (!device->f##_func) \
825 DLSYM (get_num_devices
);
826 DLSYM (register_image
);
839 /* This function finds OFFLOAD_IMAGES corresponding to DEVICE type, and
840 registers them in the plugin. */
843 gomp_register_images_for_device (struct gomp_device_descr
*device
)
846 for (i
= 0; i
< num_offload_images
; i
++)
848 struct offload_image_descr
*image
= &offload_images
[i
];
849 if (image
->type
== device
->type
)
850 device
->register_image_func (image
->host_table
, image
->target_data
);
854 /* This function initializes the runtime needed for offloading.
855 It parses the list of offload targets and tries to load the plugins for these
856 targets. Result of the function is properly initialized variable NUM_DEVICES
857 and array DEVICES, containing descriptors for corresponding devices. */
860 gomp_target_init (void)
862 const char *prefix
="libgomp-plugin-";
863 const char *suffix
= ".so.1";
864 const char *cur
, *next
;
866 int i
, new_num_devices
;
871 cur
= OFFLOAD_TARGETS
;
875 struct gomp_device_descr current_device
;
877 next
= strchr (cur
, ',');
879 plugin_name
= (char *) malloc (1 + (next
? next
- cur
: strlen (cur
))
880 + strlen (prefix
) + strlen (suffix
));
887 strcpy (plugin_name
, prefix
);
888 strncat (plugin_name
, cur
, next
? next
- cur
: strlen (cur
));
889 strcat (plugin_name
, suffix
);
891 if (gomp_load_plugin_for_device (¤t_device
, plugin_name
))
893 new_num_devices
= current_device
.get_num_devices_func ();
894 if (new_num_devices
>= 1)
896 devices
= realloc (devices
, (num_devices
+ new_num_devices
)
897 * sizeof (struct gomp_device_descr
));
905 current_device
.type
= current_device
.get_type_func ();
906 current_device
.is_initialized
= false;
907 current_device
.dev_splay_tree
.root
= NULL
;
908 gomp_register_images_for_device (¤t_device
);
909 for (i
= 0; i
< new_num_devices
; i
++)
911 current_device
.id
= num_devices
+ 1;
912 current_device
.target_id
= i
;
913 devices
[num_devices
] = current_device
;
914 gomp_mutex_init (&devices
[num_devices
].dev_env_lock
);
925 free (offload_images
);
926 offload_images
= NULL
;
927 num_offload_images
= 0;
930 #else /* PLUGIN_SUPPORT */
931 /* If dlfcn.h is unavailable we always fallback to host execution.
932 GOMP_target* routines are just stubs for this case. */
934 gomp_target_init (void)
937 #endif /* PLUGIN_SUPPORT */