blob: 11e962fab5e877a1042ba180d7be51906f850080 [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001/*
2 This file is part of drd, a data race detector.
3
sewardj85642922008-01-14 11:54:56 +00004 Copyright (C) 2006-2008 Bart Van Assche
sewardjaf44c822007-11-25 14:01:38 +00005 bart.vanassche@gmail.com
6
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"
sewardjaf44c822007-11-25 14:01:38 +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)()
sewardj85642922008-01-14 11:54:56 +000035#include "pub_tool_options.h" // VG_(clo_backtrace_size)
sewardjaf44c822007-11-25 14:01:38 +000036#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
sewardjaf44c822007-11-25 14:01:38 +000037
38
bart28230a32008-02-29 17:27:03 +000039// Local functions.
40
41static void cond_cleanup(struct cond_info* p);
42
43
44// Local variables.
45
sewardjaf44c822007-11-25 14:01:38 +000046static Bool s_trace_cond;
47
48
bart28230a32008-02-29 17:27:03 +000049// Function definitions.
50
sewardjaf44c822007-11-25 14:01:38 +000051void cond_set_trace(const Bool trace_cond)
52{
53 s_trace_cond = trace_cond;
54}
55
56static
bart0268dfa2008-03-11 20:10:21 +000057void cond_initialize(struct cond_info* const p, const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +000058{
59 tl_assert(cond != 0);
bart28230a32008-02-29 17:27:03 +000060 tl_assert(p->a1 == cond);
bart28230a32008-02-29 17:27:03 +000061 tl_assert(p->type == ClientCondvar);
sewardjaf44c822007-11-25 14:01:38 +000062
bart28230a32008-02-29 17:27:03 +000063 p->cleanup = (void(*)(DrdClientobj*))cond_cleanup;
sewardjaf44c822007-11-25 14:01:38 +000064 p->waiter_count = 0;
65 p->mutex = 0;
66}
67
bart28230a32008-02-29 17:27:03 +000068/** Free the memory that was allocated by cond_initialize(). Called by
bart72b751c2008-03-01 13:44:24 +000069 * clientobj_remove().
bart28230a32008-02-29 17:27:03 +000070 */
71static void cond_cleanup(struct cond_info* p)
72{
73 tl_assert(p);
74 if (p->mutex)
75 {
76 struct mutex_info* q;
bart72b751c2008-03-01 13:44:24 +000077 q = &clientobj_get(p->mutex, ClientMutex)->mutex;
bart3b1ee452008-02-29 19:28:15 +000078 tl_assert(q);
79 {
80 CondDestrErrInfo cde = { p->a1, q->a1, q->owner };
81 VG_(maybe_record_error)(VG_(get_running_tid)(),
82 CondDestrErr,
83 VG_(get_IP)(VG_(get_running_tid)()),
84 "Destroying condition variable that is being"
85 " waited upon",
86 &cde);
87 }
bart28230a32008-02-29 17:27:03 +000088 }
89}
90
bart0268dfa2008-03-11 20:10:21 +000091static struct cond_info* cond_get_or_allocate(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +000092{
bart28230a32008-02-29 17:27:03 +000093 struct cond_info *p;
94
95 tl_assert(offsetof(DrdClientobj, cond) == 0);
bart72b751c2008-03-01 13:44:24 +000096 p = &clientobj_get(cond, ClientCondvar)->cond;
bart28230a32008-02-29 17:27:03 +000097 if (p == 0)
sewardj721ad7b2007-11-30 08:30:29 +000098 {
bart0268dfa2008-03-11 20:10:21 +000099 p = &clientobj_add(cond, ClientCondvar)->cond;
100 cond_initialize(p, cond);
sewardj721ad7b2007-11-30 08:30:29 +0000101 }
bart28230a32008-02-29 17:27:03 +0000102 return p;
sewardjaf44c822007-11-25 14:01:38 +0000103}
104
bart72b751c2008-03-01 13:44:24 +0000105static struct cond_info* cond_get(const Addr cond)
bart28230a32008-02-29 17:27:03 +0000106{
107 tl_assert(offsetof(DrdClientobj, cond) == 0);
bart72b751c2008-03-01 13:44:24 +0000108 return &clientobj_get(cond, ClientCondvar)->cond;
bart28230a32008-02-29 17:27:03 +0000109}
110
111/** Called before pthread_cond_init(). */
bart0268dfa2008-03-11 20:10:21 +0000112void cond_pre_init(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000113{
bart72b751c2008-03-01 13:44:24 +0000114 struct cond_info* p;
115
sewardjaf44c822007-11-25 14:01:38 +0000116 if (s_trace_cond)
117 {
bart3b1ee452008-02-29 19:28:15 +0000118 VG_(message)(Vg_UserMsg,
bart4a975e12008-03-30 13:28:33 +0000119 "[%d/%d] cond_init cond 0x%lx",
bart3b1ee452008-02-29 19:28:15 +0000120 VG_(get_running_tid)(),
121 thread_get_running_tid(),
122 cond);
sewardjaf44c822007-11-25 14:01:38 +0000123 }
bart72b751c2008-03-01 13:44:24 +0000124
bart72b751c2008-03-01 13:44:24 +0000125 p = cond_get(cond);
126
127 if (p)
128 {
129 CondErrInfo cei = { .cond = cond };
130 VG_(maybe_record_error)(VG_(get_running_tid)(),
131 CondErr,
132 VG_(get_IP)(VG_(get_running_tid)()),
133 "initialized twice",
134 &cei);
135 }
136
bart0268dfa2008-03-11 20:10:21 +0000137 p = cond_get_or_allocate(cond);
sewardjaf44c822007-11-25 14:01:38 +0000138}
139
bart28230a32008-02-29 17:27:03 +0000140/** Called after pthread_cond_destroy(). */
bart72b751c2008-03-01 13:44:24 +0000141void cond_post_destroy(const Addr cond)
sewardjaf44c822007-11-25 14:01:38 +0000142{
bart72b751c2008-03-01 13:44:24 +0000143 struct cond_info* p;
144
sewardjaf44c822007-11-25 14:01:38 +0000145 if (s_trace_cond)
146 {
bart3b1ee452008-02-29 19:28:15 +0000147 VG_(message)(Vg_UserMsg,
bart4a975e12008-03-30 13:28:33 +0000148 "[%d/%d] cond_destroy cond 0x%lx",
bart3b1ee452008-02-29 19:28:15 +0000149 VG_(get_running_tid)(),
150 thread_get_running_tid(),
bart72b751c2008-03-01 13:44:24 +0000151 cond);
sewardjaf44c822007-11-25 14:01:38 +0000152 }
153
bart72b751c2008-03-01 13:44:24 +0000154 p = cond_get(cond);
155 if (p == 0)
156 {
157 CondErrInfo cei = { .cond = cond };
158 VG_(maybe_record_error)(VG_(get_running_tid)(),
159 CondErr,
160 VG_(get_IP)(VG_(get_running_tid)()),
161 "not a condition variable",
162 &cei);
163 return;
164 }
sewardjaf44c822007-11-25 14:01:38 +0000165
bart72b751c2008-03-01 13:44:24 +0000166 if (p->waiter_count != 0)
167 {
168 CondErrInfo cei = { .cond = cond };
169 VG_(maybe_record_error)(VG_(get_running_tid)(),
170 CondErr,
171 VG_(get_IP)(VG_(get_running_tid)()),
172 "destruction of condition variable being waited"
173 " upon",
174 &cei);
175 }
176
177 clientobj_remove(p->a1, ClientCondvar);
sewardjaf44c822007-11-25 14:01:38 +0000178}
179
bart28230a32008-02-29 17:27:03 +0000180/** Called before pthread_cond_wait(). */
bart0268dfa2008-03-11 20:10:21 +0000181int cond_pre_wait(const Addr cond, const Addr mutex)
sewardjaf44c822007-11-25 14:01:38 +0000182{
183 struct cond_info* p;
184
bart3b1ee452008-02-29 19:28:15 +0000185 if (s_trace_cond)
186 {
187 VG_(message)(Vg_UserMsg,
bart4a975e12008-03-30 13:28:33 +0000188 "[%d/%d] cond_pre_wait cond 0x%lx",
bart3b1ee452008-02-29 19:28:15 +0000189 VG_(get_running_tid)(),
190 thread_get_running_tid(),
191 cond);
192 }
193
bart0268dfa2008-03-11 20:10:21 +0000194 p = cond_get_or_allocate(cond);
bart3b1ee452008-02-29 19:28:15 +0000195 tl_assert(p);
196
sewardjaf44c822007-11-25 14:01:38 +0000197 if (p->waiter_count == 0)
198 {
199 p->mutex = mutex;
200 }
201 else
202 {
203 // TO DO: print a proper error message if two different threads call
204 // pthread_cond_*wait() on the same condition variable but with a different
205 // mutex argument.
206 tl_assert(p->mutex == mutex);
207 }
208 return ++p->waiter_count;
209}
210
bart28230a32008-02-29 17:27:03 +0000211/** Called after pthread_cond_wait(). */
sewardjaf44c822007-11-25 14:01:38 +0000212int cond_post_wait(const Addr cond)
213{
214 struct cond_info* p;
215
bart3b1ee452008-02-29 19:28:15 +0000216 if (s_trace_cond)
217 {
218 VG_(message)(Vg_UserMsg,
bart4a975e12008-03-30 13:28:33 +0000219 "[%d/%d] cond_post_wait cond 0x%lx",
bart3b1ee452008-02-29 19:28:15 +0000220 VG_(get_running_tid)(),
221 thread_get_running_tid(),
222 cond);
223 }
224
sewardjaf44c822007-11-25 14:01:38 +0000225 p = cond_get(cond);
bart00344642008-03-01 15:27:41 +0000226 // To do: print a proper error message if the assert below fails.
sewardjaf44c822007-11-25 14:01:38 +0000227 tl_assert(p);
bart00344642008-03-01 15:27:41 +0000228 // To do: print a proper error message if the assert below fails.
sewardjaf44c822007-11-25 14:01:38 +0000229 tl_assert(p->waiter_count > 0);
230 tl_assert(p->mutex);
231 if (--p->waiter_count == 0)
232 {
233 p->mutex = 0;
234 }
235 return p->waiter_count;
236}
237
bart3b1ee452008-02-29 19:28:15 +0000238static void cond_signal(Addr const cond)
sewardjaf44c822007-11-25 14:01:38 +0000239{
240 const ThreadId vg_tid = VG_(get_running_tid)();
241 const DrdThreadId drd_tid = VgThreadIdToDrdThreadId(vg_tid);
242 struct cond_info* const cond_p = cond_get(cond);
bart3b1ee452008-02-29 19:28:15 +0000243
sewardjaf44c822007-11-25 14:01:38 +0000244 if (cond_p && cond_p->waiter_count > 0)
245 {
246 if (! mutex_is_locked_by(cond_p->mutex, drd_tid))
247 {
bart11608002008-03-13 17:47:01 +0000248 /* A signal is sent while the associated mutex has not been locked. */
249 /* This can indicate but is not necessarily a race condition. */
250#if 0
sewardjaf44c822007-11-25 14:01:38 +0000251 CondRaceErrInfo cei;
252 cei.cond = cond;
253 cei.mutex = cond_p->mutex;
254 VG_(maybe_record_error)(vg_tid,
255 CondRaceErr,
256 VG_(get_IP)(vg_tid),
257 "CondErr",
258 &cei);
bart11608002008-03-13 17:47:01 +0000259#endif
sewardjaf44c822007-11-25 14:01:38 +0000260 }
261 }
262 else
263 {
264 /* No other thread is waiting for the signal, hence the signal will be */
265 /* lost. This is normal in a POSIX threads application. */
266 }
267}
268
bart3b1ee452008-02-29 19:28:15 +0000269/** Called before pthread_cond_signal(). */
270void cond_pre_signal(Addr const cond)
271{
272 if (s_trace_cond)
273 {
274 VG_(message)(Vg_UserMsg,
bart4a975e12008-03-30 13:28:33 +0000275 "[%d/%d] cond_signal cond 0x%lx",
bart3b1ee452008-02-29 19:28:15 +0000276 VG_(get_running_tid)(),
277 thread_get_running_tid(),
278 cond);
279 }
280
281 cond_signal(cond);
282}
283
bart28230a32008-02-29 17:27:03 +0000284/** Called before pthread_cond_broadcast(). */
sewardjaf44c822007-11-25 14:01:38 +0000285void cond_pre_broadcast(Addr const cond)
286{
bart3b1ee452008-02-29 19:28:15 +0000287 if (s_trace_cond)
288 {
289 VG_(message)(Vg_UserMsg,
bart4a975e12008-03-30 13:28:33 +0000290 "[%d/%d] cond_broadcast cond 0x%lx",
bart3b1ee452008-02-29 19:28:15 +0000291 VG_(get_running_tid)(),
292 thread_get_running_tid(),
293 cond);
294 }
295
296 cond_signal(cond);
sewardjaf44c822007-11-25 14:01:38 +0000297}
298
bart28230a32008-02-29 17:27:03 +0000299/** Called after pthread_cond_destroy(). */
sewardj85642922008-01-14 11:54:56 +0000300void cond_thread_delete(const DrdThreadId tid)
301{ }