blob: a6edfdd6a5f3e61b9ed2075356ba95b71e642f7f [file] [log] [blame]
bartbedfd232009-03-26 19:07:15 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
bart777f7fe2008-03-02 17:43:18 +00002/*
bart86562bd2009-02-16 19:43:56 +00003 This file is part of drd, a thread error detector.
bart777f7fe2008-03-02 17:43:18 +00004
bart86562bd2009-02-16 19:43:56 +00005 Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
bart777f7fe2008-03-02 17:43:18 +00006
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307, USA.
21
22 The GNU General Public License is contained in the file COPYING.
23*/
24
25
26#include "drd_clientobj.h"
27#include "drd_error.h"
28#include "drd_rwlock.h"
bart9d5b7962008-05-14 12:25:00 +000029#include "pub_tool_vki.h"
bart777f7fe2008-03-02 17:43:18 +000030#include "pub_tool_errormgr.h" // VG_(maybe_record_error)()
31#include "pub_tool_libcassert.h" // tl_assert()
32#include "pub_tool_libcprint.h" // VG_(message)()
bart9d5b7962008-05-14 12:25:00 +000033#include "pub_tool_libcproc.h" // VG_(read_millisecond_timer)()
bart777f7fe2008-03-02 17:43:18 +000034#include "pub_tool_machine.h" // VG_(get_IP)()
35#include "pub_tool_mallocfree.h" // VG_(malloc)(), VG_(free)()
36#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
37
38
bartdc1ef032009-02-15 14:18:02 +000039/* Local type definitions. */
bart777f7fe2008-03-02 17:43:18 +000040
41struct rwlock_thread_info
42{
bartbedfd232009-03-26 19:07:15 +000043 UWord tid; // DrdThreadId.
44 UInt reader_nesting_count;
45 UInt writer_nesting_count;
bartb3f33402009-07-25 11:15:03 +000046 // Segment of last unlock call by this thread that unlocked a writer lock.
47 Segment* latest_wrlocked_segment;
48 // Segment of last unlock call by this thread that unlocked a reader lock.
49 Segment* latest_rdlocked_segment;
bart777f7fe2008-03-02 17:43:18 +000050};
51
52
bartdc1ef032009-02-15 14:18:02 +000053/* Local functions. */
bart777f7fe2008-03-02 17:43:18 +000054
bartd2c5eae2009-02-21 15:27:04 +000055static void rwlock_cleanup(struct rwlock_info* p);
56static void rwlock_delete_thread(struct rwlock_info* const p,
57 const DrdThreadId tid);
bart777f7fe2008-03-02 17:43:18 +000058
59
bartdc1ef032009-02-15 14:18:02 +000060/* Local variables. */
bart777f7fe2008-03-02 17:43:18 +000061
bartdc1ef032009-02-15 14:18:02 +000062static Bool DRD_(s_trace_rwlock);
63static UInt DRD_(s_exclusive_threshold_ms);
64static UInt DRD_(s_shared_threshold_ms);
65static ULong DRD_(s_rwlock_segment_creation_count);
bart777f7fe2008-03-02 17:43:18 +000066
67
bartdc1ef032009-02-15 14:18:02 +000068/* Function definitions. */
bart777f7fe2008-03-02 17:43:18 +000069
bartdc1ef032009-02-15 14:18:02 +000070void DRD_(rwlock_set_trace)(const Bool trace_rwlock)
bart777f7fe2008-03-02 17:43:18 +000071{
bartbedfd232009-03-26 19:07:15 +000072 tl_assert(trace_rwlock == False || trace_rwlock == True);
73 DRD_(s_trace_rwlock) = trace_rwlock;
bart777f7fe2008-03-02 17:43:18 +000074}
75
bartdc1ef032009-02-15 14:18:02 +000076void DRD_(rwlock_set_exclusive_threshold)(const UInt exclusive_threshold_ms)
bart9d5b7962008-05-14 12:25:00 +000077{
bartbedfd232009-03-26 19:07:15 +000078 DRD_(s_exclusive_threshold_ms) = exclusive_threshold_ms;
bart9d5b7962008-05-14 12:25:00 +000079}
80
bartdc1ef032009-02-15 14:18:02 +000081void DRD_(rwlock_set_shared_threshold)(const UInt shared_threshold_ms)
bart9d5b7962008-05-14 12:25:00 +000082{
bartbedfd232009-03-26 19:07:15 +000083 DRD_(s_shared_threshold_ms) = shared_threshold_ms;
bart9d5b7962008-05-14 12:25:00 +000084}
85
bartdc1ef032009-02-15 14:18:02 +000086static Bool DRD_(rwlock_is_rdlocked)(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +000087{
bartbedfd232009-03-26 19:07:15 +000088 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +000089
bartbedfd232009-03-26 19:07:15 +000090 VG_(OSetGen_ResetIter)(p->thread_info);
91 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
92 {
93 return q->reader_nesting_count > 0;
94 }
95 return False;
bart777f7fe2008-03-02 17:43:18 +000096}
97
bartdc1ef032009-02-15 14:18:02 +000098static Bool DRD_(rwlock_is_wrlocked)(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +000099{
bartbedfd232009-03-26 19:07:15 +0000100 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000101
bartbedfd232009-03-26 19:07:15 +0000102 VG_(OSetGen_ResetIter)(p->thread_info);
103 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
104 {
105 return q->writer_nesting_count > 0;
106 }
107 return False;
bart777f7fe2008-03-02 17:43:18 +0000108}
109
bartdc1ef032009-02-15 14:18:02 +0000110static Bool DRD_(rwlock_is_locked)(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +0000111{
bartbedfd232009-03-26 19:07:15 +0000112 return DRD_(rwlock_is_rdlocked)(p) || DRD_(rwlock_is_wrlocked)(p);
bart777f7fe2008-03-02 17:43:18 +0000113}
114
bartdc1ef032009-02-15 14:18:02 +0000115static Bool DRD_(rwlock_is_rdlocked_by)(struct rwlock_info* p,
116 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000117{
bartbedfd232009-03-26 19:07:15 +0000118 const UWord uword_tid = tid;
119 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000120
bartbedfd232009-03-26 19:07:15 +0000121 q = VG_(OSetGen_Lookup)(p->thread_info, &uword_tid);
122 return q && q->reader_nesting_count > 0;
bart777f7fe2008-03-02 17:43:18 +0000123}
124
bartdc1ef032009-02-15 14:18:02 +0000125static Bool DRD_(rwlock_is_wrlocked_by)(struct rwlock_info* p,
126 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000127{
bartbedfd232009-03-26 19:07:15 +0000128 const UWord uword_tid = tid;
129 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000130
bartbedfd232009-03-26 19:07:15 +0000131 q = VG_(OSetGen_Lookup)(p->thread_info, &uword_tid);
132 return q && q->writer_nesting_count > 0;
bart777f7fe2008-03-02 17:43:18 +0000133}
134
bartdc1ef032009-02-15 14:18:02 +0000135static Bool DRD_(rwlock_is_locked_by)(struct rwlock_info* p,
136 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000137{
bartbedfd232009-03-26 19:07:15 +0000138 return (DRD_(rwlock_is_rdlocked_by)(p, tid)
139 || DRD_(rwlock_is_wrlocked_by)(p, tid));
bart777f7fe2008-03-02 17:43:18 +0000140}
141
bart165b90f2008-05-10 12:54:27 +0000142/** Either look up or insert a node corresponding to DRD thread id 'tid'. */
bart777f7fe2008-03-02 17:43:18 +0000143static
bartdc1ef032009-02-15 14:18:02 +0000144struct rwlock_thread_info*
145DRD_(lookup_or_insert_node)(OSet* oset, const UWord tid)
bart777f7fe2008-03-02 17:43:18 +0000146{
bartbedfd232009-03-26 19:07:15 +0000147 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000148
bartbedfd232009-03-26 19:07:15 +0000149 q = VG_(OSetGen_Lookup)(oset, &tid);
150 if (q == 0)
151 {
152 q = VG_(OSetGen_AllocNode)(oset, sizeof(*q));
153 q->tid = tid;
154 q->reader_nesting_count = 0;
155 q->writer_nesting_count = 0;
bartb3f33402009-07-25 11:15:03 +0000156 q->latest_wrlocked_segment = 0;
157 q->latest_rdlocked_segment = 0;
bartbedfd232009-03-26 19:07:15 +0000158 VG_(OSetGen_Insert)(oset, q);
159 }
160 tl_assert(q);
161 return q;
bart777f7fe2008-03-02 17:43:18 +0000162}
163
bartdc1ef032009-02-15 14:18:02 +0000164/**
165 * Combine the vector clock corresponding to the last unlock operation of
166 * reader-writer lock p into the vector clock of thread 'tid'.
bart165b90f2008-05-10 12:54:27 +0000167 */
bartdc1ef032009-02-15 14:18:02 +0000168static void DRD_(rwlock_combine_other_vc)(struct rwlock_info* const p,
169 const DrdThreadId tid,
170 const Bool readers_too)
bart777f7fe2008-03-02 17:43:18 +0000171{
bartbedfd232009-03-26 19:07:15 +0000172 struct rwlock_thread_info* q;
bart8f822af2009-06-08 18:20:42 +0000173 VectorClock old_vc;
bart777f7fe2008-03-02 17:43:18 +0000174
bart8f822af2009-06-08 18:20:42 +0000175 DRD_(vc_copy)(&old_vc, &DRD_(g_threadinfo)[tid].last->vc);
bartbedfd232009-03-26 19:07:15 +0000176 VG_(OSetGen_ResetIter)(p->thread_info);
177 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
178 {
bartb3f33402009-07-25 11:15:03 +0000179 if (q->tid != tid)
bartbedfd232009-03-26 19:07:15 +0000180 {
bartb3f33402009-07-25 11:15:03 +0000181 if (q->latest_wrlocked_segment)
182 {
183 DRD_(vc_combine)(&DRD_(g_threadinfo)[tid].last->vc,
184 &q->latest_wrlocked_segment->vc);
185 }
186 if (readers_too && q->latest_rdlocked_segment)
187 {
188 DRD_(vc_combine)(&DRD_(g_threadinfo)[tid].last->vc,
189 &q->latest_rdlocked_segment->vc);
190 }
bartbedfd232009-03-26 19:07:15 +0000191 }
192 }
bart8f822af2009-06-08 18:20:42 +0000193 DRD_(thread_update_conflict_set)(tid, &old_vc);
194 DRD_(vc_cleanup)(&old_vc);
bart777f7fe2008-03-02 17:43:18 +0000195}
196
bartc8441502009-07-27 16:03:51 +0000197/**
198 * Compare the type of the rwlock specified at initialization time with
199 * the type passed as an argument, and complain if these two types do not
200 * match.
201 */
202static Bool drd_rwlock_check_type(struct rwlock_info* const p,
203 const RwLockT rwlock_type)
204{
205 tl_assert(p);
206 /* The code below has to be updated if additional rwlock types are added. */
207 tl_assert(rwlock_type == pthread_rwlock || rwlock_type == user_rwlock);
208 tl_assert(p->rwlock_type == pthread_rwlock || p->rwlock_type == user_rwlock);
209
210 if (p->rwlock_type == rwlock_type)
211 return True;
212
213 {
214 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
215 VG_(maybe_record_error)
216 (VG_(get_running_tid)(),
217 RwlockErr,
218 VG_(get_IP)(VG_(get_running_tid)()),
219 rwlock_type == pthread_rwlock
220 ? "Attempt to use a user-defined rwlock as a POSIX rwlock"
221 : "Attempt to use a POSIX rwlock as a user-defined rwlock",
222 &REI);
223 }
224 return False;
225}
226
bart165b90f2008-05-10 12:54:27 +0000227/** Initialize the rwlock_info data structure *p. */
bart777f7fe2008-03-02 17:43:18 +0000228static
bartc8441502009-07-27 16:03:51 +0000229void DRD_(rwlock_initialize)(struct rwlock_info* const p, const Addr rwlock,
230 const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000231{
bartbedfd232009-03-26 19:07:15 +0000232 tl_assert(rwlock != 0);
233 tl_assert(p->a1 == rwlock);
234 tl_assert(p->type == ClientRwlock);
bart777f7fe2008-03-02 17:43:18 +0000235
bartbedfd232009-03-26 19:07:15 +0000236 p->cleanup = (void(*)(DrdClientobj*))rwlock_cleanup;
237 p->delete_thread
238 = (void(*)(DrdClientobj*, DrdThreadId))rwlock_delete_thread;
bartc8441502009-07-27 16:03:51 +0000239 p->rwlock_type = rwlock_type;
bartbedfd232009-03-26 19:07:15 +0000240 p->thread_info = VG_(OSetGen_Create)(
241 0, 0, VG_(malloc), "drd.rwlock.ri.1", VG_(free));
242 p->acquiry_time_ms = 0;
243 p->acquired_at = 0;
bart777f7fe2008-03-02 17:43:18 +0000244}
245
246/** Deallocate the memory that was allocated by rwlock_initialize(). */
bartd2c5eae2009-02-21 15:27:04 +0000247static void rwlock_cleanup(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +0000248{
bartbedfd232009-03-26 19:07:15 +0000249 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000250
bartbedfd232009-03-26 19:07:15 +0000251 tl_assert(p);
bart777f7fe2008-03-02 17:43:18 +0000252
bartbedfd232009-03-26 19:07:15 +0000253 if (DRD_(s_trace_rwlock))
254 {
255 VG_(message)(Vg_UserMsg,
bart63c92ea2009-07-19 17:53:56 +0000256 "[%d] rwlock_destroy 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000257 DRD_(thread_get_running_tid)(),
258 p->a1);
259 }
bart777f7fe2008-03-02 17:43:18 +0000260
bartbedfd232009-03-26 19:07:15 +0000261 if (DRD_(rwlock_is_locked)(p))
262 {
bartd45d9952009-05-31 18:53:54 +0000263 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000264 VG_(maybe_record_error)(VG_(get_running_tid)(),
265 RwlockErr,
266 VG_(get_IP)(VG_(get_running_tid)()),
267 "Destroying locked rwlock",
268 &REI);
269 }
bart777f7fe2008-03-02 17:43:18 +0000270
bartbedfd232009-03-26 19:07:15 +0000271 VG_(OSetGen_ResetIter)(p->thread_info);
272 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
273 {
bartb3f33402009-07-25 11:15:03 +0000274 DRD_(sg_put)(q->latest_wrlocked_segment);
275 DRD_(sg_put)(q->latest_rdlocked_segment);
bartbedfd232009-03-26 19:07:15 +0000276 }
bartb3f33402009-07-25 11:15:03 +0000277
bartbedfd232009-03-26 19:07:15 +0000278 VG_(OSetGen_Destroy)(p->thread_info);
bart777f7fe2008-03-02 17:43:18 +0000279}
280
281static
282struct rwlock_info*
bartc8441502009-07-27 16:03:51 +0000283DRD_(rwlock_get_or_allocate)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000284{
bartbedfd232009-03-26 19:07:15 +0000285 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000286
bartbedfd232009-03-26 19:07:15 +0000287 tl_assert(offsetof(DrdClientobj, rwlock) == 0);
288 p = &(DRD_(clientobj_get)(rwlock, ClientRwlock)->rwlock);
289 if (p)
bartc8441502009-07-27 16:03:51 +0000290 {
291 drd_rwlock_check_type(p, rwlock_type);
bartbedfd232009-03-26 19:07:15 +0000292 return p;
bartc8441502009-07-27 16:03:51 +0000293 }
bart777f7fe2008-03-02 17:43:18 +0000294
bartbedfd232009-03-26 19:07:15 +0000295 if (DRD_(clientobj_present)(rwlock, rwlock + 1))
296 {
bartd45d9952009-05-31 18:53:54 +0000297 GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
bartbedfd232009-03-26 19:07:15 +0000298 VG_(maybe_record_error)(VG_(get_running_tid)(),
299 GenericErr,
300 VG_(get_IP)(VG_(get_running_tid)()),
301 "Not a reader-writer lock",
302 &GEI);
303 return 0;
304 }
bart777f7fe2008-03-02 17:43:18 +0000305
bartbedfd232009-03-26 19:07:15 +0000306 p = &(DRD_(clientobj_add)(rwlock, ClientRwlock)->rwlock);
bartc8441502009-07-27 16:03:51 +0000307 DRD_(rwlock_initialize)(p, rwlock, rwlock_type);
bartbedfd232009-03-26 19:07:15 +0000308 return p;
bart777f7fe2008-03-02 17:43:18 +0000309}
310
bartdc1ef032009-02-15 14:18:02 +0000311static struct rwlock_info* DRD_(rwlock_get)(const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000312{
bartbedfd232009-03-26 19:07:15 +0000313 tl_assert(offsetof(DrdClientobj, rwlock) == 0);
314 return &(DRD_(clientobj_get)(rwlock, ClientRwlock)->rwlock);
bart777f7fe2008-03-02 17:43:18 +0000315}
316
317/** Called before pthread_rwlock_init(). */
bartd45d9952009-05-31 18:53:54 +0000318struct rwlock_info* DRD_(rwlock_pre_init)(const Addr rwlock,
319 const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000320{
bartbedfd232009-03-26 19:07:15 +0000321 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000322
bartbedfd232009-03-26 19:07:15 +0000323 if (DRD_(s_trace_rwlock))
324 {
325 VG_(message)(Vg_UserMsg,
bart63c92ea2009-07-19 17:53:56 +0000326 "[%d] rwlock_init 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000327 DRD_(thread_get_running_tid)(),
328 rwlock);
329 }
bart777f7fe2008-03-02 17:43:18 +0000330
bartbedfd232009-03-26 19:07:15 +0000331 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000332
bartbedfd232009-03-26 19:07:15 +0000333 if (p)
bart67707ec2009-07-27 17:02:52 +0000334 drd_rwlock_check_type(p, rwlock_type);
335
336 if (p)
bartbedfd232009-03-26 19:07:15 +0000337 {
338 const ThreadId vg_tid = VG_(get_running_tid)();
bartd45d9952009-05-31 18:53:54 +0000339 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000340 VG_(maybe_record_error)(vg_tid,
341 RwlockErr,
342 VG_(get_IP)(vg_tid),
343 "Reader-writer lock reinitialization",
344 &REI);
345 return p;
346 }
bart777f7fe2008-03-02 17:43:18 +0000347
bartc8441502009-07-27 16:03:51 +0000348 p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type);
bart777f7fe2008-03-02 17:43:18 +0000349
bartbedfd232009-03-26 19:07:15 +0000350 return p;
bart777f7fe2008-03-02 17:43:18 +0000351}
352
353/** Called after pthread_rwlock_destroy(). */
bartd45d9952009-05-31 18:53:54 +0000354void DRD_(rwlock_post_destroy)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000355{
bartbedfd232009-03-26 19:07:15 +0000356 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000357
bartbedfd232009-03-26 19:07:15 +0000358 p = DRD_(rwlock_get)(rwlock);
359 if (p == 0)
360 {
bartd45d9952009-05-31 18:53:54 +0000361 GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
bartbedfd232009-03-26 19:07:15 +0000362 VG_(maybe_record_error)(VG_(get_running_tid)(),
363 GenericErr,
364 VG_(get_IP)(VG_(get_running_tid)()),
365 "Not a reader-writer lock",
366 &GEI);
367 return;
368 }
bart777f7fe2008-03-02 17:43:18 +0000369
bart67707ec2009-07-27 17:02:52 +0000370 drd_rwlock_check_type(p, rwlock_type);
371
bartbedfd232009-03-26 19:07:15 +0000372 DRD_(clientobj_remove)(rwlock, ClientRwlock);
bart777f7fe2008-03-02 17:43:18 +0000373}
374
bartdc1ef032009-02-15 14:18:02 +0000375/**
376 * Called before pthread_rwlock_rdlock() is invoked. If a data structure for
377 * the client-side object was not yet created, do this now. Also check whether
378 * an attempt is made to lock recursively a synchronization object that must
379 * not be locked recursively.
bart777f7fe2008-03-02 17:43:18 +0000380 */
bartd45d9952009-05-31 18:53:54 +0000381void DRD_(rwlock_pre_rdlock)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000382{
bartbedfd232009-03-26 19:07:15 +0000383 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000384
bartbedfd232009-03-26 19:07:15 +0000385 if (DRD_(s_trace_rwlock))
386 {
387 VG_(message)(Vg_UserMsg,
bart63c92ea2009-07-19 17:53:56 +0000388 "[%d] pre_rwlock_rdlock 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000389 DRD_(thread_get_running_tid)(),
390 rwlock);
391 }
bart777f7fe2008-03-02 17:43:18 +0000392
bartc8441502009-07-27 16:03:51 +0000393 p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type);
bartbedfd232009-03-26 19:07:15 +0000394 tl_assert(p);
bart165b90f2008-05-10 12:54:27 +0000395
bartbedfd232009-03-26 19:07:15 +0000396 if (DRD_(rwlock_is_wrlocked_by)(p, DRD_(thread_get_running_tid)()))
397 {
398 VG_(message)(Vg_UserMsg,
399 "reader-writer lock 0x%lx is already locked for"
sewardj1e29ebc2009-07-15 14:49:17 +0000400 " writing by calling thread\n",
bartbedfd232009-03-26 19:07:15 +0000401 p->a1);
402 }
bart777f7fe2008-03-02 17:43:18 +0000403}
404
bartdc1ef032009-02-15 14:18:02 +0000405/**
406 * Update rwlock_info state when locking the pthread_rwlock_t mutex.
407 * Note: this function must be called after pthread_rwlock_rdlock() has been
408 * called, or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000409 */
bartd45d9952009-05-31 18:53:54 +0000410void DRD_(rwlock_post_rdlock)(const Addr rwlock, const RwLockT rwlock_type,
411 const Bool took_lock)
bart777f7fe2008-03-02 17:43:18 +0000412{
bartbedfd232009-03-26 19:07:15 +0000413 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
414 struct rwlock_info* p;
415 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000416
bartbedfd232009-03-26 19:07:15 +0000417 if (DRD_(s_trace_rwlock))
418 {
419 VG_(message)(Vg_UserMsg,
bart63c92ea2009-07-19 17:53:56 +0000420 "[%d] post_rwlock_rdlock 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000421 drd_tid,
422 rwlock);
423 }
bart777f7fe2008-03-02 17:43:18 +0000424
bartbedfd232009-03-26 19:07:15 +0000425 p = DRD_(rwlock_get)(rwlock);
bart165b90f2008-05-10 12:54:27 +0000426
bartbedfd232009-03-26 19:07:15 +0000427 if (! p || ! took_lock)
428 return;
bart777f7fe2008-03-02 17:43:18 +0000429
bartbedfd232009-03-26 19:07:15 +0000430 tl_assert(! DRD_(rwlock_is_wrlocked)(p));
bart777f7fe2008-03-02 17:43:18 +0000431
bartbedfd232009-03-26 19:07:15 +0000432 q = DRD_(lookup_or_insert_node)(p->thread_info, drd_tid);
433 if (++q->reader_nesting_count == 1)
434 {
bartbedfd232009-03-26 19:07:15 +0000435 DRD_(thread_new_segment)(drd_tid);
436 DRD_(s_rwlock_segment_creation_count)++;
bart7627be32009-06-06 12:26:05 +0000437 DRD_(rwlock_combine_other_vc)(p, drd_tid, False);
bart9d5b7962008-05-14 12:25:00 +0000438
bartbedfd232009-03-26 19:07:15 +0000439 p->acquiry_time_ms = VG_(read_millisecond_timer)();
440 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
441 }
bart777f7fe2008-03-02 17:43:18 +0000442}
443
bartdc1ef032009-02-15 14:18:02 +0000444/**
445 * Called before pthread_rwlock_wrlock() is invoked. If a data structure for
446 * the client-side object was not yet created, do this now. Also check whether
447 * an attempt is made to lock recursively a synchronization object that must
448 * not be locked recursively.
bart777f7fe2008-03-02 17:43:18 +0000449 */
bartd45d9952009-05-31 18:53:54 +0000450void DRD_(rwlock_pre_wrlock)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000451{
bartbedfd232009-03-26 19:07:15 +0000452 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000453
bartbedfd232009-03-26 19:07:15 +0000454 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000455
bartbedfd232009-03-26 19:07:15 +0000456 if (DRD_(s_trace_rwlock))
457 {
458 VG_(message)(Vg_UserMsg,
bart63c92ea2009-07-19 17:53:56 +0000459 "[%d] pre_rwlock_wrlock 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000460 DRD_(thread_get_running_tid)(),
461 rwlock);
462 }
bart777f7fe2008-03-02 17:43:18 +0000463
bartbedfd232009-03-26 19:07:15 +0000464 if (p == 0)
bartc8441502009-07-27 16:03:51 +0000465 p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type);
bart777f7fe2008-03-02 17:43:18 +0000466
bartbedfd232009-03-26 19:07:15 +0000467 tl_assert(p);
bart777f7fe2008-03-02 17:43:18 +0000468
bartbedfd232009-03-26 19:07:15 +0000469 if (DRD_(rwlock_is_wrlocked_by)(p, DRD_(thread_get_running_tid)()))
470 {
bartd45d9952009-05-31 18:53:54 +0000471 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000472 VG_(maybe_record_error)(VG_(get_running_tid)(),
473 RwlockErr,
474 VG_(get_IP)(VG_(get_running_tid)()),
475 "Recursive writer locking not allowed",
476 &REI);
477 }
bart777f7fe2008-03-02 17:43:18 +0000478}
479
480/**
481 * Update rwlock_info state when locking the pthread_rwlock_t rwlock.
bart165b90f2008-05-10 12:54:27 +0000482 * Note: this function must be called after pthread_rwlock_wrlock() has
483 * finished, or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000484 */
bartd45d9952009-05-31 18:53:54 +0000485void DRD_(rwlock_post_wrlock)(const Addr rwlock, const RwLockT rwlock_type,
486 const Bool took_lock)
bart777f7fe2008-03-02 17:43:18 +0000487{
bartbedfd232009-03-26 19:07:15 +0000488 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
489 struct rwlock_info* p;
490 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000491
bartbedfd232009-03-26 19:07:15 +0000492 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000493
bartbedfd232009-03-26 19:07:15 +0000494 if (DRD_(s_trace_rwlock))
495 {
496 VG_(message)(Vg_UserMsg,
bart63c92ea2009-07-19 17:53:56 +0000497 "[%d] post_rwlock_wrlock 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000498 drd_tid,
499 rwlock);
500 }
bart777f7fe2008-03-02 17:43:18 +0000501
bartbedfd232009-03-26 19:07:15 +0000502 if (! p || ! took_lock)
503 return;
bart777f7fe2008-03-02 17:43:18 +0000504
bartbedfd232009-03-26 19:07:15 +0000505 q = DRD_(lookup_or_insert_node)(p->thread_info,
506 DRD_(thread_get_running_tid)());
507 tl_assert(q->writer_nesting_count == 0);
508 q->writer_nesting_count++;
bartbedfd232009-03-26 19:07:15 +0000509 tl_assert(q->writer_nesting_count == 1);
bartbedfd232009-03-26 19:07:15 +0000510 DRD_(thread_new_segment)(drd_tid);
511 DRD_(s_rwlock_segment_creation_count)++;
bart7627be32009-06-06 12:26:05 +0000512 DRD_(rwlock_combine_other_vc)(p, drd_tid, True);
bartbedfd232009-03-26 19:07:15 +0000513 p->acquiry_time_ms = VG_(read_millisecond_timer)();
514 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
bart777f7fe2008-03-02 17:43:18 +0000515}
516
517/**
518 * Update rwlock_info state when unlocking the pthread_rwlock_t rwlock.
bart7e6de962009-02-21 09:39:09 +0000519 *
bart777f7fe2008-03-02 17:43:18 +0000520 * @param rwlock Pointer to pthread_rwlock_t data structure in the client space.
bart7e6de962009-02-21 09:39:09 +0000521 *
522 * @return New value of the rwlock recursion count.
523 *
524 * @note This function must be called before pthread_rwlock_unlock() is called,
525 * or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000526 */
bartd45d9952009-05-31 18:53:54 +0000527void DRD_(rwlock_pre_unlock)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000528{
bartbedfd232009-03-26 19:07:15 +0000529 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
530 const ThreadId vg_tid = VG_(get_running_tid)();
531 struct rwlock_info* p;
532 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000533
bartbedfd232009-03-26 19:07:15 +0000534 if (DRD_(s_trace_rwlock))
535 {
536 VG_(message)(Vg_UserMsg,
bart63c92ea2009-07-19 17:53:56 +0000537 "[%d] rwlock_unlock 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000538 drd_tid,
539 rwlock);
540 }
bart777f7fe2008-03-02 17:43:18 +0000541
bartbedfd232009-03-26 19:07:15 +0000542 p = DRD_(rwlock_get)(rwlock);
543 if (p == 0)
544 {
bartd45d9952009-05-31 18:53:54 +0000545 GenericErrInfo GEI = { DRD_(thread_get_running_tid)() };
bartbedfd232009-03-26 19:07:15 +0000546 VG_(maybe_record_error)(VG_(get_running_tid)(),
547 GenericErr,
548 VG_(get_IP)(VG_(get_running_tid)()),
549 "Not a reader-writer lock",
550 &GEI);
551 return;
552 }
bart67707ec2009-07-27 17:02:52 +0000553
554 drd_rwlock_check_type(p, rwlock_type);
555
bartbedfd232009-03-26 19:07:15 +0000556 if (! DRD_(rwlock_is_locked_by)(p, drd_tid))
557 {
bartd45d9952009-05-31 18:53:54 +0000558 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000559 VG_(maybe_record_error)(vg_tid,
560 RwlockErr,
561 VG_(get_IP)(vg_tid),
562 "Reader-writer lock not locked by calling thread",
563 &REI);
564 return;
565 }
566 q = DRD_(lookup_or_insert_node)(p->thread_info, drd_tid);
567 tl_assert(q);
568 if (q->reader_nesting_count > 0)
569 {
570 q->reader_nesting_count--;
571 if (q->reader_nesting_count == 0 && DRD_(s_shared_threshold_ms) > 0)
bart9d5b7962008-05-14 12:25:00 +0000572 {
bart430c45f2009-04-13 08:05:18 +0000573 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
bartbedfd232009-03-26 19:07:15 +0000574 if (held > DRD_(s_shared_threshold_ms))
575 {
576 HoldtimeErrInfo HEI
bartd45d9952009-05-31 18:53:54 +0000577 = { DRD_(thread_get_running_tid)(),
578 rwlock, p->acquired_at, held, DRD_(s_shared_threshold_ms) };
bartbedfd232009-03-26 19:07:15 +0000579 VG_(maybe_record_error)(vg_tid,
580 HoldtimeErr,
581 VG_(get_IP)(vg_tid),
582 "rwlock",
583 &HEI);
584 }
bart9d5b7962008-05-14 12:25:00 +0000585 }
bartb3f33402009-07-25 11:15:03 +0000586 if (q->reader_nesting_count == 0 && q->writer_nesting_count == 0)
587 {
588 /*
589 * This pthread_rwlock_unlock() call really unlocks the rwlock. Save
590 * the current vector clock of the thread such that it is available
591 * when this rwlock is locked again.
592 */
593 DRD_(thread_get_latest_segment)(&q->latest_rdlocked_segment, drd_tid);
594 DRD_(thread_new_segment)(drd_tid);
595 DRD_(s_rwlock_segment_creation_count)++;
596 }
bartbedfd232009-03-26 19:07:15 +0000597 }
598 else if (q->writer_nesting_count > 0)
599 {
600 q->writer_nesting_count--;
601 if (q->writer_nesting_count == 0 && DRD_(s_exclusive_threshold_ms) > 0)
bart9d5b7962008-05-14 12:25:00 +0000602 {
bart430c45f2009-04-13 08:05:18 +0000603 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
bartbedfd232009-03-26 19:07:15 +0000604 if (held > DRD_(s_exclusive_threshold_ms))
605 {
606 HoldtimeErrInfo HEI
bartd45d9952009-05-31 18:53:54 +0000607 = { DRD_(thread_get_running_tid)(),
608 rwlock, p->acquired_at, held,
bartbedfd232009-03-26 19:07:15 +0000609 DRD_(s_exclusive_threshold_ms) };
610 VG_(maybe_record_error)(vg_tid,
611 HoldtimeErr,
612 VG_(get_IP)(vg_tid),
613 "rwlock",
614 &HEI);
615 }
bart9d5b7962008-05-14 12:25:00 +0000616 }
bartb3f33402009-07-25 11:15:03 +0000617 if (q->reader_nesting_count == 0 && q->writer_nesting_count == 0)
618 {
619 /*
620 * This pthread_rwlock_unlock() call really unlocks the rwlock. Save
621 * the current vector clock of the thread such that it is available
622 * when this rwlock is locked again.
623 */
624 DRD_(thread_get_latest_segment)(&q->latest_wrlocked_segment, drd_tid);
625 DRD_(thread_new_segment)(drd_tid);
626 DRD_(s_rwlock_segment_creation_count)++;
627 }
bartbedfd232009-03-26 19:07:15 +0000628 }
629 else
630 {
631 tl_assert(False);
632 }
bart777f7fe2008-03-02 17:43:18 +0000633}
634
bartb3f33402009-07-25 11:15:03 +0000635/** Called when thread tid stops to exist. */
bartd2c5eae2009-02-21 15:27:04 +0000636static void rwlock_delete_thread(struct rwlock_info* const p,
637 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000638{
bartbedfd232009-03-26 19:07:15 +0000639 struct rwlock_thread_info* q;
bartb3f33402009-07-25 11:15:03 +0000640
bartbedfd232009-03-26 19:07:15 +0000641 if (DRD_(rwlock_is_locked_by)(p, tid))
642 {
bartd45d9952009-05-31 18:53:54 +0000643 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000644 VG_(maybe_record_error)(VG_(get_running_tid)(),
645 RwlockErr,
646 VG_(get_IP)(VG_(get_running_tid)()),
647 "Reader-writer lock still locked at thread exit",
648 &REI);
649 q = DRD_(lookup_or_insert_node)(p->thread_info, tid);
650 q->reader_nesting_count = 0;
651 q->writer_nesting_count = 0;
652 }
bart777f7fe2008-03-02 17:43:18 +0000653}
bart6bbefaf2008-04-19 15:16:45 +0000654
bartdc1ef032009-02-15 14:18:02 +0000655ULong DRD_(get_rwlock_segment_creation_count)(void)
bart6bbefaf2008-04-19 15:16:45 +0000656{
bartbedfd232009-03-26 19:07:15 +0000657 return DRD_(s_rwlock_segment_creation_count);
bart6bbefaf2008-04-19 15:16:45 +0000658}