blob: 61f73ebb8d335f8483a301022fed48cb27c3a709 [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,
bart63c92ea2009-07-19 17:53:56 +0000128 "[%d] cond_init cond 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000129 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 {
bartd45d9952009-05-31 18:53:54 +0000137 CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
bartbedfd232009-03-26 19:07:15 +0000138 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
bartd45d9952009-05-31 18:53:54 +0000145 p = 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,
bart63c92ea2009-07-19 17:53:56 +0000156 "[%d] cond_destroy cond 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000157 DRD_(thread_get_running_tid)(),
158 cond);
159 }
sewardjaf44c822007-11-25 14:01:38 +0000160
bartbedfd232009-03-26 19:07:15 +0000161 p = DRD_(cond_get)(cond);
162 if (p == 0)
163 {
bartd45d9952009-05-31 18:53:54 +0000164 CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
bartbedfd232009-03-26 19:07:15 +0000165 VG_(maybe_record_error)(VG_(get_running_tid)(),
166 CondErr,
167 VG_(get_IP)(VG_(get_running_tid)()),
168 "not a condition variable",
169 &cei);
170 return;
171 }
sewardjaf44c822007-11-25 14:01:38 +0000172
bartbedfd232009-03-26 19:07:15 +0000173 if (p->waiter_count != 0)
174 {
bartd45d9952009-05-31 18:53:54 +0000175 CondErrInfo cei = { .tid = DRD_(thread_get_running_tid)(), .cond = cond };
bartbedfd232009-03-26 19:07:15 +0000176 VG_(maybe_record_error)(VG_(get_running_tid)(),
177 CondErr,
178 VG_(get_IP)(VG_(get_running_tid)()),
179 "destruction of condition variable being waited"
180 " upon",
181 &cei);
182 }
bart72b751c2008-03-01 13:44:24 +0000183
bartbedfd232009-03-26 19:07:15 +0000184 DRD_(clientobj_remove)(p->a1, ClientCondvar);
sewardjaf44c822007-11-25 14:01:38 +0000185}
186
bart08e6d6a2008-06-28 16:28:49 +0000187/** Called before pthread_cond_wait(). Note: before this function is called,
188 * mutex_unlock() has already been called from drd_clientreq.c.
189 */
bartdc1ef032009-02-15 14:18:02 +0000190int DRD_(cond_pre_wait)(const Addr cond, const Addr mutex)
sewardjaf44c822007-11-25 14:01:38 +0000191{
bartbedfd232009-03-26 19:07:15 +0000192 struct cond_info* p;
193 struct mutex_info* q;
sewardjaf44c822007-11-25 14:01:38 +0000194
bartbedfd232009-03-26 19:07:15 +0000195 if (DRD_(s_trace_cond))
196 {
197 VG_(message)(Vg_UserMsg,
bart63c92ea2009-07-19 17:53:56 +0000198 "[%d] cond_pre_wait cond 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000199 DRD_(thread_get_running_tid)(),
200 cond);
201 }
bart3b1ee452008-02-29 19:28:15 +0000202
bartd45d9952009-05-31 18:53:54 +0000203 p = cond_get_or_allocate(cond);
bartbedfd232009-03-26 19:07:15 +0000204 tl_assert(p);
bart3b1ee452008-02-29 19:28:15 +0000205
bartbedfd232009-03-26 19:07:15 +0000206 if (p->waiter_count == 0)
207 {
208 p->mutex = mutex;
209 }
210 else if (p->mutex != mutex)
211 {
212 CondWaitErrInfo cwei
bartd45d9952009-05-31 18:53:54 +0000213 = { .tid = DRD_(thread_get_running_tid)(),
214 .cond = cond, .mutex1 = p->mutex, .mutex2 = mutex };
bartbedfd232009-03-26 19:07:15 +0000215 VG_(maybe_record_error)(VG_(get_running_tid)(),
216 CondWaitErr,
217 VG_(get_IP)(VG_(get_running_tid)()),
218 "Inconsistent association of condition variable"
219 " and mutex",
220 &cwei);
221 }
222 tl_assert(p->mutex);
223 q = DRD_(mutex_get)(p->mutex);
224 if (q
225 && q->owner == DRD_(thread_get_running_tid)() && q->recursion_count > 0)
226 {
227 const ThreadId vg_tid = VG_(get_running_tid)();
bartd45d9952009-05-31 18:53:54 +0000228 MutexErrInfo MEI = { DRD_(thread_get_running_tid)(),
229 q->a1, q->recursion_count, q->owner };
bartbedfd232009-03-26 19:07:15 +0000230 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,
bart63c92ea2009-07-19 17:53:56 +0000252 "[%d] cond_post_wait cond 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000253 DRD_(thread_get_running_tid)(),
254 cond);
255 }
bart3b1ee452008-02-29 19:28:15 +0000256
bartbedfd232009-03-26 19:07:15 +0000257 p = DRD_(cond_get)(cond);
258 if (p)
259 {
260 if (p->waiter_count > 0)
barta9c55082008-06-28 16:55:35 +0000261 {
bartbedfd232009-03-26 19:07:15 +0000262 --p->waiter_count;
263 if (p->waiter_count == 0)
264 {
265 p->mutex = 0;
266 }
barta9c55082008-06-28 16:55:35 +0000267 }
bartbedfd232009-03-26 19:07:15 +0000268 return p->waiter_count;
269 }
270 return 0;
sewardjaf44c822007-11-25 14:01:38 +0000271}
272
bartdc1ef032009-02-15 14:18:02 +0000273static void DRD_(cond_signal)(Addr const cond)
sewardjaf44c822007-11-25 14:01:38 +0000274{
bartbedfd232009-03-26 19:07:15 +0000275 const ThreadId vg_tid = VG_(get_running_tid)();
276 const DrdThreadId drd_tid = DRD_(VgThreadIdToDrdThreadId)(vg_tid);
277 struct cond_info* const cond_p = DRD_(cond_get)(cond);
bart3b1ee452008-02-29 19:28:15 +0000278
bartbedfd232009-03-26 19:07:15 +0000279 if (cond_p && cond_p->waiter_count > 0)
280 {
281 if (DRD_(s_report_signal_unlocked)
282 && ! DRD_(mutex_is_locked_by)(cond_p->mutex, drd_tid))
283 {
284 /* A signal is sent while the associated mutex has not been locked. */
285 /* This can indicate but is not necessarily a race condition. */
bartd45d9952009-05-31 18:53:54 +0000286 CondRaceErrInfo cei = { .tid = DRD_(thread_get_running_tid)(),
287 .cond = cond,
288 .mutex = cond_p->mutex,
289 };
bartbedfd232009-03-26 19:07:15 +0000290 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,
bart63c92ea2009-07-19 17:53:56 +0000310 "[%d] cond_signal cond 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000311 DRD_(thread_get_running_tid)(),
312 cond);
313 }
bart3b1ee452008-02-29 19:28:15 +0000314
bartbedfd232009-03-26 19:07:15 +0000315 DRD_(cond_signal)(cond);
bart3b1ee452008-02-29 19:28:15 +0000316}
317
bart28230a32008-02-29 17:27:03 +0000318/** Called before pthread_cond_broadcast(). */
bartdc1ef032009-02-15 14:18:02 +0000319void DRD_(cond_pre_broadcast)(Addr const cond)
sewardjaf44c822007-11-25 14:01:38 +0000320{
bartbedfd232009-03-26 19:07:15 +0000321 if (DRD_(s_trace_cond))
322 {
323 VG_(message)(Vg_UserMsg,
bart63c92ea2009-07-19 17:53:56 +0000324 "[%d] cond_broadcast cond 0x%lx\n",
bartbedfd232009-03-26 19:07:15 +0000325 DRD_(thread_get_running_tid)(),
326 cond);
327 }
bart3b1ee452008-02-29 19:28:15 +0000328
bartbedfd232009-03-26 19:07:15 +0000329 DRD_(cond_signal)(cond);
sewardjaf44c822007-11-25 14:01:38 +0000330}