On Tue, Jun 30, 2015 at 14:57:02 +0200, Jakub Jelinek wrote:
> On Tue, Jun 30, 2015 at 03:19:30PM +0300, Ilya Verbin wrote:
> > --- a/libgomp/target.c
> > +++ b/libgomp/target.c
> > @@ -580,10 +581,16 @@ gomp_unmap_vars (struct target_mem_desc *tgt, bool
> > do_copyfrom)
> > bool do_unmap = false;
> > if (k->refcount > 1)
> > k->refcount--;
> > - else if (k->async_refcount > 0)
> > - k->async_refcount--;
> > - else
> > - do_unmap = true;
> > + else if (k->refcount == 1)
> > + {
> > + if (k->async_refcount > 0)
> > + k->async_refcount--;
> > + else
> > + {
> > + k->refcount--;
> > + do_unmap = true;
> > + }
> > + }
>
> What is the rationale of this hunk change?
Without whis change, when k->refcount == 1, do_unmap is true, but refcount is
not decremented. So, if gomp_unmap_vars is called multiple times (now it's
possible for 4.1), refcount will remain 1, and it will try to unmap k at each
next call, that is wrong. That's why I decrement refcount to zero, and do
nothing when hit gomp_unmap_vars next time with k->refcount == 0.
> BTW, we'll likely need to treat also refcount == INT_MAX as special (never
> decrease it), because I believe declare target vars are supposed to have
> refcount of infinity rather than just 2GB-1.
I'll add special refcount for declare target vars.
> > @@ -1160,13 +1167,61 @@ GOMP_target_enter_exit_data (int device, size_t
> > mapnum, void **hostaddrs,
> > }
> >
> > if (is_enter_data)
> > - {
> > - /* TODO */
> > - }
> > + gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, true,
> > false);
>
> This will leak the return value. Either we need to arrange not to allocate
> it for enter data, or we need to assign it to some variable and free
> immediately (we don't want to perform the release operations for it).
But we can't not allocate or free immediately it, since it's used later through
splay_tree_key_s::tgt, e.g. here:
if (is_target)
{
for (i = 0; i < mapnum; i++)
{
if (tgt->list[i].key == NULL)
cur_node.tgt_offset = (uintptr_t) NULL;
else
cur_node.tgt_offset = tgt->list[i].key->tgt->tgt_start
+ tgt->list[i].key->tgt_offset;
My plan was to free tgt here:
+ if (k->refcount == 0)
+ {
+ splay_tree_remove (&devicep->mem_map, k);
+ if (k->tgt->refcount > 1)
+ k->tgt->refcount--;
+ else
+ gomp_unmap_tgt (k->tgt);
+ }
But now I understood that this will work only for simple cases like:
#pragma omp target enter data ...
...
#pragma omp target exit data ...
And will leak e.g. in:
#pragma omp target data ...
{
#pragma omp target enter data ...
}
> > else
> > - {
> > - /* TODO */
> > - }
> > + for (i = 0; i < mapnum; i++)
> > + {
> > + struct splay_tree_key_s cur_node;
> > + unsigned char kind = kinds[i] & typemask;
> > + switch (kind)
> > + {
> > + case GOMP_MAP_FROM:
> > + case GOMP_MAP_ALWAYS_FROM:
> > + case GOMP_MAP_DELETE:
> > + case GOMP_MAP_RELEASE:
> > + cur_node.host_start = (uintptr_t) hostaddrs[i];
> > + cur_node.host_end = cur_node.host_start + sizes[i];
> > + gomp_mutex_lock (&devicep->lock);
>
> I don't really like locking the mutex for each map clause in exit data
> separately. Perhaps just add a gomp_exit_data function similar to
> gomp_map_vars that will run this loop and be surrounded by the locking,
> or do it inline, but with the lock/unlock around the whole loop.
> exit data construct must have at least one map clause, so it doesn't make
> sense not to lock immediately.
I'll move locks outside of the loop.
> > + splay_tree_key k = splay_tree_lookup (&devicep->mem_map, &cur_node);
> > + if (!k)
> > + {
> > + gomp_mutex_unlock (&devicep->lock);
> > + continue;
> > + }
> > +
> > + if (k->refcount > 0)
> > + k->refcount--;
> > + if (kind == GOMP_MAP_DELETE)
> > + k->refcount = 0;
>
> See above, I believe delete should not delete refcount == INT_MAX
> mappings.
Will do that.
-- Ilya