blob: fd09e0a1febb974a3af21917eb9abd3b019f4707 [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
Elliott Hughesed398002017-06-21 14:41:24 -07004 Copyright (C) 2006-2017 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);
bartae37e6d2012-01-22 08:58:31 +0000176 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; ) {
177 if (q->tid != tid) {
bartb3f33402009-07-25 11:15:03 +0000178 if (q->latest_wrlocked_segment)
bartc6bf1842012-01-22 08:40:42 +0000179 DRD_(vc_combine)(DRD_(thread_get_vc)(tid),
bartb3f33402009-07-25 11:15:03 +0000180 &q->latest_wrlocked_segment->vc);
bartb3f33402009-07-25 11:15:03 +0000181 if (readers_too && q->latest_rdlocked_segment)
bartc6bf1842012-01-22 08:40:42 +0000182 DRD_(vc_combine)(DRD_(thread_get_vc)(tid),
bartb3f33402009-07-25 11:15:03 +0000183 &q->latest_rdlocked_segment->vc);
bartbedfd232009-03-26 19:07:15 +0000184 }
185 }
bart8f822af2009-06-08 18:20:42 +0000186 DRD_(thread_update_conflict_set)(tid, &old_vc);
187 DRD_(vc_cleanup)(&old_vc);
bart777f7fe2008-03-02 17:43:18 +0000188}
189
bartc8441502009-07-27 16:03:51 +0000190/**
191 * Compare the type of the rwlock specified at initialization time with
192 * the type passed as an argument, and complain if these two types do not
193 * match.
194 */
195static Bool drd_rwlock_check_type(struct rwlock_info* const p,
196 const RwLockT rwlock_type)
197{
198 tl_assert(p);
199 /* The code below has to be updated if additional rwlock types are added. */
200 tl_assert(rwlock_type == pthread_rwlock || rwlock_type == user_rwlock);
201 tl_assert(p->rwlock_type == pthread_rwlock || p->rwlock_type == user_rwlock);
202
203 if (p->rwlock_type == rwlock_type)
204 return True;
205
206 {
207 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
208 VG_(maybe_record_error)
209 (VG_(get_running_tid)(),
210 RwlockErr,
211 VG_(get_IP)(VG_(get_running_tid)()),
212 rwlock_type == pthread_rwlock
213 ? "Attempt to use a user-defined rwlock as a POSIX rwlock"
214 : "Attempt to use a POSIX rwlock as a user-defined rwlock",
215 &REI);
216 }
217 return False;
218}
219
bart165b90f2008-05-10 12:54:27 +0000220/** Initialize the rwlock_info data structure *p. */
bart777f7fe2008-03-02 17:43:18 +0000221static
bartc8441502009-07-27 16:03:51 +0000222void DRD_(rwlock_initialize)(struct rwlock_info* const p, const Addr rwlock,
223 const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000224{
bartbedfd232009-03-26 19:07:15 +0000225 tl_assert(rwlock != 0);
226 tl_assert(p->a1 == rwlock);
227 tl_assert(p->type == ClientRwlock);
bart777f7fe2008-03-02 17:43:18 +0000228
bartbedfd232009-03-26 19:07:15 +0000229 p->cleanup = (void(*)(DrdClientobj*))rwlock_cleanup;
230 p->delete_thread
231 = (void(*)(DrdClientobj*, DrdThreadId))rwlock_delete_thread;
bartc8441502009-07-27 16:03:51 +0000232 p->rwlock_type = rwlock_type;
bartbedfd232009-03-26 19:07:15 +0000233 p->thread_info = VG_(OSetGen_Create)(
234 0, 0, VG_(malloc), "drd.rwlock.ri.1", VG_(free));
235 p->acquiry_time_ms = 0;
236 p->acquired_at = 0;
bart777f7fe2008-03-02 17:43:18 +0000237}
238
239/** Deallocate the memory that was allocated by rwlock_initialize(). */
bartd2c5eae2009-02-21 15:27:04 +0000240static void rwlock_cleanup(struct rwlock_info* p)
bart777f7fe2008-03-02 17:43:18 +0000241{
bartbedfd232009-03-26 19:07:15 +0000242 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000243
bartbedfd232009-03-26 19:07:15 +0000244 tl_assert(p);
bart777f7fe2008-03-02 17:43:18 +0000245
bartbedfd232009-03-26 19:07:15 +0000246 if (DRD_(s_trace_rwlock))
florianea71ffb2015-08-05 14:38:57 +0000247 DRD_(trace_msg)("[%u] rwlock_destroy 0x%lx",
bartb92ff0f2011-10-08 08:29:29 +0000248 DRD_(thread_get_running_tid)(), p->a1);
bart777f7fe2008-03-02 17:43:18 +0000249
bartbedfd232009-03-26 19:07:15 +0000250 if (DRD_(rwlock_is_locked)(p))
251 {
bartd45d9952009-05-31 18:53:54 +0000252 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000253 VG_(maybe_record_error)(VG_(get_running_tid)(),
254 RwlockErr,
255 VG_(get_IP)(VG_(get_running_tid)()),
256 "Destroying locked rwlock",
257 &REI);
258 }
bart777f7fe2008-03-02 17:43:18 +0000259
bartbedfd232009-03-26 19:07:15 +0000260 VG_(OSetGen_ResetIter)(p->thread_info);
261 for ( ; (q = VG_(OSetGen_Next)(p->thread_info)) != 0; )
262 {
bartb3f33402009-07-25 11:15:03 +0000263 DRD_(sg_put)(q->latest_wrlocked_segment);
264 DRD_(sg_put)(q->latest_rdlocked_segment);
bartbedfd232009-03-26 19:07:15 +0000265 }
bartb3f33402009-07-25 11:15:03 +0000266
bartbedfd232009-03-26 19:07:15 +0000267 VG_(OSetGen_Destroy)(p->thread_info);
bart777f7fe2008-03-02 17:43:18 +0000268}
269
270static
271struct rwlock_info*
bartc8441502009-07-27 16:03:51 +0000272DRD_(rwlock_get_or_allocate)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000273{
bartbedfd232009-03-26 19:07:15 +0000274 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000275
bartbedfd232009-03-26 19:07:15 +0000276 tl_assert(offsetof(DrdClientobj, rwlock) == 0);
277 p = &(DRD_(clientobj_get)(rwlock, ClientRwlock)->rwlock);
278 if (p)
bartc8441502009-07-27 16:03:51 +0000279 {
280 drd_rwlock_check_type(p, rwlock_type);
bartbedfd232009-03-26 19:07:15 +0000281 return p;
bartc8441502009-07-27 16:03:51 +0000282 }
bart777f7fe2008-03-02 17:43:18 +0000283
bartbedfd232009-03-26 19:07:15 +0000284 if (DRD_(clientobj_present)(rwlock, rwlock + 1))
285 {
bart62cc2322010-03-07 10:54:21 +0000286 GenericErrInfo GEI = {
287 .tid = DRD_(thread_get_running_tid)(),
288 .addr = rwlock,
289 };
bartbedfd232009-03-26 19:07:15 +0000290 VG_(maybe_record_error)(VG_(get_running_tid)(),
291 GenericErr,
292 VG_(get_IP)(VG_(get_running_tid)()),
293 "Not a reader-writer lock",
294 &GEI);
295 return 0;
296 }
bart777f7fe2008-03-02 17:43:18 +0000297
bartbedfd232009-03-26 19:07:15 +0000298 p = &(DRD_(clientobj_add)(rwlock, ClientRwlock)->rwlock);
bartc8441502009-07-27 16:03:51 +0000299 DRD_(rwlock_initialize)(p, rwlock, rwlock_type);
bartbedfd232009-03-26 19:07:15 +0000300 return p;
bart777f7fe2008-03-02 17:43:18 +0000301}
302
bartdc1ef032009-02-15 14:18:02 +0000303static struct rwlock_info* DRD_(rwlock_get)(const Addr rwlock)
bart777f7fe2008-03-02 17:43:18 +0000304{
bartbedfd232009-03-26 19:07:15 +0000305 tl_assert(offsetof(DrdClientobj, rwlock) == 0);
306 return &(DRD_(clientobj_get)(rwlock, ClientRwlock)->rwlock);
bart777f7fe2008-03-02 17:43:18 +0000307}
308
309/** Called before pthread_rwlock_init(). */
bartd45d9952009-05-31 18:53:54 +0000310struct rwlock_info* DRD_(rwlock_pre_init)(const Addr rwlock,
311 const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000312{
bartbedfd232009-03-26 19:07:15 +0000313 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000314
bartbedfd232009-03-26 19:07:15 +0000315 if (DRD_(s_trace_rwlock))
florianea71ffb2015-08-05 14:38:57 +0000316 DRD_(trace_msg)("[%u] rwlock_init 0x%lx",
bartb92ff0f2011-10-08 08:29:29 +0000317 DRD_(thread_get_running_tid)(), rwlock);
bart777f7fe2008-03-02 17:43:18 +0000318
bartbedfd232009-03-26 19:07:15 +0000319 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000320
bartbedfd232009-03-26 19:07:15 +0000321 if (p)
bart67707ec2009-07-27 17:02:52 +0000322 drd_rwlock_check_type(p, rwlock_type);
323
324 if (p)
bartbedfd232009-03-26 19:07:15 +0000325 {
326 const ThreadId vg_tid = VG_(get_running_tid)();
bartd45d9952009-05-31 18:53:54 +0000327 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000328 VG_(maybe_record_error)(vg_tid,
329 RwlockErr,
330 VG_(get_IP)(vg_tid),
331 "Reader-writer lock reinitialization",
332 &REI);
333 return p;
334 }
bart777f7fe2008-03-02 17:43:18 +0000335
bartc8441502009-07-27 16:03:51 +0000336 p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type);
bart777f7fe2008-03-02 17:43:18 +0000337
bartbedfd232009-03-26 19:07:15 +0000338 return p;
bart777f7fe2008-03-02 17:43:18 +0000339}
340
341/** Called after pthread_rwlock_destroy(). */
bartd45d9952009-05-31 18:53:54 +0000342void DRD_(rwlock_post_destroy)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000343{
bartbedfd232009-03-26 19:07:15 +0000344 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000345
bartbedfd232009-03-26 19:07:15 +0000346 p = DRD_(rwlock_get)(rwlock);
347 if (p == 0)
348 {
bart62cc2322010-03-07 10:54:21 +0000349 GenericErrInfo GEI = {
350 .tid = DRD_(thread_get_running_tid)(),
351 .addr = rwlock,
352 };
bartbedfd232009-03-26 19:07:15 +0000353 VG_(maybe_record_error)(VG_(get_running_tid)(),
354 GenericErr,
355 VG_(get_IP)(VG_(get_running_tid)()),
356 "Not a reader-writer lock",
357 &GEI);
358 return;
359 }
bart777f7fe2008-03-02 17:43:18 +0000360
bart67707ec2009-07-27 17:02:52 +0000361 drd_rwlock_check_type(p, rwlock_type);
362
bartbedfd232009-03-26 19:07:15 +0000363 DRD_(clientobj_remove)(rwlock, ClientRwlock);
bart777f7fe2008-03-02 17:43:18 +0000364}
365
bartdc1ef032009-02-15 14:18:02 +0000366/**
367 * Called before pthread_rwlock_rdlock() is invoked. If a data structure for
368 * the client-side object was not yet created, do this now. Also check whether
369 * an attempt is made to lock recursively a synchronization object that must
370 * not be locked recursively.
bart777f7fe2008-03-02 17:43:18 +0000371 */
bartd45d9952009-05-31 18:53:54 +0000372void DRD_(rwlock_pre_rdlock)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000373{
bartbedfd232009-03-26 19:07:15 +0000374 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000375
bartbedfd232009-03-26 19:07:15 +0000376 if (DRD_(s_trace_rwlock))
florianea71ffb2015-08-05 14:38:57 +0000377 DRD_(trace_msg)("[%u] pre_rwlock_rdlock 0x%lx",
bartb92ff0f2011-10-08 08:29:29 +0000378 DRD_(thread_get_running_tid)(), rwlock);
bart777f7fe2008-03-02 17:43:18 +0000379
bartc8441502009-07-27 16:03:51 +0000380 p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type);
bartbedfd232009-03-26 19:07:15 +0000381 tl_assert(p);
bart165b90f2008-05-10 12:54:27 +0000382
bart74b2d972011-10-08 08:54:57 +0000383 if (DRD_(rwlock_is_wrlocked_by)(p, DRD_(thread_get_running_tid)())) {
384 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
385 VG_(maybe_record_error)(VG_(get_running_tid)(),
386 RwlockErr,
387 VG_(get_IP)(VG_(get_running_tid)()),
388 "Already locked for writing by calling thread",
389 &REI);
bartbedfd232009-03-26 19:07:15 +0000390 }
bart777f7fe2008-03-02 17:43:18 +0000391}
392
bartdc1ef032009-02-15 14:18:02 +0000393/**
394 * Update rwlock_info state when locking the pthread_rwlock_t mutex.
395 * Note: this function must be called after pthread_rwlock_rdlock() has been
396 * called, or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000397 */
bartd45d9952009-05-31 18:53:54 +0000398void DRD_(rwlock_post_rdlock)(const Addr rwlock, const RwLockT rwlock_type,
399 const Bool took_lock)
bart777f7fe2008-03-02 17:43:18 +0000400{
bartbedfd232009-03-26 19:07:15 +0000401 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
402 struct rwlock_info* p;
403 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000404
bartbedfd232009-03-26 19:07:15 +0000405 if (DRD_(s_trace_rwlock))
florianea71ffb2015-08-05 14:38:57 +0000406 DRD_(trace_msg)("[%u] post_rwlock_rdlock 0x%lx", drd_tid, rwlock);
bart777f7fe2008-03-02 17:43:18 +0000407
bartbedfd232009-03-26 19:07:15 +0000408 p = DRD_(rwlock_get)(rwlock);
bart165b90f2008-05-10 12:54:27 +0000409
bartbedfd232009-03-26 19:07:15 +0000410 if (! p || ! took_lock)
411 return;
bart777f7fe2008-03-02 17:43:18 +0000412
bartbedfd232009-03-26 19:07:15 +0000413 tl_assert(! DRD_(rwlock_is_wrlocked)(p));
bart777f7fe2008-03-02 17:43:18 +0000414
bartbedfd232009-03-26 19:07:15 +0000415 q = DRD_(lookup_or_insert_node)(p->thread_info, drd_tid);
416 if (++q->reader_nesting_count == 1)
417 {
bartbedfd232009-03-26 19:07:15 +0000418 DRD_(thread_new_segment)(drd_tid);
419 DRD_(s_rwlock_segment_creation_count)++;
bart7627be32009-06-06 12:26:05 +0000420 DRD_(rwlock_combine_other_vc)(p, drd_tid, False);
bart9d5b7962008-05-14 12:25:00 +0000421
bartbedfd232009-03-26 19:07:15 +0000422 p->acquiry_time_ms = VG_(read_millisecond_timer)();
423 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
424 }
bart777f7fe2008-03-02 17:43:18 +0000425}
426
bartdc1ef032009-02-15 14:18:02 +0000427/**
428 * Called before pthread_rwlock_wrlock() is invoked. If a data structure for
429 * the client-side object was not yet created, do this now. Also check whether
430 * an attempt is made to lock recursively a synchronization object that must
431 * not be locked recursively.
bart777f7fe2008-03-02 17:43:18 +0000432 */
bartd45d9952009-05-31 18:53:54 +0000433void DRD_(rwlock_pre_wrlock)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000434{
bartbedfd232009-03-26 19:07:15 +0000435 struct rwlock_info* p;
bart777f7fe2008-03-02 17:43:18 +0000436
bartbedfd232009-03-26 19:07:15 +0000437 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000438
bartbedfd232009-03-26 19:07:15 +0000439 if (DRD_(s_trace_rwlock))
florianea71ffb2015-08-05 14:38:57 +0000440 DRD_(trace_msg)("[%u] pre_rwlock_wrlock 0x%lx",
bartb92ff0f2011-10-08 08:29:29 +0000441 DRD_(thread_get_running_tid)(), rwlock);
bart777f7fe2008-03-02 17:43:18 +0000442
bartbedfd232009-03-26 19:07:15 +0000443 if (p == 0)
bartc8441502009-07-27 16:03:51 +0000444 p = DRD_(rwlock_get_or_allocate)(rwlock, rwlock_type);
bart777f7fe2008-03-02 17:43:18 +0000445
bartbedfd232009-03-26 19:07:15 +0000446 tl_assert(p);
bart777f7fe2008-03-02 17:43:18 +0000447
bartbedfd232009-03-26 19:07:15 +0000448 if (DRD_(rwlock_is_wrlocked_by)(p, DRD_(thread_get_running_tid)()))
449 {
bartd45d9952009-05-31 18:53:54 +0000450 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000451 VG_(maybe_record_error)(VG_(get_running_tid)(),
452 RwlockErr,
453 VG_(get_IP)(VG_(get_running_tid)()),
454 "Recursive writer locking not allowed",
455 &REI);
456 }
bart777f7fe2008-03-02 17:43:18 +0000457}
458
459/**
460 * Update rwlock_info state when locking the pthread_rwlock_t rwlock.
bart165b90f2008-05-10 12:54:27 +0000461 * Note: this function must be called after pthread_rwlock_wrlock() has
462 * finished, or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000463 */
bartd45d9952009-05-31 18:53:54 +0000464void DRD_(rwlock_post_wrlock)(const Addr rwlock, const RwLockT rwlock_type,
465 const Bool took_lock)
bart777f7fe2008-03-02 17:43:18 +0000466{
bartbedfd232009-03-26 19:07:15 +0000467 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
468 struct rwlock_info* p;
469 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000470
bartbedfd232009-03-26 19:07:15 +0000471 p = DRD_(rwlock_get)(rwlock);
bart777f7fe2008-03-02 17:43:18 +0000472
bartbedfd232009-03-26 19:07:15 +0000473 if (DRD_(s_trace_rwlock))
florianea71ffb2015-08-05 14:38:57 +0000474 DRD_(trace_msg)("[%u] post_rwlock_wrlock 0x%lx", drd_tid, rwlock);
bart777f7fe2008-03-02 17:43:18 +0000475
bartbedfd232009-03-26 19:07:15 +0000476 if (! p || ! took_lock)
477 return;
bart777f7fe2008-03-02 17:43:18 +0000478
bartbedfd232009-03-26 19:07:15 +0000479 q = DRD_(lookup_or_insert_node)(p->thread_info,
480 DRD_(thread_get_running_tid)());
481 tl_assert(q->writer_nesting_count == 0);
482 q->writer_nesting_count++;
bartbedfd232009-03-26 19:07:15 +0000483 tl_assert(q->writer_nesting_count == 1);
bartbedfd232009-03-26 19:07:15 +0000484 DRD_(thread_new_segment)(drd_tid);
485 DRD_(s_rwlock_segment_creation_count)++;
bart7627be32009-06-06 12:26:05 +0000486 DRD_(rwlock_combine_other_vc)(p, drd_tid, True);
bartbedfd232009-03-26 19:07:15 +0000487 p->acquiry_time_ms = VG_(read_millisecond_timer)();
488 p->acquired_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
bart777f7fe2008-03-02 17:43:18 +0000489}
490
491/**
492 * Update rwlock_info state when unlocking the pthread_rwlock_t rwlock.
bart7e6de962009-02-21 09:39:09 +0000493 *
bart777f7fe2008-03-02 17:43:18 +0000494 * @param rwlock Pointer to pthread_rwlock_t data structure in the client space.
bart7e6de962009-02-21 09:39:09 +0000495 *
496 * @return New value of the rwlock recursion count.
497 *
498 * @note This function must be called before pthread_rwlock_unlock() is called,
499 * or a race condition is triggered !
bart777f7fe2008-03-02 17:43:18 +0000500 */
bartd45d9952009-05-31 18:53:54 +0000501void DRD_(rwlock_pre_unlock)(const Addr rwlock, const RwLockT rwlock_type)
bart777f7fe2008-03-02 17:43:18 +0000502{
bartbedfd232009-03-26 19:07:15 +0000503 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
504 const ThreadId vg_tid = VG_(get_running_tid)();
505 struct rwlock_info* p;
506 struct rwlock_thread_info* q;
bart777f7fe2008-03-02 17:43:18 +0000507
bartbedfd232009-03-26 19:07:15 +0000508 if (DRD_(s_trace_rwlock))
florianea71ffb2015-08-05 14:38:57 +0000509 DRD_(trace_msg)("[%u] rwlock_unlock 0x%lx", drd_tid, rwlock);
bart777f7fe2008-03-02 17:43:18 +0000510
bartbedfd232009-03-26 19:07:15 +0000511 p = DRD_(rwlock_get)(rwlock);
512 if (p == 0)
513 {
bart62cc2322010-03-07 10:54:21 +0000514 GenericErrInfo GEI = {
515 .tid = DRD_(thread_get_running_tid)(),
516 .addr = rwlock,
517 };
bartbedfd232009-03-26 19:07:15 +0000518 VG_(maybe_record_error)(VG_(get_running_tid)(),
519 GenericErr,
520 VG_(get_IP)(VG_(get_running_tid)()),
521 "Not a reader-writer lock",
522 &GEI);
523 return;
524 }
bart67707ec2009-07-27 17:02:52 +0000525
526 drd_rwlock_check_type(p, rwlock_type);
527
bartbedfd232009-03-26 19:07:15 +0000528 if (! DRD_(rwlock_is_locked_by)(p, drd_tid))
529 {
bartd45d9952009-05-31 18:53:54 +0000530 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000531 VG_(maybe_record_error)(vg_tid,
532 RwlockErr,
533 VG_(get_IP)(vg_tid),
534 "Reader-writer lock not locked by calling thread",
535 &REI);
536 return;
537 }
538 q = DRD_(lookup_or_insert_node)(p->thread_info, drd_tid);
539 tl_assert(q);
540 if (q->reader_nesting_count > 0)
541 {
542 q->reader_nesting_count--;
543 if (q->reader_nesting_count == 0 && DRD_(s_shared_threshold_ms) > 0)
bart9d5b7962008-05-14 12:25:00 +0000544 {
bart430c45f2009-04-13 08:05:18 +0000545 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
bartbedfd232009-03-26 19:07:15 +0000546 if (held > DRD_(s_shared_threshold_ms))
547 {
548 HoldtimeErrInfo HEI
bartd45d9952009-05-31 18:53:54 +0000549 = { DRD_(thread_get_running_tid)(),
550 rwlock, p->acquired_at, held, DRD_(s_shared_threshold_ms) };
bartbedfd232009-03-26 19:07:15 +0000551 VG_(maybe_record_error)(vg_tid,
552 HoldtimeErr,
553 VG_(get_IP)(vg_tid),
554 "rwlock",
555 &HEI);
556 }
bart9d5b7962008-05-14 12:25:00 +0000557 }
bartb3f33402009-07-25 11:15:03 +0000558 if (q->reader_nesting_count == 0 && q->writer_nesting_count == 0)
559 {
560 /*
561 * This pthread_rwlock_unlock() call really unlocks the rwlock. Save
562 * the current vector clock of the thread such that it is available
563 * when this rwlock is locked again.
564 */
565 DRD_(thread_get_latest_segment)(&q->latest_rdlocked_segment, drd_tid);
566 DRD_(thread_new_segment)(drd_tid);
567 DRD_(s_rwlock_segment_creation_count)++;
568 }
bartbedfd232009-03-26 19:07:15 +0000569 }
570 else if (q->writer_nesting_count > 0)
571 {
572 q->writer_nesting_count--;
573 if (q->writer_nesting_count == 0 && DRD_(s_exclusive_threshold_ms) > 0)
bart9d5b7962008-05-14 12:25:00 +0000574 {
bart430c45f2009-04-13 08:05:18 +0000575 Long held = VG_(read_millisecond_timer)() - p->acquiry_time_ms;
bartbedfd232009-03-26 19:07:15 +0000576 if (held > DRD_(s_exclusive_threshold_ms))
577 {
578 HoldtimeErrInfo HEI
bartd45d9952009-05-31 18:53:54 +0000579 = { DRD_(thread_get_running_tid)(),
580 rwlock, p->acquired_at, held,
bartbedfd232009-03-26 19:07:15 +0000581 DRD_(s_exclusive_threshold_ms) };
582 VG_(maybe_record_error)(vg_tid,
583 HoldtimeErr,
584 VG_(get_IP)(vg_tid),
585 "rwlock",
586 &HEI);
587 }
bart9d5b7962008-05-14 12:25:00 +0000588 }
bartb3f33402009-07-25 11:15:03 +0000589 if (q->reader_nesting_count == 0 && q->writer_nesting_count == 0)
590 {
591 /*
592 * This pthread_rwlock_unlock() call really unlocks the rwlock. Save
593 * the current vector clock of the thread such that it is available
594 * when this rwlock is locked again.
595 */
596 DRD_(thread_get_latest_segment)(&q->latest_wrlocked_segment, drd_tid);
597 DRD_(thread_new_segment)(drd_tid);
598 DRD_(s_rwlock_segment_creation_count)++;
599 }
bartbedfd232009-03-26 19:07:15 +0000600 }
601 else
602 {
603 tl_assert(False);
604 }
bart777f7fe2008-03-02 17:43:18 +0000605}
606
bartb3f33402009-07-25 11:15:03 +0000607/** Called when thread tid stops to exist. */
bartd2c5eae2009-02-21 15:27:04 +0000608static void rwlock_delete_thread(struct rwlock_info* const p,
609 const DrdThreadId tid)
bart777f7fe2008-03-02 17:43:18 +0000610{
bartbedfd232009-03-26 19:07:15 +0000611 struct rwlock_thread_info* q;
bartb3f33402009-07-25 11:15:03 +0000612
bartbedfd232009-03-26 19:07:15 +0000613 if (DRD_(rwlock_is_locked_by)(p, tid))
614 {
bartd45d9952009-05-31 18:53:54 +0000615 RwlockErrInfo REI = { DRD_(thread_get_running_tid)(), p->a1 };
bartbedfd232009-03-26 19:07:15 +0000616 VG_(maybe_record_error)(VG_(get_running_tid)(),
617 RwlockErr,
618 VG_(get_IP)(VG_(get_running_tid)()),
619 "Reader-writer lock still locked at thread exit",
620 &REI);
621 q = DRD_(lookup_or_insert_node)(p->thread_info, tid);
622 q->reader_nesting_count = 0;
623 q->writer_nesting_count = 0;
624 }
bart777f7fe2008-03-02 17:43:18 +0000625}
bart6bbefaf2008-04-19 15:16:45 +0000626
bartdc1ef032009-02-15 14:18:02 +0000627ULong DRD_(get_rwlock_segment_creation_count)(void)
bart6bbefaf2008-04-19 15:16:45 +0000628{
bartbedfd232009-03-26 19:07:15 +0000629 return DRD_(s_rwlock_segment_creation_count);
bart6bbefaf2008-04-19 15:16:45 +0000630}