blob: 82f28acb678ecc9c063297d34e3f40f66103acd6 [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;
46 Segment* last_unlock_segment; // Segment of last unlock call by this thread.
47 Bool last_lock_was_writer_lock;
bart777f7fe2008-03-02 17:43:18 +000048};
49
50
bartdc1ef032009-02-15 14:18:02 +000051/* Local functions. */
bart777f7fe2008-03-02 17:43:18 +000052
bartd2c5eae2009-02-21 15:27:04 +000053static void rwlock_cleanup(struct rwlock_info* p);
54static void rwlock_delete_thread(struct rwlock_info* const p,
55 const DrdThreadId tid);
bart777f7fe2008-03-02 17:43:18 +000056
57
bartdc1ef032009-02-15 14:18:02 +000058/* Local variables. */
bart777f7fe2008-03-02 17:43:18 +000059
bartdc1ef032009-02-15 14:18:02 +000060static Bool DRD_(s_trace_rwlock);
61static UInt DRD_(s_exclusive_threshold_ms);
62static UInt DRD_(s_shared_threshold_ms);
63static ULong DRD_(s_rwlock_segment_creation_count);
bart777f7fe2008-03-02 17:43:18 +000064
65
bartdc1ef032009-02-15 14:18:02 +000066/* Function definitions. */
bart777f7fe2008-03-02 17:43:18 +000067
bartdc1ef032009-02-15 14:18:02 +000068void DRD_(rwlock_set_trace)(const Bool trace_rwlock)
bart777f7fe2008-03-02 17:43:18 +000069{
bartbedfd232009-03-26 19:07:15 +000070 tl_assert(trace_rwlock == False || trace_rwlock == True);
71 DRD_(s_trace_rwlock) = trace_rwlock;
bart777f7fe2008-03-02 17:43:18 +000072}
73
bartdc1ef032009-02-15 14:18:02 +000074void DRD_(rwlock_set_exclusive_threshold)(const UInt exclusive_threshold_ms)
bart9d5b7962008-05-14 12:25:00 +000075{
bartbedfd232009-03-26 19:07:15 +000076 DRD_(s_exclusive_threshold_ms) = exclusive_threshold_ms;
bart9d5b7962008-05-14 12:25:00 +000077}
78
bartdc1ef032009-02-15 14:18:02 +000079void DRD_(rwlock_set_shared_threshold)(const UInt shared_threshold_ms)
bart9d5b7962008-05-14 12:25:00 +000080{
bartbedfd232009-03-26 19:07:15 +000081 DRD_(s_shared_threshold_ms) = shared_threshold_ms;
bart9d5b7962008-05-14 12:25:00 +000082}
83
bartdc1ef032009-02-15 14:18:02 +000084static Bool DRD_(rwlock_is_rdlocked)(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +000085{
bartbedfd232009-03-26 19:07:15 +000086 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +000087
bartbedfd232009-03-26 19:07:15 +000088 VG_(OSetGen_ResetIter)(p->thread_info);
89 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
90 {
91 return q->reader_nesting_count > 0;
92 }
93 return False;
bart777f7fe2008-03-02 17:43:18 +000094}
95
bartdc1ef032009-02-15 14:18:02 +000096static Bool DRD_(rwlock_is_wrlocked)(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +000097{
bartbedfd232009-03-26 19:07:15 +000098 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +000099
bartbedfd232009-03-26 19:07:15 +0000100 VG_(OSetGen_ResetIter)(p->thread_info);
101 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
102 {
103 return q->writer_nesting_count > 0;
104 }
105 return False;
bart777f7fe2008-03-02 17:43:18 +0000106}
107
bartdc1ef032009-02-15 14:18:02 +0000108static Bool DRD_(rwlock_is_locked)(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +0000109{
bartbedfd232009-03-26 19:07:15 +0000110 return DRD_(rwlock_is_rdlocked)(p) || DRD_(rwlock_is_wrlocked)(p);
bart777f7fe2008-03-02 17:43:18 +0000111}
112
bartdc1ef032009-02-15 14:18:02 +0000113static Bool DRD_(rwlock_is_rdlocked_by)(struct rwlock_info* p,
114 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000115{
bartbedfd232009-03-26 19:07:15 +0000116 const UWord uword_tid = tid;
117 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000118
bartbedfd232009-03-26 19:07:15 +0000119 q = VG_(OSetGen_Lookup)(p->thread_info, &uword_tid);
120 return q && q->reader_nesting_count > 0;
bart777f7fe2008-03-02 17:43:18 +0000121}
122
bartdc1ef032009-02-15 14:18:02 +0000123static Bool DRD_(rwlock_is_wrlocked_by)(struct rwlock_info* p,
124 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000125{
bartbedfd232009-03-26 19:07:15 +0000126 const UWord uword_tid = tid;
127 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000128
bartbedfd232009-03-26 19:07:15 +0000129 q = VG_(OSetGen_Lookup)(p->thread_info, &uword_tid);
130 return q && q->writer_nesting_count > 0;
bart777f7fe2008-03-02 17:43:18 +0000131}
132
bartdc1ef032009-02-15 14:18:02 +0000133static Bool DRD_(rwlock_is_locked_by)(struct rwlock_info* p,
134 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000135{
bartbedfd232009-03-26 19:07:15 +0000136 return (DRD_(rwlock_is_rdlocked_by)(p, tid)
137 || DRD_(rwlock_is_wrlocked_by)(p, tid));
bart777f7fe2008-03-02 17:43:18 +0000138}
139
bart165b90f2008-05-10 12:54:27 +0000140/** Either look up or insert a node corresponding to DRD thread id 'tid'. */
bart777f7fe2008-03-02 17:43:18 +0000141static
bartdc1ef032009-02-15 14:18:02 +0000142struct rwlock_thread_info*
143DRD_(lookup_or_insert_node)(OSet* oset, const UWord tid)
bart777f7fe2008-03-02 17:43:18 +0000144{
bartbedfd232009-03-26 19:07:15 +0000145 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000146
bartbedfd232009-03-26 19:07:15 +0000147 q = VG_(OSetGen_Lookup)(oset, &tid);
148 if (q == 0)
149 {
150 q = VG_(OSetGen_AllocNode)(oset, sizeof(*q));
151 q->tid = tid;
152 q->reader_nesting_count = 0;
153 q->writer_nesting_count = 0;
154 q->last_unlock_segment = 0;
155 q->last_lock_was_writer_lock = False;
156 VG_(OSetGen_Insert)(oset, q);
157 }
158 tl_assert(q);
159 return q;
bart777f7fe2008-03-02 17:43:18 +0000160}
161
bartdc1ef032009-02-15 14:18:02 +0000162/**
163 * Combine the vector clock corresponding to the last unlock operation of
164 * reader-writer lock p into the vector clock of thread 'tid'.
bart165b90f2008-05-10 12:54:27 +0000165 */
bartdc1ef032009-02-15 14:18:02 +0000166static void DRD_(rwlock_combine_other_vc)(struct rwlock_info* const p,
167 const DrdThreadId tid,
168 const Bool readers_too)
bart777f7fe2008-03-02 17:43:18 +0000169{
bartbedfd232009-03-26 19:07:15 +0000170 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000171
bartbedfd232009-03-26 19:07:15 +0000172 VG_(OSetGen_ResetIter)(p->thread_info);
173 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
174 {
175 if (q->tid != tid && (readers_too || q->last_lock_was_writer_lock))
176 {
177 DRD_(thread_combine_vc2)(tid, &q->last_unlock_segment->vc);
178 }
179 }
bart777f7fe2008-03-02 17:43:18 +0000180}
181
bart165b90f2008-05-10 12:54:27 +0000182/** Initialize the rwlock_info data structure *p. */
bart777f7fe2008-03-02 17:43:18 +0000183static
bartdc1ef032009-02-15 14:18:02 +0000184void DRD_(rwlock_initialize)(struct rwlock_info* const p, const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000185{
bartbedfd232009-03-26 19:07:15 +0000186 tl_assert(rwlock != 0);
187 tl_assert(p->a1 == rwlock);
188 tl_assert(p->type == ClientRwlock);
bart777f7fe2008-03-02 17:43:18 +0000189
bartbedfd232009-03-26 19:07:15 +0000190 p->cleanup = (void(*)(DrdClientobj*))rwlock_cleanup;
191 p->delete_thread
192 = (void(*)(DrdClientobj*, DrdThreadId))rwlock_delete_thread;
193 p->thread_info = VG_(OSetGen_Create)(
194 0, 0, VG_(malloc), "drd.rwlock.ri.1", VG_(free));
195 p->acquiry_time_ms = 0;
196 p->acquired_at = 0;
bart777f7fe2008-03-02 17:43:18 +0000197}
198
199/** Deallocate the memory that was allocated by rwlock_initialize(). */
bartd2c5eae2009-02-21 15:27:04 +0000200static void rwlock_cleanup(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +0000201{
bartbedfd232009-03-26 19:07:15 +0000202 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000203
bartbedfd232009-03-26 19:07:15 +0000204 tl_assert(p);
bart777f7fe2008-03-02 17:43:18 +0000205
bartbedfd232009-03-26 19:07:15 +0000206 if (DRD_(s_trace_rwlock))
207 {
208 VG_(message)(Vg_UserMsg,
209 "[%d/%d] rwlock_destroy 0x%lx",
210 VG_(get_running_tid)(),
211 DRD_(thread_get_running_tid)(),
212 p->a1);
213 }
bart777f7fe2008-03-02 17:43:18 +0000214
bartbedfd232009-03-26 19:07:15 +0000215 if (DRD_(rwlock_is_locked)(p))
216 {
217 RwlockErrInfo REI = { p->a1 };
218 VG_(maybe_record_error)(VG_(get_running_tid)(),
219 RwlockErr,
220 VG_(get_IP)(VG_(get_running_tid)()),
221 "Destroying locked rwlock",
222 &REI);
223 }
bart777f7fe2008-03-02 17:43:18 +0000224
bartbedfd232009-03-26 19:07:15 +0000225 VG_(OSetGen_ResetIter)(p->thread_info);
226 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
227 {
228 DRD_(sg_put)(q->last_unlock_segment);
229 }
230 VG_(OSetGen_Destroy)(p->thread_info);
bart777f7fe2008-03-02 17:43:18 +0000231}
232
233static
234struct rwlock_info*
bartdc1ef032009-02-15 14:18:02 +0000235DRD_(rwlock_get_or_allocate)(const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000236{
bartbedfd232009-03-26 19:07:15 +0000237 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000238
bartbedfd232009-03-26 19:07:15 +0000239 tl_assert(offsetof(DrdClientobj, rwlock) == 0);
240 p = &(DRD_(clientobj_get)(rwlock, ClientRwlock)->rwlock);
241 if (p)
242 {
243 return p;
244 }
bart777f7fe2008-03-02 17:43:18 +0000245
bartbedfd232009-03-26 19:07:15 +0000246 if (DRD_(clientobj_present)(rwlock, rwlock + 1))
247 {
248 GenericErrInfo GEI;
249 VG_(maybe_record_error)(VG_(get_running_tid)(),
250 GenericErr,
251 VG_(get_IP)(VG_(get_running_tid)()),
252 "Not a reader-writer lock",
253 &GEI);
254 return 0;
255 }
bart777f7fe2008-03-02 17:43:18 +0000256
bartbedfd232009-03-26 19:07:15 +0000257 p = &(DRD_(clientobj_add)(rwlock, ClientRwlock)->rwlock);
258 DRD_(rwlock_initialize)(p, rwlock);
259 return p;
bart777f7fe2008-03-02 17:43:18 +0000260}
261
bartdc1ef032009-02-15 14:18:02 +0000262static struct rwlock_info* DRD_(rwlock_get)(const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000263{
bartbedfd232009-03-26 19:07:15 +0000264 tl_assert(offsetof(DrdClientobj, rwlock) == 0);
265 return &(DRD_(clientobj_get)(rwlock, ClientRwlock)->rwlock);
bart777f7fe2008-03-02 17:43:18 +0000266}
267
268/** Called before pthread_rwlock_init(). */
bartdc1ef032009-02-15 14:18:02 +0000269struct rwlock_info* DRD_(rwlock_pre_init)(const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000270{
bartbedfd232009-03-26 19:07:15 +0000271 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000272
bartbedfd232009-03-26 19:07:15 +0000273 if (DRD_(s_trace_rwlock))
274 {
275 VG_(message)(Vg_UserMsg,
276 "[%d/%d] rwlock_init 0x%lx",
277 VG_(get_running_tid)(),
278 DRD_(thread_get_running_tid)(),
279 rwlock);
280 }
bart777f7fe2008-03-02 17:43:18 +0000281
bartbedfd232009-03-26 19:07:15 +0000282 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000283
bartbedfd232009-03-26 19:07:15 +0000284 if (p)
285 {
286 const ThreadId vg_tid = VG_(get_running_tid)();
287 RwlockErrInfo REI
288 = { p->a1 };
289 VG_(maybe_record_error)(vg_tid,
290 RwlockErr,
291 VG_(get_IP)(vg_tid),
292 "Reader-writer lock reinitialization",
293 &REI);
294 return p;
295 }
bart777f7fe2008-03-02 17:43:18 +0000296
bartbedfd232009-03-26 19:07:15 +0000297 p = DRD_(rwlock_get_or_allocate)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000298
bartbedfd232009-03-26 19:07:15 +0000299 return p;
bart777f7fe2008-03-02 17:43:18 +0000300}
301
302/** Called after pthread_rwlock_destroy(). */
bartdc1ef032009-02-15 14:18:02 +0000303void DRD_(rwlock_post_destroy)(const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000304{
bartbedfd232009-03-26 19:07:15 +0000305 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000306
bartbedfd232009-03-26 19:07:15 +0000307 p = DRD_(rwlock_get)(rwlock);
308 if (p == 0)
309 {
310 GenericErrInfo GEI;
311 VG_(maybe_record_error)(VG_(get_running_tid)(),
312 GenericErr,
313 VG_(get_IP)(VG_(get_running_tid)()),
314 "Not a reader-writer lock",
315 &GEI);
316 return;
317 }
bart777f7fe2008-03-02 17:43:18 +0000318
bartbedfd232009-03-26 19:07:15 +0000319 DRD_(clientobj_remove)(rwlock, ClientRwlock);
bart777f7fe2008-03-02 17:43:18 +0000320}
321
bartdc1ef032009-02-15 14:18:02 +0000322/**
323 * Called before pthread_rwlock_rdlock() is invoked. If a data structure for
324 * the client-side object was not yet created, do this now. Also check whether
325 * an attempt is made to lock recursively a synchronization object that must
326 * not be locked recursively.
bart777f7fe2008-03-02 17:43:18 +0000327 */
bartdc1ef032009-02-15 14:18:02 +0000328void DRD_(rwlock_pre_rdlock)(const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000329{
bartbedfd232009-03-26 19:07:15 +0000330 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000331
bartbedfd232009-03-26 19:07:15 +0000332 if (DRD_(s_trace_rwlock))
333 {
334 VG_(message)(Vg_UserMsg,
335 "[%d/%d] pre_rwlock_rdlock 0x%lx",
336 VG_(get_running_tid)(),
337 DRD_(thread_get_running_tid)(),
338 rwlock);
339 }
bart777f7fe2008-03-02 17:43:18 +0000340
bartbedfd232009-03-26 19:07:15 +0000341 p = DRD_(rwlock_get_or_allocate)(rwlock);
342 tl_assert(p);
bart165b90f2008-05-10 12:54:27 +0000343
bartbedfd232009-03-26 19:07:15 +0000344 if (DRD_(rwlock_is_wrlocked_by)(p, DRD_(thread_get_running_tid)()))
345 {
346 VG_(message)(Vg_UserMsg,
347 "reader-writer lock 0x%lx is already locked for"
348 " writing by calling thread",
349 p->a1);
350 }
bart777f7fe2008-03-02 17:43:18 +0000351}
352
bartdc1ef032009-02-15 14:18:02 +0000353/**
354 * Update rwlock_info state when locking the pthread_rwlock_t mutex.
355 * Note: this function must be called after pthread_rwlock_rdlock() has been
356 * called, or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000357 */
bartdc1ef032009-02-15 14:18:02 +0000358void DRD_(rwlock_post_rdlock)(const Addr rwlock, const Bool took_lock)
bart777f7fe2008-03-02 17:43:18 +0000359{
bartbedfd232009-03-26 19:07:15 +0000360 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
361 struct rwlock_info* p;
362 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000363
bartbedfd232009-03-26 19:07:15 +0000364 if (DRD_(s_trace_rwlock))
365 {
366 VG_(message)(Vg_UserMsg,
367 "[%d/%d] post_rwlock_rdlock 0x%lx",
368 VG_(get_running_tid)(),
369 drd_tid,
370 rwlock);
371 }
bart777f7fe2008-03-02 17:43:18 +0000372
bartbedfd232009-03-26 19:07:15 +0000373 p = DRD_(rwlock_get)(rwlock);
bart165b90f2008-05-10 12:54:27 +0000374
bartbedfd232009-03-26 19:07:15 +0000375 if (! p || ! took_lock)
376 return;
bart777f7fe2008-03-02 17:43:18 +0000377
bartbedfd232009-03-26 19:07:15 +0000378 tl_assert(! DRD_(rwlock_is_wrlocked)(p));
bart777f7fe2008-03-02 17:43:18 +0000379
bartbedfd232009-03-26 19:07:15 +0000380 q = DRD_(lookup_or_insert_node)(p->thread_info, drd_tid);
381 if (++q->reader_nesting_count == 1)
382 {
383 DRD_(rwlock_combine_other_vc)(p, drd_tid, False);
384 q->last_lock_was_writer_lock = False;
385 DRD_(thread_new_segment)(drd_tid);
386 DRD_(s_rwlock_segment_creation_count)++;
bart9d5b7962008-05-14 12:25:00 +0000387
bartbedfd232009-03-26 19:07:15 +0000388 p->acquiry_time_ms = VG_(read_millisecond_timer)();
389 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
390 }
bart777f7fe2008-03-02 17:43:18 +0000391}
392
bartdc1ef032009-02-15 14:18:02 +0000393/**
394 * Called before pthread_rwlock_wrlock() is invoked. If a data structure for
395 * the client-side object was not yet created, do this now. Also check whether
396 * an attempt is made to lock recursively a synchronization object that must
397 * not be locked recursively.
bart777f7fe2008-03-02 17:43:18 +0000398 */
bartdc1ef032009-02-15 14:18:02 +0000399void DRD_(rwlock_pre_wrlock)(const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000400{
bartbedfd232009-03-26 19:07:15 +0000401 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000402
bartbedfd232009-03-26 19:07:15 +0000403 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000404
bartbedfd232009-03-26 19:07:15 +0000405 if (DRD_(s_trace_rwlock))
406 {
407 VG_(message)(Vg_UserMsg,
408 "[%d/%d] pre_rwlock_wrlock 0x%lx",
409 VG_(get_running_tid)(),
410 DRD_(thread_get_running_tid)(),
411 rwlock);
412 }
bart777f7fe2008-03-02 17:43:18 +0000413
bartbedfd232009-03-26 19:07:15 +0000414 if (p == 0)
415 {
416 p = DRD_(rwlock_get_or_allocate)(rwlock);
417 }
bart777f7fe2008-03-02 17:43:18 +0000418
bartbedfd232009-03-26 19:07:15 +0000419 tl_assert(p);
bart777f7fe2008-03-02 17:43:18 +0000420
bartbedfd232009-03-26 19:07:15 +0000421 if (DRD_(rwlock_is_wrlocked_by)(p, DRD_(thread_get_running_tid)()))
422 {
423 RwlockErrInfo REI = { p->a1 };
424 VG_(maybe_record_error)(VG_(get_running_tid)(),
425 RwlockErr,
426 VG_(get_IP)(VG_(get_running_tid)()),
427 "Recursive writer locking not allowed",
428 &REI);
429 }
bart777f7fe2008-03-02 17:43:18 +0000430}
431
432/**
433 * Update rwlock_info state when locking the pthread_rwlock_t rwlock.
bart165b90f2008-05-10 12:54:27 +0000434 * Note: this function must be called after pthread_rwlock_wrlock() has
435 * finished, or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000436 */
bartdc1ef032009-02-15 14:18:02 +0000437void DRD_(rwlock_post_wrlock)(const Addr rwlock, const Bool took_lock)
bart777f7fe2008-03-02 17:43:18 +0000438{
bartbedfd232009-03-26 19:07:15 +0000439 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
440 struct rwlock_info* p;
441 struct rwlock_thread_info* q;
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))
446 {
447 VG_(message)(Vg_UserMsg,
448 "[%d/%d] post_rwlock_wrlock 0x%lx",
449 VG_(get_running_tid)(),
450 drd_tid,
451 rwlock);
452 }
bart777f7fe2008-03-02 17:43:18 +0000453
bartbedfd232009-03-26 19:07:15 +0000454 if (! p || ! took_lock)
455 return;
bart777f7fe2008-03-02 17:43:18 +0000456
bartbedfd232009-03-26 19:07:15 +0000457 q = DRD_(lookup_or_insert_node)(p->thread_info,
458 DRD_(thread_get_running_tid)());
459 tl_assert(q->writer_nesting_count == 0);
460 q->writer_nesting_count++;
461 q->last_lock_was_writer_lock = True;
462 tl_assert(q->writer_nesting_count == 1);
463 DRD_(rwlock_combine_other_vc)(p, drd_tid, True);
464 DRD_(thread_new_segment)(drd_tid);
465 DRD_(s_rwlock_segment_creation_count)++;
466 p->acquiry_time_ms = VG_(read_millisecond_timer)();
467 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
bart777f7fe2008-03-02 17:43:18 +0000468}
469
470/**
471 * Update rwlock_info state when unlocking the pthread_rwlock_t rwlock.
bart7e6de962009-02-21 09:39:09 +0000472 *
bart777f7fe2008-03-02 17:43:18 +0000473 * @param rwlock Pointer to pthread_rwlock_t data structure in the client space.
bart7e6de962009-02-21 09:39:09 +0000474 *
475 * @return New value of the rwlock recursion count.
476 *
477 * @note This function must be called before pthread_rwlock_unlock() is called,
478 * or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000479 */
bartdc1ef032009-02-15 14:18:02 +0000480void DRD_(rwlock_pre_unlock)(const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000481{
bartbedfd232009-03-26 19:07:15 +0000482 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
483 const ThreadId vg_tid = VG_(get_running_tid)();
484 struct rwlock_info* p;
485 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000486
bartbedfd232009-03-26 19:07:15 +0000487 if (DRD_(s_trace_rwlock))
488 {
489 VG_(message)(Vg_UserMsg,
490 "[%d/%d] rwlock_unlock 0x%lx",
491 vg_tid,
492 drd_tid,
493 rwlock);
494 }
bart777f7fe2008-03-02 17:43:18 +0000495
bartbedfd232009-03-26 19:07:15 +0000496 p = DRD_(rwlock_get)(rwlock);
497 if (p == 0)
498 {
499 GenericErrInfo GEI;
500 VG_(maybe_record_error)(VG_(get_running_tid)(),
501 GenericErr,
502 VG_(get_IP)(VG_(get_running_tid)()),
503 "Not a reader-writer lock",
504 &GEI);
505 return;
506 }
507 if (! DRD_(rwlock_is_locked_by)(p, drd_tid))
508 {
509 RwlockErrInfo REI = { p->a1 };
510 VG_(maybe_record_error)(vg_tid,
511 RwlockErr,
512 VG_(get_IP)(vg_tid),
513 "Reader-writer lock not locked by calling thread",
514 &REI);
515 return;
516 }
517 q = DRD_(lookup_or_insert_node)(p->thread_info, drd_tid);
518 tl_assert(q);
519 if (q->reader_nesting_count > 0)
520 {
521 q->reader_nesting_count--;
522 if (q->reader_nesting_count == 0 && DRD_(s_shared_threshold_ms) > 0)
bart9d5b7962008-05-14 12:25:00 +0000523 {
bart430c45f2009-04-13 08:05:18 +0000524 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
bartbedfd232009-03-26 19:07:15 +0000525 if (held > DRD_(s_shared_threshold_ms))
526 {
527 HoldtimeErrInfo HEI
528 = { rwlock, p->acquired_at, held, DRD_(s_shared_threshold_ms) };
529 VG_(maybe_record_error)(vg_tid,
530 HoldtimeErr,
531 VG_(get_IP)(vg_tid),
532 "rwlock",
533 &HEI);
534 }
bart9d5b7962008-05-14 12:25:00 +0000535 }
bartbedfd232009-03-26 19:07:15 +0000536 }
537 else if (q->writer_nesting_count > 0)
538 {
539 q->writer_nesting_count--;
540 if (q->writer_nesting_count == 0 && DRD_(s_exclusive_threshold_ms) > 0)
bart9d5b7962008-05-14 12:25:00 +0000541 {
bart430c45f2009-04-13 08:05:18 +0000542 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
bartbedfd232009-03-26 19:07:15 +0000543 if (held > DRD_(s_exclusive_threshold_ms))
544 {
545 HoldtimeErrInfo HEI
546 = { rwlock, p->acquired_at, held,
547 DRD_(s_exclusive_threshold_ms) };
548 VG_(maybe_record_error)(vg_tid,
549 HoldtimeErr,
550 VG_(get_IP)(vg_tid),
551 "rwlock",
552 &HEI);
553 }
bart9d5b7962008-05-14 12:25:00 +0000554 }
bartbedfd232009-03-26 19:07:15 +0000555 }
556 else
557 {
558 tl_assert(False);
559 }
bart777f7fe2008-03-02 17:43:18 +0000560
bartbedfd232009-03-26 19:07:15 +0000561 if (q->reader_nesting_count == 0 && q->writer_nesting_count == 0)
562 {
563 /* This pthread_rwlock_unlock() call really unlocks the rwlock. Save */
564 /* the current vector clock of the thread such that it is available */
565 /* when this rwlock is locked again. */
bart777f7fe2008-03-02 17:43:18 +0000566
bartbedfd232009-03-26 19:07:15 +0000567 DRD_(thread_get_latest_segment)(&q->last_unlock_segment, drd_tid);
568 DRD_(thread_new_segment)(drd_tid);
569 DRD_(s_rwlock_segment_creation_count)++;
570 }
bart777f7fe2008-03-02 17:43:18 +0000571}
572
573/**
574 * Call this function when thread tid stops to exist, such that the
575 * "last owner" field can be cleared if it still refers to that thread.
576 */
bartd2c5eae2009-02-21 15:27:04 +0000577static void rwlock_delete_thread(struct rwlock_info* const p,
578 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000579{
bartbedfd232009-03-26 19:07:15 +0000580 struct rwlock_thread_info* q;
581 if (DRD_(rwlock_is_locked_by)(p, tid))
582 {
583 RwlockErrInfo REI = { p->a1 };
584 VG_(maybe_record_error)(VG_(get_running_tid)(),
585 RwlockErr,
586 VG_(get_IP)(VG_(get_running_tid)()),
587 "Reader-writer lock still locked at thread exit",
588 &REI);
589 q = DRD_(lookup_or_insert_node)(p->thread_info, tid);
590 q->reader_nesting_count = 0;
591 q->writer_nesting_count = 0;
592 }
bart777f7fe2008-03-02 17:43:18 +0000593}
bart6bbefaf2008-04-19 15:16:45 +0000594
bartdc1ef032009-02-15 14:18:02 +0000595ULong DRD_(get_rwlock_segment_creation_count)(void)
bart6bbefaf2008-04-19 15:16:45 +0000596{
bartbedfd232009-03-26 19:07:15 +0000597 return DRD_(s_rwlock_segment_creation_count);
bart6bbefaf2008-04-19 15:16:45 +0000598}