http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40362



--- Comment #12 from Dmitry Vyukov <dvyukov at google dot com> 2012-12-29 
12:31:02 UTC ---

(In reply to comment #11)

> (In reply to comment #10)

> > gomp_ptrlock_get() function is not thread-safe. It's not only about 
> > atomicity,

> > it's also about memory ordering. Thread that calls gomp_ptrlock_set() can

> > reorder stores to ws and the store to ptrlock->ptr. Alpha processors can 
> > even

> > reorder load from ws and load of ptrlock->ptr (they do not respect data

> > dependencies).

> 

> Wait a second ptrlock->ptr is really ws->next_ws.ptr which is really

> (ws+offset) so there is no data dependency here as far as I can see.



If that would be the case, then it would be even worser. But it's not the case,

there is certainly a data dependency between load of prtlock->ptr itself and

load of data through prtlock->ptr.



  ws = gomp_ptrlock_get (&ws->next_ws);

  if (ws == NULL)

...

  else

    {

      thr->ts.work_share = ws;









>   As Jakub

> mentioned before ws->next_ws.ptr only from NULL to non-null.



I do not see how it affects anything.



> So as far as I

> can tell it still stands as being thread-safe just not detectable from either

> valgrind or tsan.



tsan does not produce false warnings. data races are undefined behavior.





>  This is just like some of the false uninitialized warnings

> which gcc can emit.  It is sometimes hard to prove that the code is fine 
> except

> with extra knowledge like the NULL to non-NULL.

> 

> And about the stores being reordered:

>     gomp_ptrlock_set (&thr->ts.last_work_share->next_ws, thr->ts.work_share);

> 

> so ptr is always ws.



What do you mean?



> I again looked at the code and I still agree with Jakub's reasoning.



Among other things (e.g. just launching nuclear missiles), the following code:



  if (gomp_work_share_start (false))

    {

      gomp_loop_init (thr->ts.work_share, start, end, incr,

              GFS_STATIC, chunk_size);

      gomp_work_share_init_done ();

    }



can be executed as:



  if (gomp_work_share_start (false))

    {

        thr->ts.last_work_share->next_ws.ptr = thr->ts.work_share;

        gomp_loop_init (thr->ts.work_share, start, end, incr,

              GFS_STATIC, chunk_size);

        gomp_mutex_unlock (&thr->ts.last_work_share->next_ws.lock);

    }



Then it will kaboom!

Reply via email to