blob: 9e4a16ea257579a1dc5648635d2f29b7d22f24b3 [file] [log] [blame]
bartbedfd232009-03-26 19:07:15 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
sewardjaf44c822007-11-25 14:01:38 +00002/*
bart86562bd2009-02-16 19:43:56 +00003 This file is part of drd, a thread error detector.
sewardjaf44c822007-11-25 14:01:38 +00004
bart86562bd2009-02-16 19:43:56 +00005 Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
sewardjaf44c822007-11-25 14:01:38 +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
bart28230a32008-02-29 17:27:03 +000026#include "drd_clientobj.h"
sewardjaf44c822007-11-25 14:01:38 +000027#include "drd_cond.h"
28#include "drd_error.h"
29#include "drd_mutex.h"
30#include "drd_suppression.h"
bart46b5fce2008-06-28 13:01:30 +000031#include "pub_tool_errormgr.h" /* VG_(maybe_record_error)() */
32#include "pub_tool_libcassert.h" /* tl_assert() */
33#include "pub_tool_libcprint.h" /* VG_(printf)() */
34#include "pub_tool_machine.h" /* VG_(get_IP)() */
35#include "pub_tool_options.h" /* VG_(clo_backtrace_size) */
36#include "pub_tool_threadstate.h" /* VG_(get_running_tid)() */
sewardjaf44c822007-11-25 14:01:38 +000037
38
bart46b5fce2008-06-28 13:01:30 +000039/* Local functions. */
bart28230a32008-02-29 17:27:03 +000040
bartdc1ef032009-02-15 14:18:02 +000041static void DRD_(cond_cleanup)(struct cond_info* p);
bart28230a32008-02-29 17:27:03 +000042
43
bart46b5fce2008-06-28 13:01:30 +000044/* Local variables. */
bart28230a32008-02-29 17:27:03 +000045
bartdc1ef032009-02-15 14:18:02 +000046static Bool DRD_(s_report_signal_unlocked) = True;
47static Bool DRD_(s_trace_cond);
sewardjaf44c822007-11-25 14:01:38 +000048
49
bart46b5fce2008-06-28 13:01:30 +000050/* Function definitions. */
bart28230a32008-02-29 17:27:03 +000051
bartdc1ef032009-02-15 14:18:02 +000052void DRD_(cond_set_report_signal_unlocked)(const Bool r)
bart764dea22009-02-15 13:16:52 +000053{
bartbedfd232009-03-26 19:07:15 +000054 DRD_(s_report_signal_unlocked) = r;
bart764dea22009-02-15 13:16:52 +000055}
56
bartdc1ef032009-02-15 14:18:02 +000057void DRD_(cond_set_trace)(const Bool trace_cond)
sewardjaf44c822007-11-25 14:01:38 +000058{
bartbedfd232009-03-26 19:07:15 +000059 DRD_(s_trace_cond) = trace_cond;
sewardjaf44c822007-11-25 14:01:38 +000060}
61
62static
bartdc1ef032009-02-15 14:18:02 +000063void DRD_(cond_initialize)(struct cond_info* const p, const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +000064{
bartbedfd232009-03-26 19:07:15 +000065 tl_assert(cond != 0);
66 tl_assert(p->a1 == cond);
67 tl_assert(p->type == ClientCondvar);
sewardjaf44c822007-11-25 14:01:38 +000068
bartbedfd232009-03-26 19:07:15 +000069 p->cleanup = (void(*)(DrdClientobj*))(DRD_(cond_cleanup));
70 p->delete_thread = 0;
71 p->waiter_count = 0;
72 p->mutex = 0;
sewardjaf44c822007-11-25 14:01:38 +000073}
74
bart195e41f2009-02-15 11:34:57 +000075/**
76 * Free the memory that was allocated by cond_initialize(). Called by
77 * DRD_(clientobj_remove)().
bart28230a32008-02-29 17:27:03 +000078 */
bartdc1ef032009-02-15 14:18:02 +000079static void DRD_(cond_cleanup)(struct cond_info* p)
bart28230a32008-02-29 17:27:03 +000080{
bartbedfd232009-03-26 19:07:15 +000081 tl_assert(p);
82 if (p->mutex)
83 {
84 struct mutex_info* q;
85 q = &(DRD_(clientobj_get)(p->mutex, ClientMutex)->mutex);
86 tl_assert(q);
87 {
bartd45d9952009-05-31 18:53:54 +000088 CondDestrErrInfo cde = { DRD_(thread_get_running_tid)(),
89 p->a1, q->a1, q->owner };
bartbedfd232009-03-26 19:07:15 +000090 VG_(maybe_record_error)(VG_(get_running_tid)(),
91 CondDestrErr,
92 VG_(get_IP)(VG_(get_running_tid)()),
93 "Destroying condition variable that is being"
94 " waited upon",
95 &cde);
96 }
97 }
bart28230a32008-02-29 17:27:03 +000098}
99
bartd45d9952009-05-31 18:53:54 +0000100static struct cond_info* cond_get_or_allocate(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000101{
bartbedfd232009-03-26 19:07:15 +0000102 struct cond_info *p;
bart28230a32008-02-29 17:27:03 +0000103
bartbedfd232009-03-26 19:07:15 +0000104 tl_assert(offsetof(DrdClientobj, cond) == 0);
105 p = &(DRD_(clientobj_get)(cond, ClientCondvar)->cond);
106 if (p == 0)
107 {
108 p = &(DRD_(clientobj_add)(cond, ClientCondvar)->cond);
109 DRD_(cond_initialize)(p, cond);
110 }
111 return p;
sewardjaf44c822007-11-25 14:01:38 +0000112}
113
bartd45d9952009-05-31 18:53:54 +0000114struct cond_info* DRD_(cond_get)(const Addr cond)
bart28230a32008-02-29 17:27:03 +0000115{
bartbedfd232009-03-26 19:07:15 +0000116 tl_assert(offsetof(DrdClientobj, cond) == 0);
117 return &(DRD_(clientobj_get)(cond, ClientCondvar)->cond);
bart28230a32008-02-29 17:27:03 +0000118}
119
120/** Called before pthread_cond_init(). */
bartdc1ef032009-02-15 14:18:02 +0000121void DRD_(cond_pre_init)(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000122{
bartbedfd232009-03-26 19:07:15 +0000123 struct cond_info* p;
bart72b751c2008-03-01 13:44:24 +0000124
bartbedfd232009-03-26 19:07:15 +0000125 if (DRD_(s_trace_cond))
126 {
127 VG_(message)(Vg_UserMsg,
128 "[%d/%d] cond_init cond 0x%lx",
129 VG_(get_running_tid)(),
130 DRD_(thread_get_running_tid)(),
131 cond);
132 }
bart72b751c2008-03-01 13:44:24 +0000133
bartbedfd232009-03-26 19:07:15 +0000134 p = DRD_(cond_get)(cond);
bart72b751c2008-03-01 13:44:24 +0000135
bartbedfd232009-03-26 19:07:15 +0000136 if (p)
137 {
bartd45d9952009-05-31 18:53:54 +0000138 CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
bartbedfd232009-03-26 19:07:15 +0000139 VG_(maybe_record_error)(VG_(get_running_tid)(),
140 CondErr,
141 VG_(get_IP)(VG_(get_running_tid)()),
142 "initialized twice",
143 &cei);
144 }
bart72b751c2008-03-01 13:44:24 +0000145
bartd45d9952009-05-31 18:53:54 +0000146 p = cond_get_or_allocate(cond);
sewardjaf44c822007-11-25 14:01:38 +0000147}
148
bart28230a32008-02-29 17:27:03 +0000149/** Called after pthread_cond_destroy(). */
bartdc1ef032009-02-15 14:18:02 +0000150void DRD_(cond_post_destroy)(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000151{
bartbedfd232009-03-26 19:07:15 +0000152 struct cond_info* p;
bart72b751c2008-03-01 13:44:24 +0000153
bartbedfd232009-03-26 19:07:15 +0000154 if (DRD_(s_trace_cond))
155 {
156 VG_(message)(Vg_UserMsg,
157 "[%d/%d] cond_destroy cond 0x%lx",
158 VG_(get_running_tid)(),
159 DRD_(thread_get_running_tid)(),
160 cond);
161 }
sewardjaf44c822007-11-25 14:01:38 +0000162
bartbedfd232009-03-26 19:07:15 +0000163 p = DRD_(cond_get)(cond);
164 if (p == 0)
165 {
bartd45d9952009-05-31 18:53:54 +0000166 CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
bartbedfd232009-03-26 19:07:15 +0000167 VG_(maybe_record_error)(VG_(get_running_tid)(),
168 CondErr,
169 VG_(get_IP)(VG_(get_running_tid)()),
170 "not a condition variable",
171 &cei);
172 return;
173 }
sewardjaf44c822007-11-25 14:01:38 +0000174
bartbedfd232009-03-26 19:07:15 +0000175 if (p->waiter_count != 0)
176 {
bartd45d9952009-05-31 18:53:54 +0000177 CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
bartbedfd232009-03-26 19:07:15 +0000178 VG_(maybe_record_error)(VG_(get_running_tid)(),
179 CondErr,
180 VG_(get_IP)(VG_(get_running_tid)()),
181 "destruction of condition variable being waited"
182 " upon",
183 &cei);
184 }
bart72b751c2008-03-01 13:44:24 +0000185
bartbedfd232009-03-26 19:07:15 +0000186 DRD_(clientobj_remove)(p->a1, ClientCondvar);
sewardjaf44c822007-11-25 14:01:38 +0000187}
188
bart08e6d6a2008-06-28 16:28:49 +0000189/** Called before pthread_cond_wait(). Note: before this function is called,
190 * mutex_unlock() has already been called from drd_clientreq.c.
191 */
bartdc1ef032009-02-15 14:18:02 +0000192int DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
sewardjaf44c822007-11-25 14:01:38 +0000193{
bartbedfd232009-03-26 19:07:15 +0000194 struct cond_info* p;
195 struct mutex_info* q;
sewardjaf44c822007-11-25 14:01:38 +0000196
bartbedfd232009-03-26 19:07:15 +0000197 if (DRD_(s_trace_cond))
198 {
199 VG_(message)(Vg_UserMsg,
200 "[%d/%d] cond_pre_wait cond 0x%lx",
201 VG_(get_running_tid)(),
202 DRD_(thread_get_running_tid)(),
203 cond);
204 }
bart3b1ee452008-02-29 19:28:15 +0000205
bartd45d9952009-05-31 18:53:54 +0000206 p = cond_get_or_allocate(cond);
bartbedfd232009-03-26 19:07:15 +0000207 tl_assert(p);
bart3b1ee452008-02-29 19:28:15 +0000208
bartbedfd232009-03-26 19:07:15 +0000209 if (p->waiter_count == 0)
210 {
211 p->mutex = mutex;
212 }
213 else if (p->mutex != mutex)
214 {
215 CondWaitErrInfo cwei
bartd45d9952009-05-31 18:53:54 +0000216 = { .tid = DRD_(thread_get_running_tid)(),
217 .cond = cond, .mutex1 = p->mutex, .mutex2 = mutex };
bartbedfd232009-03-26 19:07:15 +0000218 VG_(maybe_record_error)(VG_(get_running_tid)(),
219 CondWaitErr,
220 VG_(get_IP)(VG_(get_running_tid)()),
221 "Inconsistent association of condition variable"
222 " and mutex",
223 &cwei);
224 }
225 tl_assert(p->mutex);
226 q = DRD_(mutex_get)(p->mutex);
227 if (q
228 && q->owner == DRD_(thread_get_running_tid)() && q->recursion_count > 0)
229 {
230 const ThreadId vg_tid = VG_(get_running_tid)();
bartd45d9952009-05-31 18:53:54 +0000231 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
232 q->a1, q->recursion_count, q->owner };
bartbedfd232009-03-26 19:07:15 +0000233 VG_(maybe_record_error)(vg_tid,
234 MutexErr,
235 VG_(get_IP)(vg_tid),
236 "Mutex locked recursively",
237 &MEI);
238 }
239 else if (q == 0)
240 {
241 DRD_(not_a_mutex)(p->mutex);
242 }
bart08e6d6a2008-06-28 16:28:49 +0000243
bartbedfd232009-03-26 19:07:15 +0000244 return ++p->waiter_count;
sewardjaf44c822007-11-25 14:01:38 +0000245}
246
bart28230a32008-02-29 17:27:03 +0000247/** Called after pthread_cond_wait(). */
bartdc1ef032009-02-15 14:18:02 +0000248int DRD_(cond_post_wait)(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000249{
bartbedfd232009-03-26 19:07:15 +0000250 struct cond_info* p;
sewardjaf44c822007-11-25 14:01:38 +0000251
bartbedfd232009-03-26 19:07:15 +0000252 if (DRD_(s_trace_cond))
253 {
254 VG_(message)(Vg_UserMsg,
255 "[%d/%d] cond_post_wait cond 0x%lx",
256 VG_(get_running_tid)(),
257 DRD_(thread_get_running_tid)(),
258 cond);
259 }
bart3b1ee452008-02-29 19:28:15 +0000260
bartbedfd232009-03-26 19:07:15 +0000261 p = DRD_(cond_get)(cond);
262 if (p)
263 {
264 if (p->waiter_count > 0)
barta9c55082008-06-28 16:55:35 +0000265 {
bartbedfd232009-03-26 19:07:15 +0000266 --p->waiter_count;
267 if (p->waiter_count == 0)
268 {
269 p->mutex = 0;
270 }
barta9c55082008-06-28 16:55:35 +0000271 }
bartbedfd232009-03-26 19:07:15 +0000272 return p->waiter_count;
273 }
274 return 0;
sewardjaf44c822007-11-25 14:01:38 +0000275}
276
bartdc1ef032009-02-15 14:18:02 +0000277static void DRD_(cond_signal)(Addr const cond)
sewardjaf44c822007-11-25 14:01:38 +0000278{
bartbedfd232009-03-26 19:07:15 +0000279 const ThreadId vg_tid = VG_(get_running_tid)();
280 const DrdThreadId drd_tid = DRD_(VgThreadIdToDrdThreadId)(vg_tid);
281 struct cond_info* const cond_p = DRD_(cond_get)(cond);
bart3b1ee452008-02-29 19:28:15 +0000282
bartbedfd232009-03-26 19:07:15 +0000283 if (cond_p && cond_p->waiter_count > 0)
284 {
285 if (DRD_(s_report_signal_unlocked)
286 && ! DRD_(mutex_is_locked_by)(cond_p->mutex, drd_tid))
287 {
288 /* A signal is sent while the associated mutex has not been locked. */
289 /* This can indicate but is not necessarily a race condition. */
bartd45d9952009-05-31 18:53:54 +0000290 CondRaceErrInfo cei = { .tid = DRD_(thread_get_running_tid)(),
291 .cond = cond,
292 .mutex = cond_p->mutex,
293 };
bartbedfd232009-03-26 19:07:15 +0000294 VG_(maybe_record_error)(vg_tid,
295 CondRaceErr,
296 VG_(get_IP)(vg_tid),
297 "CondErr",
298 &cei);
299 }
300 }
301 else
302 {
303 /* No other thread is waiting for the signal, hence the signal will be */
304 /* lost. This is normal in a POSIX threads application. */
305 }
sewardjaf44c822007-11-25 14:01:38 +0000306}
307
bart3b1ee452008-02-29 19:28:15 +0000308/** Called before pthread_cond_signal(). */
bartdc1ef032009-02-15 14:18:02 +0000309void DRD_(cond_pre_signal)(Addr const cond)
bart3b1ee452008-02-29 19:28:15 +0000310{
bartbedfd232009-03-26 19:07:15 +0000311 if (DRD_(s_trace_cond))
312 {
313 VG_(message)(Vg_UserMsg,
314 "[%d/%d] cond_signal cond 0x%lx",
315 VG_(get_running_tid)(),
316 DRD_(thread_get_running_tid)(),
317 cond);
318 }
bart3b1ee452008-02-29 19:28:15 +0000319
bartbedfd232009-03-26 19:07:15 +0000320 DRD_(cond_signal)(cond);
bart3b1ee452008-02-29 19:28:15 +0000321}
322
bart28230a32008-02-29 17:27:03 +0000323/** Called before pthread_cond_broadcast(). */
bartdc1ef032009-02-15 14:18:02 +0000324void DRD_(cond_pre_broadcast)(Addr const cond)
sewardjaf44c822007-11-25 14:01:38 +0000325{
bartbedfd232009-03-26 19:07:15 +0000326 if (DRD_(s_trace_cond))
327 {
328 VG_(message)(Vg_UserMsg,
329 "[%d/%d] cond_broadcast cond 0x%lx",
330 VG_(get_running_tid)(),
331 DRD_(thread_get_running_tid)(),
332 cond);
333 }
bart3b1ee452008-02-29 19:28:15 +0000334
bartbedfd232009-03-26 19:07:15 +0000335 DRD_(cond_signal)(cond);
sewardjaf44c822007-11-25 14:01:38 +0000336}