2 This file is part of drd, a thread error detector.
4 Copyright (C) 2006-2017 Bart Van Assche <bvanassche@acm.org>.
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.
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.
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
21 The GNU General Public License is contained in the file COPYING.
25 #include "drd_clientobj.h"
27 #include "drd_error.h"
28 #include "drd_mutex.h"
29 #include "pub_tool_errormgr.h" /* VG_(maybe_record_error)() */
30 #include "pub_tool_libcassert.h" /* tl_assert() */
31 #include "pub_tool_libcbase.h" /* VG_(memcmp)() */
32 #include "pub_tool_libcprint.h" /* VG_(printf)() */
33 #include "pub_tool_machine.h" /* VG_(get_IP)() */
34 #include "pub_tool_threadstate.h" /* VG_(get_running_tid)() */
37 /* Local functions. */
39 static void DRD_(cond_cleanup
)(struct cond_info
* p
);
42 /* Local variables. */
44 static Bool
DRD_(s_report_signal_unlocked
) = True
;
45 static Bool
DRD_(s_trace_cond
);
48 /* Function definitions. */
50 void DRD_(cond_set_report_signal_unlocked
)(const Bool r
)
52 DRD_(s_report_signal_unlocked
) = r
;
55 void DRD_(cond_set_trace
)(const Bool trace_cond
)
57 DRD_(s_trace_cond
) = trace_cond
;
61 void DRD_(cond_initialize
)(struct cond_info
* const p
, const Addr cond
)
64 tl_assert(p
->a1
== cond
);
65 tl_assert(p
->type
== ClientCondvar
);
67 p
->cleanup
= (void(*)(DrdClientobj
*))(DRD_(cond_cleanup
));
74 * Free the memory that was allocated by cond_initialize(). Called by
75 * DRD_(clientobj_remove)().
77 static void DRD_(cond_cleanup
)(struct cond_info
* p
)
83 q
= &(DRD_(clientobj_get
)(p
->mutex
, ClientMutex
)->mutex
);
85 CondDestrErrInfo cde
= {
86 DRD_(thread_get_running_tid
)(),
89 q
? q
->owner
: DRD_INVALID_THREADID
91 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
93 VG_(get_IP
)(VG_(get_running_tid
)()),
94 "Destroying condition variable that is being"
102 * Report that the synchronization object at address 'addr' is of the
105 static void wrong_type(const Addr addr
)
107 GenericErrInfo gei
= {
108 .tid
= DRD_(thread_get_running_tid
)(),
111 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
113 VG_(get_IP
)(VG_(get_running_tid
)()),
114 "wrong type of synchronization object",
118 static struct cond_info
* cond_get_or_allocate(const Addr cond
)
122 tl_assert(offsetof(DrdClientobj
, cond
) == 0);
123 p
= &(DRD_(clientobj_get
)(cond
, ClientCondvar
)->cond
);
127 if (DRD_(clientobj_present
)(cond
, cond
+ 1))
133 p
= &(DRD_(clientobj_add
)(cond
, ClientCondvar
)->cond
);
134 DRD_(cond_initialize
)(p
, cond
);
138 struct cond_info
* DRD_(cond_get
)(const Addr cond
)
140 tl_assert(offsetof(DrdClientobj
, cond
) == 0);
141 return &(DRD_(clientobj_get
)(cond
, ClientCondvar
)->cond
);
144 /** Called before pthread_cond_init(). */
145 void DRD_(cond_pre_init
)(const Addr cond
)
149 if (DRD_(s_trace_cond
))
150 DRD_(trace_msg
)("[%u] cond_init cond 0x%lx",
151 DRD_(thread_get_running_tid
)(), cond
);
153 p
= DRD_(cond_get
)(cond
);
156 CondErrInfo cei
= { .tid
= DRD_(thread_get_running_tid
)(), .cond
= cond
};
157 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
159 VG_(get_IP
)(VG_(get_running_tid
)()),
164 cond_get_or_allocate(cond
);
167 /** Called after pthread_cond_destroy(). */
168 void DRD_(cond_post_destroy
)(const Addr cond
, const Bool destroy_succeeded
)
172 if (DRD_(s_trace_cond
))
173 DRD_(trace_msg
)("[%u] cond_destroy cond 0x%lx",
174 DRD_(thread_get_running_tid
)(), cond
);
176 p
= DRD_(cond_get
)(cond
);
179 CondErrInfo cei
= { .tid
= DRD_(thread_get_running_tid
)(), .cond
= cond
};
180 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
182 VG_(get_IP
)(VG_(get_running_tid
)()),
183 "not a condition variable",
188 if (p
->waiter_count
!= 0)
190 CondErrInfo cei
= { .tid
= DRD_(thread_get_running_tid
)(), .cond
= cond
};
191 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
193 VG_(get_IP
)(VG_(get_running_tid
)()),
194 "destruction of condition variable being waited"
199 if (destroy_succeeded
)
200 DRD_(clientobj_remove
)(p
->a1
, ClientCondvar
);
204 * Called before pthread_cond_wait(). Note: before this function is called,
205 * mutex_unlock() has already been called from drd_clientreq.c.
207 void DRD_(cond_pre_wait
)(const Addr cond
, const Addr mutex
)
210 struct mutex_info
* q
;
212 if (DRD_(s_trace_cond
))
213 DRD_(trace_msg
)("[%u] cond_pre_wait cond 0x%lx",
214 DRD_(thread_get_running_tid
)(), cond
);
216 p
= cond_get_or_allocate(cond
);
219 CondErrInfo cei
= { .tid
= DRD_(thread_get_running_tid
)(), .cond
= cond
};
220 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
222 VG_(get_IP
)(VG_(get_running_tid
)()),
223 "not a condition variable",
228 if (p
->waiter_count
== 0)
232 else if (p
->mutex
!= mutex
)
235 = { .tid
= DRD_(thread_get_running_tid
)(),
236 .cond
= cond
, .mutex1
= p
->mutex
, .mutex2
= mutex
};
237 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
239 VG_(get_IP
)(VG_(get_running_tid
)()),
240 "Inconsistent association of condition variable"
245 q
= DRD_(mutex_get
)(p
->mutex
);
247 && q
->owner
== DRD_(thread_get_running_tid
)() && q
->recursion_count
> 0)
249 const ThreadId vg_tid
= VG_(get_running_tid
)();
250 MutexErrInfo MEI
= { DRD_(thread_get_running_tid
)(),
251 q
->a1
, q
->recursion_count
, q
->owner
};
252 VG_(maybe_record_error
)(vg_tid
,
255 "Mutex locked recursively",
260 DRD_(not_a_mutex
)(p
->mutex
);
267 * Called after pthread_cond_wait().
269 void DRD_(cond_post_wait
)(const Addr cond
)
273 if (DRD_(s_trace_cond
))
274 DRD_(trace_msg
)("[%u] cond_post_wait cond 0x%lx",
275 DRD_(thread_get_running_tid
)(), cond
);
277 p
= DRD_(cond_get
)(cond
);
280 CondDestrErrInfo cde
= {
281 DRD_(thread_get_running_tid
)(), cond
, 0, DRD_INVALID_THREADID
283 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
285 VG_(get_IP
)(VG_(get_running_tid
)()),
286 "condition variable has been destroyed while"
287 " being waited upon",
292 if (p
->waiter_count
> 0)
295 if (p
->waiter_count
== 0)
302 static void cond_signal(const DrdThreadId tid
, struct cond_info
* const cond_p
)
304 const ThreadId vg_tid
= VG_(get_running_tid
)();
305 const DrdThreadId drd_tid
= DRD_(VgThreadIdToDrdThreadId
)(vg_tid
);
309 if (cond_p
->waiter_count
> 0)
311 if (DRD_(s_report_signal_unlocked
)
312 && ! DRD_(mutex_is_locked_by
)(cond_p
->mutex
, drd_tid
))
315 * A signal is sent while the associated mutex has not been locked.
316 * This can indicate but is not necessarily a race condition.
318 CondRaceErrInfo cei
= { .tid
= DRD_(thread_get_running_tid
)(),
320 .mutex
= cond_p
->mutex
,
322 VG_(maybe_record_error
)(vg_tid
,
332 * No other thread is waiting for the signal, hence the signal will
333 * be lost. This is normal in a POSIX threads application.
338 static void not_initialized(Addr
const cond
)
340 CondErrInfo cei
= { .tid
= DRD_(thread_get_running_tid
)(), .cond
= cond
};
341 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
343 VG_(get_IP
)(VG_(get_running_tid
)()),
344 "condition variable has not been initialized",
348 /** Called before pthread_cond_signal(). */
349 void DRD_(cond_pre_signal
)(Addr
const cond
)
353 p
= DRD_(cond_get
)(cond
);
354 if (DRD_(s_trace_cond
))
355 DRD_(trace_msg
)("[%u] cond_signal cond 0x%lx",
356 DRD_(thread_get_running_tid
)(), cond
);
358 tl_assert(DRD_(pthread_cond_initializer
));
359 if (!p
&& VG_(memcmp
)((void*)cond
, (void*)DRD_(pthread_cond_initializer
),
360 DRD_(pthread_cond_initializer_size
)) != 0)
362 not_initialized(cond
);
367 p
= cond_get_or_allocate(cond
);
369 cond_signal(DRD_(thread_get_running_tid
)(), p
);
372 /** Called before pthread_cond_broadcast(). */
373 void DRD_(cond_pre_broadcast
)(Addr
const cond
)
377 if (DRD_(s_trace_cond
))
378 DRD_(trace_msg
)("[%u] cond_broadcast cond 0x%lx",
379 DRD_(thread_get_running_tid
)(), cond
);
381 p
= DRD_(cond_get
)(cond
);
382 tl_assert(DRD_(pthread_cond_initializer
));
383 if (!p
&& VG_(memcmp
)((void*)cond
, (void*)DRD_(pthread_cond_initializer
),
384 DRD_(pthread_cond_initializer_size
)) != 0)
386 not_initialized(cond
);
391 p
= cond_get_or_allocate(cond
);
393 cond_signal(DRD_(thread_get_running_tid
)(), p
);