1b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  This file is part of drd, a thread error detector.
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  Copyright (C) 2006-2011 Bart Van Assche <bvanassche@acm.org>.
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  This program is free software; you can redistribute it and/or
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  modify it under the terms of the GNU General Public License as
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  published by the Free Software Foundation; either version 2 of the
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  License, or (at your option) any later version.
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  This program is distributed in the hope that it will be useful, but
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  WITHOUT ANY WARRANTY; without even the implied warranty of
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  General Public License for more details.
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  You should have received a copy of the GNU General Public License
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  along with this program; if not, write to the Free Software
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  02111-1307, USA.
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  The GNU General Public License is contained in the file COPYING.
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "drd_barrier.h"
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "drd_clientobj.h"
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "drd_error.h"
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "drd_suppression.h"
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_errormgr.h"    // VG_(maybe_record_error)()
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcassert.h"  // tl_assert()
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcprint.h"   // VG_(printf)()
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_machine.h"     // VG_(get_IP)()
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_mallocfree.h"  // VG_(malloc)(), VG_(free)()
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_oset.h"
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Type definitions. */
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Information associated with one thread participating in a barrier. */
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct barrier_thread_info
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord       tid;           // A DrdThreadId declared as UWord because
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              // this member variable is the key of an OSet.
46b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Segment*    sg;            // Segment of the last pthread_barrier() call
47b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              // by thread tid.
489bea4c13fca0e3bb4b719dcb3ed63d47d479294eKenny Root   Segment*    post_wait_sg;  // Segment created after *_barrier_wait() finished
49b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   ExeContext* wait_call_ctxt;// call stack for *_barrier_wait() call.
50b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Bool       thread_finished;// Whether thread 'tid' has finished.
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Local functions. */
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void barrier_cleanup(struct barrier_info* p);
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void barrier_delete_thread(struct barrier_info* const p,
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  const DrdThreadId tid);
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic const char* barrier_get_typename(struct barrier_info* const p);
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic const char* barrier_type_name(const BarrierT bt);
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid barrier_report_wait_delete_race(const struct barrier_info* const p,
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     const struct barrier_thread_info* const q);
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Local variables. */
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool  s_trace_barrier = False;
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong s_barrier_segment_creation_count;
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Function definitions. */
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(barrier_set_trace)(const Bool trace_barrier)
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   s_trace_barrier = trace_barrier;
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/**
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Initialize the structure *p with the specified thread ID and iteration
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * information.
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(barrier_thread_initialize)(struct barrier_thread_info* const p,
85b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                     const DrdThreadId tid)
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
87b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->tid             = tid;
88b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->sg              = NULL;
89b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->post_wait_sg    = 0;
90b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->wait_call_ctxt  = 0;
91b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   p->thread_finished = False;
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/**
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Deallocate the memory that is owned by members of
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * struct barrier_thread_info.
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void DRD_(barrier_thread_destroy)(struct barrier_thread_info* const p)
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(p);
101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   DRD_(sg_put)(p->sg);
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DRD_(sg_put)(p->post_wait_sg);
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/**
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Initialize the structure *p with the specified client-side barrier address,
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * barrier object size and number of participants in each barrier.
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(barrier_initialize)(struct barrier_info* const p,
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              const Addr barrier,
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              const BarrierT barrier_type,
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              const Word count)
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   int i;
116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(barrier != 0);
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(barrier_type == pthread_barrier || barrier_type == gomp_barrier);
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(p->a1 == barrier);
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p->cleanup           = (void(*)(DrdClientobj*))barrier_cleanup;
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p->delete_thread
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = (void(*)(DrdClientobj*, DrdThreadId))barrier_delete_thread;
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p->barrier_type      = barrier_type;
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p->count             = count;
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p->pre_iteration     = 0;
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p->post_iteration    = 0;
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p->pre_waiters_left  = count;
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p->post_waiters_left = count;
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(sizeof(((struct barrier_thread_info*)0)->tid) == sizeof(Word));
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(sizeof(((struct barrier_thread_info*)0)->tid)
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             >= sizeof(DrdThreadId));
134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < 2; i++) {
135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      p->oset[i] = VG_(OSetGen_Create)(0, 0, VG_(malloc), "drd.barrier.bi.1",
136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                       VG_(free));
137b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/**
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Deallocate the memory owned by the struct barrier_info object and also
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * all the nodes in the OSet p->oset.
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Called by clientobj_destroy().
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void barrier_cleanup(struct barrier_info* p)
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct barrier_thread_info* q;
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Segment* latest_sg = 0;
150b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   OSet* oset;
151b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   int i;
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(p);
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
155b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   DRD_(thread_get_latest_segment)(&latest_sg, DRD_(thread_get_running_tid)());
156b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(latest_sg);
157b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
158b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (p->pre_waiters_left != p->count) {
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      BarrierErrInfo bei = { DRD_(thread_get_running_tid)(), p->a1, 0, 0 };
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(maybe_record_error)(VG_(get_running_tid)(),
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              BarrierErr,
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              VG_(get_IP)(VG_(get_running_tid)()),
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              "Destruction of barrier that is being waited"
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              " upon",
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              &bei);
166b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
167b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      oset = p->oset[1 - (p->pre_iteration & 1)];
168b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(OSetGen_ResetIter)(oset);
169b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      for ( ; (q = VG_(OSetGen_Next)(oset)) != 0; ) {
170b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (q->post_wait_sg && !DRD_(vc_lte)(&q->post_wait_sg->vc,
171b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                              &latest_sg->vc))
172b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         {
173b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            barrier_report_wait_delete_race(p, q);
174b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
175b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DRD_(barrier_thread_destroy)(q);
1769bea4c13fca0e3bb4b719dcb3ed63d47d479294eKenny Root      }
177b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1789bea4c13fca0e3bb4b719dcb3ed63d47d479294eKenny Root
179b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < 2; i++) {
180b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(OSetGen_Destroy)(p->oset[i]);
181b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      p->oset[i] = NULL;
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DRD_(sg_put)(latest_sg);
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/**
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Look up the client-side barrier address barrier in s_barrier[]. If not
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * found, add it.
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct barrier_info*
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDRD_(barrier_get_or_allocate)(const Addr barrier,
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              const BarrierT barrier_type, const Word count)
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct barrier_info *p;
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(barrier_type == pthread_barrier || barrier_type == gomp_barrier);
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(offsetof(DrdClientobj, barrier) == 0);
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = &(DRD_(clientobj_get)(barrier, ClientBarrier)->barrier);
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (p == 0)
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p = &(DRD_(clientobj_add)(barrier, ClientBarrier)->barrier);
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DRD_(barrier_initialize)(p, barrier, barrier_type, count);
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return p;
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/**
211b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * Look up the address of the struct barrier_info associated with the
212b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * client-side barrier object.
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic struct barrier_info* DRD_(barrier_get)(const Addr barrier)
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(offsetof(DrdClientobj, barrier) == 0);
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return &(DRD_(clientobj_get)(barrier, ClientBarrier)->barrier);
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/**
221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * Initialize a barrier with given client address, barrier type and number of
222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * participants. The 'reinitialization' argument indicates whether a barrier
223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov * object is being initialized or reinitialized.
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Called before pthread_barrier_init().
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(barrier_init)(const Addr barrier,
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        const BarrierT barrier_type, const Word count,
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        const Bool reinitialization)
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct barrier_info* p;
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(barrier_type == pthread_barrier || barrier_type == gomp_barrier);
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (count == 0)
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      BarrierErrInfo bei = { DRD_(thread_get_running_tid)(), barrier, 0, 0 };
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(maybe_record_error)(VG_(get_running_tid)(),
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              BarrierErr,
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              VG_(get_IP)(VG_(get_running_tid)()),
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              "pthread_barrier_init: 'count' argument is zero",
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              &bei);
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (! reinitialization && barrier_type == pthread_barrier)
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p = DRD_(barrier_get)(barrier);
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (p)
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         BarrierErrInfo bei = { DRD_(thread_get_running_tid)(), barrier, 0, 0 };
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(maybe_record_error)(VG_(get_running_tid)(),
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 BarrierErr,
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 VG_(get_IP)(VG_(get_running_tid)()),
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "Barrier reinitialization",
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 &bei);
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
258b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = DRD_(barrier_get_or_allocate)(barrier, barrier_type, count);
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
261b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (s_trace_barrier) {
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (reinitialization)
263b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DRD_(trace_msg)("[%d] barrier_reinit    %s 0x%lx count %ld -> %ld",
264b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                         DRD_(thread_get_running_tid)(),
265b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                         barrier_get_typename(p), barrier, p->count, count);
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
267b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DRD_(trace_msg)("[%d] barrier_init      %s 0x%lx",
268b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                         DRD_(thread_get_running_tid)(),
269b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                         barrier_get_typename(p),
270b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                         barrier);
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (reinitialization && p->count != count)
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (p->pre_waiters_left != p->count || p->post_waiters_left != p->count)
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         BarrierErrInfo bei = { DRD_(thread_get_running_tid)(), p->a1, 0, 0 };
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(maybe_record_error)(VG_(get_running_tid)(),
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 BarrierErr,
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 VG_(get_IP)(VG_(get_running_tid)()),
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "Reinitialization of barrier with active"
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 " waiters",
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 &bei);
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p->count = count;
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Called after pthread_barrier_destroy() / gomp_barrier_destroy(). */
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(barrier_destroy)(const Addr barrier, const BarrierT barrier_type)
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct barrier_info* p;
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = DRD_(barrier_get)(barrier);
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (s_trace_barrier)
297b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DRD_(trace_msg)("[%d] barrier_destroy   %s 0x%lx",
298b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      DRD_(thread_get_running_tid)(),
299b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      barrier_get_typename(p), barrier);
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (p == 0)
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      GenericErrInfo GEI = {
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 .tid = DRD_(thread_get_running_tid)(),
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 .addr = barrier,
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      };
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(maybe_record_error)(VG_(get_running_tid)(),
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              GenericErr,
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              VG_(get_IP)(VG_(get_running_tid)()),
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              "Not a barrier",
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              &GEI);
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (p->pre_waiters_left != p->count || p->post_waiters_left != p->count)
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      BarrierErrInfo bei = { DRD_(thread_get_running_tid)(), p->a1, 0, 0 };
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(maybe_record_error)(VG_(get_running_tid)(),
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              BarrierErr,
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              VG_(get_IP)(VG_(get_running_tid)()),
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              "Destruction of a barrier with active waiters",
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              &bei);
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DRD_(clientobj_remove)(p->a1, ClientBarrier);
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Called before pthread_barrier_wait() / gomp_barrier_wait(). */
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(barrier_pre_wait)(const DrdThreadId tid, const Addr barrier,
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            const BarrierT barrier_type)
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct barrier_info* p;
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct barrier_thread_info* q;
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const UWord word_tid = tid;
335b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   OSet* oset;
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = DRD_(barrier_get)(barrier);
338b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (p == 0 && barrier_type == gomp_barrier) {
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * gomp_barrier_wait() call has been intercepted but gomp_barrier_init()
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * not. The only cause I know of that can trigger this is that libgomp.so
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       * has been compiled with --enable-linux-futex.
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       */
344b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      BarrierErrInfo bei = { DRD_(thread_get_running_tid)(), 0, 0, 0 };
345b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(maybe_record_error)(VG_(get_running_tid)(),
346b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              BarrierErr,
347b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              VG_(get_IP)(VG_(get_running_tid)()),
348b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              "Please verify whether gcc has been configured"
349b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              " with option --disable-linux-futex. See also"
350b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              " the section about OpenMP in the DRD manual.",
351b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              &bei);
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(p);
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (s_trace_barrier)
356b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DRD_(trace_msg)("[%d] barrier_pre_wait  %s 0x%lx iteration %ld",
357b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      DRD_(thread_get_running_tid)(),
358b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      barrier_get_typename(p), barrier, p->pre_iteration);
359b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
360b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Clean up nodes associated with finished threads. */
361b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   oset = p->oset[p->pre_iteration & 1];
362b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(oset);
363b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(OSetGen_ResetIter)(oset);
364b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for ( ; (q = VG_(OSetGen_Next)(oset)) != 0; ) {
365b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (q->thread_finished) {
366b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         void* r = VG_(OSetGen_Remove)(oset, &q->tid);
367b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         tl_assert(r == q);
368b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DRD_(barrier_thread_destroy)(q);
369b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(OSetGen_FreeNode)(oset, q);
370b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(OSetGen_ResetIterAt)(oset, &word_tid);
371b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Allocate the per-thread data structure if necessary. */
374b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   q = VG_(OSetGen_Lookup)(oset, &word_tid);
375b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (q == NULL) {
376b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      q = VG_(OSetGen_AllocNode)(oset, sizeof(*q));
377b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DRD_(barrier_thread_initialize)(q, tid);
378b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(OSetGen_Insert)(oset, q);
379b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(VG_(OSetGen_Lookup)(oset, &word_tid) == q);
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Record *_barrier_wait() call context. */
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   q->wait_call_ctxt = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * Store a pointer to the latest segment of the current thread in the
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * per-thread data structure.
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    */
389b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   DRD_(thread_get_latest_segment)(&q->sg, tid);
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * If the same number of threads as the barrier count indicates have
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * called the pre *_barrier_wait() wrapper, toggle p->pre_iteration and
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * reset the p->pre_waiters_left counter.
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    */
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (--p->pre_waiters_left <= 0)
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
398b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      p->pre_iteration++;
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p->pre_waiters_left = p->count;
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Called after pthread_barrier_wait() / gomp_barrier_wait(). */
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(barrier_post_wait)(const DrdThreadId tid, const Addr barrier,
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             const BarrierT barrier_type, const Bool waited,
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             const Bool serializing)
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct barrier_info* p;
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const UWord word_tid = tid;
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct barrier_thread_info* q;
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct barrier_thread_info* r;
412b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   OSet* oset;
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   p = DRD_(barrier_get)(barrier);
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (s_trace_barrier)
417b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DRD_(trace_msg)("[%d] barrier_post_wait %s 0x%lx iteration %ld%s",
418b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      tid, p ? barrier_get_typename(p) : "(?)",
419b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      barrier, p ? p->post_iteration : -1,
420b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      serializing ? " (serializing)" : "");
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * If p == 0, this means that the barrier has been destroyed after
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * *_barrier_wait() returned and before this function was called. Just
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * return in that case -- race conditions between *_barrier_wait()
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * and *_barrier_destroy() are detected by the *_barrier_destroy() wrapper.
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    */
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (p == 0)
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If the *_barrier_wait() call returned an error code, exit. */
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (! waited)
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
435b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   oset = p->oset[p->post_iteration & 1];
436b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   q = VG_(OSetGen_Lookup)(oset, &word_tid);
437b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (p->pre_iteration - p->post_iteration > 1) {
438b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      BarrierErrInfo bei = { DRD_(thread_get_running_tid)(), p->a1, 0, 0 };
439b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(maybe_record_error)(VG_(get_running_tid)(),
440b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              BarrierErr,
441b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              VG_(get_IP)(VG_(get_running_tid)()),
442b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              "Number of concurrent pthread_barrier_wait()"
443b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              " calls exceeds the barrier count",
444b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                              &bei);
445b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (q == NULL) {
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      BarrierErrInfo bei = { DRD_(thread_get_running_tid)(), p->a1, 0, 0 };
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(maybe_record_error)(VG_(get_running_tid)(),
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              BarrierErr,
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              VG_(get_IP)(VG_(get_running_tid)()),
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              "Error in barrier implementation"
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              " -- barrier_wait() started before"
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              " barrier_destroy() and finished after"
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              " barrier_destroy()",
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              &bei);
455b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
456b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (q == NULL) {
457b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      q = VG_(OSetGen_AllocNode)(oset, sizeof(*q));
458b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DRD_(barrier_thread_initialize)(q, tid);
459b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(OSetGen_Insert)(oset, q);
460b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(VG_(OSetGen_Lookup)(oset, &word_tid) == q);
461b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DRD_(thread_get_latest_segment)(&q->sg, tid);
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Create a new segment and store a pointer to that segment. */
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DRD_(thread_new_segment)(tid);
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DRD_(thread_get_latest_segment)(&q->post_wait_sg, tid);
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   s_barrier_segment_creation_count++;
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * Combine all vector clocks that were stored in the pre_barrier_wait
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * wrapper with the vector clock of the current thread.
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    */
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VectorClock old_vc;
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DRD_(vc_copy)(&old_vc, &DRD_(g_threadinfo)[tid].last->vc);
477b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(OSetGen_ResetIter)(oset);
478b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      for ( ; (r = VG_(OSetGen_Next)(oset)) != 0; )
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (r != q)
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         {
482b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            tl_assert(r->sg);
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DRD_(vc_combine)(&DRD_(g_threadinfo)[tid].last->vc,
484b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                             &r->sg->vc);
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DRD_(thread_update_conflict_set)(tid, &old_vc);
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DRD_(vc_cleanup)(&old_vc);
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * If the same number of threads as the barrier count indicates have
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * called the post *_barrier_wait() wrapper, toggle p->post_iteration and
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * reset the p->post_waiters_left counter.
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    */
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (--p->post_waiters_left <= 0)
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
498b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      p->post_iteration++;
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p->post_waiters_left = p->count;
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Called when thread tid stops to exist. */
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void barrier_delete_thread(struct barrier_info* const p,
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  const DrdThreadId tid)
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct barrier_thread_info* q;
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const UWord word_tid = tid;
509b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   int i;
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
511b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < 2; i++) {
512b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      q = VG_(OSetGen_Lookup)(p->oset[i], &word_tid);
513b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (q)
514b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         q->thread_finished = True;
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/**
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Report that *_barrier_destroy() has been called but that this call was
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * not synchronized with the last *_barrier_wait() call on the same barrier.
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This topic has been discussed extensively on comp.programming.threads
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * (February 3, 2009). See also
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * <a href="http://groups.google.com/group/comp.programming.threads/browse_thread/thread/4f65535d6192aa50/a5f4bf1e3b437c4d">Immediately destroying pthread barriers</a>.
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid barrier_report_wait_delete_race(const struct barrier_info* const p,
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     const struct barrier_thread_info* const q)
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(p);
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(q);
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      BarrierErrInfo bei
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = { DRD_(thread_get_running_tid)(), p->a1, q->tid, q->wait_call_ctxt };
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(maybe_record_error)(VG_(get_running_tid)(),
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              BarrierErr,
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              VG_(get_IP)(VG_(get_running_tid)()),
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              "Destruction of barrier not synchronized with"
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              " barrier wait call",
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              &bei);
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic const char* barrier_get_typename(struct barrier_info* const p)
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(p);
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return barrier_type_name(p->barrier_type);
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic const char* barrier_type_name(const BarrierT bt)
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (bt)
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case pthread_barrier:
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return "pthread barrier";
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case gomp_barrier:
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return "gomp barrier";
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return "?";
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong DRD_(get_barrier_segment_creation_count)(void)
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return s_barrier_segment_creation_count;
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
568