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