blob: a698e1cebc91865817a8c25c7d062821bfef6999 [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 {
88 CondDestrErrInfo cde = { p->a1, q->a1, q->owner };
89 VG_(maybe_record_error)(VG_(get_running_tid)(),
90 CondDestrErr,
91 VG_(get_IP)(VG_(get_running_tid)()),
92 "Destroying condition variable that is being"
93 " waited upon",
94 &cde);
95 }
96 }
bart28230a32008-02-29 17:27:03 +000097}
98
bartdc1ef032009-02-15 14:18:02 +000099static struct cond_info* DRD_(cond_get_or_allocate)(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000100{
bartbedfd232009-03-26 19:07:15 +0000101 struct cond_info *p;
bart28230a32008-02-29 17:27:03 +0000102
bartbedfd232009-03-26 19:07:15 +0000103 tl_assert(offsetof(DrdClientobj, cond) == 0);
104 p = &(DRD_(clientobj_get)(cond, ClientCondvar)->cond);
105 if (p == 0)
106 {
107 p = &(DRD_(clientobj_add)(cond, ClientCondvar)->cond);
108 DRD_(cond_initialize)(p, cond);
109 }
110 return p;
sewardjaf44c822007-11-25 14:01:38 +0000111}
112
bartdc1ef032009-02-15 14:18:02 +0000113static struct cond_info* DRD_(cond_get)(const Addr cond)
bart28230a32008-02-29 17:27:03 +0000114{
bartbedfd232009-03-26 19:07:15 +0000115 tl_assert(offsetof(DrdClientobj, cond) == 0);
116 return &(DRD_(clientobj_get)(cond, ClientCondvar)->cond);
bart28230a32008-02-29 17:27:03 +0000117}
118
119/** Called before pthread_cond_init(). */
bartdc1ef032009-02-15 14:18:02 +0000120void DRD_(cond_pre_init)(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000121{
bartbedfd232009-03-26 19:07:15 +0000122 struct cond_info* p;
bart72b751c2008-03-01 13:44:24 +0000123
bartbedfd232009-03-26 19:07:15 +0000124 if (DRD_(s_trace_cond))
125 {
126 VG_(message)(Vg_UserMsg,
127 "[%d/%d] cond_init cond 0x%lx",
128 VG_(get_running_tid)(),
129 DRD_(thread_get_running_tid)(),
130 cond);
131 }
bart72b751c2008-03-01 13:44:24 +0000132
bartbedfd232009-03-26 19:07:15 +0000133 p = DRD_(cond_get)(cond);
bart72b751c2008-03-01 13:44:24 +0000134
bartbedfd232009-03-26 19:07:15 +0000135 if (p)
136 {
137 CondErrInfo cei = { .cond = cond };
138 VG_(maybe_record_error)(VG_(get_running_tid)(),
139 CondErr,
140 VG_(get_IP)(VG_(get_running_tid)()),
141 "initialized twice",
142 &cei);
143 }
bart72b751c2008-03-01 13:44:24 +0000144
bartbedfd232009-03-26 19:07:15 +0000145 p = DRD_(cond_get_or_allocate)(cond);
sewardjaf44c822007-11-25 14:01:38 +0000146}
147
bart28230a32008-02-29 17:27:03 +0000148/** Called after pthread_cond_destroy(). */
bartdc1ef032009-02-15 14:18:02 +0000149void DRD_(cond_post_destroy)(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000150{
bartbedfd232009-03-26 19:07:15 +0000151 struct cond_info* p;
bart72b751c2008-03-01 13:44:24 +0000152
bartbedfd232009-03-26 19:07:15 +0000153 if (DRD_(s_trace_cond))
154 {
155 VG_(message)(Vg_UserMsg,
156 "[%d/%d] cond_destroy cond 0x%lx",
157 VG_(get_running_tid)(),
158 DRD_(thread_get_running_tid)(),
159 cond);
160 }
sewardjaf44c822007-11-25 14:01:38 +0000161
bartbedfd232009-03-26 19:07:15 +0000162 p = DRD_(cond_get)(cond);
163 if (p == 0)
164 {
165 CondErrInfo cei = { .cond = cond };
166 VG_(maybe_record_error)(VG_(get_running_tid)(),
167 CondErr,
168 VG_(get_IP)(VG_(get_running_tid)()),
169 "not a condition variable",
170 &cei);
171 return;
172 }
sewardjaf44c822007-11-25 14:01:38 +0000173
bartbedfd232009-03-26 19:07:15 +0000174 if (p->waiter_count != 0)
175 {
176 CondErrInfo cei = { .cond = cond };
177 VG_(maybe_record_error)(VG_(get_running_tid)(),
178 CondErr,
179 VG_(get_IP)(VG_(get_running_tid)()),
180 "destruction of condition variable being waited"
181 " upon",
182 &cei);
183 }
bart72b751c2008-03-01 13:44:24 +0000184
bartbedfd232009-03-26 19:07:15 +0000185 DRD_(clientobj_remove)(p->a1, ClientCondvar);
sewardjaf44c822007-11-25 14:01:38 +0000186}
187
bart08e6d6a2008-06-28 16:28:49 +0000188/** Called before pthread_cond_wait(). Note: before this function is called,
189 * mutex_unlock() has already been called from drd_clientreq.c.
190 */
bartdc1ef032009-02-15 14:18:02 +0000191int DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
sewardjaf44c822007-11-25 14:01:38 +0000192{
bartbedfd232009-03-26 19:07:15 +0000193 struct cond_info* p;
194 struct mutex_info* q;
sewardjaf44c822007-11-25 14:01:38 +0000195
bartbedfd232009-03-26 19:07:15 +0000196 if (DRD_(s_trace_cond))
197 {
198 VG_(message)(Vg_UserMsg,
199 "[%d/%d] cond_pre_wait cond 0x%lx",
200 VG_(get_running_tid)(),
201 DRD_(thread_get_running_tid)(),
202 cond);
203 }
bart3b1ee452008-02-29 19:28:15 +0000204
bartbedfd232009-03-26 19:07:15 +0000205 p = DRD_(cond_get_or_allocate)(cond);
206 tl_assert(p);
bart3b1ee452008-02-29 19:28:15 +0000207
bartbedfd232009-03-26 19:07:15 +0000208 if (p->waiter_count == 0)
209 {
210 p->mutex = mutex;
211 }
212 else if (p->mutex != mutex)
213 {
214 CondWaitErrInfo cwei
215 = { .cond = cond, .mutex1 = p->mutex, .mutex2 = mutex };
216 VG_(maybe_record_error)(VG_(get_running_tid)(),
217 CondWaitErr,
218 VG_(get_IP)(VG_(get_running_tid)()),
219 "Inconsistent association of condition variable"
220 " and mutex",
221 &cwei);
222 }
223 tl_assert(p->mutex);
224 q = DRD_(mutex_get)(p->mutex);
225 if (q
226 && q->owner == DRD_(thread_get_running_tid)() && q->recursion_count > 0)
227 {
228 const ThreadId vg_tid = VG_(get_running_tid)();
229 MutexErrInfo MEI = { q->a1, q->recursion_count, q->owner };
230 VG_(maybe_record_error)(vg_tid,
231 MutexErr,
232 VG_(get_IP)(vg_tid),
233 "Mutex locked recursively",
234 &MEI);
235 }
236 else if (q == 0)
237 {
238 DRD_(not_a_mutex)(p->mutex);
239 }
bart08e6d6a2008-06-28 16:28:49 +0000240
bartbedfd232009-03-26 19:07:15 +0000241 return ++p->waiter_count;
sewardjaf44c822007-11-25 14:01:38 +0000242}
243
bart28230a32008-02-29 17:27:03 +0000244/** Called after pthread_cond_wait(). */
bartdc1ef032009-02-15 14:18:02 +0000245int DRD_(cond_post_wait)(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000246{
bartbedfd232009-03-26 19:07:15 +0000247 struct cond_info* p;
sewardjaf44c822007-11-25 14:01:38 +0000248
bartbedfd232009-03-26 19:07:15 +0000249 if (DRD_(s_trace_cond))
250 {
251 VG_(message)(Vg_UserMsg,
252 "[%d/%d] cond_post_wait cond 0x%lx",
253 VG_(get_running_tid)(),
254 DRD_(thread_get_running_tid)(),
255 cond);
256 }
bart3b1ee452008-02-29 19:28:15 +0000257
bartbedfd232009-03-26 19:07:15 +0000258 p = DRD_(cond_get)(cond);
259 if (p)
260 {
261 if (p->waiter_count > 0)
barta9c55082008-06-28 16:55:35 +0000262 {
bartbedfd232009-03-26 19:07:15 +0000263 --p->waiter_count;
264 if (p->waiter_count == 0)
265 {
266 p->mutex = 0;
267 }
barta9c55082008-06-28 16:55:35 +0000268 }
bartbedfd232009-03-26 19:07:15 +0000269 return p->waiter_count;
270 }
271 return 0;
sewardjaf44c822007-11-25 14:01:38 +0000272}
273
bartdc1ef032009-02-15 14:18:02 +0000274static void DRD_(cond_signal)(Addr const cond)
sewardjaf44c822007-11-25 14:01:38 +0000275{
bartbedfd232009-03-26 19:07:15 +0000276 const ThreadId vg_tid = VG_(get_running_tid)();
277 const DrdThreadId drd_tid = DRD_(VgThreadIdToDrdThreadId)(vg_tid);
278 struct cond_info* const cond_p = DRD_(cond_get)(cond);
bart3b1ee452008-02-29 19:28:15 +0000279
bartbedfd232009-03-26 19:07:15 +0000280 if (cond_p && cond_p->waiter_count > 0)
281 {
282 if (DRD_(s_report_signal_unlocked)
283 && ! DRD_(mutex_is_locked_by)(cond_p->mutex, drd_tid))
284 {
285 /* A signal is sent while the associated mutex has not been locked. */
286 /* This can indicate but is not necessarily a race condition. */
287 CondRaceErrInfo cei;
288 cei.cond = cond;
289 cei.mutex = cond_p->mutex;
290 VG_(maybe_record_error)(vg_tid,
291 CondRaceErr,
292 VG_(get_IP)(vg_tid),
293 "CondErr",
294 &cei);
295 }
296 }
297 else
298 {
299 /* No other thread is waiting for the signal, hence the signal will be */
300 /* lost. This is normal in a POSIX threads application. */
301 }
sewardjaf44c822007-11-25 14:01:38 +0000302}
303
bart3b1ee452008-02-29 19:28:15 +0000304/** Called before pthread_cond_signal(). */
bartdc1ef032009-02-15 14:18:02 +0000305void DRD_(cond_pre_signal)(Addr const cond)
bart3b1ee452008-02-29 19:28:15 +0000306{
bartbedfd232009-03-26 19:07:15 +0000307 if (DRD_(s_trace_cond))
308 {
309 VG_(message)(Vg_UserMsg,
310 "[%d/%d] cond_signal cond 0x%lx",
311 VG_(get_running_tid)(),
312 DRD_(thread_get_running_tid)(),
313 cond);
314 }
bart3b1ee452008-02-29 19:28:15 +0000315
bartbedfd232009-03-26 19:07:15 +0000316 DRD_(cond_signal)(cond);
bart3b1ee452008-02-29 19:28:15 +0000317}
318
bart28230a32008-02-29 17:27:03 +0000319/** Called before pthread_cond_broadcast(). */
bartdc1ef032009-02-15 14:18:02 +0000320void DRD_(cond_pre_broadcast)(Addr const cond)
sewardjaf44c822007-11-25 14:01:38 +0000321{
bartbedfd232009-03-26 19:07:15 +0000322 if (DRD_(s_trace_cond))
323 {
324 VG_(message)(Vg_UserMsg,
325 "[%d/%d] cond_broadcast cond 0x%lx",
326 VG_(get_running_tid)(),
327 DRD_(thread_get_running_tid)(),
328 cond);
329 }
bart3b1ee452008-02-29 19:28:15 +0000330
bartbedfd232009-03-26 19:07:15 +0000331 DRD_(cond_signal)(cond);
sewardjaf44c822007-11-25 14:01:38 +0000332}