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

Reply via email to