1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This file is part of drd, a thread error detector. 3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 4663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng Copyright (C) 2006-2012 Bart Van Assche <bvanassche@acm.org>. 5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is free software; you can redistribute it and/or 7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown modify it under the terms of the GNU General Public License as 8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown published by the Free Software Foundation; either version 2 of the 9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown License, or (at your option) any later version. 10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown This program is distributed in the hope that it will be useful, but 12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown WITHOUT ANY WARRANTY; without even the implied warranty of 13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown General Public License for more details. 15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown You should have received a copy of the GNU General Public License 17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown along with this program; if not, write to the Free Software 18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 02111-1307, USA. 20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown The GNU General Public License is contained in the file COPYING. 22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/ 23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "drd_clientobj.h" 26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "drd_error.h" 27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "drd_rwlock.h" 28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_vki.h" 29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_errormgr.h" // VG_(maybe_record_error)() 30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcassert.h" // tl_assert() 31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcprint.h" // VG_(message)() 32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcproc.h" // VG_(read_millisecond_timer)() 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_threadstate.h" // VG_(get_running_tid)() 36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Local type definitions. */ 39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct rwlock_thread_info 41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UWord tid; // DrdThreadId. 43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt reader_nesting_count; 44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown UInt writer_nesting_count; 45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Segment of last unlock call by this thread that unlocked a writer lock. 46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Segment* latest_wrlocked_segment; 47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown // Segment of last unlock call by this thread that unlocked a reader lock. 48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Segment* latest_rdlocked_segment; 49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}; 50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Local functions. */ 53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void rwlock_cleanup(struct rwlock_info* p); 55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void rwlock_delete_thread(struct rwlock_info* const p, 56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const DrdThreadId tid); 57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Local variables. */ 60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool DRD_(s_trace_rwlock); 62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt DRD_(s_exclusive_threshold_ms); 63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt DRD_(s_shared_threshold_ms); 64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong DRD_(s_rwlock_segment_creation_count); 65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Function definitions. */ 68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(rwlock_set_trace)(const Bool trace_rwlock) 70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(trace_rwlock == False || trace_rwlock == True); 72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(s_trace_rwlock) = trace_rwlock; 73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(rwlock_set_exclusive_threshold)(const UInt exclusive_threshold_ms) 76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(s_exclusive_threshold_ms) = exclusive_threshold_ms; 78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(rwlock_set_shared_threshold)(const UInt shared_threshold_ms) 81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(s_shared_threshold_ms) = shared_threshold_ms; 83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool DRD_(rwlock_is_rdlocked)(struct rwlock_info* p) 86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(OSetGen_ResetIter)(p->thread_info); 90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; ) 91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return q->reader_nesting_count > 0; 93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool DRD_(rwlock_is_wrlocked)(struct rwlock_info* p) 98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(OSetGen_ResetIter)(p->thread_info); 102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; ) 103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return q->writer_nesting_count > 0; 105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool DRD_(rwlock_is_locked)(struct rwlock_info* p) 110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return DRD_(rwlock_is_rdlocked)(p) || DRD_(rwlock_is_wrlocked)(p); 112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool DRD_(rwlock_is_rdlocked_by)(struct rwlock_info* p, 115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const DrdThreadId tid) 116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const UWord uword_tid = tid; 118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q = VG_(OSetGen_Lookup)(p->thread_info, &uword_tid); 121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return q && q->reader_nesting_count > 0; 122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool DRD_(rwlock_is_wrlocked_by)(struct rwlock_info* p, 125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const DrdThreadId tid) 126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const UWord uword_tid = tid; 128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q = VG_(OSetGen_Lookup)(p->thread_info, &uword_tid); 131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return q && q->writer_nesting_count > 0; 132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool DRD_(rwlock_is_locked_by)(struct rwlock_info* p, 135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const DrdThreadId tid) 136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return (DRD_(rwlock_is_rdlocked_by)(p, tid) 138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown || DRD_(rwlock_is_wrlocked_by)(p, tid)); 139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Either look up or insert a node corresponding to DRD thread id 'tid'. */ 142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct rwlock_thread_info* 144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDRD_(lookup_or_insert_node)(OSet* oset, const UWord tid) 145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q = VG_(OSetGen_Lookup)(oset, &tid); 149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (q == 0) 150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q = VG_(OSetGen_AllocNode)(oset, sizeof(*q)); 152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q->tid = tid; 153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q->reader_nesting_count = 0; 154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q->writer_nesting_count = 0; 155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q->latest_wrlocked_segment = 0; 156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q->latest_rdlocked_segment = 0; 157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(OSetGen_Insert)(oset, q); 158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(q); 160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return q; 161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** 164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Combine the vector clock corresponding to the last unlock operation of 165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * reader-writer lock p into the vector clock of thread 'tid'. 166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void DRD_(rwlock_combine_other_vc)(struct rwlock_info* const p, 168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const DrdThreadId tid, 169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Bool readers_too) 170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VectorClock old_vc; 173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 174663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng DRD_(vc_copy)(&old_vc, DRD_(thread_get_vc)(tid)); 175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(OSetGen_ResetIter)(p->thread_info); 176663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; ) { 177663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng if (q->tid != tid) { 178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (q->latest_wrlocked_segment) 179663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng DRD_(vc_combine)(DRD_(thread_get_vc)(tid), 180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &q->latest_wrlocked_segment->vc); 181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (readers_too && q->latest_rdlocked_segment) 182663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng DRD_(vc_combine)(DRD_(thread_get_vc)(tid), 183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &q->latest_rdlocked_segment->vc); 184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(thread_update_conflict_set)(tid, &old_vc); 187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(vc_cleanup)(&old_vc); 188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** 191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Compare the type of the rwlock specified at initialization time with 192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * the type passed as an argument, and complain if these two types do not 193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * match. 194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool drd_rwlock_check_type(struct rwlock_info* const p, 196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const RwLockT rwlock_type) 197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(p); 199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* The code below has to be updated if additional rwlock types are added. */ 200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(rwlock_type == pthread_rwlock || rwlock_type == user_rwlock); 201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(p->rwlock_type == pthread_rwlock || p->rwlock_type == user_rwlock); 202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (p->rwlock_type == rwlock_type) 204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return True; 205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 }; 208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error) 209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown (VG_(get_running_tid)(), 210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErr, 211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(VG_(get_running_tid)()), 212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown rwlock_type == pthread_rwlock 213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown ? "Attempt to use a user-defined rwlock as a POSIX rwlock" 214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown : "Attempt to use a POSIX rwlock as a user-defined rwlock", 215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &REI); 216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return False; 218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Initialize the rwlock_info data structure *p. */ 221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(rwlock_initialize)(struct rwlock_info* const p, const Addr rwlock, 223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const RwLockT rwlock_type) 224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(rwlock != 0); 226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(p->a1 == rwlock); 227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(p->type == ClientRwlock); 228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->cleanup = (void(*)(DrdClientobj*))rwlock_cleanup; 230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->delete_thread 231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown = (void(*)(DrdClientobj*, DrdThreadId))rwlock_delete_thread; 232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->rwlock_type = rwlock_type; 233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->thread_info = VG_(OSetGen_Create)( 234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 0, 0, VG_(malloc), "drd.rwlock.ri.1", VG_(free)); 235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->acquiry_time_ms = 0; 236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->acquired_at = 0; 237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Deallocate the memory that was allocated by rwlock_initialize(). */ 240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void rwlock_cleanup(struct rwlock_info* p) 241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(p); 245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(s_trace_rwlock)) 247b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(trace_msg)("[%d] rwlock_destroy 0x%lx", 248b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(thread_get_running_tid)(), p->a1); 249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(rwlock_is_locked)(p)) 251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 }; 253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error)(VG_(get_running_tid)(), 254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErr, 255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(VG_(get_running_tid)()), 256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "Destroying locked rwlock", 257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &REI); 258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(OSetGen_ResetIter)(p->thread_info); 261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; ) 262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(sg_put)(q->latest_wrlocked_segment); 264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(sg_put)(q->latest_rdlocked_segment); 265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(OSetGen_Destroy)(p->thread_info); 268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic 271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct rwlock_info* 272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDRD_(rwlock_get_or_allocate)(const Addr rwlock, const RwLockT rwlock_type) 273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_info* p; 275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(offsetof(DrdClientobj, rwlock) == 0); 277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = &(DRD_(clientobj_get)(rwlock, ClientRwlock)->rwlock); 278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (p) 279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown drd_rwlock_check_type(p, rwlock_type); 281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return p; 282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(clientobj_present)(rwlock, rwlock + 1)) 285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown GenericErrInfo GEI = { 287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown .tid = DRD_(thread_get_running_tid)(), 288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown .addr = rwlock, 289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown }; 290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error)(VG_(get_running_tid)(), 291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown GenericErr, 292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(VG_(get_running_tid)()), 293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "Not a reader-writer lock", 294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &GEI); 295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return 0; 296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = &(DRD_(clientobj_add)(rwlock, ClientRwlock)->rwlock); 299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(rwlock_initialize)(p, rwlock, rwlock_type); 300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return p; 301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic struct rwlock_info* DRD_(rwlock_get)(const Addr rwlock) 304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(offsetof(DrdClientobj, rwlock) == 0); 306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return &(DRD_(clientobj_get)(rwlock, ClientRwlock)->rwlock); 307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Called before pthread_rwlock_init(). */ 310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct rwlock_info* DRD_(rwlock_pre_init)(const Addr rwlock, 311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const RwLockT rwlock_type) 312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_info* p; 314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(s_trace_rwlock)) 316b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(trace_msg)("[%d] rwlock_init 0x%lx", 317b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(thread_get_running_tid)(), rwlock); 318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = DRD_(rwlock_get)(rwlock); 320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (p) 322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown drd_rwlock_check_type(p, rwlock_type); 323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (p) 325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ThreadId vg_tid = VG_(get_running_tid)(); 327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 }; 328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error)(vg_tid, 329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErr, 330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(vg_tid), 331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "Reader-writer lock reinitialization", 332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &REI); 333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return p; 334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type); 337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return p; 339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Called after pthread_rwlock_destroy(). */ 342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(rwlock_post_destroy)(const Addr rwlock, const RwLockT rwlock_type) 343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_info* p; 345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = DRD_(rwlock_get)(rwlock); 347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (p == 0) 348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown GenericErrInfo GEI = { 350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown .tid = DRD_(thread_get_running_tid)(), 351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown .addr = rwlock, 352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown }; 353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error)(VG_(get_running_tid)(), 354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown GenericErr, 355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(VG_(get_running_tid)()), 356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "Not a reader-writer lock", 357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &GEI); 358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown drd_rwlock_check_type(p, rwlock_type); 362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(clientobj_remove)(rwlock, ClientRwlock); 364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** 367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Called before pthread_rwlock_rdlock() is invoked. If a data structure for 368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * the client-side object was not yet created, do this now. Also check whether 369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * an attempt is made to lock recursively a synchronization object that must 370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * not be locked recursively. 371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(rwlock_pre_rdlock)(const Addr rwlock, const RwLockT rwlock_type) 373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_info* p; 375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(s_trace_rwlock)) 377b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(trace_msg)("[%d] pre_rwlock_rdlock 0x%lx", 378b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(thread_get_running_tid)(), rwlock); 379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type); 381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(p); 382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 383b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov if (DRD_(rwlock_is_wrlocked_by)(p, DRD_(thread_get_running_tid)())) { 384b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 }; 385b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(maybe_record_error)(VG_(get_running_tid)(), 386b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov RwlockErr, 387b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov VG_(get_IP)(VG_(get_running_tid)()), 388b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov "Already locked for writing by calling thread", 389b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov &REI); 390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** 394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Update rwlock_info state when locking the pthread_rwlock_t mutex. 395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Note: this function must be called after pthread_rwlock_rdlock() has been 396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * called, or a race condition is triggered ! 397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(rwlock_post_rdlock)(const Addr rwlock, const RwLockT rwlock_type, 399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Bool took_lock) 400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const DrdThreadId drd_tid = DRD_(thread_get_running_tid)(); 402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_info* p; 403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(s_trace_rwlock)) 406b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(trace_msg)("[%d] post_rwlock_rdlock 0x%lx", drd_tid, rwlock); 407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = DRD_(rwlock_get)(rwlock); 409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (! p || ! took_lock) 411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(! DRD_(rwlock_is_wrlocked)(p)); 414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q = DRD_(lookup_or_insert_node)(p->thread_info, drd_tid); 416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (++q->reader_nesting_count == 1) 417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(thread_new_segment)(drd_tid); 419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(s_rwlock_segment_creation_count)++; 420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(rwlock_combine_other_vc)(p, drd_tid, False); 421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->acquiry_time_ms = VG_(read_millisecond_timer)(); 423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0); 424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** 428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Called before pthread_rwlock_wrlock() is invoked. If a data structure for 429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * the client-side object was not yet created, do this now. Also check whether 430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * an attempt is made to lock recursively a synchronization object that must 431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * not be locked recursively. 432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(rwlock_pre_wrlock)(const Addr rwlock, const RwLockT rwlock_type) 434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_info* p; 436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = DRD_(rwlock_get)(rwlock); 438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(s_trace_rwlock)) 440b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(trace_msg)("[%d] pre_rwlock_wrlock 0x%lx", 441b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(thread_get_running_tid)(), rwlock); 442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (p == 0) 444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type); 445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(p); 447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(rwlock_is_wrlocked_by)(p, DRD_(thread_get_running_tid)())) 449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 }; 451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error)(VG_(get_running_tid)(), 452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErr, 453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(VG_(get_running_tid)()), 454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "Recursive writer locking not allowed", 455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &REI); 456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** 460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Update rwlock_info state when locking the pthread_rwlock_t rwlock. 461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Note: this function must be called after pthread_rwlock_wrlock() has 462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * finished, or a race condition is triggered ! 463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(rwlock_post_wrlock)(const Addr rwlock, const RwLockT rwlock_type, 465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const Bool took_lock) 466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const DrdThreadId drd_tid = DRD_(thread_get_running_tid)(); 468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_info* p; 469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = DRD_(rwlock_get)(rwlock); 472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(s_trace_rwlock)) 474b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(trace_msg)("[%d] post_rwlock_wrlock 0x%lx", drd_tid, rwlock); 475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (! p || ! took_lock) 477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q = DRD_(lookup_or_insert_node)(p->thread_info, 480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(thread_get_running_tid)()); 481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(q->writer_nesting_count == 0); 482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q->writer_nesting_count++; 483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(q->writer_nesting_count == 1); 484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(thread_new_segment)(drd_tid); 485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(s_rwlock_segment_creation_count)++; 486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(rwlock_combine_other_vc)(p, drd_tid, True); 487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->acquiry_time_ms = VG_(read_millisecond_timer)(); 488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0); 489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** 492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Update rwlock_info state when unlocking the pthread_rwlock_t rwlock. 493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * @param rwlock Pointer to pthread_rwlock_t data structure in the client space. 495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * @return New value of the rwlock recursion count. 497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * 498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * @note This function must be called before pthread_rwlock_unlock() is called, 499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * or a race condition is triggered ! 500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid DRD_(rwlock_pre_unlock)(const Addr rwlock, const RwLockT rwlock_type) 502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const DrdThreadId drd_tid = DRD_(thread_get_running_tid)(); 504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const ThreadId vg_tid = VG_(get_running_tid)(); 505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_info* p; 506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(s_trace_rwlock)) 509b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov DRD_(trace_msg)("[%d] rwlock_unlock 0x%lx", drd_tid, rwlock); 510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown p = DRD_(rwlock_get)(rwlock); 512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (p == 0) 513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown GenericErrInfo GEI = { 515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown .tid = DRD_(thread_get_running_tid)(), 516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown .addr = rwlock, 517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown }; 518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error)(VG_(get_running_tid)(), 519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown GenericErr, 520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(VG_(get_running_tid)()), 521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "Not a reader-writer lock", 522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &GEI); 523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown drd_rwlock_check_type(p, rwlock_type); 527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (! DRD_(rwlock_is_locked_by)(p, drd_tid)) 529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 }; 531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error)(vg_tid, 532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErr, 533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(vg_tid), 534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "Reader-writer lock not locked by calling thread", 535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &REI); 536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return; 537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q = DRD_(lookup_or_insert_node)(p->thread_info, drd_tid); 539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(q); 540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (q->reader_nesting_count > 0) 541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q->reader_nesting_count--; 543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (q->reader_nesting_count == 0 && DRD_(s_shared_threshold_ms) > 0) 544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms; 546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (held > DRD_(s_shared_threshold_ms)) 547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HoldtimeErrInfo HEI 549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown = { DRD_(thread_get_running_tid)(), 550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown rwlock, p->acquired_at, held, DRD_(s_shared_threshold_ms) }; 551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error)(vg_tid, 552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HoldtimeErr, 553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(vg_tid), 554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "rwlock", 555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &HEI); 556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (q->reader_nesting_count == 0 && q->writer_nesting_count == 0) 559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* 561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This pthread_rwlock_unlock() call really unlocks the rwlock. Save 562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * the current vector clock of the thread such that it is available 563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * when this rwlock is locked again. 564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(thread_get_latest_segment)(&q->latest_rdlocked_segment, drd_tid); 566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(thread_new_segment)(drd_tid); 567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(s_rwlock_segment_creation_count)++; 568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else if (q->writer_nesting_count > 0) 571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q->writer_nesting_count--; 573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (q->writer_nesting_count == 0 && DRD_(s_exclusive_threshold_ms) > 0) 574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms; 576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (held > DRD_(s_exclusive_threshold_ms)) 577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HoldtimeErrInfo HEI 579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown = { DRD_(thread_get_running_tid)(), 580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown rwlock, p->acquired_at, held, 581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(s_exclusive_threshold_ms) }; 582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error)(vg_tid, 583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown HoldtimeErr, 584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(vg_tid), 585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "rwlock", 586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &HEI); 587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (q->reader_nesting_count == 0 && q->writer_nesting_count == 0) 590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown /* 592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This pthread_rwlock_unlock() call really unlocks the rwlock. Save 593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * the current vector clock of the thread such that it is available 594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * when this rwlock is locked again. 595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */ 596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(thread_get_latest_segment)(&q->latest_wrlocked_segment, drd_tid); 597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(thread_new_segment)(drd_tid); 598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown DRD_(s_rwlock_segment_creation_count)++; 599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown else 602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown tl_assert(False); 604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/** Called when thread tid stops to exist. */ 608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void rwlock_delete_thread(struct rwlock_info* const p, 609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown const DrdThreadId tid) 610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown struct rwlock_thread_info* q; 612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown if (DRD_(rwlock_is_locked_by)(p, tid)) 614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown { 615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 }; 616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(maybe_record_error)(VG_(get_running_tid)(), 617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown RwlockErr, 618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown VG_(get_IP)(VG_(get_running_tid)()), 619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown "Reader-writer lock still locked at thread exit", 620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown &REI); 621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q = DRD_(lookup_or_insert_node)(p->thread_info, tid); 622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q->reader_nesting_count = 0; 623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown q->writer_nesting_count = 0; 624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown } 625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown 627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong DRD_(get_rwlock_segment_creation_count)(void) 628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{ 629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown return DRD_(s_rwlock_segment_creation_count); 630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown} 631