You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
|
|
|
|
1
(11) |
2
(8) |
|
3
(8) |
4
(8) |
5
(8) |
6
(19) |
7
(17) |
8
(12) |
9
(10) |
|
10
(15) |
11
(18) |
12
(14) |
13
(16) |
14
(24) |
15
(16) |
16
(12) |
|
17
(25) |
18
(23) |
19
(12) |
20
(10) |
21
(9) |
22
(12) |
23
(13) |
|
24
(19) |
25
(7) |
26
(39) |
27
(22) |
28
(22) |
29
(16) |
30
(13) |
|
31
(23) |
|
|
|
|
|
|
|
From: Nicholas N. <nj...@cs...> - 2006-12-14 22:13:22
|
On Thu, 14 Dec 2006, Bart Van Assche wrote: > Being able to attach a debugger just after a race is detected would > indeed be a nice feature. The core's error-handling mechanism allows this by default. Just use --db-attach (or whatever it's called). Nick |
|
From: Bart V. A. <bar...@gm...> - 2006-12-14 14:54:55
|
On 12/14/06, Duncan Sands <bal...@fr...> wrote: > Hi Bart, thanks for this tool! If I understand right, it > works like this: if two thread access the same memory in > an unserialized way (i.e. there is nothing to force the > memory accesses to occur in a particular order) then drd > reports which code sections were responsible > (1st segment start..1st segment end, 2nd segment start.. > 2nd segment end) and shows what the accessed memory was: > > ==12909== Data addresses accessed by both segments: > ==12909== 0x0479107C sz 4 W W (stack of thread 9) > ==12909== 0x0479108C sz 32 W W (stack of thread 9) > > Presumably W W means that both the 1st segment and the > 2nd segment wrote to this memory location (I guess W > also covers: both read and wrote). I guess sz 32 > means it happened to all of the 32 bytes starting at > the address. > > It's not clear to me how to make use of the address > information. I guess at some point drd will offer > the possibility of attaching the debugger when a > race is detected, which would help... There is indeed still some work to do before drd's error reports will be easy to comprehend. I'm not sure however that I will be able to print detailed information about the meaning of data addresses from within the drd tool. The plan is to make the call stacks more precise, such that the call stack information is sufficient to find the cause of the race. This approach is similar to memcheck: memcheck prints a data address + exact call stack. Being able to attach a debugger just after a race is detected would indeed be a nice feature. Bart. |
|
From: Duncan S. <bal...@fr...> - 2006-12-14 13:26:09
|
Hi Bart, thanks for this tool! If I understand right, it works like this: if two thread access the same memory in an unserialized way (i.e. there is nothing to force the memory accesses to occur in a particular order) then drd reports which code sections were responsible (1st segment start..1st segment end, 2nd segment start.. 2nd segment end) and shows what the accessed memory was: ==12909== Data addresses accessed by both segments: ==12909== 0x0479107C sz 4 W W (stack of thread 9) ==12909== 0x0479108C sz 32 W W (stack of thread 9) Presumably W W means that both the 1st segment and the 2nd segment wrote to this memory location (I guess W also covers: both read and wrote). I guess sz 32 means it happened to all of the 32 bytes starting at the address. It's not clear to me how to make use of the address information. I guess at some point drd will offer the possibility of attaching the debugger when a race is detected, which would help... Best wishes, Duncan. |
|
From: Bart V. A. <bar...@gm...> - 2006-12-14 12:40:05
|
On 12/14/06, Tom Hughes <to...@co...> wrote: > > We know that it isn't installing a wrapper for unlock (at least > under that name) but is it installing one for init? ie what does > trace-symtab about the init symbol? > > More to the point, what does --trace-redir say? That should tell > you more about wrapper than watching the symbol table. > > Even more to the point, what does objdump say about the symbols? ie > run this command: > > objdump -T <path to pthread library> | fgrep pthread_spin >From the --trace-redir=yes output (I have filtered the output on pthread_spin_ -- please note that pthread_spin_unlock is missing from the second REDIR STATE section): --5596-- << --5596-- ------ REDIR STATE after VG_(redir_notify_new_SegInfo) ------ --5596-- TOPSPECS of soname NONE --5596-- libpthread.so.0 pthread_create@* W-> 0x04020154 --5596-- libpthread.so.0 pthread_detach W-> 0x040200E4 --5596-- libpthread.so.0 pthread_spin_trylock W-> 0x0401FFBF --5596-- libpthread.so.0 pthread_spin_lock W-> 0x0401FF1F --5596-- libpthread.so.0 pthread_spin_destroy W-> 0x0401FE87 --5596-- libpthread.so.0 pthread_spin_init W-> 0x0401FDE2 --5596-- libpthread.so.0 pthread_cond_destroy@* W-> 0x0401FD4A --5596-- libpthread.so.0 pthread_cond_init@* W-> 0x0401FCA5 --5596-- libpthread.so.0 pthread_cond_timedwait@* W-> 0x0401FBB1 --5596-- libpthread.so.0 pthread_cond_wait@* W-> 0x0401FAC6 --5596-- libpthread.so.0 pthread_mutex_unlock W-> 0x0401FA2E --5596-- libpthread.so.0 pthread_mutex_trylock W-> 0x0401F98E --5596-- libpthread.so.0 pthread_mutex_lock W-> 0x0401F8EE --5596-- libpthread.so.0 pthread_mutex_destroy W-> 0x0401F856 --5596-- libpthread.so.0 pthread_mutex_init W-> 0x0401F7B1 --5596-- libpthread.so.0 pthread_join W-> 0x0401F708 --5596-- TOPSPECS of soname NONE --5596-- TOPSPECS of soname NONE --5596-- TOPSPECS of soname NONE --5596-- TOPSPECS of soname ld-linux.so.2 --5596-- ------ ACTIVE ------ --5596-- >> ... choosing between 'pthread_spin_destroy' and 'pthread_spin_destroy' choosing between 'pthread_spin_lock' and 'pthread_spin_lock' choosing between 'pthread_spin_trylock' and 'pthread_spin_trylock' choosing between 'pthread_spin_unlock' and 'pthread_spin_init' choosing between 'pthread_spin_unlock' and 'pthread_spin_init' ... choosing between 'pthread_spin_init' and 'pthread_spin_init' ... --5596-- << --5596-- ------ REDIR STATE after VG_(redir_notify_new_SegInfo) ------ --5596-- TOPSPECS of soname libpthread.so.0 --5596-- TOPSPECS of soname NONE --5596-- libpthread.so.0 pthread_create@* W-> 0x04020154 --5596-- libpthread.so.0 pthread_detach W-> 0x040200E4 --5596-- libpthread.so.0 pthread_spin_trylock W-> 0x0401FFBF --5596-- libpthread.so.0 pthread_spin_lock W-> 0x0401FF1F --5596-- libpthread.so.0 pthread_spin_destroy W-> 0x0401FE87 --5596-- libpthread.so.0 pthread_spin_init W-> 0x0401FDE2 --5596-- libpthread.so.0 pthread_cond_destroy@* W-> 0x0401FD4A --5596-- libpthread.so.0 pthread_cond_init@* W-> 0x0401FCA5 --5596-- libpthread.so.0 pthread_cond_timedwait@* W-> 0x0401FBB1 --5596-- libpthread.so.0 pthread_cond_wait@* W-> 0x0401FAC6 --5596-- libpthread.so.0 pthread_mutex_unlock W-> 0x0401FA2E --5596-- libpthread.so.0 pthread_mutex_trylock W-> 0x0401F98E --5596-- libpthread.so.0 pthread_mutex_lock W-> 0x0401F8EE --5596-- libpthread.so.0 pthread_mutex_destroy W-> 0x0401F856 --5596-- libpthread.so.0 pthread_mutex_init W-> 0x0401F7B1 --5596-- libpthread.so.0 pthread_join W-> 0x0401F708 --5596-- TOPSPECS of soname NONE --5596-- TOPSPECS of soname NONE --5596-- TOPSPECS of soname NONE --5596-- TOPSPECS of soname ld-linux.so.2 --5596-- ------ ACTIVE ------ --5596-- 0x04041670 (pthread_create@@GLIB) W-> 0x04020154 pthread_create@* --5596-- 0x04042070 (pthread_create@GLIBC) W-> 0x04020154 pthread_create@* --5596-- 0x04042530 (pthread_detach ) W-> 0x040200E4 pthread_detach --5596-- 0x04042590 (pthread_join ) W-> 0x0401F708 pthread_join --5596-- 0x040432D0 (pthread_mutex_init ) W-> 0x0401F7B1 pthread_mutex_init --5596-- 0x040433B0 (pthread_mutex_destro) W-> 0x0401F856 pthread_mutex_destroy --5596-- 0x040433E0 (pthread_mutex_lock ) W-> 0x0401F8EE pthread_mutex_lock --5596-- 0x04043720 (pthread_mutex_tryloc) W-> 0x0401F98E pthread_mutex_trylock --5596-- 0x04043E00 (pthread_mutex_unlock) W-> 0x0401FA2E pthread_mutex_unlock --5596-- 0x040445A0 (pthread_cond_init@@G) W-> 0x0401FCA5 pthread_cond_init@* --5596-- 0x04044650 (pthread_cond_destroy) W-> 0x0401FD4A pthread_cond_destroy@* --5596-- 0x04044760 (pthread_cond_wait@@G) W-> 0x0401FAC6 pthread_cond_wait@* --5596-- 0x04044970 (pthread_cond_timedwa) W-> 0x0401FBB1 pthread_cond_timedwait@* --5596-- 0x04044DB0 (pthread_cond_init@GL) W-> 0x0401FCA5 pthread_cond_init@* --5596-- 0x04044DE0 (pthread_cond_destroy) W-> 0x0401FD4A pthread_cond_destroy@* --5596-- 0x04044E10 (pthread_cond_wait@GL) W-> 0x0401FAC6 pthread_cond_wait@* --5596-- 0x04044E80 (pthread_cond_timedwa) W-> 0x0401FBB1 pthread_cond_timedwait@* --5596-- 0x04045090 (pthread_spin_destroy) W-> 0x0401FE87 pthread_spin_destroy --5596-- 0x040450A0 (pthread_spin_lock ) W-> 0x0401FF1F pthread_spin_lock --5596-- 0x040450C0 (pthread_spin_trylock) W-> 0x0401FFBF pthread_spin_trylock --5596-- 0x040450E0 (pthread_spin_init ) W-> 0x0401FDE2 pthread_spin_init --5596-- >> ... --5596-- REDIR: 0x40450E0 (pthread_spin_init) redirected to 0x401FDE2 (pthread_spin_init) ... .--5596-- REDIR: 0x40450A0 (pthread_spin_lock) redirected to 0x401FF1F (pthread_spin_lock) ... objdump output: $ objdump -T /lib/libpthread.so.0 |grep pthread_spin 000090c0 g DF .text 00000018 GLIBC_2.2 pthread_spin_trylock 000090a0 g DF .text 0000000f GLIBC_2.2 pthread_spin_lock 00009090 g DF .text 00000007 GLIBC_2.2 pthread_spin_destroy 000090e0 g DF .text 0000000d GLIBC_2.2 pthread_spin_unlock 000090e0 g DF .text 0000000d GLIBC_2.2 pthread_spin_init Bart. |
|
From: Tom H. <to...@co...> - 2006-12-14 10:54:19
|
In message <e2e...@ma...>
Bart Van Assche <bar...@gm...> wrote:
> On 12/14/06, Tom Hughes <to...@co...> wrote:
>> Bart Van Assche <bar...@gm...> wrote:
>>
>> > On 12/14/06, Julian Seward <js...@ac...> wrote:
>> >
>> >> Well, you could write a wrapper for pthread_spin_init() instead?
>> >> Or supply wrappers for both, factoring the real work into a routine
>> >> shared by both wrappers. The latter sounds like a more robust approach.
>> >
>> > The problem is that with the current implementation of function
>> > wrapping, calls to pthread_spin_unlock() are not wrapped at all --
>> > neither to the wrapper defined for pthread_spin_unlock() nor to the
>> > wrapper defined for pthread_spin_init(). I see two possible solutions:
>>
>> If you have setup a wrapper for init, and unlock is at the same
>> address in your copy of the library, then that wrapper should
>> absolutely be getting called on a call to unlock.
>>
>> The name is only used to find the right code to wrap - the trap
>> into the wrapper is all based on the address so if code at the
>> wrapped address is executed the wrapper should be called.
>
> I have performed the following test:
We know that it isn't installing a wrapper for unlock (at least
under that name) but is it installing one for init? ie what does
trace-symtab about the init symbol?
More to the point, what does --trace-redir say? That should tell
you more about wrapper than watching the symbol table.
Even more to the point, what does objdump say about the symbols? ie
run this command:
objdump -T <path to pthread library> | fgrep pthread_spin
Tom
--
Tom Hughes (to...@co...)
http://www.compton.nu/
|
|
From: Bart V. A. <bar...@gm...> - 2006-12-14 10:43:18
|
On 12/14/06, Tom Hughes <to...@co...> wrote:
> Bart Van Assche <bar...@gm...> wrote:
>
> > On 12/14/06, Julian Seward <js...@ac...> wrote:
> >
> >> Well, you could write a wrapper for pthread_spin_init() instead?
> >> Or supply wrappers for both, factoring the real work into a routine
> >> shared by both wrappers. The latter sounds like a more robust approach.
> >
> > The problem is that with the current implementation of function
> > wrapping, calls to pthread_spin_unlock() are not wrapped at all --
> > neither to the wrapper defined for pthread_spin_unlock() nor to the
> > wrapper defined for pthread_spin_init(). I see two possible solutions:
>
> If you have setup a wrapper for init, and unlock is at the same
> address in your copy of the library, then that wrapper should
> absolutely be getting called on a call to unlock.
>
> The name is only used to find the right code to wrap - the trap
> into the wrapper is all based on the address so if code at the
> wrapped address is executed the wrapper should be called.
>
> Tom
I have performed the following test:
- Compiled Valgrind from source (revision 6400 + latest drd patch +
enabled pthread_spin_... wrappers in drd/drd_preloaded.c by changing
line 375 from #if 0 into #if 1).
- Used pth_detached.c as test program (see also attachment). I
modified pth_detached.c such that it uses spinlocks.
- Ran the following test:
$ VALGRIND_LIB=.in_place coregrind/valgrind -v --tool=drd
none/tests/pth_detached
I have attached the output (vg-output.txt). The
output of the following command is also very interesting, but turned
out to be too large to include as an attachment:
VALGRIND_LIB=.in_place coregrind/valgrind -v --trace-symtab=yes
--tool=drd none/tests/pth_detached
- As you can see, this test triggers an assertion failure in drd. This
test namely triggers a situation where drd thinks that two threads own
the spinlock at the same time. This is because Valgrind's core wrapped
pthread_spin_init() and pthread_spin_lock(), but not
pthread_spin_unlock().
- My conclusion is that Valgrind's core is unable to wrap
pthread_spin_unlock() because it does not add the symbol
pthread_spin_unlock to its symbol table while reading the ELF file
/lib/libpthread.so. I concluded this from the following output (with
--trace-symtab=yes):
raw symbol [ 103]: GLO FUN : val 0x0000000000, sz 13
pthread_spin_unlock@@GLIBC_2.2
ignore -- valu=0: pthread_spin_unlock@@GLIBC_2.2
Did I misinterprete Valgrind's debugging output ?
Bart.
|
|
From: Bart V. A. <bar...@gm...> - 2006-12-14 10:39:38
|
On 12/14/06, Nicholas Nethercote <nj...@cs...> wrote: > > I couldn't work out how the different thread_name components fit together. > Can you briefly describe them? As usual, I'm wondering if we can avoid > adding new stuff to the core :) This is how it currently works: - The client tells to Valgrind's core which name it wants to associate with each thread via a client request (VG_USERREQ__SET_THREAD_NAME). - When Valgrind's core encounters this client request, it stores the thread name and remembers that thread name until the thread finishes. - Each time a thread name changes, the core calls VG_TRACK(thread_name)(tid, name). - The drd tool registers a tracking function such that it is informed about thread name changes. The drd tool includes these thread names in its error reports. The drd tool also remembers thread names longer than the core. E.g. after a thread finished and before it is joined via pthread_join(), the core already has discarded all information related to that thread but drd still knows about that thread (name, POSIX thread ID, etc.). - Currently Valgrind's core does nothing else with thread names than storing them and making these names available to tools. I recommend however to include thread names in the error reports of all tools. When using e.g. memcheck on multithreaded programs, it is very helpful to know which thread an error report relates to. The only option available now is to switch back from NPTL to linuxthreads, such that the process ID included in each line of output relates uniquely to a thread. But even with linuxthreads I have to make the application keep a file in /tmp up to date with the relationship between pid_t and thread name, such that it becomes possible to translate pid_t's into thread names. Including thread names directly in memcheck's error reports would make memcheck easier to use with multithreaded software. Bart. |
|
From: Nicholas N. <nj...@cs...> - 2006-12-14 10:11:46
|
On Thu, 14 Dec 2006, Bart Van Assche wrote: >> > - Added a tracking function that is called every time a thread name >> changes >> > (track_thread_name()). >> >> Why is this needed? > > Adding such a tracking function was the easiest way for me to keep > thread names in the core and in the drd tool in sync. I couldn't work out how the different thread_name components fit together. Can you briefly describe them? As usual, I'm wondering if we can avoid adding new stuff to the core :) N |
|
From: Tom H. <to...@co...> - 2006-12-14 09:30:44
|
In message <e2e...@ma...>
Bart Van Assche <bar...@gm...> wrote:
> On 12/14/06, Julian Seward <js...@ac...> wrote:
>
>> Well, you could write a wrapper for pthread_spin_init() instead?
>> Or supply wrappers for both, factoring the real work into a routine
>> shared by both wrappers. The latter sounds like a more robust approach.
>
> The problem is that with the current implementation of function
> wrapping, calls to pthread_spin_unlock() are not wrapped at all --
> neither to the wrapper defined for pthread_spin_unlock() nor to the
> wrapper defined for pthread_spin_init(). I see two possible solutions:
If you have setup a wrapper for init, and unlock is at the same
address in your copy of the library, then that wrapper should
absolutely be getting called on a call to unlock.
The name is only used to find the right code to wrap - the trap
into the wrapper is all based on the address so if code at the
wrapped address is executed the wrapper should be called.
Tom
--
Tom Hughes (to...@co...)
http://www.compton.nu/
|
|
From: Bart V. A. <bar...@gm...> - 2006-12-14 09:14:44
|
On 12/14/06, Julian Seward <js...@ac...> wrote: > Well, you could write a wrapper for pthread_spin_init() instead? > Or supply wrappers for both, factoring the real work into a routine > shared by both wrappers. The latter sounds like a more robust approach. The problem is that with the current implementation of function wrapping, calls to pthread_spin_unlock() are not wrapped at all -- neither to the wrapper defined for pthread_spin_unlock() nor to the wrapper defined for pthread_spin_init(). I see two possible solutions: - Change Valgrind's core such that it supports function wrapping for functions like pthread_spin_unlock(). - Convince Valgrind's users to use the pthread_mutex_...() calls instead of the pthread_spin_...() calls. At least with the glibc implementation of pthread_mutex_lock(), no system calls are performed if the mutex can be locked immediately. So there is no real performance advantage in using pthread_spin_...() calls over pthread_mutex_...() calls. Additionally, the pthread_mutex_lock() call is more OS-friendly then pthread_spin_lock() when it has to block. Bart. |
|
From: Bart V. A. <bar...@gm...> - 2006-12-14 09:08:46
|
On 12/14/06, Nicholas Nethercote <nj...@cs...> wrote: > On Wed, 13 Dec 2006, Bart Van Assche wrote: > > > - Added a tracking function that is called every time a thread name changes > > (track_thread_name()). > > Why is this needed? Adding such a tracking function was the easiest way for me to keep thread names in the core and in the drd tool in sync. There is also one modification in the patch I forgot to mention in the summary: I moved the statement VG_TRACK ( post_thread_create, tst->os_state.parent, tid ) in file coregrind/m_syswrap/syswrap-linux.c to just before the statement VG_(set_running)(tid, "thread_wrapper(starting new thread)"). A similar change still has to be made in the AIX system call wrappers. Bart. |
|
From: <js...@ac...> - 2006-12-14 05:09:22
|
Nightly build on phoenix ( SuSE 10.0 ) started at 2006-12-14 04:30:01 GMT Checking out vex source tree ... done Building vex ... done Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 250 tests, 6 stderr failures, 2 stdout failures, 0 posttest failures == memcheck/tests/leak-tree (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_switch (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) none/tests/pth_detached (stdout) ================================================= == Results from 24 hours ago == ================================================= Checking out vex source tree ... done Building vex ... done Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 250 tests, 6 stderr failures, 2 stdout failures, 0 posttest failures == memcheck/tests/leak-tree (stderr) memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_switch (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) none/tests/tls (stdout) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Thu Dec 14 04:50:38 2006 --- new.short Thu Dec 14 05:09:28 2006 *************** *** 18,20 **** none/tests/mremap2 (stdout) ! none/tests/tls (stdout) --- 18,20 ---- none/tests/mremap2 (stdout) ! none/tests/pth_detached (stdout) |
|
From: <js...@ac...> - 2006-12-14 04:55:28
|
Nightly build on minnie ( SuSE 10.0, ppc32 ) started at 2006-12-14 09:00:01 GMT Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 215 tests, 10 stderr failures, 7 stdout failures, 0 posttest failures == memcheck/tests/leak-tree (stderr) memcheck/tests/leakotron (stdout) memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_changes (stderr) memcheck/tests/xml1 (stderr) none/tests/faultstatus (stderr) none/tests/fdleak_cmsg (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) none/tests/ppc32/jm-fp (stdout) none/tests/ppc32/jm-fp (stderr) none/tests/ppc32/jm-int (stdout) none/tests/ppc32/round (stdout) none/tests/ppc32/round (stderr) none/tests/ppc32/test_fx (stdout) none/tests/ppc32/test_fx (stderr) none/tests/ppc32/test_gx (stdout) |
|
From: Tom H. <to...@co...> - 2006-12-14 04:22:04
|
Nightly build on dunsmere ( athlon, Fedora Core 6 ) started at 2006-12-14 03:30:07 GMT Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 252 tests, 5 stderr failures, 2 stdout failures, 0 posttest failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_switch (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) none/tests/pth_detached (stdout) |
|
From: <sv...@va...> - 2006-12-14 03:29:24
|
Author: njn
Date: 2006-12-14 03:29:18 +0000 (Thu, 14 Dec 2006)
New Revision: 6400
Log:
Make VG_STREQ return True or False, rather than any integer.
Modified:
trunk/include/pub_tool_libcbase.h
Modified: trunk/include/pub_tool_libcbase.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/include/pub_tool_libcbase.h 2006-12-14 02:55:58 UTC (rev 6399)
+++ trunk/include/pub_tool_libcbase.h 2006-12-14 03:29:18 UTC (rev 6400)
@@ -50,8 +50,8 @@
------------------------------------------------------------------ */
=20
/* Use this for normal null-termination-style string comparison */
-#define VG_STREQ(s1,s2) (s1 !=3D NULL && s2 !=3D NULL \
- && VG_(strcmp)((s1),(s2))=3D=3D0)
+#define VG_STREQ(s1,s2) ( (s1 !=3D NULL && s2 !=3D NULL \
+ && VG_(strcmp)((s1),(s2))=3D=3D0) ? True : Fa=
lse )
=20
extern Int VG_(strlen) ( const Char* str );
extern Char* VG_(strcat) ( Char* dest, const Char* src );
|
|
From: Tom H. <th...@cy...> - 2006-12-14 03:25:02
|
Nightly build on dellow ( x86_64, Fedora Core 6 ) started at 2006-12-14 03:10:03 GMT Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 280 tests, 4 stderr failures, 1 stdout failure, 0 posttest failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 280 tests, 4 stderr failures, 2 stdout failures, 0 posttest failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/xml1 (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) none/tests/pth_detached (stdout) ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Thu Dec 14 03:16:40 2006 --- new.short Thu Dec 14 03:23:05 2006 *************** *** 8,10 **** ! == 280 tests, 4 stderr failures, 2 stdout failures, 0 posttest failures == memcheck/tests/pointer-trace (stderr) --- 8,10 ---- ! == 280 tests, 4 stderr failures, 1 stdout failure, 0 posttest failures == memcheck/tests/pointer-trace (stderr) *************** *** 14,16 **** none/tests/mremap2 (stdout) - none/tests/pth_detached (stdout) --- 14,15 ---- |
|
From: Tom H. <th...@cy...> - 2006-12-14 03:24:07
|
Nightly build on alvis ( i686, Red Hat 7.3 ) started at 2006-12-14 03:15:02 GMT Results differ from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Last 20 lines of verbose log follow echo /tmp/ccJPosWb.s:4393: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccJPosWb.s:4513: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccJPosWb.s:4633: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccJPosWb.s:4753: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccJPosWb.s:4873: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccJPosWb.s:4993: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccJPosWb.s:5113: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccJPosWb.s:5233: Error: no such instruction: `fisttpq -56(%ebp)' make[5]: *** [insn_sse3.o] Error 1 rm insn_mmx.c insn_sse2.c insn_fpu.c insn_mmxext.c insn_sse.c insn_sse3.c insn_cmov.c insn_basic.c make[5]: Leaving directory `/tmp/valgrind.21339/valgrind/none/tests/x86' make[4]: *** [check-am] Error 2 make[4]: Leaving directory `/tmp/valgrind.21339/valgrind/none/tests/x86' make[3]: *** [check-recursive] Error 1 make[3]: Leaving directory `/tmp/valgrind.21339/valgrind/none/tests' make[2]: *** [check-recursive] Error 1 make[2]: Leaving directory `/tmp/valgrind.21339/valgrind/none' make[1]: *** [check-recursive] Error 1 make[1]: Leaving directory `/tmp/valgrind.21339/valgrind' make: *** [check] Error 2 ================================================= == Results from 24 hours ago == ================================================= Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Last 20 lines of verbose log follow echo /tmp/ccE1eZS4.s:4393: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccE1eZS4.s:4513: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccE1eZS4.s:4633: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccE1eZS4.s:4753: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccE1eZS4.s:4873: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccE1eZS4.s:4993: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccE1eZS4.s:5113: Error: no such instruction: `fisttpq -56(%ebp)' /tmp/ccE1eZS4.s:5233: Error: no such instruction: `fisttpq -56(%ebp)' make[5]: *** [insn_sse3.o] Error 1 rm insn_mmx.c insn_sse2.c insn_fpu.c insn_mmxext.c insn_sse.c insn_sse3.c insn_cmov.c insn_basic.c make[5]: Leaving directory `/tmp/valgrind.21339/valgrind/none/tests/x86' make[4]: *** [check-am] Error 2 make[4]: Leaving directory `/tmp/valgrind.21339/valgrind/none/tests/x86' make[3]: *** [check-recursive] Error 1 make[3]: Leaving directory `/tmp/valgrind.21339/valgrind/none/tests' make[2]: *** [check-recursive] Error 1 make[2]: Leaving directory `/tmp/valgrind.21339/valgrind/none' make[1]: *** [check-recursive] Error 1 make[1]: Leaving directory `/tmp/valgrind.21339/valgrind' make: *** [check] Error 2 ================================================= == Difference between 24 hours ago and now == ================================================= *** old.short Thu Dec 14 03:18:56 2006 --- new.short Thu Dec 14 03:22:42 2006 *************** *** 7,16 **** Last 20 lines of verbose log follow echo ! /tmp/ccE1eZS4.s:4393: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccE1eZS4.s:4513: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccE1eZS4.s:4633: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccE1eZS4.s:4753: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccE1eZS4.s:4873: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccE1eZS4.s:4993: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccE1eZS4.s:5113: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccE1eZS4.s:5233: Error: no such instruction: `fisttpq -56(%ebp)' make[5]: *** [insn_sse3.o] Error 1 --- 7,16 ---- Last 20 lines of verbose log follow echo ! /tmp/ccJPosWb.s:4393: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccJPosWb.s:4513: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccJPosWb.s:4633: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccJPosWb.s:4753: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccJPosWb.s:4873: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccJPosWb.s:4993: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccJPosWb.s:5113: Error: no such instruction: `fisttpq -56(%ebp)' ! /tmp/ccJPosWb.s:5233: Error: no such instruction: `fisttpq -56(%ebp)' make[5]: *** [insn_sse3.o] Error 1 |
|
From: Tom H. <th...@cy...> - 2006-12-14 03:19:21
|
Nightly build on lloyd ( x86_64, Fedora Core 3 ) started at 2006-12-14 03:05:04 GMT Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 280 tests, 5 stderr failures, 1 stdout failure, 0 posttest failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_switch (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) |
|
From: Tom H. <th...@cy...> - 2006-12-14 03:13:23
|
Nightly build on gill ( x86_64, Fedora Core 2 ) started at 2006-12-14 03:00:04 GMT Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 282 tests, 6 stderr failures, 1 stdout failure, 0 posttest failures == memcheck/tests/pointer-trace (stderr) memcheck/tests/stack_switch (stderr) memcheck/tests/x86/scalar (stderr) memcheck/tests/x86/scalar_supp (stderr) none/tests/fdleak_fcntl (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) |
|
From: Nicholas N. <nj...@cs...> - 2006-12-14 03:08:29
|
On Wed, 13 Dec 2006, Bart Van Assche wrote: > A new patch is available: > http://home.euphonynet.be/bvassche/valgrind/valgrind-6397-drd-2006-12-13.patch.gz > > Changes compared to the previous version (2006-12-09): > - Eliminated the changes to the thread states in Valgrind's core. Great! > - Renamed track_detached_thread_finished() into track_thread_finished(). > This tracking function is now called independent of whether the thread is a > detached or joinable POSIX thread. Great! > - Added a tracking function that is called every time a thread name changes > (track_thread_name()). Why is this needed? > - Changed thread name size from 16 to 32 characters. > - Decoupled Valgrind's thread ID's (ThreadId) and DRD's thread ID's > (DrdThreadId). Good. > - Eliminated all thread state information from drd's client-side function > wrappers. > - When option -v is passed to Valgrind, drd prints some statistics of its > own. > - Bug fix (thanks to Julian): fixed vector clock updating at > pthread_mutex_lock() calls -- the drd now reliably reports the same set of > races upon every run. Previously the set of races reported was dependent on > how Valgrind scheduled the client's threads. > - Various small changes to drd. All good! > Next issues I will work on: segment merging, and more accurate error > reporting. This should solve the OOM errors triggered by drd and make the > tool more usable. > > Any comments on the proposed core changes and/or the drd tool are welcome. These changes look great. I appreciate that you have addressed the concerns Julian and I have raised previously. The minimal set of coregrind/ changes is looking good. Nick |
|
From: <sv...@va...> - 2006-12-14 02:56:00
|
Author: njn
Date: 2006-12-14 02:55:58 +0000 (Thu, 14 Dec 2006)
New Revision: 6399
Log:
Removed the unused pthread_model and thread_model modules.
Mostly commented out the unused stuff relating to ThreadErrs and MutexErr=
s,
which no longer exist.
Removed:
trunk/coregrind/m_pthreadmodel.c
trunk/coregrind/m_threadmodel.c
trunk/coregrind/pub_core_pthreadmodel.h
trunk/coregrind/pub_core_threadmodel.h
Modified:
trunk/coregrind/Makefile.am
trunk/coregrind/m_errormgr.c
trunk/coregrind/pub_core_errormgr.h
trunk/glibc-2.2.supp
trunk/glibc-2.3.supp
Modified: trunk/coregrind/Makefile.am
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/Makefile.am 2006-12-14 00:28:50 UTC (rev 6398)
+++ trunk/coregrind/Makefile.am 2006-12-14 02:55:58 UTC (rev 6399)
@@ -112,7 +112,6 @@
pub_core_mallocfree.h \
pub_core_options.h \
pub_core_oset.h \
- pub_core_pthreadmodel.h \
pub_core_redir.h \
pub_core_replacemalloc.h\
pub_core_scheduler.h \
@@ -122,7 +121,6 @@
pub_core_stacktrace.h \
pub_core_syscall.h \
pub_core_syswrap.h \
- pub_core_threadmodel.h \
pub_core_threadstate.h \
pub_core_tooliface.h \
pub_core_trampoline.h \
@@ -177,13 +175,11 @@
m_mallocfree.c \
m_options.c \
m_oset.c \
- m_pthreadmodel.c \
m_redir.c \
m_signals.c \
m_stacks.c \
m_stacktrace.c \
m_syscall.c \
- m_threadmodel.c \
m_threadstate.c \
m_tooliface.c \
m_trampoline.S \
Modified: trunk/coregrind/m_errormgr.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_errormgr.c 2006-12-14 00:28:50 UTC (rev 6398)
+++ trunk/coregrind/m_errormgr.c 2006-12-14 02:55:58 UTC (rev 6399)
@@ -170,7 +170,10 @@
* effectively extend it by defining their own enums in the (0..) range.=
*/
typedef
enum {
- PThreadSupp =3D -1, /* Matches PThreadErr */
+ // Nb: thread errors are a relic of the time when Valgrind's core
+ // could detect them. This example is left commented-out as an
+ // example should new core errors ever be added.
+ ThreadSupp =3D -1, /* Matches ThreadErr */
}
CoreSuppKind;
=20
@@ -269,10 +272,10 @@
return False;
=20
switch (e1->ekind) {
- // case ThreadErr:
- // case MutexErr:
- // vg_assert(VG_(needs).core_errors);
- // return VG_(tm_error_equal)(res, e1, e2);
+ //(example code, see comment on CoreSuppKind above)
+ //case ThreadErr:
+ // vg_assert(VG_(needs).core_errors);
+ // return <something>
default:=20
if (VG_(needs).tool_errors) {
return VG_TDICT_CALL(tool_eq_Error, res, e1, e2);
@@ -302,11 +305,11 @@
}
=20
switch (err->ekind) {
- // case ThreadErr:
- // case MutexErr:
- // vg_assert(VG_(needs).core_errors);
- // VG_(tm_error_print)(err);
- // break;
+ //(example code, see comment on CoreSuppKind above)
+ //case ThreadErr:
+ // vg_assert(VG_(needs).core_errors);
+ // VG_(tm_error_print)(err);
+ // break;
default:=20
if (VG_(needs).tool_errors)
VG_TDICT_CALL( tool_pp_Error, err );
@@ -420,10 +423,12 @@
if (stop_at > VG_MAX_SUPP_CALLERS) stop_at =3D VG_MAX_SUPP_CALLERS;
vg_assert(stop_at > 0);
=20
- if (ThreadErr =3D=3D err->ekind || MutexErr =3D=3D err->ekind) {
- VG_(printf)("{\n");
- VG_(printf)(" <insert a suppression name here>\n");
- VG_(printf)(" core:PThread\n");
+ //(example code, see comment on CoreSuppKind above)
+ if (0) { =20
+ //if (0) ThreadErr =3D=3D err->ekind) {
+ // VG_(printf)("{\n");
+ // VG_(printf)(" <insert a suppression name here>\n");
+ // VG_(printf)(" core:Thread\n");
=20
} else {
Char* name =3D VG_TDICT_CALL(tool_get_error_name, err);
@@ -601,11 +606,11 @@
=20
/* update 'extra' */
switch (ekind) {
- // case ThreadErr:
- // case MutexErr:
- // vg_assert(VG_(needs).core_errors);
- // extra_size =3D VG_(tm_error_update_extra)(p);
- // break;
+ //(example code, see comment on CoreSuppKind above)
+ //case ThreadErr:
+ // vg_assert(VG_(needs).core_errors);
+ // extra_size =3D <something>
+ // break;
default:
vg_assert(VG_(needs).tool_errors);
extra_size =3D VG_TDICT_CALL(tool_update_extra, p);
@@ -1013,9 +1018,10 @@
if (VG_(needs).core_errors && tool_name_present("core", tool_names=
))
{
// A core suppression
- if (VG_STREQ(supp_name, "PThread"))
- supp->skind =3D PThreadSupp;
- else
+ //(example code, see comment on CoreSuppKind above)
+ //if (VG_STREQ(supp_name, "Thread"))
+ // supp->skind =3D ThreadSupp;
+ //else
BOMB("unknown core suppression type");
}
else if (VG_(needs).tool_errors &&=20
@@ -1120,8 +1126,9 @@
Bool supp_matches_error(Supp* su, Error* err)
{
switch (su->skind) {
- case PThreadSupp:
- return (err->ekind =3D=3D ThreadErr || err->ekind =3D=3D MutexE=
rr);
+ //(example code, see comment on CoreSuppKind above)
+ //case ThreadSupp:
+ // return (err->ekind =3D=3D ThreadErr);
default:
if (VG_(needs).tool_errors) {
return VG_TDICT_CALL(tool_error_matches_suppression, err, su=
);
Deleted: trunk/coregrind/m_pthreadmodel.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_pthreadmodel.c 2006-12-14 00:28:50 UTC (rev 6398)
+++ trunk/coregrind/m_pthreadmodel.c 2006-12-14 02:55:58 UTC (rev 6399)
@@ -1,604 +0,0 @@
-
-/*--------------------------------------------------------------------*/
-/*--- Pthreads library modelling. m_pthreadmodel.c ---*/
-/*--------------------------------------------------------------------*/
-
-/*
- This file is part of Valgrind, a dynamic binary instrumentation
- framework.
-
- Copyright (C) 2005 Jeremy Fitzhardinge
- je...@go...
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307, USA.
-
- The GNU General Public License is contained in the file COPYING.
-*/
-
-/*=20
- This file wraps the client's use of libpthread functions and calls
- on vg_threadmodel.c to model the state of the the client's threads.
- The intent is to 1) look for problem's in the client's use of the
- pthread API, and 2) tell tools which care about thread events (eg,
- helgrind).
-
- This file is intended to be implementation-independent. It assumes
- that the client is using the same pthread.h as the one we include
- here, but makes minimal assumptions about the actual structures
- defined and so on (ie, the exact nature of pthread_t).
-
- (For now we assume there's a 1:1 relationship between pthread_t's
- and Valgrind-visible threads; N:M implementations will need further
- work.)
-
- The model is based on the pthread standard rather than any
- particular implementation, in order to encourage portable use of
- libpthread. On the other hand, we will probably need to implement
- particular implementation extensions if they're widely used.
- =20
- One tricky problem we need to solve is the mapping between
- pthread_t identifiers and internal thread identifiers.
- */
-
-#include "pub_core_basics.h"
-
-#if 0
-
-#define __USE_GNU
-#define __USE_UNIX98
-#include <pthread.h>
-
-static const Bool debug =3D False;
-
-static Bool check_wrappings(void);
-
-#define ENTER(x) \
- do { \
- if (VG_(clo_trace_pthreads)) \
- VG_(message)(Vg_DebugMsg, ">>> %d entering %s", \
- VG_(get_running_tid)(), #x); \
- } while(0)
-
-static const Char *pp_retval(enum return_type rt, Word retval)
-{
- static Char buf[50];
-
- switch(rt) {
- case RT_RETURN:
- VG_(sprintf)(buf, "return %d 0x%x", retval, retval);
- return buf;
-
- case RT_LONGJMP:
- return "LONGJMPed out";
-
- case RT_EXIT:
- return "thread exit";
- }
- return "??";
-}
-
-#define LEAVE(x, rt, retval) \
- do { \
- if (VG_(clo_trace_pthreads)) \
- VG_(message)(Vg_DebugMsg, "<<< %d leaving %s -> %s", \
- VG_(get_running_tid)(), #x, pp_retval(rt, retval)); \
- } while(0)
-
-struct pthread_map
-{
- pthread_t id;
-
- ThreadId tid;
-};
-
-static Int pthread_cmp(const void *v1, const void *v2)
-{
- const pthread_t *a =3D (const pthread_t *)v1;
- const pthread_t *b =3D (const pthread_t *)v2;
- =20
- return VG_(memcmp)(a, b, sizeof(*a));
-}
-
-static SkipList sk_pthread_map =3D VG_SKIPLIST_INIT(struct pthread_map, =
id, pthread_cmp,=20
- NULL, VG_AR_CORE);
-
-/* Find a ThreadId for a particular pthread_t; block until it becomes av=
ailable */
-static ThreadId get_pthread_mapping(pthread_t id)
-{
- /* Nasty little spin loop; revise if this turns out to be a
- problem. This should only spin for as long as it takes for the
- child thread to register the pthread_t. */
- for(;;) {
- struct pthread_map *m =3D VG_(SkipList_Find_Exact)(&sk_pthread_map=
, &id);
-
- if (m && m->tid !=3D VG_INVALID_THREADID)
- return m->tid;
-
- //VG_(printf)("find %x -> %p\n", id, m);
- VG_(vg_yield)();
- }
-}
-
-/* Create a mapping between a ThreadId and a pthread_t */
-static void pthread_id_mapping(ThreadId tid, Addr idp, UInt idsz)
-{
- pthread_t id =3D *(pthread_t *)idp;
- struct pthread_map *m =3D VG_(SkipList_Find_Exact)(&sk_pthread_map, &=
id);
-
- if (debug)
- VG_(printf)("Thread %d maps to %p\n", tid, id);
- =20
- if (m =3D=3D NULL) {
- m =3D VG_(SkipNode_Alloc)(&sk_pthread_map);
- m->id =3D id;
- m->tid =3D tid;
- VG_(SkipList_Insert)(&sk_pthread_map, m);
- } else {
- if (m->tid !=3D VG_INVALID_THREADID && m->tid !=3D tid)
- VG_(message)(Vg_UserMsg, "Thread %d is creating duplicate mapping for =
pthread identifier %x; previously mapped to %d\n",
- tid, (UInt)id, m->tid);
- m->tid =3D tid;
- }
-}
-
-static void check_thread_exists(ThreadId tid)
-{
- if (!VG_(tm_thread_exists)(tid)) {
- if (debug)
- VG_(printf)("creating thread %d\n", tid);
- VG_(tm_thread_create)(VG_INVALID_THREADID, tid, False);
- }
-}
-
-static Addr startfunc_wrapper =3D 0;
-
-void VG_(pthread_startfunc_wrapper)(Addr wrapper)
-{
- startfunc_wrapper =3D wrapper;
-}
-
-struct pthread_create_nonce {
- Bool detached;
- pthread_t *threadid;
-};
-
-static void *before_pthread_create(va_list va)
-{
- pthread_t *threadp =3D va_arg(va, pthread_t *);
- const pthread_attr_t *attr =3D va_arg(va, const pthread_attr_t *);
- void *(*start)(void *) =3D va_arg(va, void *(*)(void *));
- void *arg =3D va_arg(va, void *);
- struct pthread_create_nonce *n;
- struct vg_pthread_newthread_data *data;=20
- ThreadState *tst;
-
- if (!check_wrappings())
- return NULL;
-
- ENTER(pthread_create);
-
- /* Data is in the client heap and is freed by the client in the
- startfunc_wrapper. */
- vg_assert(startfunc_wrapper !=3D 0);
-
- tst =3D VG_(get_ThreadState)(VG_(get_running_tid)());
-
- // XXX: why use TL_(malloc)() here? What characteristics does this
- // allocation require? =20
- // [Possible: When using a tool that replaces malloc(), we want to ca=
ll
- // the replacement version. Otherwise, we want to use VG_(cli_mallo=
c)().
- // So we go via the default version of TL_(malloc)() in vg_default?]
- tl_assert2(0, "read the comment in the code about this...");
-
- // XXX: These three lines are going to have to change. They relied o=
n
- // TL_(malloc) being a weak symbol, and it just doesn't fit with the
- // VG_(tdict) approach that we've switched to. The right way to do t=
his
- // will be to provide a function in the core that checks if
- // VG_(tdict).malloc_malloc has been set; if so, it should
- // call it, if not, it should call VG_(cli_malloc)().
-// VG_(tl_malloc_called_deliberately) =3D True;
-// data =3D TL_(malloc)(sizeof(*data));
-// VG_(tl_malloc_called_deliberately) =3D False;
-
- VG_TRACK(pre_mem_write, Vg_CorePThread, tst->tid, "new thread data",
- (Addr)data, sizeof(*data));
- data->startfunc =3D start;
- data->arg =3D arg;
- VG_TRACK(post_mem_write, (Addr)data, sizeof(*data));
-
- /* Substitute arguments
- XXX hack: need an API to do this. */
- ((Word *)tst->arch.m_esp)[3] =3D startfunc_wrapper;
- ((Word *)tst->arch.m_esp)[4] =3D (Word)data;
-
- if (debug)
- VG_(printf)("starting thread at wrapper %p\n", startfunc_wrapper);
-
- n =3D VG_(arena_malloc)(VG_AR_CORE, sizeof(*n));
- n->detached =3D attr && !!attr->__detachstate;
- n->threadid =3D threadp;
-
- return n;
-}
-
-static void after_pthread_create(void *nonce, enum return_type rt, Word =
retval)
-{
- struct pthread_create_nonce *n =3D (struct pthread_create_nonce *)non=
ce;
- ThreadId tid =3D VG_(get_running_tid)();
-
- if (n =3D=3D NULL)
- return;
-
- if (rt =3D=3D RT_RETURN && retval =3D=3D 0) {
- if (!VG_(tm_thread_exists)(tid))
- VG_(tm_thread_create)(tid, get_pthread_mapping(*n->threadid),
- n->detached);
- else {
- if (n->detached)
- VG_(tm_thread_detach)(tid);
- /* XXX set creator tid as well? */
- }
- }
-
- VG_(arena_free)(VG_AR_CORE, n);
-
- LEAVE(pthread_create, rt, retval);
-}
-
-static void *before_pthread_join(va_list va)
-{
- pthread_t pt_joinee =3D va_arg(va, pthread_t);
- ThreadId joinee;
-
- if (!check_wrappings())
- return NULL;
-
- ENTER(pthread_join);
-
- joinee =3D get_pthread_mapping(pt_joinee);
-
- VG_(tm_thread_join)(VG_(get_running_tid)(), joinee);
-
- return NULL;
-}
-
-static void after_pthread_join(void *v, enum return_type rt, Word retval=
)
-{
- /* nothing to be done? */
- if (!check_wrappings())
- return;
-
- LEAVE(pthread_join, rt, retval);
-}
-
-struct pthread_detach_data {
- pthread_t id;
-};
-
-static void *before_pthread_detach(va_list va)
-{
- pthread_t id =3D va_arg(va, pthread_t);
- struct pthread_detach_data *data;
-
- if (!check_wrappings())
- return NULL;
-
- ENTER(pthread_detach);
-
- data =3D VG_(arena_malloc)(VG_AR_CORE, sizeof(*data));
- data->id =3D id;
-
- return data;
-}
-
-static void after_pthread_detach(void *nonce, enum return_type rt, Word =
retval)
-{
- struct pthread_detach_data *data =3D (struct pthread_detach_data *)no=
nce;
- ThreadId tid;
-
- if (data =3D=3D NULL)
- return;
-
- tid =3D get_pthread_mapping(data->id);
-
- VG_(arena_free)(VG_AR_CORE, data);
- =20
- if (rt =3D=3D RT_RETURN && retval =3D=3D 0)
- VG_(tm_thread_detach)(tid);
- =20
- LEAVE(pthread_detach, rt, retval);
-}
-
-
-
-static void *before_pthread_self(va_list va)
-{
- /* If pthread_t is a structure, then this might be passed a pointer
- to the return value. On Linux/glibc, it's a simple scalar, so it =
is
- returned normally. */
- if (!check_wrappings())
- return NULL;
-
- ENTER(pthread_self);
-
- check_thread_exists(VG_(get_running_tid)());
- return NULL;
-}
-
-static void after_pthread_self(void *nonce, enum return_type rt, Word re=
tval)
-{
- pthread_t ret =3D (pthread_t)retval;
-
- if (!check_wrappings())
- return;
-
- pthread_id_mapping(VG_(get_running_tid)(), (Addr)&ret, sizeof(ret));
-
- LEAVE(pthread_self, rt, retval);
-}
-
-
-/* If a mutex hasn't been initialized, check it against all the static
- initializers to see if it appears to have been statically
- initialized. */
-static void check_mutex_init(ThreadId tid, pthread_mutex_t *mx)
-{
- static const pthread_mutex_t initializers[] =3D {
- PTHREAD_MUTEX_INITIALIZER,
- PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
- PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP,
- PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP,
- };
- Int i;
- =20
- if (VG_(tm_mutex_exists)((Addr)mx))
- return;
-
- VG_TRACK(pre_mem_read, Vg_CorePThread, tid, "pthread_mutex_t", (Addr)=
mx, sizeof(*mx));
-
- for(i =3D 0; i < sizeof(initializers)/sizeof(*initializers); i++)
- if (VG_(memcmp)(&initializers[i], mx, sizeof(*mx)) =3D=3D 0) {
- VG_(tm_mutex_init)(tid, (Addr)mx);
- break;
- }
-}
-
-static void *before_pthread_mutex_init(va_list va)
-{
- pthread_mutex_t *mx =3D va_arg(va, pthread_mutex_t *);
- const pthread_mutexattr_t *attr =3D va_arg(va, const pthread_mutexatt=
r_t *);
-
- if (!check_wrappings())
- return NULL;
-
- ENTER(pthread_mutex_init);
-
- /* XXX look for recursive mutex */
- /* XXX look for non-process scope */
- (void)attr;
-
- return mx;
-}
-
-static void after_pthread_mutex_init(void *nonce, enum return_type rt, W=
ord retval)
-{
- if (!check_wrappings())
- return;
-
- if (rt =3D=3D RT_RETURN && retval =3D=3D 0)
- VG_(tm_mutex_init)(VG_(get_running_tid)(), (Addr)nonce);
-
- LEAVE(pthread_mutex_init, rt, retval);
-}
-
-static void *before_pthread_mutex_destroy(va_list va)
-{
- pthread_mutex_t *mx =3D va_arg(va, pthread_mutex_t *);
-
- if (!check_wrappings())
- return NULL;
-
- ENTER(pthread_mutex_destroy);
-
- VG_(tm_mutex_destroy)(VG_(get_running_tid)(), (Addr)mx);
-
- return NULL;
-}
-
-static void after_pthread_mutex_destroy(void *nonce, enum return_type rt=
, Word retval)
-{
- if (!check_wrappings())
- return;
-
- LEAVE(pthread_mutex_destroy, rt, retval);
-}
-
-static void *before_pthread_mutex_lock(va_list va)
-{
- pthread_mutex_t *mx =3D va_arg(va, pthread_mutex_t *);
-
- if (!check_wrappings())
- return NULL;
-
- ENTER(pthread_mutex_lock);
-
- if (debug)
- VG_(printf)("%d locking %p\n", VG_(get_running_tid)(), mx);
- check_thread_exists(VG_(get_running_tid)());
- check_mutex_init(VG_(get_running_tid)(), mx); /* mutex might be stati=
cally initialized */
- VG_(tm_mutex_trylock)(VG_(get_running_tid)(), (Addr)mx);
-
- return mx;
-}
-
-static void after_pthread_mutex_lock(void *nonce, enum return_type rt, W=
ord retval)
-{
- if (!check_wrappings())
- return;
-
- if (rt =3D=3D RT_RETURN && retval =3D=3D 0)
- VG_(tm_mutex_acquire)(VG_(get_running_tid)(), (Addr)nonce);
- else {
- if (debug)
- VG_(printf)("after mutex_lock failed: rt=3D%d ret=3D%d\n", rt, retval)=
;
- VG_(tm_mutex_giveup)(VG_(get_running_tid)(), (Addr)nonce);
- }
-
- LEAVE(pthread_mutex_lock, rt, retval);
-}
-
-static void *before_pthread_mutex_trylock(va_list va)
-{
- pthread_mutex_t *mx =3D va_arg(va, pthread_mutex_t *);
-
- if (!check_wrappings())
- return NULL;
-
- ENTER(pthread_mutex_trylock);
-
- if (debug)
- VG_(printf)("%d trylocking %p\n", VG_(get_running_tid)(), mx);
- check_thread_exists(VG_(get_running_tid)());
- check_mutex_init(VG_(get_running_tid)(), mx); /* mutex might be stati=
cally initialized */
- VG_(tm_mutex_trylock)(VG_(get_running_tid)(), (Addr)mx);
-
- return mx;
-}
-
-static void after_pthread_mutex_trylock(void *nonce, enum return_type rt=
, Word retval)
-{
- if (nonce =3D=3D NULL)
- return;
- =20
- if (rt =3D=3D RT_RETURN && retval =3D=3D 0)
- VG_(tm_mutex_acquire)(VG_(get_running_tid)(), (Addr)nonce);
- else {
- if (debug)
- VG_(printf)("after mutex_trylock failed: rt=3D%d ret=3D%d\n", rt, retv=
al);
- VG_(tm_mutex_giveup)(VG_(get_running_tid)(), (Addr)nonce);
- }
-
- LEAVE(pthread_mutex_trylock, rt, retval);
-}
-
-static void *before_pthread_mutex_unlock(va_list va)
-{
- pthread_mutex_t *mx =3D va_arg(va, pthread_mutex_t *);
-
- if (!check_wrappings())
- return NULL;
-
- ENTER(pthread_mutex_unlock);
- =20
- VG_(tm_mutex_tryunlock)(VG_(get_running_tid)(), (Addr)mx);
-
- return mx;
-}
-
-static void after_pthread_mutex_unlock(void *nonce, enum return_type rt,=
Word retval)
-{
- if (nonce =3D=3D NULL)
- return;
-
- if (rt =3D=3D RT_RETURN && retval =3D=3D 0)
- VG_(tm_mutex_unlock)(VG_(get_running_tid)(), (Addr)nonce); /* comp=
lete unlock */
- else
- VG_(tm_mutex_acquire)(VG_(get_running_tid)(), (Addr)nonce); /* re-=
acquire */
-
- LEAVE(pthread_mutex_unlock, rt, retval);
-}
-
-
-static struct pt_wraps {
- const Char *name;
- FuncWrapper wrapper;
- const CodeRedirect *redir;
-} wraps[] =3D {
-#define WRAP(func, extra) { #func extra, { before_##func, after_##func }=
}
- WRAP(pthread_create, "@@GLIBC_2.1"), /* XXX TODO: 2.0 ABI (?) */
- WRAP(pthread_join, ""),
- WRAP(pthread_detach, ""),
-
- WRAP(pthread_self, ""),
-
- WRAP(pthread_mutex_init, ""),
- WRAP(pthread_mutex_destroy, ""),
- WRAP(pthread_mutex_lock, ""),
- WRAP(pthread_mutex_trylock, ""),
- WRAP(pthread_mutex_unlock, ""),
-#undef WRAP
-};
-
-/* Check to see if all the wrappers are resolved */
-static Bool check_wrappings()
-{
- Int i;
- static Bool ok =3D True;
- static Bool checked =3D False;
-
- if (checked)
- return ok;
-
- for(i =3D 0; i < sizeof(wraps)/sizeof(*wraps); i++) {
- if (!VG_(is_resolved)(wraps[i].redir)) {
- VG_(message)(Vg_DebugMsg, "Pthread wrapper for \"%s\" is not resolved"=
,
- wraps[i].name);
- ok =3D False;
- }
- }
-
- if (startfunc_wrapper =3D=3D 0) {
- VG_(message)(Vg_DebugMsg, "Pthread wrapper for thread start functi=
on is not resolved");
- ok =3D False;
- }
-
- if (!ok)
- VG_(message)(Vg_DebugMsg, "Missing intercepts; model disabled");
-
- checked =3D True;
- return ok;
-}
-
-/*=20
- Set up all the wrappers for interesting functions.
- */
-void VG_(pthread_init)()
-{
- Int i;
-
- for(i =3D 0; i < sizeof(wraps)/sizeof(*wraps); i++) {
- //VG_(printf)("adding pthread wrapper for %s\n", wraps[i].name);
- wraps[i].redir =3D VG_(add_wrapper)("soname:libpthread.so.0",=20
- wraps[i].name, &wraps[i].wrapper);
- }
- VG_(tm_init)();
- VG_(tm_thread_create)(VG_INVALID_THREADID, VG_(master_tid), True);
-}
-
-#else /* !0 */
-/* Stubs for now */
-//:: void VG_(pthread_init)()
-//:: {
-//:: }
-//::=20
-//:: void VG_(pthread_startfunc_wrapper)(Addr wrapper)
-//:: {
-//:: }
-#endif /* 0 */
-
-/*--------------------------------------------------------------------*/
-/*--- end ---*/
-/*--------------------------------------------------------------------*/
Deleted: trunk/coregrind/m_threadmodel.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_threadmodel.c 2006-12-14 00:28:50 UTC (rev 6398)
+++ trunk/coregrind/m_threadmodel.c 2006-12-14 02:55:58 UTC (rev 6399)
@@ -1,1284 +0,0 @@
-
-/*--------------------------------------------------------------------*/
-/*--- Thread modelling. m_threadmodel.c ---*/
-/*--------------------------------------------------------------------*/
-
-/*
- This file is part of Valgrind, a dynamic binary instrumentation
- framework.
-
- Copyright (C) 2005-2006 Jeremy Fitzhardinge
- je...@go...
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307, USA.
-
- The GNU General Public License is contained in the file COPYING.
-*/
-
-/*=20
- This file implements an abstract thread model, by which a client's
- thread usage is validated. The model the file implements is
- intended to be enough to contain pthreads, or perhaps a superset,
- but it is not pthread-specific; that's done in in vg_pthreadmodel.c
-
- While the primary client of this file is vg_pthreadmodel.c, it is
- also intended that clients can make direct use of this file for
- home-grown threading libraries. It is therefore useful for both
- validating the library itself as well as the users of the library.
-
- A note on terminology:=20
-
- The states referred to in this file ("blocked state", "zombie
- state") are specific to this threads model, and have nothing do to
- with the scheduler status for a thread. For example, a thread
- could be "blocked" in a lock but be in VgTs_Runnable status,
- because the lock is actually a spinlock.
-
- "Fails" means "reports an error" and possibly means that the model
- is getting out of sync with the actual implementation. This model
- only reports problems to the user, and doesn't attempt to actually
- change the behaviour of the implementation.
-
- NB:=20
-
- This file assumes there's a 1:1 relationship between application
- threads and Valgrind threads, which means that 1:N and M:N thread
- models are not (yet) supported. At some point we may need to
- introduce a separate notion of a "thread" for modelling purposes.
- */
-
-#include "pub_core_basics.h"
-#include "pub_core_vki.h"
-#include "pub_core_errormgr.h"
-#include "pub_core_execontext.h"
-#include "pub_core_libcassert.h"
-#include "pub_core_libcbase.h"
-#include "pub_core_libcprint.h"
-#include "pub_core_mallocfree.h"
-#include "pub_core_oset.h"
-#include "pub_core_threadmodel.h"
-#include "pub_core_threadstate.h"
-#include "pub_core_tooliface.h"
-
-struct thread;
-struct mutex;
-struct condvar;
-
-static const Bool debug_thread =3D False;
-static const Bool debug_mutex =3D False;
-
-/* --------------------------------------------------
- Thread lifetime
- =20
- Threads are all expressed in terms of internal ThreadIds. The
- thread library interface needs to map from the library's identifers
- to ThreadIds.
- -------------------------------------------------- */
-
-/* Per-thread state. We maintain our own here rather than hanging it
- off ThreadState, so that we have the option of not having a 1:1
- relationship between modelled threads and Valgrind threads. */
-struct thread
-{
- ThreadId tid;
- ThreadId creator;
-
- Bool detached; /* thread is detached */
-
- enum thread_state {
- TS_Alive, /* alive */
- TS_Zombie, /* waiting to be joined on (detached is False) */
- TS_Dead, /* all dead */
- =20
- TS_Running, /* running */
- TS_MutexBlocked, /* blocked on mutex */
- TS_CVBlocked, /* blocked on condvar */
- TS_JoinBlocked, /* blocked in join */
- } state;
-
- struct mutex *mx_blocked; /* mutex we're blocked on (state=3D=3DTS_M=
utexBlocked) */
- struct condvar *cv_blocked; /* condvar we're blocked on (state=3D=3DT=
S_CVBlocked) */
- struct thread *th_blocked; /* thread we're blocked on (state=3D=3DTS_=
JoinBlocked) */
-
- ExeContext *ec_created; /* where created */
- ExeContext *ec_blocked; /* where blocked/unblocked */
-};
-
-enum thread_error
-{
- THE_NotExist, /* thread doesn't exist */
- THE_NotAlive, /* thread isn't alive (use after death) */
- THE_Rebirth, /* thread already alive */
- THE_Blocked, /* thread not supposed to be blocked */
- THE_NotBlocked, /* thread supposed to be blocked */
- THE_Detached, /* thread is detached */
-};
-
-struct thread_error_data
-{
- enum thread_error err;
- struct thread *th;
- const Char *action;
-};
-
-static const Char *pp_threadstate(const struct thread *th)
-{
- if (th =3D=3D NULL)
- return "non-existent";
-
- switch(th->state) {
- case TS_Alive: return "alive";
- case TS_Zombie: return "zombie";
- case TS_Dead: return "dead";
- case TS_Running: return "running";
- case TS_MutexBlocked:return "mutex-blocked";
- case TS_CVBlocked: return "cv-blocked";
- case TS_JoinBlocked: return "join-blocked";
- default: return "???";
- }
-}
-
-static void thread_validate(struct thread *th)
-{
- switch(th->state) {
- case TS_Alive:
- case TS_Running:
- case TS_Dead:
- case TS_Zombie:
- vg_assert(th->mx_blocked =3D=3D NULL);
- vg_assert(th->cv_blocked =3D=3D NULL);
- vg_assert(th->th_blocked =3D=3D NULL);
- break;
-
- case TS_MutexBlocked:
- vg_assert(th->mx_blocked !=3D NULL);
- vg_assert(th->cv_blocked =3D=3D NULL);
- vg_assert(th->th_blocked =3D=3D NULL);
- break;
-
- case TS_CVBlocked:
- vg_assert(th->mx_blocked =3D=3D NULL);
- vg_assert(th->cv_blocked !=3D NULL);
- vg_assert(th->th_blocked =3D=3D NULL);
- break;
-
- case TS_JoinBlocked:
- vg_assert(th->mx_blocked =3D=3D NULL);
- vg_assert(th->cv_blocked =3D=3D NULL);
- vg_assert(th->th_blocked !=3D NULL);
- break;
- }
-}
-
-static void thread_setstate(struct thread *th, enum thread_state state)
-{
- ExeContext *ec;
-
- if (th->state =3D=3D state)
- return;
-
- ec =3D VG_(record_ExeContext)(th->tid);
-
- switch(state) {
- case TS_Alive:
- case TS_Dead:
- th->ec_created =3D ec;
- break;
-
- case TS_Running:
- case TS_MutexBlocked:
- case TS_CVBlocked:
- case TS_JoinBlocked:
- case TS_Zombie:
- th->ec_blocked =3D ec;
- }
-
- th->state =3D state;
- if (debug_thread)
- VG_(printf)("setting thread(%d) -> %s\n", th->tid, pp_threadstate(=
th));
- thread_validate(th);
-}
-
-static void do_thread_run(struct thread *th)
-{
- th->mx_blocked =3D NULL;
- th->cv_blocked =3D NULL;
- th->th_blocked =3D NULL;
- thread_setstate(th, TS_Running);
-}
-
-static void do_thread_block_mutex(struct thread *th, struct mutex *mx)
-{
- th->mx_blocked =3D mx;
- th->cv_blocked =3D NULL;
- th->th_blocked =3D NULL;
- thread_setstate(th, TS_MutexBlocked);
-}
-
-static void do_thread_block_condvar(struct thread *th, struct condvar *c=
v)
-{
- th->mx_blocked =3D NULL;
- th->cv_blocked =3D cv;
- th->th_blocked =3D NULL;
- thread_setstate(th, TS_CVBlocked);
-}
-
-static void do_thread_block_join(struct thread *th, struct thread *joine=
e)
-{
- th->mx_blocked =3D NULL;
- th->cv_blocked =3D NULL;
- th->th_blocked =3D joinee;
- thread_setstate(th, TS_JoinBlocked);
-}
-
-static void do_thread_block_zombie(struct thread *th)
-{
- th->mx_blocked =3D NULL;
- th->cv_blocked =3D NULL;
- th->th_blocked =3D NULL;
- thread_setstate(th, TS_Zombie);
-}
-
-static void do_thread_dead(struct thread *th)
-{
- th->mx_blocked =3D NULL;
- th->cv_blocked =3D NULL;
- th->th_blocked =3D NULL;
- thread_setstate(th, TS_Dead);
-}
-
-static OSet *threadSet =3D NULL;
-
-static struct thread *thread_get(ThreadId tid)
-{
- return VG_(OSet_Lookup)(threadSet, &tid);
-}
-
-static void thread_report(ThreadId tid, enum thread_error err, const Cha=
r *action)
-{
- Char *errstr =3D "?";
- struct thread *th =3D thread_get(tid);
- struct thread_error_data errdata;
-
- switch(err) {
- case THE_NotExist: errstr =3D "non existent"; break;
- case THE_NotAlive: errstr =3D "not alive"; break;
- case THE_Rebirth: errstr =3D "re-born"; break;
- case THE_Blocked: errstr =3D "blocked"; break;
- case THE_NotBlocked: errstr =3D "not blocked"; break;
- case THE_Detached: errstr =3D "detached"; break;
- }
-
- errdata.err =3D err;
- errdata.th =3D th;
- errdata.action =3D action;
- =20
- VG_(maybe_record_error)(VG_(get_running_tid)(), ThreadErr, 0, errstr,=
&errdata);
-}
-
-static void pp_thread_error(Error *err)
-{
- struct thread_error_data *errdata =3D VG_(get_error_extra)(err);
- struct thread *th =3D errdata->th;
- Char *errstr =3D VG_(get_error_string)(err);
- =20
- VG_(message)(Vg_UserMsg, "Found %s thread in state %s while %s",
- errstr, pp_threadstate(th), errdata->action);
- VG_(pp_ExeContext)(VG_(get_error_where)(err));
-
- if (th) {
- VG_(message)(Vg_UserMsg, " Thread %d was %s",
- th->tid, th->state =3D=3D TS_Dead ? "destroyed" : "created");
- VG_(pp_ExeContext)(th->ec_created);
- }
-}
-
-/* Thread creation */
-void VG_(tm_thread_create)(ThreadId creator, ThreadId tid, Bool detached=
)
-{
- struct thread *th =3D thread_get(tid);
-
- if (debug_thread)
- VG_(printf)("thread %d creates %d %s\n", creator, tid, detached ? =
"detached" : "");
- if (th !=3D NULL) {
- if (th->state !=3D TS_Dead)
- thread_report(tid, THE_Rebirth, "creating");
- } else {
- th =3D VG_(OSet_AllocNode)(threadSet, sizeof(struct thread));
- th->tid =3D tid;
- VG_(OSet_Insert)(threadSet, th);
- }
-
- th->creator =3D creator;
- th->detached =3D detached;
- th->mx_blocked =3D NULL;
- th->cv_blocked =3D NULL;
- th->th_blocked =3D NULL;
-
- thread_setstate(th, TS_Alive);
- do_thread_run(th);
-}
-
-Bool VG_(tm_thread_exists)(ThreadId tid)
-{
- struct thread *th =3D thread_get(tid);
-
- return th && th->state !=3D TS_Dead;
-}
-
-/* A thread is terminating itself
- - fails if tid has already terminated
- - if detached, tid becomes invalid for all further operations
- - if not detached, the thread remains in a Zombie state until
- someone joins on it
- */
-void VG_(tm_thread_exit)(ThreadId tid)
-{
- struct thread *th =3D thread_get(tid);
-
- if (th =3D=3D NULL)
- thread_report(tid, THE_NotExist, "exiting");
- else {
- struct thread *joiner;
-
- switch(th->state) {
- case TS_Dead:
- case TS_Zombie: /* already exited once */
- thread_report(tid, THE_NotAlive, "exiting");
- break;
-
- case TS_MutexBlocked:
- case TS_CVBlocked:
- case TS_JoinBlocked:
- thread_report(tid, THE_Blocked, "exiting");
- break;
-
- case TS_Alive:
- case TS_Running:
- /* OK */
- break;
- }
-
- /* ugly - walk all threads to find people joining with us */
- /* In pthreads its an error to have multiple joiners, but that
- seems a bit specific to implement here; there should a way
- for the thread library binding to handle this. */
- VG_(OSet_ResetIter)(threadSet);
- while ((joiner =3D VG_(OSet_Next)(threadSet)) !=3D NULL) {
- if (joiner->state =3D=3D TS_JoinBlocked && joiner->th_blocked =3D=3D t=
h) {
- /* found someone - wake them up */
- do_thread_run(joiner);
-
- /* we're dead */
- do_thread_dead(th);
- }
- }
-
- if (th->state !=3D TS_Dead)
- do_thread_block_zombie(th);
- }
-}
-
-void VG_(tm_thread_detach)(ThreadId tid)
-{
- struct thread *th =3D thread_get(tid);
-
- if (th =3D=3D NULL)
- thread_report(tid, THE_NotExist, "detaching");
- else {
- if (th->detached)
- thread_report(tid, THE_Detached, "detaching");
- else {
- /* XXX look for waiters */
- th->detached =3D True;
- }
- }
-}
-
-/* One thread blocks until another has terminated
- - fails if joinee is detached
- - fails if joinee doesn't exist
- - once the join completes, joinee is dead
- */
-void VG_(tm_thread_join)(ThreadId joinerid, ThreadId joineeid)
-{
- struct thread *joiner =3D thread_get(joinerid);
- struct thread *joinee =3D thread_get(joineeid);
-
- /* First, check the joinee thread's state */
- if (joinee =3D=3D NULL)
- thread_report(joineeid, THE_NotExist, "joining as joinee");
- else {
- switch(joinee->state) {
- case TS_Alive: /* really shouldn't see them in this state... */
- case TS_Running:
- case TS_Zombie:
- case TS_MutexBlocked:
- case TS_CVBlocked:
- case TS_JoinBlocked:
- /* OK */
- break;
-
- case TS_Dead:
- thread_report(joineeid, THE_NotAlive, "joining as joinee");
- break;
- }
- }
-
- /* now the joiner... */
- if (joiner =3D=3D NULL)
- thread_report(joineeid, THE_NotExist, "joining as joiner");
- else {
- switch(joiner->state) {
- case TS_Alive: /* ? */
- case TS_Running: /* OK */
- break;
-
- case TS_Zombie: /* back from the dead */
- case TS_Dead:
- thread_report(joineeid, THE_NotAlive, "joining as joiner");
- break;
-
- case TS_MutexBlocked:
- case TS_CVBlocked:
- case TS_JoinBlocked:
- thread_report(joineeid, THE_Blocked, "joining as joiner");
- break;
- }
-
- if (joinee->detached)
- thread_report(joineeid, THE_Detached, "joining as joiner");
- else {
- /* block if the joinee hasn't exited yet */
- if (joinee) {
- switch(joinee->state) {
- case TS_Dead:
- break;
-
- default:
- if (joinee->state =3D=3D TS_Zombie)
- do_thread_dead(joinee);
- else
- do_thread_block_join(joiner, joinee);
- }
- }
- }
- }
-}
-
-/* Context switch to a new thread */
-void VG_(tm_thread_switchto)(ThreadId tid)
-{
- VG_TRACK( thread_run, tid );
-}
-
-static void thread_block_mutex(ThreadId tid, struct mutex *mx)
-{
- struct thread *th =3D thread_get(tid);
-
- if (th =3D=3D NULL) {
- /* should an unknown thread doing something make it spring to life=
? */
- thread_report(tid, THE_NotExist, "blocking on mutex");
- return;
- }
- switch(th->state) {
- case TS_Dead:
- case TS_Zombie:
- thread_report(th->tid, THE_NotAlive, "blocking on mutex");
- break;
-
- case TS_MutexBlocked:
- case TS_CVBlocked:
- case TS_JoinBlocked:
- thread_report(th->tid, THE_Blocked, "blocking on mutex");
- break;
-
- case TS_Alive:
- case TS_Running: /* OK */
- break;
- }
-
- do_thread_block_mutex(th, mx);
-}
-
-static void thread_unblock_mutex(ThreadId tid, struct mutex *mx, const C=
har *action)
-{
- struct thread *th =3D thread_get(tid);
-
- if (th =3D=3D NULL) {
- /* should an unknown thread doing something make it spring to life=
? */
- thread_report(tid, THE_NotExist, "giving up on mutex");
- return;
- }
-
- switch(th->state) {
- case TS_MutexBlocked: /* OK */
- break;
-
- case TS_Alive:
- case TS_Running:
- thread_report(tid, THE_NotBlocked, action);
- break;
-
- case TS_CVBlocked:
- case TS_JoinBlocked:
- thread_report(tid, THE_Blocked, action);
- break;
-
- case TS_Dead:
- case TS_Zombie:
- thread_report(tid, THE_NotAlive, action);
- break;
- }
-
- do_thread_run(th);
-}
-
-/* --------------------------------------------------
- Mutexes
-
- This models simple, non-recursive mutexes.
- -------------------------------------------------- */
-
-struct mutex
-{
- Addr mutex; /* address of mutex */
- ThreadId owner; /* owner if state =3D=3D MX_Locked */
- enum mutex_state {
- MX_Init,
- MX_Free,
- MX_Locked,
- MX_Unlocking, /* half-unlocked */
- MX_Dead
- } state; /* mutex state */
-
- ExeContext *ec_create; /* where created/destroyed */
- ExeContext *ec_locked; /* where last locked/unlocked */
-};
-
-enum mutex_error
-{
- MXE_NotExist, /* never existed */
- MXE_NotInit, /* not initialized (use after destroy) */
- MXE_ReInit, /* already initialized */
- MXE_NotLocked, /* not locked */
- MXE_Locked, /* is locked */
- MXE_Deadlock, /* deadlock detected */
- MXE_NotOwner, /* non-owner trying to change lock */
-};
-
-struct mutex_error_data
-{
- enum mutex_error err;
- struct mutex *mx;
- const Char *action;
-};
-
-static struct mutex *mutex_get(Addr mutexp);
-
-static const Char *pp_mutexstate(const struct mutex *mx)
-{
- static Char buf[20];
-
- switch(mx->state) {
- case MX_Init: return "Init";
- case MX_Free: return "Free";
- case MX_Dead: return "Dead";
-
- case MX_Locked:
- VG_(sprintf)(buf, "Locked by tid %d", mx->owner);
- break;
-
- case MX_Unlocking:
- VG_(sprintf)(buf, "Being unlocked by tid %d", mx->owner);
- break;
-
- default:
- VG_(sprintf)(buf, "?? %d", mx->state);
- break;
- }
-
- return buf;
-}
-
-static void mutex_setstate(ThreadId tid, struct mutex *mx, enum mutex_st=
ate st)
-{
- ExeContext *ec =3D VG_(record_ExeContext)(tid);
-
- switch(st) {
- case MX_Init:
- case MX_Dead:
- mx->ec_create =3D ec;
- break;
-
- case MX_Unlocking:
- case MX_Locked:
- case MX_Free:
- mx->ec_locked =3D ec;
- break;
- }
-
- mx->state =3D st;
- if (debug_mutex)
- VG_(printf)("setting mutex(%p) -> %s\n", mx->mutex, pp_mutexstate(=
mx));
-}
-
-static void mutex_report(ThreadId tid, Addr mutexp, enum mutex_error err=
, const Char *action)
-{
- Char *errstr=3D"?";
- struct mutex *mx =3D mutex_get(mutexp);
- struct mutex_error_data errdata;
-
- switch(err) {
- case MXE_NotExist: errstr=3D"non-existent"; break;
- case MXE_NotInit: errstr=3D"uninitialized"; break;
- case MXE_ReInit: errstr=3D"already initialized"; break;
- case MXE_NotLocked: errstr=3D"not locked"; break;
- case MXE_Locked: errstr=3D"locked"; break;
- case MXE_NotOwner: errstr=3D"unowned"; break;
- case MXE_Deadlock: errstr=3D"deadlock on"; break;
- }
-
- errdata.err =3D err;
- errdata.mx =3D mx;
- errdata.action =3D action;
- =20
- VG_(maybe_record_error)(tid, MutexErr, 0, errstr, &errdata);
-}
-
-static void pp_mutex_error(Error *err)
-{
- struct mutex_error_data *errdata =3D VG_(get_error_extra)(err);
- struct mutex *mx =3D errdata->mx;
- Char *errstr =3D VG_(get_error_string)(err);
- =20
- VG_(message)(Vg_UserMsg, "Found %s mutex %p while %s",
- errstr, mx ? mx->mutex : 0, errdata->action);
- VG_(pp_ExeContext)(VG_(get_error_where)(err));
-
- switch (mx->state) {
- case MX_Init:
- case MX_Dead:
- break;
- case MX_Locked:
- VG_(message)(Vg_UserMsg, " Mutex was locked by thread %d", mx->=
owner);
- VG_(pp_ExeContext)(mx->ec_locked);
- break;
- case MX_Unlocking:
- VG_(message)(Vg_UserMsg, " Mutex being unlocked");
- VG_(pp_ExeContext)(mx->ec_locked);
- break;
- case MX_Free:
- VG_(message)(Vg_UserMsg, " Mutex was unlocked");
- VG_(pp_ExeContext)(mx->ec_locked);
- break;
- }
-
- VG_(message)(Vg_UserMsg, " Mutex was %s",
- mx->state =3D=3D MX_Dead ? "destroyed" : "created");
- VG_(pp_ExeContext)(mx->ec_create);
-}
-
-static OSet *mutexSet =3D NULL;
-
-static struct mutex *mutex_get(Addr mutexp)
-{
- return VG_(OSet_Lookup)(mutexSet, &mutexp);
-}
-
-static Bool mx_is_initialized(Addr mutexp)
-{
- const struct mutex *mx =3D mutex_get(mutexp);
-
- return mx && mx->state !=3D MX_Dead;
-}
-
-static struct mutex *mutex_check_initialized(ThreadId tid, Addr mutexp, =
const Char *action)
-{
- struct mutex *mx;
-
- vg_assert(tid !=3D VG_INVALID_THREADID);
-
- if (!mx_is_initialized(mutexp)) {
- mutex_report(tid, mutexp, MXE_NotInit, action);
- VG_(tm_mutex_init)(tid, mutexp);
- }
-
- mx =3D mutex_get(mutexp);
- vg_assert(mx !=3D NULL);
-
- return mx;
-}
-
-#if 0
-static Bool mx_is_locked(Addr mutexp)
-{
- const struct mutex *mx =3D mutex_get(mutexp);
-
- return mx && (mx->state =3D=3D MX_Locked);
-}
-#endif
-
-/* Mutex at mutexp is initialized. This must be done before any
- further mutex operations are OK. Fails if:
- - mutexp already exists (and is locked?)
-*/
-void VG_(tm_mutex_init)(ThreadId tid, Addr mutexp)
-{
- struct mutex *mx =3D mutex_get(mutexp);
-
- if (mx =3D=3D NULL) {
- mx =3D VG_(OSet_AllocNode)(mutexSet, sizeof(struct mutex));
- mx->mutex =3D mutexp;
- VG_(OSet_Insert)(mutexSet, mx);
- } else if (mx->state !=3D MX_Dead)
- mutex_report(tid, mutexp, MXE_ReInit, "initializing");
-
- mx->owner =3D VG_INVALID_THREADID;
-
- mutex_setstate(tid, mx, MX_Init);
- mutex_setstate(tid, mx, MX_Free);
-}
-
-Bool VG_(tm_mutex_exists)(Addr mutexp)
-{
- return mx_is_initialized(mutexp);
-}
-
-/* Mutex is being destroyed. Fails if:
- - mutex was not initialized
- - mutex is locked (?)
- */
-void VG_(tm_mutex_destroy)(ThreadId tid, Addr mutexp)
-{
- struct mutex *mx =3D mutex_get(mutexp);
-
- if (mx =3D=3D NULL)
- mutex_report(tid, mutexp, MXE_NotExist, "destroying");
- else {
- switch(mx->state) {
- case MX_Dead:
- mutex_report(tid, mutexp, MXE_NotInit, "destroying");
- break;
-
- case MX_Locked:
- case MX_Unlocking:
- mutex_report(tid, mutexp, MXE_Locked, "destroying");
- VG_(tm_mutex_unlock)(tid, mutexp);
- break;
-
- case MX_Init:
- case MX_Free:
- /* OK */
- break;
- }
- mutex_setstate(tid, mx, MX_Dead);
- }
-}
-
-/* A thread attempts to lock a mutex. If "blocking" then the thread
- is put into a blocked state until the lock is acquired. Fails if:
- - tid is invalid
- - mutex has not been initialized
- - thread is blocked on another object (?)
- - blocking on this mutex could cause a deadlock
- (Lock rank detection?)
- */
-void VG_(tm_mutex_trylock)(ThreadId tid, Addr mutexp)
-{
- struct mutex *mx;
-
- mx =3D mutex_check_initialized(tid, mutexp, "trylocking");
-
- thread_block_mutex(tid, mx);
-
- if (mx->state =3D=3D MX_Locked && mx->owner =3D=3D tid) /* deadlock *=
/
- mutex_report(tid, mutexp, MXE_Deadlock, "trylocking");
-
- VG_TRACK( pre_mutex_lock, tid, mutexp );
-}
-
-/* Give up waiting for a mutex. Fails if:
- - thread is not currently blocked on the mutex
- */
-void VG_(tm_mutex_giveup)(ThreadId tid, Addr mutexp)
-{
- struct mutex *mx;
-
- mx =3D mutex_check_initialized(tid, mutexp, "giving up");
-
- thread_unblock_mutex(tid, mx, "giving up on mutex");
-}
-
-/* A thread acquires a mutex. Fails if:
- - thread is not blocked waiting for the mutex
- - mutex is held by another thread
- */
-void VG_(tm_mutex_acquire)(ThreadId tid, Addr mutexp)
-{
- struct mutex *mx;
-
- mx =3D mutex_check_initialized(tid, mutexp, "acquiring"); =20
- =20
- switch(mx->state) {
- case MX_Unlocking: /* ownership transfer or relock */
- VG_TRACK( post_mutex_unlock, mx->owner, mutexp );
- if (mx->owner !=3D tid)
- thread_unblock_mutex(tid, mx, "acquiring mutex");
- break;
-
- case MX_Free:
- thread_unblock_mutex(tid, mx, "acquiring mutex");
- break;
-
- case MX_Locked:
- if (debug_mutex)
- VG_(printf)("mutex=3D%p mx->state=3D%s\n", mutexp, pp_mutexstate(mx));
- VG_TRACK( post_mutex_unlock, mx->owner, mutexp );
- mutex_report(tid, mutexp, MXE_Locked, "acquiring");
- thread_unblock_mutex(tid, mx, "acquiring mutex");
- break;
-
- case MX_Init:
- case MX_Dead:
- vg_assert(0);
- }=20
- =20
- mx->owner =3D tid;
- mutex_setstate(tid, mx, MX_Locked);
-
- VG_TRACK( post_mutex_lock, tid, mutexp );
-}
-
-/* Try unlocking a lock. This will move it into a state where it can
- either be unlocked, or change ownership to another thread. If
- unlock fails, it will remain locked. */
-void VG_(tm_mutex_tryunlock)(ThreadId tid, Addr mutexp)
-{
- struct thread *th;
- struct mutex *mx;
-
- mx =3D mutex_check_initialized(tid, mutexp, "try-unlocking");
-
- th =3D thread_get(tid);
-
- if (th =3D=3D NULL)
- thread_report(tid, THE_NotExist, "try-unlocking mutex");
- else {
- switch(th->state) {
- case TS_Alive:
- case TS_Running: /* OK */
- break;
-
- case TS_Dead:
- case TS_Zombie:
- thread_report(tid, THE_NotAlive, "try-unlocking mutex");
- break;
-
- case TS_JoinBlocked:
- case TS_CVBlocked:
- case TS_MutexBlocked:
- thread_report(tid, THE_Blocked, "try-unlocking mutex");
- do_thread_run(th);
- break;
- }
- }
-
- switch(mx->state) {
- case MX_Locked:
- if (mx->owner !=3D tid)
- mutex_report(tid, mutexp, MXE_NotOwner, "try-unlocking");
- break;
-
- case MX_Free:
- mutex_report(tid, mutexp, MXE_NotLocked, "try-unlocking");
- break;
-
- case MX_Unlocking:
- mutex_report(tid, mutexp, MXE_NotLocked, "try-unlocking");
- break;
-
- case MX_Init:
- case MX_Dead:
- vg_assert(0);
- }
-
- mutex_setstate(tid, mx, MX_Unlocking);
-}
-
-/* Finish unlocking a Mutex. The mutex can validly be in one of three
- states:
- - Unlocking
- - Locked, owned by someone else (someone else got it in the meantime)
- - Free (someone else completed a lock-unlock cycle)
- */
-void VG_(tm_mutex_unlock)(ThreadId tid, Addr mutexp)
-{
- struct mutex *mx;
- struct thread *th;
-
- mx =3D mutex_check_initialized(tid, mutexp, "unlocking mutex");
-
- th =3D thread_get(tid);
-
- if (th =3D=3D NULL)
- thread_report(tid, THE_NotExist, "unlocking mutex");
- else {
- switch(th->state) {
- case TS_Alive:
- case TS_Running: /* OK */
- break;
-
- case TS_Dead:
- case TS_Zombie:
- thread_report(tid, THE_NotAlive, "unlocking mutex");
- break;
-
- case TS_JoinBlocked:
- case TS_CVBlocked:
- case TS_MutexBlocked:
- thread_report(tid, THE_Blocked, "unlocking mutex");
- do_thread_run(th);
- break;
- }
- }
-
- switch(mx->state) {
- case MX_Locked:
- /* Someone else might have taken ownership in the meantime */
- if (mx->owner =3D=3D tid)
- mutex_report(tid, mutexp, MXE_Locked, "unlocking");
- break;
-
- case MX_Free:
- /* OK - nothing to do */
- break;
-
- case MX_Unlocking:
- /* OK - we need to complete the unlock */
- VG_TRACK( post_mutex_unlock, tid, mutexp );
- mutex_setstate(tid, mx, MX_Free);
- break;
-
- case MX_Init:
- case MX_Dead:
- vg_assert(0);
- }
-}
-
-/* --------------------------------------------------
- Condition variables
- -------------------------------------------------- */
-
-struct condvar_waiter
-{
- ThreadId waiter;
- =20
- struct condvar *condvar;
- struct mutex *mutex;
-
- struct condvar_waiter *next;
-};
-
-struct condvar=20
-{
- Addr condvar;
-
- enum condvar_state {
- CV_Dead,
- CV_Alive,
- } state;
-
- struct condvar_waiter *waiters; // XXX skiplist?
-
- =20
- ExeContext *ec_created; // where created
- ExeContext *ec_signalled; // where last signalled
-};
-
-enum condvar_err {
- CVE_NotExist,
- CVE_NotInit,
- CVE_ReInit,
- CVE_Busy,
- CVE_Blocked,
-};
-
-static OSet *condvarSet =3D NULL;
-
-static struct condvar *condvar_get(Addr condp)
-{
- return VG_(OSet_Lookup)(condvarSet, &condp);
-}
-
-static Bool condvar_is_initialized(Addr condp)
-{
- const struct condvar *cv =3D condvar_get(condp);
-
- return cv && cv->state !=3D CV_Dead;
-}
-
-static void condvar_report(ThreadId tid, Addr condp, enum condvar_err er=
r, const Char *action)
-{
-}
-
-static struct condvar *condvar_check_initialized(ThreadId tid, Addr cond=
p, const Char *action)
-{
- struct condvar *cv;
- vg_assert(tid !=3D VG_INVALID_THREADID);
- =20
- if (!condvar_is_initialized(condp)) {
- condvar_report(tid, condp, CVE_NotInit, action);
- VG_(tm_cond_init)(tid, condp);
- }
-
- cv =3D condvar_get(condp);
- vg_assert(cv !=3D NULL);
-
- return cv;
-}
-
-/* Initialize a condition variable. Fails if:
- - condp has already been initialized
- */
-void VG_(tm_cond_init)(ThreadId tid, Addr condp)
-{
- struct condvar *cv =3D condvar_get(condp);
-
- if (cv =3D=3D NULL) {
- cv =3D VG_(OSet_AllocNode)(condvarSet, sizeof(struct condvar));
- cv->condvar =3D condp;
- cv->waiters =3D NULL;
- VG_(OSet_Insert)(condvarSet, cv);
- } else if (cv->state !=3D CV_Dead) {
- condvar_report(tid, condp, CVE_ReInit, "initializing");
- /* ? what about existing waiters? */
- }
-
- cv->state =3D CV_Alive;
-}
-
-/* Destroy a condition variable. Fails if:
- - condp has not been initialized
- - condp is currently being waited on
- */
-void VG_(tm_cond_destroy)(ThreadId tid, Addr condp)
-{
- struct condvar *cv =3D condvar_get(condp);
-
- if (cv =3D=3D NULL)
- condvar_report(tid, condp, CVE_NotExist, "destroying");
- else {
- if (cv->state !=3D CV_Alive)
- condvar_report(tid, condp, CVE_NotInit, "destroying");
- if (cv->waiters !=3D NULL)
- condvar_report(tid, condp, CVE_Busy, "destroying");
- cv->state =3D CV_Dead;
- }
-}
-
-static struct condvar_waiter *get_waiter(const struct condvar *cv, Threa=
dId tid)
-{
- struct condvar_waiter *w;
-
- for(w =3D cv->waiters; w; w =3D w->next)
- if (w->waiter =3D=3D tid)
- return w;
- return NULL;
-}
-
-/* Wait for a condition, putting thread into blocked state. Fails if:
- - condp has not been initialized
- - thread doesn't hold mutexp
- - thread is blocked on some other object
- - thread is already blocked on mutex
- */
-void VG_(tm_cond_wait)(ThreadId tid, Addr condp, Addr mutexp)
-{
- struct thread *th =3D thread_get(tid);
- struct mutex *mx;
- struct condvar *cv;
- struct condvar_waiter *waiter;
-
- /* Condvar must exist */
- cv =3D condvar_check_initialized(tid, condp, "waiting");
-
- /* Mutex must exist */
- mx =3D mutex_check_initialized(tid, mutexp, "waiting on condvar");
-
- /* Thread must own mutex */
- if (mx->state !=3D MX_Locked) {
- mutex_report(tid, mutexp, MXE_NotLocked, "waiting on condvar");
- VG_(tm_mutex_trylock)(tid, mutexp);
- VG_(tm_mutex_acquire)(tid, mutexp);
- } else if (mx->owner !=3D tid) {
- mutex_report(tid, mutexp, MXE_NotOwner, "waiting on condvar");
- mx->owner =3D tid;
- }
-
- /* Thread must not be already waiting for condvar */
- waiter =3D get_waiter(cv, tid);
- if (waiter !=3D NULL)
- condvar_report(tid, condp, CVE_Blocked, "waiting");
- else {
- waiter =3D VG_(arena_malloc)(VG_AR_CORE, sizeof(*waiter));
- waiter->condvar =3D cv;
- waiter->mutex =3D mx;
- waiter->next =3D cv->waiters;
- cv->waiters =3D waiter;
- }
-
- /* Thread is now blocking on condvar */
- do_thread_block_condvar(th, cv);
-
- /* (half) release mutex */
- VG_(tm_mutex_tryunlock)(tid, mutexp);
-}
-
-/* Wake from a condition, either because we've been signalled, or
- because of timeout. Fails if:
- - thread is not waiting on condp
- */
-void VG_(tm_cond_wakeup)(ThreadId tid, Addr condp, Addr mutexp)
-{
-}
-
-/* Signal a condition variable. Fails if:
- - condp has not been initialized
- */
-void VG_(tm_cond_signal)(ThreadId tid, Addr condp)
-{
-}
-
-/* --------------------------------------------------
- Error handling
- -------------------------------------------------- */
-
-UInt VG_(tm_error_update_extra)(Error *err)
-{
- switch (VG_(get_error_kind)(err)) {
- case ThreadErr: {
- struct thread_error_data *errdata =3D VG_(get_error_extra)(err)=
;
- struct thread *new_th =3D VG_(arena_malloc)(VG_AR_CORE, sizeof(=
struct thread));
-
- VG_(memcpy)(new_th, errdata->th, sizeof(struct thread));
-
- errdata->th =3D new_th;
-
- return sizeof(struct thread_error_data);
- }
-
- case MutexErr: {
- struct mutex_error_data *errdata =3D VG_(get_error_extra)(err);
- struct mutex *new_mx =3D VG_(arena_malloc)(VG_AR_CORE, sizeof(s=
truct mutex));
-
- VG_(memcpy)(new_mx, errdata->mx, sizeof(struct mutex));
-
- errdata->mx =3D new_mx;
-
- return sizeof(struct mutex_error_data);
- }
-
- default:
- return 0;
- }
-}
-
-Bool VG_(tm_error_equal)(VgRes res, Error *e1, Error *e2)
-{
- /* Guaranteed by calling function */
- vg_assert(VG_(get_error_kind)(e1) =3D=3D VG_(get_error_kind)(e2));
- =20
- switch (VG_(get_error_kind)(e1)) {
- case ThreadErr: {
- struct thread_error_data *errdata1 =3D VG_(get_error_extra)(e1)=
;
- struct thread_error_data *errdata2 =3D VG_(get_error_extra)(e2)=
;
-
- return errdata1->err =3D=3D errdata2->err;
- }
-
- case MutexErr: {
- struct mutex_error_data *errdata1 =3D VG_(get_error_extra)(e1);
- struct mutex_error_data *errdata2 =3D VG_(get_error_extra)(e2);
-
- return errdata1->err =3D=3D errdata2->err;
- }
-
- default:=20
- VG_(printf)("Error:\n unknown error code %d\n",
- VG_(get_error_kind)(e1));
- VG_(core_panic)("unknown error code in VG_(tm_error_equal)");
- }
-}
-
-void VG_(tm_error_print)(Error *err)
-{
- switch (VG_(get_error_kind)(err)) {
- case ThreadErr:
- pp_thread_error(err);
- break;
- case MutexErr:
- pp_mutex_error(err);
- break;
- }
-}
-
-/* --------------------------------------------------
- Initialisation
- -------------------------------------------------- */
-
-static Word tm_compare_tid(ThreadId *tid1, ThreadId *tid2)
-{
- if (*tid1 < *tid2) return -1;
- if (*tid1 > *tid2) return 1;
- return 0;
-}
-
-static Word tm_compare_addr(Addr *addr1, Addr *addr2)
-{
- if (*addr1 < *addr2) return -1;
- if (*addr1 > *addr2) return 1;
- return 0;
-}
-
-static void* oset_malloc(SizeT szB)
-{
- return VG_(arena_malloc)(VG_AR_CORE, szB);
-}
-
-static void oset_free(void * p)
-{
- VG_(arena_free)(VG_AR_CORE, p);
-}
-
-void VG_(tm_init)()
-{
- VG_(needs_core_errors)();
-
- threadSet =3D VG_(OSet_Create)(offsetof(struct thread, tid),
- (OSetCmp_t)tm_compare_tid,
- oset_malloc, oset_free);
- mutexSet =3D VG_(OSet_Create)(offsetof(struct mutex, mutex),
- (OSetCmp_t)tm_compare_addr,
- oset_malloc, oset_free);
- condvarSet =3D VG_(OSet_Create)(offsetof(struct condvar, condvar),
- (OSetCmp_t)tm_compare_addr,
- oset_malloc, oset_free);
-}
-
-/*--------------------------------------------------------------------*/
-/*--- end ---*/
-/*--------------------------------------------------------------------*/
Modified: trunk/coregrind/pub_core_errormgr.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/pub_core_errormgr.h 2006-12-14 00:28:50 UTC (rev 6398=
)
+++ trunk/coregrind/pub_core_errormgr.h 2006-12-14 02:55:58 UTC (rev 6399=
)
@@ -39,12 +39,13 @@
=20
#include "pub_tool_errormgr.h"
=20
-// XXX: should this be in pthreadmodel.c?
// These must be negative, so as to not overlap with tool error kinds.
typedef
enum {=20
- ThreadErr =3D -1, // Thread error
- MutexErr =3D -2, // Mutex error
+ // Nb: thread errors are a relic of the time when Valgrind's core
+ // could detect them. This example is left as an example should n=
ew
+ // core errors ever be added.
+ ThreadErr =3D -1,
}
CoreErrorKind;
=20
Deleted: trunk/coregrind/pub_core_pthreadmodel.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/pub_core_pthreadmodel.h 2006-12-14 00:28:50 UTC (rev =
6398)
+++ trunk/coregrind/pub_core_pthreadmodel.h 2006-12-14 02:55:58 UTC (rev =
6399)
@@ -1,50 +0,0 @@
-
-/*--------------------------------------------------------------------*/
-/*--- Pthread modelling. pub_core_pthreadmodel.h ---*/
-/*--------------------------------------------------------------------*/
-
-/*
- This file is part of Valgrind, a dynamic binary instrumentation
- framework.
-
- Copyright (C) 2005 Jer...
[truncated message content] |
|
From: <js...@ac...> - 2006-12-14 01:16:26
|
Nightly build on g5 ( SuSE 10.1, ppc970 ) started at 2006-12-14 02:00:01 CET Results unchanged from 24 hours ago Checking out valgrind source tree ... done Configuring valgrind ... done Building valgrind ... done Running regression tests ... failed Regression test results follow == 221 tests, 6 stderr failures, 4 stdout failures, 0 posttest failures == memcheck/tests/deep_templates (stdout) memcheck/tests/leak-cycle (stderr) memcheck/tests/leak-tree (stderr) memcheck/tests/pointer-trace (stderr) none/tests/faultstatus (stderr) none/tests/fdleak_cmsg (stderr) none/tests/mremap (stderr) none/tests/mremap2 (stdout) none/tests/ppc32/jm-int (stdout) none/tests/ppc64/jm-int (stdout) |
|
From: <sv...@va...> - 2006-12-14 00:28:53
|
Author: njn
Date: 2006-12-14 00:28:50 +0000 (Thu, 14 Dec 2006)
New Revision: 6398
Log:
Remove some very old and incorrect info in the headers.
Modified:
trunk/glibc-2.2.supp
trunk/glibc-2.3.supp
trunk/glibc-2.4.supp
trunk/glibc-2.5.supp
trunk/xfree-3.supp
trunk/xfree-4.supp
Modified: trunk/glibc-2.2.supp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/glibc-2.2.supp 2006-12-13 14:35:03 UTC (rev 6397)
+++ trunk/glibc-2.2.supp 2006-12-14 00:28:50 UTC (rev 6398)
@@ -22,7 +22,6 @@
#
# and the optional extra info is:
# if Param: name of system call param
-# if Free: name of free-ing fn)
=20
#-------- For SuSE 8.2 (gcc 3.3, glibc 2.3.2)
{
Modified: trunk/glibc-2.3.supp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/glibc-2.3.supp 2006-12-13 14:35:03 UTC (rev 6397)
+++ trunk/glibc-2.3.supp 2006-12-14 00:28:50 UTC (rev 6398)
@@ -22,7 +22,6 @@
#
# and the optional extra info is:
# if Param: name of system call param
-# if Free: name of free-ing fn)
=20
{
__GI___stpcpy/*
Modified: trunk/glibc-2.4.supp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/glibc-2.4.supp 2006-12-13 14:35:03 UTC (rev 6397)
+++ trunk/glibc-2.4.supp 2006-12-14 00:28:50 UTC (rev 6398)
@@ -22,7 +22,6 @@
#
# and the optional extra info is:
# if Param: name of system call param
-# if Free: name of free-ing fn)
=20
##----------------------------------------------------------------------=
##
## Suppressions for Fedora Core 5 on ppc32/amd64 (glibc-2.3.90)
Modified: trunk/glibc-2.5.supp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/glibc-2.5.supp 2006-12-13 14:35:03 UTC (rev 6397)
+++ trunk/glibc-2.5.supp 2006-12-14 00:28:50 UTC (rev 6398)
@@ -22,7 +22,6 @@
#
# and the optional extra info is:
# if Param: name of system call param
-# if Free: name of free-ing fn)
=20
{
dl-hack1
Modified: trunk/xfree-3.supp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/xfree-3.supp 2006-12-13 14:35:03 UTC (rev 6397)
+++ trunk/xfree-3.supp 2006-12-14 00:28:50 UTC (rev 6398)
@@ -22,7 +22,6 @@
#
# and the optional extra info is:
# if Param: name of system call param
-# if Free: name of free-ing fn)
=20
##----------------------------------------------------------------------=
##
=20
Modified: trunk/xfree-4.supp
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/xfree-4.supp 2006-12-13 14:35:03 UTC (rev 6397)
+++ trunk/xfree-4.supp 2006-12-14 00:28:50 UTC (rev 6398)
@@ -22,7 +22,6 @@
#
# and the optional extra info is:
# if Param: name of system call param
-# if Free: name of free-ing fn)
=20
# Resulting from R H 8.0
{
|
|
From: Julian S. <js...@ac...> - 2006-12-14 00:02:42
|
On Wednesday 13 December 2006 09:26, Bart Van Assche wrote: > On 12/13/06, Tom Hughes <to...@co...> wrote: > > I think the problem is that pthread_spin_unlock is an alias for > > pthread_spin_init (ie they are the same routine) and valgrind sees > > the init routine first so attaches that name to the address: > > > > dellow [~] % objdump -T /lib64/libpthread.so.0 | grep > > pthread_spin_unlock 000000382700ab70 g DF .text 0000000000000009 > > GLIBC_2.2.5 pthread_spin_unlock > > > > dellow [~] % objdump -T /lib64/libpthread.so.0 | grep 000000382700ab70 > > 000000382700ab70 g DF .text 0000000000000009 GLIBC_2.2.5 > > pthread_spin_init 000000382700ab70 g DF .text 0000000000000009 > > GLIBC_2.2.5 pthread_spin_unlock > > > > I don't think valgrind's symbol table can cope with a many-one mapping > > from names to addresses, so we just remember the first name we see. > > > > Given that the main use of the symbol table is mapping the other way > > for backtraces, this makes some sense, as you can only show one name > > for an address in a backtrace. > > > > Tom > > This explanation sounds perfectly reasonable, but doesn't give me a > solution: does the above mean that it's impossible to implement a > wrapper for pthread_spin_unlock() in a Valgrind tool ? Well, you could write a wrapper for pthread_spin_init() instead? Or supply wrappers for both, factoring the real work into a routine shared by both wrappers. The latter sounds like a more robust approach. J |