1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  This file is part of drd, a thread error detector.
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov  Copyright (C) 2006-2013 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