blob: aaa61e0dddea8712b80bb4ea7ce9ae772801000d [file] [log] [blame]
bart777f7fe2008-03-02 17:43:18 +00001/*
bart86562bd2009-02-16 19:43:56 +00002 This file is part of drd, a thread error detector.
bart777f7fe2008-03-02 17:43:18 +00003
bart922304f2011-03-13 12:02:44 +00004 Copyright (C) 2006-2011 Bart Van Assche <bvanassche@acm.org>.
bart777f7fe2008-03-02 17:43:18 +00005
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307, USA.
20
21 The GNU General Public License is contained in the file COPYING.
22*/
23
24
25#include "drd_clientobj.h"
26#include "drd_error.h"
27#include "drd_rwlock.h"
bart9d5b7962008-05-14 12:25:00 +000028#include "pub_tool_vki.h"
bart777f7fe2008-03-02 17:43:18 +000029#include "pub_tool_errormgr.h" // VG_(maybe_record_error)()
30#include "pub_tool_libcassert.h" // tl_assert()
31#include "pub_tool_libcprint.h" // VG_(message)()
bart9d5b7962008-05-14 12:25:00 +000032#include "pub_tool_libcproc.h" // VG_(read_millisecond_timer)()
bart777f7fe2008-03-02 17:43:18 +000033#include "pub_tool_machine.h" // VG_(get_IP)()
34#include "pub_tool_mallocfree.h" // VG_(malloc)(), VG_(free)()
35#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
36
37
bartdc1ef032009-02-15 14:18:02 +000038/* Local type definitions. */
bart777f7fe2008-03-02 17:43:18 +000039
40struct rwlock_thread_info
41{
bartbedfd232009-03-26 19:07:15 +000042 UWord tid; // DrdThreadId.
43 UInt reader_nesting_count;
44 UInt writer_nesting_count;
bartb3f33402009-07-25 11:15:03 +000045 // Segment of last unlock call by this thread that unlocked a writer lock.
46 Segment* latest_wrlocked_segment;
47 // Segment of last unlock call by this thread that unlocked a reader lock.
48 Segment* latest_rdlocked_segment;
bart777f7fe2008-03-02 17:43:18 +000049};
50
51
bartdc1ef032009-02-15 14:18:02 +000052/* Local functions. */
bart777f7fe2008-03-02 17:43:18 +000053
bartd2c5eae2009-02-21 15:27:04 +000054static void rwlock_cleanup(struct rwlock_info* p);
55static void rwlock_delete_thread(struct rwlock_info* const p,
56 const DrdThreadId tid);
bart777f7fe2008-03-02 17:43:18 +000057
58
bartdc1ef032009-02-15 14:18:02 +000059/* Local variables. */
bart777f7fe2008-03-02 17:43:18 +000060
bartdc1ef032009-02-15 14:18:02 +000061static Bool DRD_(s_trace_rwlock);
62static UInt DRD_(s_exclusive_threshold_ms);
63static UInt DRD_(s_shared_threshold_ms);
64static ULong DRD_(s_rwlock_segment_creation_count);
bart777f7fe2008-03-02 17:43:18 +000065
66
bartdc1ef032009-02-15 14:18:02 +000067/* Function definitions. */
bart777f7fe2008-03-02 17:43:18 +000068
bartdc1ef032009-02-15 14:18:02 +000069void DRD_(rwlock_set_trace)(const Bool trace_rwlock)
bart777f7fe2008-03-02 17:43:18 +000070{
bartbedfd232009-03-26 19:07:15 +000071 tl_assert(trace_rwlock == False || trace_rwlock == True);
72 DRD_(s_trace_rwlock) = trace_rwlock;
bart777f7fe2008-03-02 17:43:18 +000073}
74
bartdc1ef032009-02-15 14:18:02 +000075void DRD_(rwlock_set_exclusive_threshold)(const UInt exclusive_threshold_ms)
bart9d5b7962008-05-14 12:25:00 +000076{
bartbedfd232009-03-26 19:07:15 +000077 DRD_(s_exclusive_threshold_ms) = exclusive_threshold_ms;
bart9d5b7962008-05-14 12:25:00 +000078}
79
bartdc1ef032009-02-15 14:18:02 +000080void DRD_(rwlock_set_shared_threshold)(const UInt shared_threshold_ms)
bart9d5b7962008-05-14 12:25:00 +000081{
bartbedfd232009-03-26 19:07:15 +000082 DRD_(s_shared_threshold_ms) = shared_threshold_ms;
bart9d5b7962008-05-14 12:25:00 +000083}
84
bartdc1ef032009-02-15 14:18:02 +000085static Bool DRD_(rwlock_is_rdlocked)(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +000086{
bartbedfd232009-03-26 19:07:15 +000087 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +000088
bartbedfd232009-03-26 19:07:15 +000089 VG_(OSetGen_ResetIter)(p->thread_info);
90 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
91 {
92 return q->reader_nesting_count > 0;
93 }
94 return False;
bart777f7fe2008-03-02 17:43:18 +000095}
96
bartdc1ef032009-02-15 14:18:02 +000097static Bool DRD_(rwlock_is_wrlocked)(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +000098{
bartbedfd232009-03-26 19:07:15 +000099 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000100
bartbedfd232009-03-26 19:07:15 +0000101 VG_(OSetGen_ResetIter)(p->thread_info);
102 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
103 {
104 return q->writer_nesting_count > 0;
105 }
106 return False;
bart777f7fe2008-03-02 17:43:18 +0000107}
108
bartdc1ef032009-02-15 14:18:02 +0000109static Bool DRD_(rwlock_is_locked)(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +0000110{
bartbedfd232009-03-26 19:07:15 +0000111 return DRD_(rwlock_is_rdlocked)(p) || DRD_(rwlock_is_wrlocked)(p);
bart777f7fe2008-03-02 17:43:18 +0000112}
113
bartdc1ef032009-02-15 14:18:02 +0000114static Bool DRD_(rwlock_is_rdlocked_by)(struct rwlock_info* p,
115 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000116{
bartbedfd232009-03-26 19:07:15 +0000117 const UWord uword_tid = tid;
118 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000119
bartbedfd232009-03-26 19:07:15 +0000120 q = VG_(OSetGen_Lookup)(p->thread_info, &uword_tid);
121 return q && q->reader_nesting_count > 0;
bart777f7fe2008-03-02 17:43:18 +0000122}
123
bartdc1ef032009-02-15 14:18:02 +0000124static Bool DRD_(rwlock_is_wrlocked_by)(struct rwlock_info* p,
125 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000126{
bartbedfd232009-03-26 19:07:15 +0000127 const UWord uword_tid = tid;
128 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000129
bartbedfd232009-03-26 19:07:15 +0000130 q = VG_(OSetGen_Lookup)(p->thread_info, &uword_tid);
131 return q && q->writer_nesting_count > 0;
bart777f7fe2008-03-02 17:43:18 +0000132}
133
bartdc1ef032009-02-15 14:18:02 +0000134static Bool DRD_(rwlock_is_locked_by)(struct rwlock_info* p,
135 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000136{
bartbedfd232009-03-26 19:07:15 +0000137 return (DRD_(rwlock_is_rdlocked_by)(p, tid)
138 || DRD_(rwlock_is_wrlocked_by)(p, tid));
bart777f7fe2008-03-02 17:43:18 +0000139}
140
bart165b90f2008-05-10 12:54:27 +0000141/** Either look up or insert a node corresponding to DRD thread id 'tid'. */
bart777f7fe2008-03-02 17:43:18 +0000142static
bartdc1ef032009-02-15 14:18:02 +0000143struct rwlock_thread_info*
144DRD_(lookup_or_insert_node)(OSet* oset, const UWord tid)
bart777f7fe2008-03-02 17:43:18 +0000145{
bartbedfd232009-03-26 19:07:15 +0000146 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000147
bartbedfd232009-03-26 19:07:15 +0000148 q = VG_(OSetGen_Lookup)(oset, &tid);
149 if (q == 0)
150 {
151 q = VG_(OSetGen_AllocNode)(oset, sizeof(*q));
152 q->tid = tid;
153 q->reader_nesting_count = 0;
154 q->writer_nesting_count = 0;
bartb3f33402009-07-25 11:15:03 +0000155 q->latest_wrlocked_segment = 0;
156 q->latest_rdlocked_segment = 0;
bartbedfd232009-03-26 19:07:15 +0000157 VG_(OSetGen_Insert)(oset, q);
158 }
159 tl_assert(q);
160 return q;
bart777f7fe2008-03-02 17:43:18 +0000161}
162
bartdc1ef032009-02-15 14:18:02 +0000163/**
164 * Combine the vector clock corresponding to the last unlock operation of
165 * reader-writer lock p into the vector clock of thread 'tid'.
bart165b90f2008-05-10 12:54:27 +0000166 */
bartdc1ef032009-02-15 14:18:02 +0000167static void DRD_(rwlock_combine_other_vc)(struct rwlock_info* const p,
168 const DrdThreadId tid,
169 const Bool readers_too)
bart777f7fe2008-03-02 17:43:18 +0000170{
bartbedfd232009-03-26 19:07:15 +0000171 struct rwlock_thread_info* q;
bart8f822af2009-06-08 18:20:42 +0000172 VectorClock old_vc;
bart777f7fe2008-03-02 17:43:18 +0000173
bartc6bf1842012-01-22 08:40:42 +0000174 DRD_(vc_copy)(&old_vc, DRD_(thread_get_vc)(tid));
bartbedfd232009-03-26 19:07:15 +0000175 VG_(OSetGen_ResetIter)(p->thread_info);
176 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
177 {
bartb3f33402009-07-25 11:15:03 +0000178 if (q->tid != tid)
bartbedfd232009-03-26 19:07:15 +0000179 {
bartb3f33402009-07-25 11:15:03 +0000180 if (q->latest_wrlocked_segment)
181 {
bartc6bf1842012-01-22 08:40:42 +0000182 DRD_(vc_combine)(DRD_(thread_get_vc)(tid),
bartb3f33402009-07-25 11:15:03 +0000183 &q->latest_wrlocked_segment->vc);
184 }
185 if (readers_too && q->latest_rdlocked_segment)
186 {
bartc6bf1842012-01-22 08:40:42 +0000187 DRD_(vc_combine)(DRD_(thread_get_vc)(tid),
bartb3f33402009-07-25 11:15:03 +0000188 &q->latest_rdlocked_segment->vc);
189 }
bartbedfd232009-03-26 19:07:15 +0000190 }
191 }
bart8f822af2009-06-08 18:20:42 +0000192 DRD_(thread_update_conflict_set)(tid, &old_vc);
193 DRD_(vc_cleanup)(&old_vc);
bart777f7fe2008-03-02 17:43:18 +0000194}
195
bartc8441502009-07-27 16:03:51 +0000196/**
197 * Compare the type of the rwlock specified at initialization time with
198 * the type passed as an argument, and complain if these two types do not
199 * match.
200 */
201static Bool drd_rwlock_check_type(struct rwlock_info* const p,
202 const RwLockT rwlock_type)
203{
204 tl_assert(p);
205 /* The code below has to be updated if additional rwlock types are added. */
206 tl_assert(rwlock_type == pthread_rwlock || rwlock_type == user_rwlock);
207 tl_assert(p->rwlock_type == pthread_rwlock || p->rwlock_type == user_rwlock);
208
209 if (p->rwlock_type == rwlock_type)
210 return True;
211
212 {
213 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
214 VG_(maybe_record_error)
215 (VG_(get_running_tid)(),
216 RwlockErr,
217 VG_(get_IP)(VG_(get_running_tid)()),
218 rwlock_type == pthread_rwlock
219 ? "Attempt to use a user-defined rwlock as a POSIX rwlock"
220 : "Attempt to use a POSIX rwlock as a user-defined rwlock",
221 &REI);
222 }
223 return False;
224}
225
bart165b90f2008-05-10 12:54:27 +0000226/** Initialize the rwlock_info data structure *p. */
bart777f7fe2008-03-02 17:43:18 +0000227static
bartc8441502009-07-27 16:03:51 +0000228void DRD_(rwlock_initialize)(struct rwlock_info* const p, const Addr rwlock,
229 const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000230{
bartbedfd232009-03-26 19:07:15 +0000231 tl_assert(rwlock != 0);
232 tl_assert(p->a1 == rwlock);
233 tl_assert(p->type == ClientRwlock);
bart777f7fe2008-03-02 17:43:18 +0000234
bartbedfd232009-03-26 19:07:15 +0000235 p->cleanup = (void(*)(DrdClientobj*))rwlock_cleanup;
236 p->delete_thread
237 = (void(*)(DrdClientobj*, DrdThreadId))rwlock_delete_thread;
bartc8441502009-07-27 16:03:51 +0000238 p->rwlock_type = rwlock_type;
bartbedfd232009-03-26 19:07:15 +0000239 p->thread_info = VG_(OSetGen_Create)(
240 0, 0, VG_(malloc), "drd.rwlock.ri.1", VG_(free));
241 p->acquiry_time_ms = 0;
242 p->acquired_at = 0;
bart777f7fe2008-03-02 17:43:18 +0000243}
244
245/** Deallocate the memory that was allocated by rwlock_initialize(). */
bartd2c5eae2009-02-21 15:27:04 +0000246static void rwlock_cleanup(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +0000247{
bartbedfd232009-03-26 19:07:15 +0000248 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000249
bartbedfd232009-03-26 19:07:15 +0000250 tl_assert(p);
bart777f7fe2008-03-02 17:43:18 +0000251
bartbedfd232009-03-26 19:07:15 +0000252 if (DRD_(s_trace_rwlock))
bartad994e82011-10-13 18:04:30 +0000253 DRD_(trace_msg)("[%d] rwlock_destroy 0x%lx",
bartb92ff0f2011-10-08 08:29:29 +0000254 DRD_(thread_get_running_tid)(), p->a1);
bart777f7fe2008-03-02 17:43:18 +0000255
bartbedfd232009-03-26 19:07:15 +0000256 if (DRD_(rwlock_is_locked)(p))
257 {
bartd45d9952009-05-31 18:53:54 +0000258 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000259 VG_(maybe_record_error)(VG_(get_running_tid)(),
260 RwlockErr,
261 VG_(get_IP)(VG_(get_running_tid)()),
262 "Destroying locked rwlock",
263 &REI);
264 }
bart777f7fe2008-03-02 17:43:18 +0000265
bartbedfd232009-03-26 19:07:15 +0000266 VG_(OSetGen_ResetIter)(p->thread_info);
267 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
268 {
bartb3f33402009-07-25 11:15:03 +0000269 DRD_(sg_put)(q->latest_wrlocked_segment);
270 DRD_(sg_put)(q->latest_rdlocked_segment);
bartbedfd232009-03-26 19:07:15 +0000271 }
bartb3f33402009-07-25 11:15:03 +0000272
bartbedfd232009-03-26 19:07:15 +0000273 VG_(OSetGen_Destroy)(p->thread_info);
bart777f7fe2008-03-02 17:43:18 +0000274}
275
276static
277struct rwlock_info*
bartc8441502009-07-27 16:03:51 +0000278DRD_(rwlock_get_or_allocate)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000279{
bartbedfd232009-03-26 19:07:15 +0000280 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000281
bartbedfd232009-03-26 19:07:15 +0000282 tl_assert(offsetof(DrdClientobj, rwlock) == 0);
283 p = &(DRD_(clientobj_get)(rwlock, ClientRwlock)->rwlock);
284 if (p)
bartc8441502009-07-27 16:03:51 +0000285 {
286 drd_rwlock_check_type(p, rwlock_type);
bartbedfd232009-03-26 19:07:15 +0000287 return p;
bartc8441502009-07-27 16:03:51 +0000288 }
bart777f7fe2008-03-02 17:43:18 +0000289
bartbedfd232009-03-26 19:07:15 +0000290 if (DRD_(clientobj_present)(rwlock, rwlock + 1))
291 {
bart62cc2322010-03-07 10:54:21 +0000292 GenericErrInfo GEI = {
293 .tid = DRD_(thread_get_running_tid)(),
294 .addr = rwlock,
295 };
bartbedfd232009-03-26 19:07:15 +0000296 VG_(maybe_record_error)(VG_(get_running_tid)(),
297 GenericErr,
298 VG_(get_IP)(VG_(get_running_tid)()),
299 "Not a reader-writer lock",
300 &GEI);
301 return 0;
302 }
bart777f7fe2008-03-02 17:43:18 +0000303
bartbedfd232009-03-26 19:07:15 +0000304 p = &(DRD_(clientobj_add)(rwlock, ClientRwlock)->rwlock);
bartc8441502009-07-27 16:03:51 +0000305 DRD_(rwlock_initialize)(p, rwlock, rwlock_type);
bartbedfd232009-03-26 19:07:15 +0000306 return p;
bart777f7fe2008-03-02 17:43:18 +0000307}
308
bartdc1ef032009-02-15 14:18:02 +0000309static struct rwlock_info* DRD_(rwlock_get)(const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000310{
bartbedfd232009-03-26 19:07:15 +0000311 tl_assert(offsetof(DrdClientobj, rwlock) == 0);
312 return &(DRD_(clientobj_get)(rwlock, ClientRwlock)->rwlock);
bart777f7fe2008-03-02 17:43:18 +0000313}
314
315/** Called before pthread_rwlock_init(). */
bartd45d9952009-05-31 18:53:54 +0000316struct rwlock_info* DRD_(rwlock_pre_init)(const Addr rwlock,
317 const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000318{
bartbedfd232009-03-26 19:07:15 +0000319 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000320
bartbedfd232009-03-26 19:07:15 +0000321 if (DRD_(s_trace_rwlock))
bartad994e82011-10-13 18:04:30 +0000322 DRD_(trace_msg)("[%d] rwlock_init 0x%lx",
bartb92ff0f2011-10-08 08:29:29 +0000323 DRD_(thread_get_running_tid)(), rwlock);
bart777f7fe2008-03-02 17:43:18 +0000324
bartbedfd232009-03-26 19:07:15 +0000325 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000326
bartbedfd232009-03-26 19:07:15 +0000327 if (p)
bart67707ec2009-07-27 17:02:52 +0000328 drd_rwlock_check_type(p, rwlock_type);
329
330 if (p)
bartbedfd232009-03-26 19:07:15 +0000331 {
332 const ThreadId vg_tid = VG_(get_running_tid)();
bartd45d9952009-05-31 18:53:54 +0000333 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000334 VG_(maybe_record_error)(vg_tid,
335 RwlockErr,
336 VG_(get_IP)(vg_tid),
337 "Reader-writer lock reinitialization",
338 &REI);
339 return p;
340 }
bart777f7fe2008-03-02 17:43:18 +0000341
bartc8441502009-07-27 16:03:51 +0000342 p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type);
bart777f7fe2008-03-02 17:43:18 +0000343
bartbedfd232009-03-26 19:07:15 +0000344 return p;
bart777f7fe2008-03-02 17:43:18 +0000345}
346
347/** Called after pthread_rwlock_destroy(). */
bartd45d9952009-05-31 18:53:54 +0000348void DRD_(rwlock_post_destroy)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000349{
bartbedfd232009-03-26 19:07:15 +0000350 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000351
bartbedfd232009-03-26 19:07:15 +0000352 p = DRD_(rwlock_get)(rwlock);
353 if (p == 0)
354 {
bart62cc2322010-03-07 10:54:21 +0000355 GenericErrInfo GEI = {
356 .tid = DRD_(thread_get_running_tid)(),
357 .addr = rwlock,
358 };
bartbedfd232009-03-26 19:07:15 +0000359 VG_(maybe_record_error)(VG_(get_running_tid)(),
360 GenericErr,
361 VG_(get_IP)(VG_(get_running_tid)()),
362 "Not a reader-writer lock",
363 &GEI);
364 return;
365 }
bart777f7fe2008-03-02 17:43:18 +0000366
bart67707ec2009-07-27 17:02:52 +0000367 drd_rwlock_check_type(p, rwlock_type);
368
bartbedfd232009-03-26 19:07:15 +0000369 DRD_(clientobj_remove)(rwlock, ClientRwlock);
bart777f7fe2008-03-02 17:43:18 +0000370}
371
bartdc1ef032009-02-15 14:18:02 +0000372/**
373 * Called before pthread_rwlock_rdlock() is invoked. If a data structure for
374 * the client-side object was not yet created, do this now. Also check whether
375 * an attempt is made to lock recursively a synchronization object that must
376 * not be locked recursively.
bart777f7fe2008-03-02 17:43:18 +0000377 */
bartd45d9952009-05-31 18:53:54 +0000378void DRD_(rwlock_pre_rdlock)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000379{
bartbedfd232009-03-26 19:07:15 +0000380 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000381
bartbedfd232009-03-26 19:07:15 +0000382 if (DRD_(s_trace_rwlock))
bartad994e82011-10-13 18:04:30 +0000383 DRD_(trace_msg)("[%d] pre_rwlock_rdlock 0x%lx",
bartb92ff0f2011-10-08 08:29:29 +0000384 DRD_(thread_get_running_tid)(), rwlock);
bart777f7fe2008-03-02 17:43:18 +0000385
bartc8441502009-07-27 16:03:51 +0000386 p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type);
bartbedfd232009-03-26 19:07:15 +0000387 tl_assert(p);
bart165b90f2008-05-10 12:54:27 +0000388
bart74b2d972011-10-08 08:54:57 +0000389 if (DRD_(rwlock_is_wrlocked_by)(p, DRD_(thread_get_running_tid)())) {
390 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
391 VG_(maybe_record_error)(VG_(get_running_tid)(),
392 RwlockErr,
393 VG_(get_IP)(VG_(get_running_tid)()),
394 "Already locked for writing by calling thread",
395 &REI);
bartbedfd232009-03-26 19:07:15 +0000396 }
bart777f7fe2008-03-02 17:43:18 +0000397}
398
bartdc1ef032009-02-15 14:18:02 +0000399/**
400 * Update rwlock_info state when locking the pthread_rwlock_t mutex.
401 * Note: this function must be called after pthread_rwlock_rdlock() has been
402 * called, or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000403 */
bartd45d9952009-05-31 18:53:54 +0000404void DRD_(rwlock_post_rdlock)(const Addr rwlock, const RwLockT rwlock_type,
405 const Bool took_lock)
bart777f7fe2008-03-02 17:43:18 +0000406{
bartbedfd232009-03-26 19:07:15 +0000407 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
408 struct rwlock_info* p;
409 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000410
bartbedfd232009-03-26 19:07:15 +0000411 if (DRD_(s_trace_rwlock))
bartad994e82011-10-13 18:04:30 +0000412 DRD_(trace_msg)("[%d] post_rwlock_rdlock 0x%lx", drd_tid, rwlock);
bart777f7fe2008-03-02 17:43:18 +0000413
bartbedfd232009-03-26 19:07:15 +0000414 p = DRD_(rwlock_get)(rwlock);
bart165b90f2008-05-10 12:54:27 +0000415
bartbedfd232009-03-26 19:07:15 +0000416 if (! p || ! took_lock)
417 return;
bart777f7fe2008-03-02 17:43:18 +0000418
bartbedfd232009-03-26 19:07:15 +0000419 tl_assert(! DRD_(rwlock_is_wrlocked)(p));
bart777f7fe2008-03-02 17:43:18 +0000420
bartbedfd232009-03-26 19:07:15 +0000421 q = DRD_(lookup_or_insert_node)(p->thread_info, drd_tid);
422 if (++q->reader_nesting_count == 1)
423 {
bartbedfd232009-03-26 19:07:15 +0000424 DRD_(thread_new_segment)(drd_tid);
425 DRD_(s_rwlock_segment_creation_count)++;
bart7627be32009-06-06 12:26:05 +0000426 DRD_(rwlock_combine_other_vc)(p, drd_tid, False);
bart9d5b7962008-05-14 12:25:00 +0000427
bartbedfd232009-03-26 19:07:15 +0000428 p->acquiry_time_ms = VG_(read_millisecond_timer)();
429 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
430 }
bart777f7fe2008-03-02 17:43:18 +0000431}
432
bartdc1ef032009-02-15 14:18:02 +0000433/**
434 * Called before pthread_rwlock_wrlock() is invoked. If a data structure for
435 * the client-side object was not yet created, do this now. Also check whether
436 * an attempt is made to lock recursively a synchronization object that must
437 * not be locked recursively.
bart777f7fe2008-03-02 17:43:18 +0000438 */
bartd45d9952009-05-31 18:53:54 +0000439void DRD_(rwlock_pre_wrlock)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000440{
bartbedfd232009-03-26 19:07:15 +0000441 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000442
bartbedfd232009-03-26 19:07:15 +0000443 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000444
bartbedfd232009-03-26 19:07:15 +0000445 if (DRD_(s_trace_rwlock))
bartad994e82011-10-13 18:04:30 +0000446 DRD_(trace_msg)("[%d] pre_rwlock_wrlock 0x%lx",
bartb92ff0f2011-10-08 08:29:29 +0000447 DRD_(thread_get_running_tid)(), rwlock);
bart777f7fe2008-03-02 17:43:18 +0000448
bartbedfd232009-03-26 19:07:15 +0000449 if (p == 0)
bartc8441502009-07-27 16:03:51 +0000450 p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type);
bart777f7fe2008-03-02 17:43:18 +0000451
bartbedfd232009-03-26 19:07:15 +0000452 tl_assert(p);
bart777f7fe2008-03-02 17:43:18 +0000453
bartbedfd232009-03-26 19:07:15 +0000454 if (DRD_(rwlock_is_wrlocked_by)(p, DRD_(thread_get_running_tid)()))
455 {
bartd45d9952009-05-31 18:53:54 +0000456 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000457 VG_(maybe_record_error)(VG_(get_running_tid)(),
458 RwlockErr,
459 VG_(get_IP)(VG_(get_running_tid)()),
460 "Recursive writer locking not allowed",
461 &REI);
462 }
bart777f7fe2008-03-02 17:43:18 +0000463}
464
465/**
466 * Update rwlock_info state when locking the pthread_rwlock_t rwlock.
bart165b90f2008-05-10 12:54:27 +0000467 * Note: this function must be called after pthread_rwlock_wrlock() has
468 * finished, or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000469 */
bartd45d9952009-05-31 18:53:54 +0000470void DRD_(rwlock_post_wrlock)(const Addr rwlock, const RwLockT rwlock_type,
471 const Bool took_lock)
bart777f7fe2008-03-02 17:43:18 +0000472{
bartbedfd232009-03-26 19:07:15 +0000473 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
474 struct rwlock_info* p;
475 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000476
bartbedfd232009-03-26 19:07:15 +0000477 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000478
bartbedfd232009-03-26 19:07:15 +0000479 if (DRD_(s_trace_rwlock))
bartad994e82011-10-13 18:04:30 +0000480 DRD_(trace_msg)("[%d] post_rwlock_wrlock 0x%lx", drd_tid, rwlock);
bart777f7fe2008-03-02 17:43:18 +0000481
bartbedfd232009-03-26 19:07:15 +0000482 if (! p || ! took_lock)
483 return;
bart777f7fe2008-03-02 17:43:18 +0000484
bartbedfd232009-03-26 19:07:15 +0000485 q = DRD_(lookup_or_insert_node)(p->thread_info,
486 DRD_(thread_get_running_tid)());
487 tl_assert(q->writer_nesting_count == 0);
488 q->writer_nesting_count++;
bartbedfd232009-03-26 19:07:15 +0000489 tl_assert(q->writer_nesting_count == 1);
bartbedfd232009-03-26 19:07:15 +0000490 DRD_(thread_new_segment)(drd_tid);
491 DRD_(s_rwlock_segment_creation_count)++;
bart7627be32009-06-06 12:26:05 +0000492 DRD_(rwlock_combine_other_vc)(p, drd_tid, True);
bartbedfd232009-03-26 19:07:15 +0000493 p->acquiry_time_ms = VG_(read_millisecond_timer)();
494 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
bart777f7fe2008-03-02 17:43:18 +0000495}
496
497/**
498 * Update rwlock_info state when unlocking the pthread_rwlock_t rwlock.
bart7e6de962009-02-21 09:39:09 +0000499 *
bart777f7fe2008-03-02 17:43:18 +0000500 * @param rwlock Pointer to pthread_rwlock_t data structure in the client space.
bart7e6de962009-02-21 09:39:09 +0000501 *
502 * @return New value of the rwlock recursion count.
503 *
504 * @note This function must be called before pthread_rwlock_unlock() is called,
505 * or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000506 */
bartd45d9952009-05-31 18:53:54 +0000507void DRD_(rwlock_pre_unlock)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000508{
bartbedfd232009-03-26 19:07:15 +0000509 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
510 const ThreadId vg_tid = VG_(get_running_tid)();
511 struct rwlock_info* p;
512 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000513
bartbedfd232009-03-26 19:07:15 +0000514 if (DRD_(s_trace_rwlock))
bartad994e82011-10-13 18:04:30 +0000515 DRD_(trace_msg)("[%d] rwlock_unlock 0x%lx", drd_tid, rwlock);
bart777f7fe2008-03-02 17:43:18 +0000516
bartbedfd232009-03-26 19:07:15 +0000517 p = DRD_(rwlock_get)(rwlock);
518 if (p == 0)
519 {
bart62cc2322010-03-07 10:54:21 +0000520 GenericErrInfo GEI = {
521 .tid = DRD_(thread_get_running_tid)(),
522 .addr = rwlock,
523 };
bartbedfd232009-03-26 19:07:15 +0000524 VG_(maybe_record_error)(VG_(get_running_tid)(),
525 GenericErr,
526 VG_(get_IP)(VG_(get_running_tid)()),
527 "Not a reader-writer lock",
528 &GEI);
529 return;
530 }
bart67707ec2009-07-27 17:02:52 +0000531
532 drd_rwlock_check_type(p, rwlock_type);
533
bartbedfd232009-03-26 19:07:15 +0000534 if (! DRD_(rwlock_is_locked_by)(p, drd_tid))
535 {
bartd45d9952009-05-31 18:53:54 +0000536 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000537 VG_(maybe_record_error)(vg_tid,
538 RwlockErr,
539 VG_(get_IP)(vg_tid),
540 "Reader-writer lock not locked by calling thread",
541 &REI);
542 return;
543 }
544 q = DRD_(lookup_or_insert_node)(p->thread_info, drd_tid);
545 tl_assert(q);
546 if (q->reader_nesting_count > 0)
547 {
548 q->reader_nesting_count--;
549 if (q->reader_nesting_count == 0 && DRD_(s_shared_threshold_ms) > 0)
bart9d5b7962008-05-14 12:25:00 +0000550 {
bart430c45f2009-04-13 08:05:18 +0000551 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
bartbedfd232009-03-26 19:07:15 +0000552 if (held > DRD_(s_shared_threshold_ms))
553 {
554 HoldtimeErrInfo HEI
bartd45d9952009-05-31 18:53:54 +0000555 = { DRD_(thread_get_running_tid)(),
556 rwlock, p->acquired_at, held, DRD_(s_shared_threshold_ms) };
bartbedfd232009-03-26 19:07:15 +0000557 VG_(maybe_record_error)(vg_tid,
558 HoldtimeErr,
559 VG_(get_IP)(vg_tid),
560 "rwlock",
561 &HEI);
562 }
bart9d5b7962008-05-14 12:25:00 +0000563 }
bartb3f33402009-07-25 11:15:03 +0000564 if (q->reader_nesting_count == 0 && q->writer_nesting_count == 0)
565 {
566 /*
567 * This pthread_rwlock_unlock() call really unlocks the rwlock. Save
568 * the current vector clock of the thread such that it is available
569 * when this rwlock is locked again.
570 */
571 DRD_(thread_get_latest_segment)(&q->latest_rdlocked_segment, drd_tid);
572 DRD_(thread_new_segment)(drd_tid);
573 DRD_(s_rwlock_segment_creation_count)++;
574 }
bartbedfd232009-03-26 19:07:15 +0000575 }
576 else if (q->writer_nesting_count > 0)
577 {
578 q->writer_nesting_count--;
579 if (q->writer_nesting_count == 0 && DRD_(s_exclusive_threshold_ms) > 0)
bart9d5b7962008-05-14 12:25:00 +0000580 {
bart430c45f2009-04-13 08:05:18 +0000581 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
bartbedfd232009-03-26 19:07:15 +0000582 if (held > DRD_(s_exclusive_threshold_ms))
583 {
584 HoldtimeErrInfo HEI
bartd45d9952009-05-31 18:53:54 +0000585 = { DRD_(thread_get_running_tid)(),
586 rwlock, p->acquired_at, held,
bartbedfd232009-03-26 19:07:15 +0000587 DRD_(s_exclusive_threshold_ms) };
588 VG_(maybe_record_error)(vg_tid,
589 HoldtimeErr,
590 VG_(get_IP)(vg_tid),
591 "rwlock",
592 &HEI);
593 }
bart9d5b7962008-05-14 12:25:00 +0000594 }
bartb3f33402009-07-25 11:15:03 +0000595 if (q->reader_nesting_count == 0 && q->writer_nesting_count == 0)
596 {
597 /*
598 * This pthread_rwlock_unlock() call really unlocks the rwlock. Save
599 * the current vector clock of the thread such that it is available
600 * when this rwlock is locked again.
601 */
602 DRD_(thread_get_latest_segment)(&q->latest_wrlocked_segment, drd_tid);
603 DRD_(thread_new_segment)(drd_tid);
604 DRD_(s_rwlock_segment_creation_count)++;
605 }
bartbedfd232009-03-26 19:07:15 +0000606 }
607 else
608 {
609 tl_assert(False);
610 }
bart777f7fe2008-03-02 17:43:18 +0000611}
612
bartb3f33402009-07-25 11:15:03 +0000613/** Called when thread tid stops to exist. */
bartd2c5eae2009-02-21 15:27:04 +0000614static void rwlock_delete_thread(struct rwlock_info* const p,
615 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000616{
bartbedfd232009-03-26 19:07:15 +0000617 struct rwlock_thread_info* q;
bartb3f33402009-07-25 11:15:03 +0000618
bartbedfd232009-03-26 19:07:15 +0000619 if (DRD_(rwlock_is_locked_by)(p, tid))
620 {
bartd45d9952009-05-31 18:53:54 +0000621 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000622 VG_(maybe_record_error)(VG_(get_running_tid)(),
623 RwlockErr,
624 VG_(get_IP)(VG_(get_running_tid)()),
625 "Reader-writer lock still locked at thread exit",
626 &REI);
627 q = DRD_(lookup_or_insert_node)(p->thread_info, tid);
628 q->reader_nesting_count = 0;
629 q->writer_nesting_count = 0;
630 }
bart777f7fe2008-03-02 17:43:18 +0000631}
bart6bbefaf2008-04-19 15:16:45 +0000632
bartdc1ef032009-02-15 14:18:02 +0000633ULong DRD_(get_rwlock_segment_creation_count)(void)
bart6bbefaf2008-04-19 15:16:45 +0000634{
bartbedfd232009-03-26 19:07:15 +0000635 return DRD_(s_rwlock_segment_creation_count);
bart6bbefaf2008-04-19 15:16:45 +0000636}