blob: da99d06294a8d21fb7800346527941952fd24996 [file] [log] [blame]
sewardj85642922008-01-14 11:54:56 +00001/*
bart86562bd2009-02-16 19:43:56 +00002 This file is part of drd, a thread error detector.
sewardj85642922008-01-14 11:54:56 +00003
bart86562bd2009-02-16 19:43:56 +00004 Copyright (C) 2006-2009 Bart Van Assche <bart.vanassche@gmail.com>.
sewardj85642922008-01-14 11:54:56 +00005
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.
10
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.
15
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
19 02111-1307, USA.
20
21 The GNU General Public License is contained in the file COPYING.
22*/
23
24
bart28230a32008-02-29 17:27:03 +000025#include "drd_clientobj.h"
sewardj85642922008-01-14 11:54:56 +000026#include "drd_error.h"
27#include "drd_semaphore.h"
28#include "drd_suppression.h"
sewardj85642922008-01-14 11:54:56 +000029#include "pub_tool_errormgr.h" // VG_(maybe_record_error)()
30#include "pub_tool_libcassert.h" // tl_assert()
31#include "pub_tool_libcprint.h" // VG_(printf)()
32#include "pub_tool_machine.h" // VG_(get_IP)()
bart3e017fa2008-12-17 19:20:13 +000033#include "pub_tool_mallocfree.h" // VG_(malloc), VG_(free)
sewardj85642922008-01-14 11:54:56 +000034#include "pub_tool_threadstate.h" // VG_(get_running_tid)()
35
36
bartdc1ef032009-02-15 14:18:02 +000037/* Local functions. */
sewardj85642922008-01-14 11:54:56 +000038
bartdc1ef032009-02-15 14:18:02 +000039static void DRD_(semaphore_cleanup)(struct semaphore_info* p);
sewardj85642922008-01-14 11:54:56 +000040
41
bartdc1ef032009-02-15 14:18:02 +000042/* Local variables. */
sewardj85642922008-01-14 11:54:56 +000043
bartdc1ef032009-02-15 14:18:02 +000044static Bool DRD_(s_trace_semaphore);
45static ULong DRD_(s_semaphore_segment_creation_count);
sewardj85642922008-01-14 11:54:56 +000046
47
bartdc1ef032009-02-15 14:18:02 +000048/* Function definitions. */
sewardj85642922008-01-14 11:54:56 +000049
bartdc1ef032009-02-15 14:18:02 +000050/** Push a segment at the end of the queue 'p->last_sem_post_seg'. */
51static void DRD_(segment_push)(struct semaphore_info* p, Segment* sg)
bart3e017fa2008-12-17 19:20:13 +000052{
53 Word n;
54
55 tl_assert(sg);
56 n = VG_(addToXA)(p->last_sem_post_seg, &sg);
57#if 0
58 VG_(message)(Vg_UserMsg, "0x%lx push: added at position %ld/%ld",
59 p->a1, n, VG_(sizeXA)(p->last_sem_post_seg));
60#endif
61 tl_assert(*(Segment**)VG_(indexXA)(p->last_sem_post_seg, n) == sg);
62}
63
bartdc1ef032009-02-15 14:18:02 +000064/** Pop a segment from the beginning of the queue 'p->last_sem_post_seg'. */
65static Segment* DRD_(segment_pop)(struct semaphore_info* p)
bart3e017fa2008-12-17 19:20:13 +000066{
67 Word sz;
68 Segment* sg;
69
70 sz = VG_(sizeXA)(p->last_sem_post_seg);
71#if 0
72 VG_(message)(Vg_UserMsg, "0x%lx pop: removed from position %ld/%ld",
73 p->a1, sz - 1, sz);
74#endif
75 sg = 0;
76 if (sz > 0)
77 {
78 sg = *(Segment**)VG_(indexXA)(p->last_sem_post_seg, sz - 1);
79 tl_assert(sg);
80 VG_(dropTailXA)(p->last_sem_post_seg, 1);
81 }
82 return sg;
83}
84
bartdc1ef032009-02-15 14:18:02 +000085/** Enable or disable tracing of semaphore actions. */
86void DRD_(semaphore_set_trace)(const Bool trace_semaphore)
sewardj85642922008-01-14 11:54:56 +000087{
bartdc1ef032009-02-15 14:18:02 +000088 DRD_(s_trace_semaphore) = trace_semaphore;
sewardj85642922008-01-14 11:54:56 +000089}
90
bartdc1ef032009-02-15 14:18:02 +000091/**
92 * Initialize the memory 'p' points at as a semaphore_info structure for the
93 * client semaphore at client addres 'semaphore'.
94 */
sewardj85642922008-01-14 11:54:56 +000095static
bartdc1ef032009-02-15 14:18:02 +000096void DRD_(semaphore_initialize)(struct semaphore_info* const p,
97 const Addr semaphore)
sewardj85642922008-01-14 11:54:56 +000098{
99 tl_assert(semaphore != 0);
bart28230a32008-02-29 17:27:03 +0000100 tl_assert(p->a1 == semaphore);
bart28230a32008-02-29 17:27:03 +0000101 tl_assert(p->type == ClientSemaphore);
sewardj85642922008-01-14 11:54:56 +0000102
bartdc1ef032009-02-15 14:18:02 +0000103 p->cleanup = (void(*)(DrdClientobj*))(DRD_(semaphore_cleanup));
bartc8914e92008-12-24 09:45:41 +0000104 p->waits_to_skip = 0;
bart94866cc2008-12-21 17:20:22 +0000105 p->value = 0;
106 p->waiters = 0;
sewardj85642922008-01-14 11:54:56 +0000107 p->last_sem_post_tid = DRD_INVALID_THREADID;
bart3e017fa2008-12-17 19:20:13 +0000108 p->last_sem_post_seg = VG_(newXA)(VG_(malloc), "drd.sg-stack",
109 VG_(free), sizeof(Segment*));
sewardj85642922008-01-14 11:54:56 +0000110}
111
bart195e41f2009-02-15 11:34:57 +0000112/**
113 * Free the memory that was allocated by semaphore_initialize(). Called by
114 * DRD_(clientobj_remove)().
bart28230a32008-02-29 17:27:03 +0000115 */
bartdc1ef032009-02-15 14:18:02 +0000116static void DRD_(semaphore_cleanup)(struct semaphore_info* p)
bart28230a32008-02-29 17:27:03 +0000117{
bart3e017fa2008-12-17 19:20:13 +0000118 Segment* sg;
119
bart28230a32008-02-29 17:27:03 +0000120 if (p->waiters > 0)
121 {
bart3b1ee452008-02-29 19:28:15 +0000122 SemaphoreErrInfo sei = { p->a1 };
123 VG_(maybe_record_error)(VG_(get_running_tid)(),
124 SemaphoreErr,
125 VG_(get_IP)(VG_(get_running_tid)()),
126 "Destruction of semaphore that is being waited"
127 " upon",
128 &sei);
bart28230a32008-02-29 17:27:03 +0000129 }
bartdc1ef032009-02-15 14:18:02 +0000130 while ((sg = DRD_(segment_pop)(p)))
bart62ada3f2009-02-14 17:19:58 +0000131 DRD_(sg_put)(sg);
bart3e017fa2008-12-17 19:20:13 +0000132 VG_(deleteXA)(p->last_sem_post_seg);
bart28230a32008-02-29 17:27:03 +0000133}
134
bartdc1ef032009-02-15 14:18:02 +0000135/**
136 * Return a pointer to the structure with information about the specified
137 * client semaphore. Allocate a new structure if such a structure did not
138 * yet exist.
139 */
sewardj85642922008-01-14 11:54:56 +0000140static
141struct semaphore_info*
bartdc1ef032009-02-15 14:18:02 +0000142DRD_(semaphore_get_or_allocate)(const Addr semaphore)
sewardj85642922008-01-14 11:54:56 +0000143{
bart28230a32008-02-29 17:27:03 +0000144 struct semaphore_info *p;
sewardj85642922008-01-14 11:54:56 +0000145
bart28230a32008-02-29 17:27:03 +0000146 tl_assert(offsetof(DrdClientobj, semaphore) == 0);
bart195e41f2009-02-15 11:34:57 +0000147 p = &(DRD_(clientobj_get)(semaphore, ClientSemaphore)->semaphore);
bart28230a32008-02-29 17:27:03 +0000148 if (p == 0)
sewardj85642922008-01-14 11:54:56 +0000149 {
bart28230a32008-02-29 17:27:03 +0000150 tl_assert(offsetof(DrdClientobj, semaphore) == 0);
bart195e41f2009-02-15 11:34:57 +0000151 p = &(DRD_(clientobj_add)(semaphore, ClientSemaphore)->semaphore);
bartdc1ef032009-02-15 14:18:02 +0000152 DRD_(semaphore_initialize)(p, semaphore);
sewardj85642922008-01-14 11:54:56 +0000153 }
bart28230a32008-02-29 17:27:03 +0000154 return p;
sewardj85642922008-01-14 11:54:56 +0000155}
156
bartdc1ef032009-02-15 14:18:02 +0000157/**
158 * Return a pointer to the structure with information about the specified
159 * client semaphore, or null if no such structure was found.
160 */
161static struct semaphore_info* DRD_(semaphore_get)(const Addr semaphore)
bart28230a32008-02-29 17:27:03 +0000162{
163 tl_assert(offsetof(DrdClientobj, semaphore) == 0);
bart195e41f2009-02-15 11:34:57 +0000164 return &(DRD_(clientobj_get)(semaphore, ClientSemaphore)->semaphore);
bart28230a32008-02-29 17:27:03 +0000165}
166
167/** Called before sem_init(). */
bartdc1ef032009-02-15 14:18:02 +0000168struct semaphore_info* DRD_(semaphore_init)(const Addr semaphore,
169 const Word pshared,
170 const UInt value)
sewardj85642922008-01-14 11:54:56 +0000171{
172 struct semaphore_info* p;
bart94866cc2008-12-21 17:20:22 +0000173 Segment* sg;
sewardj85642922008-01-14 11:54:56 +0000174
bartdc1ef032009-02-15 14:18:02 +0000175 if (DRD_(s_trace_semaphore))
bart3b1ee452008-02-29 19:28:15 +0000176 {
177 VG_(message)(Vg_UserMsg,
bartafb42b72008-12-17 07:32:09 +0000178 "[%d/%d] semaphore_init 0x%lx value %u",
bart3b1ee452008-02-29 19:28:15 +0000179 VG_(get_running_tid)(),
bart62a784c2009-02-15 13:11:14 +0000180 DRD_(thread_get_running_tid)(),
bartda9436b2008-12-14 08:56:49 +0000181 semaphore,
182 value);
bart3b1ee452008-02-29 19:28:15 +0000183 }
bartdc1ef032009-02-15 14:18:02 +0000184 p = DRD_(semaphore_get)(semaphore);
bartd9e39ec2008-06-28 15:03:26 +0000185 if (p)
bart0268dfa2008-03-11 20:10:21 +0000186 {
bartd9e39ec2008-06-28 15:03:26 +0000187 const ThreadId vg_tid = VG_(get_running_tid)();
188 SemaphoreErrInfo SEI = { semaphore };
189 VG_(maybe_record_error)(vg_tid,
190 SemaphoreErr,
191 VG_(get_IP)(vg_tid),
192 "Semaphore reinitialization",
193 &SEI);
bart94866cc2008-12-21 17:20:22 +0000194 // Remove all segments from the segment stack.
bartdc1ef032009-02-15 14:18:02 +0000195 while ((sg = DRD_(segment_pop)(p)))
bart94866cc2008-12-21 17:20:22 +0000196 {
bart62ada3f2009-02-14 17:19:58 +0000197 DRD_(sg_put)(sg);
bart94866cc2008-12-21 17:20:22 +0000198 }
bart0268dfa2008-03-11 20:10:21 +0000199 }
bartd9e39ec2008-06-28 15:03:26 +0000200 else
201 {
bartdc1ef032009-02-15 14:18:02 +0000202 p = DRD_(semaphore_get_or_allocate)(semaphore);
bartd9e39ec2008-06-28 15:03:26 +0000203 }
204 tl_assert(p);
bartc8914e92008-12-24 09:45:41 +0000205 p->waits_to_skip = value;
bart94866cc2008-12-21 17:20:22 +0000206 p->value = value;
sewardj85642922008-01-14 11:54:56 +0000207 return p;
208}
209
bart28230a32008-02-29 17:27:03 +0000210/** Called after sem_destroy(). */
bartdc1ef032009-02-15 14:18:02 +0000211void DRD_(semaphore_destroy)(const Addr semaphore)
sewardj85642922008-01-14 11:54:56 +0000212{
bart72b751c2008-03-01 13:44:24 +0000213 struct semaphore_info* p;
bart3b1ee452008-02-29 19:28:15 +0000214
bartdc1ef032009-02-15 14:18:02 +0000215 p = DRD_(semaphore_get)(semaphore);
bartda9436b2008-12-14 08:56:49 +0000216
bartdc1ef032009-02-15 14:18:02 +0000217 if (DRD_(s_trace_semaphore))
bart3b1ee452008-02-29 19:28:15 +0000218 {
219 VG_(message)(Vg_UserMsg,
bartafb42b72008-12-17 07:32:09 +0000220 "[%d/%d] semaphore_destroy 0x%lx value %u",
bart3b1ee452008-02-29 19:28:15 +0000221 VG_(get_running_tid)(),
bart62a784c2009-02-15 13:11:14 +0000222 DRD_(thread_get_running_tid)(),
bartda9436b2008-12-14 08:56:49 +0000223 semaphore,
224 p ? p->value : 0);
bart3b1ee452008-02-29 19:28:15 +0000225 }
226
bart72b751c2008-03-01 13:44:24 +0000227 if (p == 0)
228 {
229 GenericErrInfo GEI;
230 VG_(maybe_record_error)(VG_(get_running_tid)(),
231 GenericErr,
232 VG_(get_IP)(VG_(get_running_tid)()),
233 "Not a semaphore",
234 &GEI);
235 return;
236 }
237
bart195e41f2009-02-15 11:34:57 +0000238 DRD_(clientobj_remove)(semaphore, ClientSemaphore);
sewardj85642922008-01-14 11:54:56 +0000239}
240
bart28230a32008-02-29 17:27:03 +0000241/** Called before sem_wait(). */
bartdc1ef032009-02-15 14:18:02 +0000242void DRD_(semaphore_pre_wait)(const Addr semaphore)
sewardj85642922008-01-14 11:54:56 +0000243{
244 struct semaphore_info* p;
245
bartdc1ef032009-02-15 14:18:02 +0000246 p = DRD_(semaphore_get_or_allocate)(semaphore);
bart28230a32008-02-29 17:27:03 +0000247 tl_assert(p);
bart74a5f212008-05-11 06:43:07 +0000248 tl_assert((int)p->waiters >= 0);
bart28230a32008-02-29 17:27:03 +0000249 p->waiters++;
250 tl_assert(p->waiters > 0);
251}
252
bartdc1ef032009-02-15 14:18:02 +0000253/**
254 * Called after sem_wait() finished.
255 * @note Do not rely on the value of 'waited' -- some glibc versions do
256 * not set it correctly.
bart28230a32008-02-29 17:27:03 +0000257 */
bartdc1ef032009-02-15 14:18:02 +0000258void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore,
259 const Bool waited)
bart28230a32008-02-29 17:27:03 +0000260{
261 struct semaphore_info* p;
bart3e017fa2008-12-17 19:20:13 +0000262 Segment* sg;
bart28230a32008-02-29 17:27:03 +0000263
bartdc1ef032009-02-15 14:18:02 +0000264 p = DRD_(semaphore_get)(semaphore);
265 if (DRD_(s_trace_semaphore))
bart28230a32008-02-29 17:27:03 +0000266 {
bart3b1ee452008-02-29 19:28:15 +0000267 VG_(message)(Vg_UserMsg,
bart3e017fa2008-12-17 19:20:13 +0000268 "[%d/%d] semaphore_wait 0x%lx value %u -> %u",
bart3b1ee452008-02-29 19:28:15 +0000269 VG_(get_running_tid)(),
bart62a784c2009-02-15 13:11:14 +0000270 DRD_(thread_get_running_tid)(),
bartda9436b2008-12-14 08:56:49 +0000271 semaphore,
bart3e017fa2008-12-17 19:20:13 +0000272 p ? p->value : 0,
bartda9436b2008-12-14 08:56:49 +0000273 p ? p->value - 1 : 0);
bart28230a32008-02-29 17:27:03 +0000274 }
bart3e017fa2008-12-17 19:20:13 +0000275 tl_assert(p);
bart28230a32008-02-29 17:27:03 +0000276 tl_assert(p->waiters > 0);
277 p->waiters--;
bart74a5f212008-05-11 06:43:07 +0000278 tl_assert((int)p->waiters >= 0);
279 tl_assert((int)p->value >= 0);
bart28230a32008-02-29 17:27:03 +0000280 if (p->value == 0)
281 {
bart3b1ee452008-02-29 19:28:15 +0000282 SemaphoreErrInfo sei = { semaphore };
283 VG_(maybe_record_error)(VG_(get_running_tid)(),
284 SemaphoreErr,
285 VG_(get_IP)(VG_(get_running_tid)()),
286 "Invalid semaphore",
287 &sei);
bart28230a32008-02-29 17:27:03 +0000288 return;
289 }
sewardj85642922008-01-14 11:54:56 +0000290 p->value--;
bart74a5f212008-05-11 06:43:07 +0000291 tl_assert((int)p->value >= 0);
bartc8914e92008-12-24 09:45:41 +0000292 if (p->waits_to_skip > 0)
293 p->waits_to_skip--;
bart94866cc2008-12-21 17:20:22 +0000294 else
barta2b6e1b2008-03-17 18:32:39 +0000295 {
bartdc1ef032009-02-15 14:18:02 +0000296 sg = DRD_(segment_pop)(p);
bart94866cc2008-12-21 17:20:22 +0000297 tl_assert(sg);
298 if (sg)
bart3e017fa2008-12-17 19:20:13 +0000299 {
bart94866cc2008-12-21 17:20:22 +0000300 if (p->last_sem_post_tid != tid
301 && p->last_sem_post_tid != DRD_INVALID_THREADID)
302 {
bart62a784c2009-02-15 13:11:14 +0000303 DRD_(thread_combine_vc2)(tid, &sg->vc);
bart94866cc2008-12-21 17:20:22 +0000304 }
bart62ada3f2009-02-14 17:19:58 +0000305 DRD_(sg_put)(sg);
bart62a784c2009-02-15 13:11:14 +0000306 DRD_(thread_new_segment)(tid);
bartdc1ef032009-02-15 14:18:02 +0000307 DRD_(s_semaphore_segment_creation_count)++;
bart3e017fa2008-12-17 19:20:13 +0000308 }
barta2b6e1b2008-03-17 18:32:39 +0000309 }
sewardj85642922008-01-14 11:54:56 +0000310}
311
312/** Called before sem_post(). */
bartdc1ef032009-02-15 14:18:02 +0000313void DRD_(semaphore_pre_post)(const DrdThreadId tid, const Addr semaphore)
sewardj85642922008-01-14 11:54:56 +0000314{
315 struct semaphore_info* p;
bart3e017fa2008-12-17 19:20:13 +0000316 Segment* sg;
sewardj85642922008-01-14 11:54:56 +0000317
bartdc1ef032009-02-15 14:18:02 +0000318 p = DRD_(semaphore_get_or_allocate)(semaphore);
bartda9436b2008-12-14 08:56:49 +0000319 p->value++;
320
bartdc1ef032009-02-15 14:18:02 +0000321 if (DRD_(s_trace_semaphore))
bart3b1ee452008-02-29 19:28:15 +0000322 {
323 VG_(message)(Vg_UserMsg,
bart3e017fa2008-12-17 19:20:13 +0000324 "[%d/%d] semaphore_post 0x%lx value %u -> %u",
bart3b1ee452008-02-29 19:28:15 +0000325 VG_(get_running_tid)(),
bart62a784c2009-02-15 13:11:14 +0000326 DRD_(thread_get_running_tid)(),
bartda9436b2008-12-14 08:56:49 +0000327 semaphore,
bart3e017fa2008-12-17 19:20:13 +0000328 p->value - 1, p->value);
bart3b1ee452008-02-29 19:28:15 +0000329 }
bartda9436b2008-12-14 08:56:49 +0000330
bart3e017fa2008-12-17 19:20:13 +0000331 p->last_sem_post_tid = tid;
bart62a784c2009-02-15 13:11:14 +0000332 DRD_(thread_new_segment)(tid);
bart3e017fa2008-12-17 19:20:13 +0000333 sg = 0;
bart62a784c2009-02-15 13:11:14 +0000334 DRD_(thread_get_latest_segment)(&sg, tid);
bart3e017fa2008-12-17 19:20:13 +0000335 tl_assert(sg);
bartdc1ef032009-02-15 14:18:02 +0000336 DRD_(segment_push)(p, sg);
337 DRD_(s_semaphore_segment_creation_count)++;
sewardj85642922008-01-14 11:54:56 +0000338}
339
340/** Called after sem_post() finished successfully. */
bartdc1ef032009-02-15 14:18:02 +0000341void DRD_(semaphore_post_post)(const DrdThreadId tid, const Addr semaphore,
342 const Bool waited)
sewardj85642922008-01-14 11:54:56 +0000343{
bart25896d92008-02-17 09:21:05 +0000344 /* Note: it is hard to implement the sem_post() wrapper correctly in */
345 /* case sem_post() returns an error code. This is because handling this */
346 /* case correctly requires restoring the vector clock associated with */
347 /* the semaphore to its original value here. In order to do that without */
348 /* introducing a race condition, extra locking has to be added around */
349 /* each semaphore call. Such extra locking would have to be added in */
350 /* drd_intercepts.c. However, it is hard to implement synchronization */
351 /* in drd_intercepts.c in a portable way without calling already */
352 /* redirected functions. */
sewardj85642922008-01-14 11:54:56 +0000353}
354
bartdc1ef032009-02-15 14:18:02 +0000355void DRD_(semaphore_thread_delete)(const DrdThreadId threadid)
sewardj85642922008-01-14 11:54:56 +0000356{ }
bart6bbefaf2008-04-19 15:16:45 +0000357
bartdc1ef032009-02-15 14:18:02 +0000358ULong DRD_(get_semaphore_segment_creation_count)(void)
bart6bbefaf2008-04-19 15:16:45 +0000359{
bartdc1ef032009-02-15 14:18:02 +0000360 return DRD_(s_semaphore_segment_creation_count);
bart6bbefaf2008-04-19 15:16:45 +0000361}