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"
26 #include "drd_error.h"
27 #include "drd_semaphore.h"
28 #include "drd_suppression.h"
29 #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)()
33 #include "pub_tool_mallocfree.h" // VG_(malloc), VG_(free)
34 #include "pub_tool_threadstate.h" // VG_(get_running_tid)()
37 /* Local functions. */
39 static void semaphore_cleanup(struct semaphore_info
* p
);
42 /* Local variables. */
44 static Bool s_trace_semaphore
;
45 static ULong s_semaphore_segment_creation_count
;
48 /* Function definitions. */
50 /** Push a segment at the end of the queue 'p->last_sem_post_seg'. */
51 static void drd_segment_push(struct semaphore_info
* p
, Segment
* sg
)
56 n
= VG_(addToXA
)(p
->last_sem_post_seg
, &sg
);
58 VG_(message
)(Vg_DebugMsg
, "0x%lx push: added at position %ld/%ld\n",
59 p
->a1
, n
, VG_(sizeXA
)(p
->last_sem_post_seg
));
61 tl_assert(*(Segment
**)VG_(indexXA
)(p
->last_sem_post_seg
, n
) == sg
);
64 /** Pop a segment from the beginning of the queue 'p->last_sem_post_seg'. */
65 static Segment
* drd_segment_pop(struct semaphore_info
* p
)
70 sz
= VG_(sizeXA
)(p
->last_sem_post_seg
);
72 VG_(message
)(Vg_DebugMsg
, "0x%lx pop: removed from position %ld/%ld\n",
78 sg
= *(Segment
**)VG_(indexXA
)(p
->last_sem_post_seg
, sz
- 1);
80 VG_(dropTailXA
)(p
->last_sem_post_seg
, 1);
85 /** Enable or disable tracing of semaphore actions. */
86 void DRD_(semaphore_set_trace
)(const Bool trace_semaphore
)
88 s_trace_semaphore
= trace_semaphore
;
92 * Initialize the memory 'p' points at as a semaphore_info structure for the
93 * client semaphore at client address 'semaphore'.
96 void drd_semaphore_initialize(struct semaphore_info
* const p
,
99 tl_assert(semaphore
!= 0);
100 tl_assert(p
->a1
== semaphore
);
101 tl_assert(p
->type
== ClientSemaphore
);
103 p
->cleanup
= (void(*)(DrdClientobj
*))semaphore_cleanup
;
104 p
->delete_thread
= 0;
105 p
->waits_to_skip
= 0;
108 p
->last_sem_post_tid
= DRD_INVALID_THREADID
;
109 p
->last_sem_post_seg
= VG_(newXA
)(VG_(malloc
), "drd.sg-stack",
110 VG_(free
), sizeof(Segment
*));
114 * Free the memory that was allocated by semaphore_initialize(). Called by
115 * DRD_(clientobj_remove)().
117 static void semaphore_cleanup(struct semaphore_info
* p
)
123 SemaphoreErrInfo sei
= { DRD_(thread_get_running_tid
)(), p
->a1
};
124 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
126 VG_(get_IP
)(VG_(get_running_tid
)()),
127 "Destruction of semaphore that is being waited"
131 while ((sg
= drd_segment_pop(p
)))
133 VG_(deleteXA
)(p
->last_sem_post_seg
);
137 * Return a pointer to the structure with information about the specified
138 * client semaphore. Allocate a new structure if such a structure did not
142 struct semaphore_info
*
143 drd_semaphore_get_or_allocate(const Addr semaphore
)
145 struct semaphore_info
*p
;
147 tl_assert(offsetof(DrdClientobj
, semaphore
) == 0);
148 p
= &(DRD_(clientobj_get
)(semaphore
, ClientSemaphore
)->semaphore
);
151 tl_assert(offsetof(DrdClientobj
, semaphore
) == 0);
152 p
= &(DRD_(clientobj_add
)(semaphore
, ClientSemaphore
)->semaphore
);
153 drd_semaphore_initialize(p
, semaphore
);
159 * Return a pointer to the structure with information about the specified
160 * client semaphore, or null if no such structure was found.
162 static struct semaphore_info
* semaphore_get(const Addr semaphore
)
164 tl_assert(offsetof(DrdClientobj
, semaphore
) == 0);
165 return &(DRD_(clientobj_get
)(semaphore
, ClientSemaphore
)->semaphore
);
168 /** Called before sem_init(). */
169 struct semaphore_info
* DRD_(semaphore_init
)(const Addr semaphore
,
173 struct semaphore_info
* p
;
176 if (s_trace_semaphore
)
177 DRD_(trace_msg
)("[%u] sem_init 0x%lx value %u",
178 DRD_(thread_get_running_tid
)(), semaphore
, value
);
180 p
= semaphore_get(semaphore
);
183 const ThreadId vg_tid
= VG_(get_running_tid
)();
184 SemaphoreErrInfo SEI
= { DRD_(thread_get_running_tid
)(), semaphore
};
185 VG_(maybe_record_error
)(vg_tid
,
188 "Semaphore reinitialization",
190 // Remove all segments from the segment stack.
191 while ((sg
= drd_segment_pop(p
)))
198 #if defined(VGO_darwin)
199 const ThreadId vg_tid
= VG_(get_running_tid
)();
200 GenericErrInfo GEI
= { DRD_(thread_get_running_tid
)(), 0 };
201 VG_(maybe_record_error
)(vg_tid
,
204 "sem_init() is not yet supported on Darwin",
208 p
= drd_semaphore_get_or_allocate(semaphore
);
212 p
->waits_to_skip
= value
;
217 /** Called after sem_destroy(). */
218 void DRD_(semaphore_destroy
)(const Addr semaphore
)
220 struct semaphore_info
* p
;
222 p
= semaphore_get(semaphore
);
224 if (s_trace_semaphore
)
225 DRD_(trace_msg
)("[%u] sem_destroy 0x%lx value %u",
226 DRD_(thread_get_running_tid
)(), semaphore
,
231 GenericErrInfo GEI
= {
232 .tid
= DRD_(thread_get_running_tid
)(),
235 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
237 VG_(get_IP
)(VG_(get_running_tid
)()),
243 DRD_(clientobj_remove
)(semaphore
, ClientSemaphore
);
246 /** Called after sem_open(). */
247 struct semaphore_info
* DRD_(semaphore_open
)(const Addr semaphore
,
248 const HChar
* name
, const Word oflag
,
249 const Word mode
, const UInt value
)
251 struct semaphore_info
* p
;
254 if (s_trace_semaphore
)
255 DRD_(trace_msg
)("[%u] sem_open 0x%lx name %s"
256 " oflag %#lx mode %#lo value %u",
257 DRD_(thread_get_running_tid
)(),
258 semaphore
, name
, (UWord
)oflag
, (UWord
)mode
, value
);
260 /* Return if the sem_open() call failed. */
264 p
= semaphore_get(semaphore
);
267 const ThreadId vg_tid
= VG_(get_running_tid
)();
268 SemaphoreErrInfo SEI
= { DRD_(thread_get_running_tid
)(), semaphore
};
269 VG_(maybe_record_error
)(vg_tid
,
272 "Semaphore reinitialization",
274 // Remove all segments from the segment stack.
275 while ((sg
= drd_segment_pop(p
)))
282 p
= drd_semaphore_get_or_allocate(semaphore
);
285 p
->waits_to_skip
= value
;
290 /** Called before sem_close(). */
291 void DRD_(semaphore_close
)(const Addr semaphore
)
293 struct semaphore_info
* p
;
295 p
= semaphore_get(semaphore
);
297 if (s_trace_semaphore
)
298 DRD_(trace_msg
)("[%u] sem_close 0x%lx value %u",
299 DRD_(thread_get_running_tid
)(), semaphore
,
304 GenericErrInfo GEI
= {
305 .tid
= DRD_(thread_get_running_tid
)(),
308 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
310 VG_(get_IP
)(VG_(get_running_tid
)()),
316 DRD_(clientobj_remove
)(semaphore
, ClientSemaphore
);
319 /** Called before sem_wait(). */
320 void DRD_(semaphore_pre_wait
)(const Addr semaphore
)
322 struct semaphore_info
* p
;
324 tl_assert(semaphore
< semaphore
+ 1);
325 p
= drd_semaphore_get_or_allocate(semaphore
);
329 if ((Word
)(p
->waiters
) <= 0)
331 SemaphoreErrInfo sei
= { DRD_(thread_get_running_tid
)(), semaphore
};
332 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
334 VG_(get_IP
)(VG_(get_running_tid
)()),
341 * Called after sem_wait() finished.
342 * @note Some C libraries do not set the 'waited' value correctly.
344 void DRD_(semaphore_post_wait
)(const DrdThreadId tid
, const Addr semaphore
,
347 struct semaphore_info
* p
;
350 tl_assert(waited
== 0 || waited
== 1);
351 p
= semaphore_get(semaphore
);
352 if (s_trace_semaphore
)
353 DRD_(trace_msg
)("[%u] sem_wait 0x%lx value %u -> %u%s",
354 DRD_(thread_get_running_tid
)(), semaphore
,
355 p
? p
->value
: 0, p
? p
->value
- waited
: 0,
356 waited
? "" : " (did not wait)");
364 * Note: if another thread destroyed and reinitialized a semaphore while
365 * the current thread was waiting in sem_wait, p->waiters may have been
366 * set to zero by drd_semaphore_initialize() after
367 * DRD_(semaphore_pre_wait)() has finished before
368 * DRD_(semaphore_post_wait)() has been called.
370 if (p
== NULL
|| (Int
)(p
->value
) < 0 || (Word
)(p
->waiters
) < 0)
372 SemaphoreErrInfo sei
= { DRD_(thread_get_running_tid
)(), semaphore
};
373 VG_(maybe_record_error
)(VG_(get_running_tid
)(),
375 VG_(get_IP
)(VG_(get_running_tid
)()),
384 if (p
->waits_to_skip
> 0)
388 sg
= drd_segment_pop(p
);
390 if (p
->last_sem_post_tid
!= tid
391 && p
->last_sem_post_tid
!= DRD_INVALID_THREADID
)
393 DRD_(thread_new_segment_and_combine_vc
)(tid
, sg
);
396 DRD_(thread_new_segment
)(tid
);
397 s_semaphore_segment_creation_count
++;
402 /** Called before sem_post(). */
403 void DRD_(semaphore_pre_post
)(const DrdThreadId tid
, const Addr semaphore
)
405 struct semaphore_info
* p
;
408 p
= drd_semaphore_get_or_allocate(semaphore
);
411 if (s_trace_semaphore
)
412 DRD_(trace_msg
)("[%u] sem_post 0x%lx value %u -> %u",
413 DRD_(thread_get_running_tid
)(),
414 semaphore
, p
->value
- 1, p
->value
);
416 p
->last_sem_post_tid
= tid
;
418 DRD_(thread_get_latest_segment
)(&sg
, tid
);
420 drd_segment_push(p
, sg
);
421 DRD_(thread_new_segment
)(tid
);
422 s_semaphore_segment_creation_count
++;
425 /** Called after sem_post() finished. */
426 void DRD_(semaphore_post_post
)(const DrdThreadId tid
, const Addr semaphore
,
427 const Bool succeeded
)
430 * Note: it is hard to implement the sem_post() wrapper correctly in
431 * case sem_post() returns an error code. This is because handling this
432 * case correctly requires restoring the vector clock associated with
433 * the semaphore to its original value here. In order to do that without
434 * introducing a race condition, extra locking has to be added around
435 * each semaphore call. Such extra locking would have to be added in
436 * drd_pthread_intercepts.c. However, it is hard to implement
437 * synchronization in drd_pthread_intercepts.c in a portable way without
438 * calling already redirected functions.
442 ULong
DRD_(get_semaphore_segment_creation_count
)(void)
444 return s_semaphore_segment_creation_count
;