mirror of
https://github.com/ioacademy-jikim/debugging
synced 2026-08-30 09:19:28 +00:00
first commit
This commit is contained in:
+1
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,221 @@
|
||||
|
||||
include $(top_srcdir)/Makefile.tool-tests.am
|
||||
|
||||
dist_noinst_SCRIPTS = filter_stderr \
|
||||
filter_stderr_solaris \
|
||||
filter_helgrind \
|
||||
filter_xml
|
||||
|
||||
EXTRA_DIST = \
|
||||
annotate_hbefore.vgtest annotate_hbefore.stdout.exp \
|
||||
annotate_hbefore.stderr.exp \
|
||||
annotate_rwlock.vgtest annotate_rwlock.stdout.exp \
|
||||
annotate_rwlock.stderr.exp \
|
||||
annotate_smart_pointer.vgtest annotate_smart_pointer.stdout.exp \
|
||||
annotate_smart_pointer.stderr.exp \
|
||||
cond_init_destroy.vgtest cond_init_destroy.stderr.exp \
|
||||
cond_timedwait_invalid.vgtest cond_timedwait_invalid.stdout.exp \
|
||||
cond_timedwait_invalid.stderr.exp \
|
||||
cond_timedwait_test.vgtest cond_timedwait_test.stdout.exp \
|
||||
cond_timedwait_test.stderr.exp \
|
||||
bar_bad.vgtest bar_bad.stdout.exp bar_bad.stderr.exp \
|
||||
bar_trivial.vgtest bar_trivial.stdout.exp bar_trivial.stderr.exp \
|
||||
free_is_write.vgtest free_is_write.stdout.exp \
|
||||
free_is_write.stderr.exp \
|
||||
hg01_all_ok.vgtest hg01_all_ok.stdout.exp hg01_all_ok.stderr.exp \
|
||||
hg02_deadlock.vgtest hg02_deadlock.stdout.exp hg02_deadlock.stderr.exp \
|
||||
hg03_inherit.vgtest hg03_inherit.stdout.exp hg03_inherit.stderr.exp \
|
||||
hg04_race.vgtest hg04_race.stdout.exp hg04_race.stderr.exp \
|
||||
hg05_race2.vgtest hg05_race2.stdout.exp hg05_race2.stderr.exp \
|
||||
hg06_readshared.vgtest hg06_readshared.stdout.exp \
|
||||
hg06_readshared.stderr.exp \
|
||||
locked_vs_unlocked1_fwd.vgtest \
|
||||
locked_vs_unlocked1_fwd.stderr.exp \
|
||||
locked_vs_unlocked1_fwd.stdout.exp \
|
||||
locked_vs_unlocked1_rev.vgtest \
|
||||
locked_vs_unlocked1_rev.stderr.exp \
|
||||
locked_vs_unlocked1_rev.stdout.exp \
|
||||
locked_vs_unlocked2.vgtest \
|
||||
locked_vs_unlocked2.stderr.exp \
|
||||
locked_vs_unlocked2.stdout.exp \
|
||||
locked_vs_unlocked3.vgtest \
|
||||
locked_vs_unlocked3.stderr.exp \
|
||||
locked_vs_unlocked3.stdout.exp \
|
||||
pth_barrier1.vgtest pth_barrier1.stdout.exp pth_barrier1.stderr.exp \
|
||||
pth_barrier2.vgtest pth_barrier2.stdout.exp pth_barrier2.stderr.exp \
|
||||
pth_barrier3.vgtest pth_barrier3.stdout.exp pth_barrier3.stderr.exp \
|
||||
pth_destroy_cond.vgtest \
|
||||
pth_destroy_cond.stdout.exp pth_destroy_cond.stderr.exp \
|
||||
pth_cond_destroy_busy.vgtest pth_cond_destroy_busy.stderr.exp \
|
||||
pth_cond_destroy_busy.stderr.exp-ppc64 \
|
||||
pth_cond_destroy_busy.stderr.exp-solaris \
|
||||
pth_spinlock.vgtest pth_spinlock.stdout.exp pth_spinlock.stderr.exp \
|
||||
rwlock_race.vgtest rwlock_race.stdout.exp rwlock_race.stderr.exp \
|
||||
rwlock_test.vgtest rwlock_test.stdout.exp rwlock_test.stderr.exp \
|
||||
shmem_abits.vgtest shmem_abits.stdout.exp shmem_abits.stderr.exp \
|
||||
stackteardown.vgtest stackteardown.stdout.exp stackteardown.stderr.exp \
|
||||
t2t_laog.vgtest t2t_laog.stdout.exp t2t_laog.stderr.exp \
|
||||
tc01_simple_race.vgtest tc01_simple_race.stdout.exp \
|
||||
tc01_simple_race.stderr.exp \
|
||||
tc02_simple_tls.vgtest tc02_simple_tls.stdout.exp \
|
||||
tc02_simple_tls.stderr.exp \
|
||||
tc03_re_excl.vgtest tc03_re_excl.stdout.exp \
|
||||
tc03_re_excl.stderr.exp \
|
||||
tc04_free_lock.vgtest tc04_free_lock.stdout.exp \
|
||||
tc04_free_lock.stderr.exp \
|
||||
tc05_simple_race.vgtest tc05_simple_race.stdout.exp \
|
||||
tc05_simple_race.stderr.exp \
|
||||
tc06_two_races.vgtest tc06_two_races.stdout.exp \
|
||||
tc06_two_races.stderr.exp \
|
||||
tc06_two_races_xml.vgtest tc06_two_races_xml.stdout.exp \
|
||||
tc06_two_races_xml.stderr.exp \
|
||||
tc07_hbl1.vgtest tc07_hbl1.stdout.exp tc07_hbl1.stderr.exp \
|
||||
tc08_hbl2.vgtest tc08_hbl2.stdout.exp tc08_hbl2.stderr.exp \
|
||||
tc09_bad_unlock.vgtest tc09_bad_unlock.stdout.exp \
|
||||
tc09_bad_unlock.stderr.exp tc09_bad_unlock.stderr.exp-solaris \
|
||||
tc10_rec_lock.vgtest tc10_rec_lock.stdout.exp tc10_rec_lock.stderr.exp \
|
||||
tc11_XCHG.vgtest tc11_XCHG.stdout.exp tc11_XCHG.stderr.exp \
|
||||
tc12_rwl_trivial.vgtest tc12_rwl_trivial.stdout.exp \
|
||||
tc12_rwl_trivial.stderr.exp \
|
||||
tc12_rwl_trivial.stderr.exp-darwin970 \
|
||||
tc12_rwl_trivial.stderr.exp-solaris \
|
||||
tc13_laog1.vgtest tc13_laog1.stdout.exp tc13_laog1.stderr.exp \
|
||||
tc14_laog_dinphils.vgtest tc14_laog_dinphils.stdout.exp \
|
||||
tc14_laog_dinphils.stderr.exp \
|
||||
tc15_laog_lockdel.vgtest tc15_laog_lockdel.stdout.exp \
|
||||
tc15_laog_lockdel.stderr.exp \
|
||||
tc16_byterace.vgtest tc16_byterace.stdout.exp \
|
||||
tc16_byterace.stderr.exp \
|
||||
tc17_sembar.vgtest tc17_sembar.stdout.exp \
|
||||
tc17_sembar.stderr.exp \
|
||||
tc18_semabuse.vgtest tc18_semabuse.stdout.exp \
|
||||
tc18_semabuse.stderr.exp \
|
||||
tc18_semabuse.stderr.exp-linux-mips32 \
|
||||
tc18_semabuse.stderr.exp-linux-mips32-b \
|
||||
tc18_semabuse.stderr.exp-solaris \
|
||||
tc19_shadowmem.vgtest tc19_shadowmem.stdout.exp \
|
||||
tc19_shadowmem.stderr.exp tc19_shadowmem.stderr.exp-mips32 \
|
||||
tc20_verifywrap.vgtest tc20_verifywrap.stdout.exp \
|
||||
tc20_verifywrap.stderr.exp \
|
||||
tc20_verifywrap.stderr.exp-glibc-2.18 \
|
||||
tc20_verifywrap.stderr.exp-glibc-2.21 \
|
||||
tc20_verifywrap.stderr.exp-mips32 \
|
||||
tc20_verifywrap.stderr.exp-mips32-b \
|
||||
tc20_verifywrap.stderr.exp-s390x \
|
||||
tc20_verifywrap.stderr.exp-solaris \
|
||||
tc21_pthonce.vgtest tc21_pthonce.stdout.exp tc21_pthonce.stderr.exp \
|
||||
tc22_exit_w_lock.vgtest tc22_exit_w_lock.stdout.exp \
|
||||
tc22_exit_w_lock.stderr.exp \
|
||||
tc22_exit_w_lock.stderr.exp-kfail-x86 \
|
||||
tc22_exit_w_lock.stderr.exp-solaris \
|
||||
tc23_bogus_condwait.vgtest tc23_bogus_condwait.stdout.exp \
|
||||
tc23_bogus_condwait.stderr.exp \
|
||||
tc23_bogus_condwait.stderr.exp-mips32 \
|
||||
tc24_nonzero_sem.vgtest tc24_nonzero_sem.stdout.exp \
|
||||
tc24_nonzero_sem.stderr.exp \
|
||||
tls_threads.vgtest tls_threads.stdout.exp \
|
||||
tls_threads.stderr.exp
|
||||
|
||||
# Wrapper headers used by some check programs.
|
||||
noinst_HEADERS = safe-pthread.h safe-semaphore.h
|
||||
|
||||
# XXX: tc18_semabuse uses operations that are unsupported on Darwin. It
|
||||
# should be conditionally compiled like tc20_verifywrap is.
|
||||
check_PROGRAMS = \
|
||||
annotate_hbefore \
|
||||
cond_init_destroy \
|
||||
cond_timedwait_invalid \
|
||||
cond_timedwait_test \
|
||||
free_is_write \
|
||||
hg01_all_ok \
|
||||
hg02_deadlock \
|
||||
hg03_inherit \
|
||||
hg04_race \
|
||||
hg05_race2 \
|
||||
hg06_readshared \
|
||||
locked_vs_unlocked1 \
|
||||
locked_vs_unlocked2 \
|
||||
locked_vs_unlocked3 \
|
||||
pth_destroy_cond \
|
||||
shmem_abits \
|
||||
stackteardown \
|
||||
t2t \
|
||||
tc01_simple_race \
|
||||
tc02_simple_tls \
|
||||
tc03_re_excl \
|
||||
tc04_free_lock \
|
||||
tc05_simple_race \
|
||||
tc06_two_races \
|
||||
tc07_hbl1 \
|
||||
tc08_hbl2 \
|
||||
tc09_bad_unlock \
|
||||
tc10_rec_lock \
|
||||
tc11_XCHG \
|
||||
tc12_rwl_trivial \
|
||||
tc13_laog1 \
|
||||
tc14_laog_dinphils \
|
||||
tc15_laog_lockdel \
|
||||
tc16_byterace \
|
||||
tc17_sembar \
|
||||
tc18_semabuse \
|
||||
tc19_shadowmem \
|
||||
tc21_pthonce \
|
||||
tc23_bogus_condwait \
|
||||
tc24_nonzero_sem \
|
||||
tls_threads
|
||||
|
||||
# DDD: it seg faults, and then the Valgrind exit path hangs
|
||||
# JRS 29 July 09: it craps out in the stack unwinder, in
|
||||
#==13480== at 0xF00B81FF: ??? f00b8180 VG_(get_StackTrace_wrk)
|
||||
#==13480== by 0xF00B83F8: ??? f00b8340 VG_(get_StackTrace)
|
||||
#==13480== by 0xF009FE19: ??? f009fd70 record_ExeContext_wrk
|
||||
#==13480== by 0xF009D92E: ??? f009d8c0 construct_error
|
||||
#==13480== by 0xF009F001: ??? f009eef0 VG_(maybe_record_error)
|
||||
#==13480== by 0xF0081F80: ??? f0081f00 HG_(record_error_misc)
|
||||
#==13480== by 0xF0089C00: ??? f0089b80 evh__pre_thread_ll_exit
|
||||
#==13480== by 0xF01111D1: ??? f0111070 run_a_thread_NORETURN
|
||||
#==13480== by 0xF0111512: ??? f0111500 start_thread_NORETURN
|
||||
# when the thread being unwound is at __bsdthread_terminate+0
|
||||
#
|
||||
# Like Tom says, the stack unwinder protection is bollocks.
|
||||
# We should junk all previous schemes and simply get the
|
||||
# stack unwinder to consult aspacem at each frame (cache-accelerated,
|
||||
# of course) to check each page it visits is accessible.
|
||||
#
|
||||
if ! VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
|
||||
check_PROGRAMS += \
|
||||
tc22_exit_w_lock
|
||||
endif
|
||||
|
||||
if VGCONF_PLATFORMS_INCLUDE_ARM_LINUX
|
||||
annotate_hbefore_CFLAGS = $(AM_CFLAGS) -mcpu=cortex-a8
|
||||
tc07_hbl1_CFLAGS = $(AM_CFLAGS) -mcpu=cortex-a8
|
||||
tc08_hbl2_CFLAGS = $(AM_CFLAGS) -mcpu=cortex-a8
|
||||
else
|
||||
annotate_hbefore_CFLAGS = $(AM_CFLAGS)
|
||||
tc07_hbl1_CFLAGS = $(AM_CFLAGS)
|
||||
tc08_hbl2_CFLAGS = $(AM_CFLAGS)
|
||||
endif
|
||||
|
||||
if HAVE_PTHREAD_BARRIER
|
||||
check_PROGRAMS += bar_bad bar_trivial
|
||||
endif
|
||||
|
||||
if HAVE_PTHREAD_MUTEX_TIMEDLOCK
|
||||
check_PROGRAMS += tc20_verifywrap
|
||||
endif
|
||||
|
||||
if HAVE_BUILTIN_ATOMIC
|
||||
check_PROGRAMS += annotate_rwlock
|
||||
endif
|
||||
|
||||
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
|
||||
AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
|
||||
|
||||
LDADD = -lpthread
|
||||
|
||||
if VGCONF_OS_IS_DARWIN
|
||||
annotate_hbefore_CFLAGS = $(AM_CFLAGS) -mdynamic-no-pic
|
||||
else
|
||||
annotate_hbefore_CFLAGS = $(AM_CFLAGS)
|
||||
endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,416 @@
|
||||
|
||||
/* Program which uses a happens-before edge to coordinate an access to
|
||||
variable 'shared_var' between two threads. The h-b edge is created
|
||||
by a custom (kludgesome!) mechanism and hence we need to use
|
||||
ANNOTATES_HAPPEN_{BEFORE,AFTER} to explain to Helgrind what's going
|
||||
on (else it reports a race). */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../../helgrind/helgrind.h"
|
||||
|
||||
/* Todo: move all this do_acasW guff into a support library. It's
|
||||
useful for multiple tests, not just this one.
|
||||
|
||||
XXX: all the do_acasW routines assume the supplied address
|
||||
is UWord (naturally) aligned. */
|
||||
|
||||
|
||||
typedef unsigned long int UWord;
|
||||
|
||||
#if defined(VGA_ppc64be) || defined(VGA_ppc64le)
|
||||
|
||||
// ppc64
|
||||
/* return 1 if success, 0 if failure */
|
||||
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
|
||||
{
|
||||
UWord old, success;
|
||||
|
||||
/* Fetch the old value, and set the reservation */
|
||||
__asm__ __volatile__ (
|
||||
"ldarx %0, 0,%1" "\n" // rD,rA,rB
|
||||
: /*out*/ "=b"(old)
|
||||
: /*in*/ "b"(addr)
|
||||
: /*trash*/ "memory","cc"
|
||||
);
|
||||
|
||||
/* If the old value isn't as expected, we've had it */
|
||||
if (old != expected) return 0;
|
||||
|
||||
/* otherwise try to stuff the new value in */
|
||||
__asm__ __volatile__(
|
||||
"stdcx. %2, 0,%1" "\n" // rS,rA,rB
|
||||
"mfcr %0" "\n\t"
|
||||
"srdi %0,%0,29" "\n\t"
|
||||
"andi. %0,%0,1" "\n"
|
||||
: /*out*/ "=b"(success)
|
||||
: /*in*/ "b"(addr), "b"(nyu)
|
||||
);
|
||||
|
||||
assert(success == 0 || success == 1);
|
||||
return success;
|
||||
}
|
||||
|
||||
#elif defined(VGA_ppc32)
|
||||
|
||||
// ppc32
|
||||
/* return 1 if success, 0 if failure */
|
||||
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
|
||||
{
|
||||
UWord old, success;
|
||||
|
||||
/* Fetch the old value, and set the reservation */
|
||||
__asm__ __volatile__ (
|
||||
"lwarx %0, 0,%1" "\n" // rD,rA,rB
|
||||
: /*out*/ "=b"(old)
|
||||
: /*in*/ "b"(addr)
|
||||
: /*trash*/ "memory","cc"
|
||||
);
|
||||
|
||||
/* If the old value isn't as expected, we've had it */
|
||||
if (old != expected) return 0;
|
||||
|
||||
/* otherwise try to stuff the new value in */
|
||||
__asm__ __volatile__(
|
||||
"stwcx. %2, 0,%1" "\n" // rS,rA,rB
|
||||
"mfcr %0" "\n\t"
|
||||
"srwi %0,%0,29" "\n\t"
|
||||
"andi. %0,%0,1" "\n"
|
||||
: /*out*/ "=b"(success)
|
||||
: /*in*/ "b"(addr), "b"(nyu)
|
||||
);
|
||||
|
||||
assert(success == 0 || success == 1);
|
||||
return success;
|
||||
}
|
||||
|
||||
#elif defined(VGA_amd64)
|
||||
|
||||
// amd64
|
||||
/* return 1 if success, 0 if failure */
|
||||
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
|
||||
{
|
||||
UWord block[4] = { (UWord)addr, expected, nyu, 2 };
|
||||
__asm__ __volatile__(
|
||||
"movq 0(%%rsi), %%rdi" "\n\t" // addr
|
||||
"movq 8(%%rsi), %%rax" "\n\t" // expected
|
||||
"movq 16(%%rsi), %%rbx" "\n\t" // nyu
|
||||
"xorq %%rcx,%%rcx" "\n\t"
|
||||
"lock; cmpxchgq %%rbx,(%%rdi)" "\n\t"
|
||||
"setz %%cl" "\n\t"
|
||||
"movq %%rcx, 24(%%rsi)" "\n"
|
||||
: /*out*/
|
||||
: /*in*/ "S"(&block[0])
|
||||
: /*trash*/"memory","cc","rdi","rax","rbx","rcx"
|
||||
);
|
||||
assert(block[3] == 0 || block[3] == 1);
|
||||
return block[3] & 1;
|
||||
}
|
||||
|
||||
#elif defined(VGA_x86)
|
||||
|
||||
// x86
|
||||
/* return 1 if success, 0 if failure */
|
||||
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
|
||||
{
|
||||
UWord block[4] = { (UWord)addr, expected, nyu, 2 };
|
||||
__asm__ __volatile__(
|
||||
"pushl %%ebx" "\n\t"
|
||||
"movl 0(%%esi), %%edi" "\n\t" // addr
|
||||
"movl 4(%%esi), %%eax" "\n\t" // expected
|
||||
"movl 8(%%esi), %%ebx" "\n\t" // nyu
|
||||
"xorl %%ecx,%%ecx" "\n\t"
|
||||
"lock; cmpxchgl %%ebx,(%%edi)" "\n\t"
|
||||
"setz %%cl" "\n\t"
|
||||
"movl %%ecx, 12(%%esi)" "\n\t"
|
||||
"popl %%ebx" "\n"
|
||||
: /*out*/
|
||||
: /*in*/ "S"(&block[0])
|
||||
: /*trash*/"memory","cc","edi","eax","ecx"
|
||||
);
|
||||
assert(block[3] == 0 || block[3] == 1);
|
||||
return block[3] & 1;
|
||||
}
|
||||
|
||||
#elif defined(VGA_arm)
|
||||
|
||||
// arm
|
||||
/* return 1 if success, 0 if failure */
|
||||
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
|
||||
{
|
||||
UWord old, success;
|
||||
UWord block[2] = { (UWord)addr, nyu };
|
||||
|
||||
/* Fetch the old value, and set the reservation */
|
||||
__asm__ __volatile__ (
|
||||
"ldrex %0, [%1]" "\n"
|
||||
: /*out*/ "=r"(old)
|
||||
: /*in*/ "r"(addr)
|
||||
);
|
||||
|
||||
/* If the old value isn't as expected, we've had it */
|
||||
if (old != expected) return 0;
|
||||
|
||||
/* otherwise try to stuff the new value in */
|
||||
__asm__ __volatile__(
|
||||
"ldr r4, [%1, #0]" "\n\t"
|
||||
"ldr r5, [%1, #4]" "\n\t"
|
||||
"strex r6, r5, [r4, #0]" "\n\t"
|
||||
"eor %0, r6, #1" "\n\t"
|
||||
: /*out*/ "=r"(success)
|
||||
: /*in*/ "r"(&block[0])
|
||||
: /*trash*/ "r4","r5","r6","memory"
|
||||
);
|
||||
assert(success == 0 || success == 1);
|
||||
return success;
|
||||
}
|
||||
|
||||
#elif defined(VGA_arm64)
|
||||
|
||||
// arm64
|
||||
/* return 1 if success, 0 if failure */
|
||||
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
|
||||
{
|
||||
UWord old, success;
|
||||
UWord block[2] = { (UWord)addr, nyu };
|
||||
|
||||
/* Fetch the old value, and set the reservation */
|
||||
__asm__ __volatile__ (
|
||||
"ldxr %0, [%1]" "\n"
|
||||
: /*out*/ "=r"(old)
|
||||
: /*in*/ "r"(addr)
|
||||
);
|
||||
|
||||
/* If the old value isn't as expected, we've had it */
|
||||
if (old != expected) return 0;
|
||||
|
||||
/* otherwise try to stuff the new value in */
|
||||
__asm__ __volatile__(
|
||||
"ldr x4, [%1, #0]" "\n\t"
|
||||
"ldr x5, [%1, #8]" "\n\t"
|
||||
"stxr w6, x5, [x4, #0]" "\n\t"
|
||||
"eor %0, x6, #1" "\n\t"
|
||||
: /*out*/ "=r"(success)
|
||||
: /*in*/ "r"(&block[0])
|
||||
: /*trash*/ "x4","x5","x6","memory"
|
||||
);
|
||||
assert(success == 0 || success == 1);
|
||||
return success;
|
||||
}
|
||||
|
||||
#elif defined(VGA_s390x)
|
||||
|
||||
// s390x
|
||||
/* return 1 if success, 0 if failure */
|
||||
UWord do_acasW(UWord* addr, UWord expected, UWord nyu )
|
||||
{
|
||||
int cc;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"csg %2,%3,%1\n\t"
|
||||
"ipm %0\n\t"
|
||||
"srl %0,28\n\t"
|
||||
: /* out */ "=r" (cc)
|
||||
: /* in */ "Q" (*addr), "d" (expected), "d" (nyu)
|
||||
: "memory", "cc"
|
||||
);
|
||||
return cc == 0;
|
||||
}
|
||||
|
||||
#elif defined(VGA_mips32)
|
||||
|
||||
// mips32
|
||||
/* return 1 if success, 0 if failure */
|
||||
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
|
||||
{
|
||||
UWord success;
|
||||
UWord block[3] = { (UWord)addr, nyu, expected};
|
||||
|
||||
__asm__ __volatile__(
|
||||
".set noreorder" "\n\t"
|
||||
"lw $t0, 0(%1)" "\n\t"
|
||||
"lw $t2, 8(%1)" "\n\t"
|
||||
"lw $t3, 4(%1)" "\n\t"
|
||||
"ll $t1, 0($t0)" "\n\t"
|
||||
"bne $t1, $t2, exit_0" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"sc $t3, 0($t0)" "\n\t"
|
||||
"move %0, $t3" "\n\t"
|
||||
"b exit" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"exit_0:" "\n\t"
|
||||
"move %0, $zero" "\n\t"
|
||||
"exit:" "\n\t"
|
||||
: /*out*/ "=r"(success)
|
||||
: /*in*/ "r"(&block[0])
|
||||
: /*trash*/ "t0", "t1", "t2", "t3", "memory"
|
||||
);
|
||||
|
||||
assert(success == 0 || success == 1);
|
||||
return success;
|
||||
}
|
||||
|
||||
#elif defined(VGA_mips64)
|
||||
|
||||
// mips64
|
||||
/* return 1 if success, 0 if failure */
|
||||
UWord do_acasW ( UWord* addr, UWord expected, UWord nyu )
|
||||
{
|
||||
UWord success;
|
||||
UWord block[3] = { (UWord)addr, nyu, expected};
|
||||
|
||||
__asm__ __volatile__(
|
||||
".set noreorder" "\n\t"
|
||||
"ld $t0, 0(%1)" "\n\t"
|
||||
"ld $t2, 16(%1)" "\n\t"
|
||||
"ld $t3, 8(%1)" "\n\t"
|
||||
"ll $t1, 0($t0)" "\n\t"
|
||||
"bne $t1, $t2, exit_0" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"sc $t3, 0($t0)" "\n\t"
|
||||
"move %0, $t3" "\n\t"
|
||||
"b exit" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"exit_0:" "\n\t"
|
||||
"move %0, $zero" "\n\t"
|
||||
"exit:" "\n\t"
|
||||
: /*out*/ "=r"(success)
|
||||
: /*in*/ "r"(&block[0])
|
||||
: /*trash*/ "t0", "t1", "t2", "t3", "memory"
|
||||
);
|
||||
|
||||
assert(success == 0 || success == 1);
|
||||
return success;
|
||||
}
|
||||
|
||||
#elif defined(VGA_tilegx)
|
||||
|
||||
/* return 1 if success, 0 if failure */
|
||||
UWord do_acasW(UWord* addr, UWord expected, UWord nyu )
|
||||
{
|
||||
/* Load the compare value into special register 0x2780 */
|
||||
__insn_mtspr(0x2780, expected);
|
||||
return __insn_cmpexch(addr, nyu);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void atomic_incW ( UWord* w )
|
||||
{
|
||||
while (1) {
|
||||
UWord old = *w;
|
||||
UWord nyu = old + 1;
|
||||
UWord ok = do_acasW( w, old, nyu );
|
||||
if (ok) break;
|
||||
};
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
#define NNN 1000000
|
||||
|
||||
void* thread_fn ( void* arg )
|
||||
{
|
||||
UWord* w = (UWord*)arg;
|
||||
int i;
|
||||
for (i = 0; i < NNN; i++)
|
||||
atomic_incW( w );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
int r;
|
||||
//ANNOTATE_HAPPENS_BEFORE(0);
|
||||
//return 0;
|
||||
UWord w = 0;
|
||||
pthread_t t1, t2;
|
||||
|
||||
r= pthread_create( &t1, NULL, &thread_fn, (void*)&w ); assert(!r);
|
||||
r= pthread_create( &t2, NULL, &thread_fn, (void*)&w ); assert(!r);
|
||||
|
||||
r= pthread_join( t1, NULL ); assert(!r);
|
||||
r= pthread_join( t2, NULL ); assert(!r);
|
||||
|
||||
printf("result = %lu\n", w );
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int shared_var = 0; // is not raced upon
|
||||
|
||||
|
||||
void delayXms ( int i )
|
||||
{
|
||||
struct timespec ts = { 0, 1 * 1000 * 1000 };
|
||||
// We do the sleep in small pieces to have scheduling
|
||||
// events ensuring a fair switch between threads, even
|
||||
// without --fair-sched=yes. This is a.o. needed for
|
||||
// running this test under an outer helgrind or an outer
|
||||
// sgcheck.
|
||||
while (i > 0) {
|
||||
nanosleep(&ts, NULL);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
void do_wait ( UWord* w )
|
||||
{
|
||||
UWord w0 = *w;
|
||||
UWord volatile * wV = w;
|
||||
while (*wV == w0)
|
||||
delayXms(1); // small sleeps, ensuring context switches
|
||||
ANNOTATE_HAPPENS_AFTER(w);
|
||||
}
|
||||
|
||||
void do_signal ( UWord* w )
|
||||
{
|
||||
ANNOTATE_HAPPENS_BEFORE(w);
|
||||
atomic_incW(w);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void* thread_fn1 ( void* arg )
|
||||
{
|
||||
UWord* w = (UWord*)arg;
|
||||
delayXms(500); // ensure t2 gets to its wait first
|
||||
shared_var = 1; // first access
|
||||
do_signal(w); // cause h-b edge to second thread
|
||||
|
||||
delayXms(500);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* thread_fn2 ( void* arg )
|
||||
{
|
||||
UWord* w = (UWord*)arg;
|
||||
do_wait(w); // wait for h-b edge from first thread
|
||||
shared_var = 2; // second access
|
||||
|
||||
delayXms(500);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
int r;
|
||||
UWord w = 0;
|
||||
pthread_t t1, t2;
|
||||
|
||||
r= pthread_create( &t1, NULL, &thread_fn1, (void*)&w ); assert(!r);
|
||||
r= pthread_create( &t2, NULL, &thread_fn2, (void*)&w ); assert(!r);
|
||||
|
||||
r= pthread_join( t1, NULL ); assert(!r);
|
||||
r= pthread_join( t2, NULL ); assert(!r);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
vgopts: -q --fair-sched=try
|
||||
prog: annotate_hbefore
|
||||
@@ -0,0 +1,176 @@
|
||||
|
||||
/* This program is a marginally modified copy of
|
||||
drd/tests/annotate_rwlock.c,
|
||||
|
||||
which was originally written by Bart van Assche.
|
||||
|
||||
Unfortunately due to the need to #include helgrind.h instead of
|
||||
drd.h, it can't be an exact copy.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file annotate_rwlock.c
|
||||
*
|
||||
* @brief Multithreaded test program that triggers various access patterns
|
||||
* without triggering any race conditions using a reader-writer lock
|
||||
* implemented via busy-waiting. Annotations are used to tell DRD
|
||||
* which higher-level rwlock operations are being performed.
|
||||
*/
|
||||
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h> /* usleep() */
|
||||
#include "../../config.h"
|
||||
#include "../../helgrind/helgrind.h"
|
||||
|
||||
|
||||
#ifndef HAVE_BUILTIN_ATOMIC
|
||||
#error Sorry, but this test program can only be compiled by a compiler that\
|
||||
has built-in functions for atomic memory access.
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
volatile int locked;
|
||||
int writer_count;
|
||||
int reader_count;
|
||||
} rwlock_t;
|
||||
|
||||
|
||||
static rwlock_t s_rwlock;
|
||||
static int s_counter;
|
||||
|
||||
|
||||
static void rwlock_init(rwlock_t* p)
|
||||
{
|
||||
// DRD_IGNORE_VAR(*p);
|
||||
p->locked = 0;
|
||||
p->writer_count = 0;
|
||||
p->reader_count = 0;
|
||||
ANNOTATE_RWLOCK_CREATE(p);
|
||||
}
|
||||
|
||||
static void rwlock_destroy(rwlock_t* p)
|
||||
{
|
||||
ANNOTATE_RWLOCK_DESTROY(p);
|
||||
assert(p->locked == 0);
|
||||
assert(p->writer_count == 0);
|
||||
assert(p->reader_count == 0);
|
||||
}
|
||||
|
||||
static void rwlock_rdlock(rwlock_t* p)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
|
||||
;
|
||||
if (p->writer_count == 0)
|
||||
break;
|
||||
#ifdef __APPLE__
|
||||
/* Darwin doesn't have an implementation of pthread_yield(). */
|
||||
usleep(100 * 1000);
|
||||
#else
|
||||
sched_yield();
|
||||
#endif
|
||||
(void) __sync_fetch_and_sub(&p->locked, 1);
|
||||
}
|
||||
p->reader_count++;
|
||||
assert(p->reader_count >= 0);
|
||||
assert(p->writer_count >= 0);
|
||||
assert(p->reader_count == 0 || p->writer_count == 0);
|
||||
(void) __sync_fetch_and_sub(&p->locked, 1);
|
||||
//ANNOTATE_READERLOCK_ACQUIRED(p);
|
||||
ANNOTATE_RWLOCK_ACQUIRED(p, 0);
|
||||
}
|
||||
|
||||
static void rwlock_wrlock(rwlock_t* p)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
|
||||
;
|
||||
if (p->reader_count == 0)
|
||||
break;
|
||||
#ifdef __APPLE__
|
||||
/* Darwin doesn't have an implementation of pthread_yield(). */
|
||||
usleep(100 * 1000);
|
||||
#else
|
||||
sched_yield();
|
||||
#endif
|
||||
(void) __sync_fetch_and_sub(&p->locked, 1);
|
||||
}
|
||||
p->writer_count++;
|
||||
assert(p->reader_count >= 0);
|
||||
assert(p->writer_count >= 0);
|
||||
assert(p->reader_count == 0 || p->writer_count == 0);
|
||||
(void) __sync_fetch_and_sub(&p->locked, 1);
|
||||
// ANNOTATE_WRITERLOCK_ACQUIRED(p);
|
||||
ANNOTATE_RWLOCK_ACQUIRED(p, 1);
|
||||
}
|
||||
|
||||
static void rwlock_unlock(rwlock_t* p)
|
||||
{
|
||||
while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
|
||||
;
|
||||
if (p->reader_count > 0)
|
||||
{
|
||||
p->reader_count--;
|
||||
//ANNOTATE_READERLOCK_RELEASED(p);
|
||||
ANNOTATE_RWLOCK_RELEASED(p, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->writer_count--;
|
||||
//ANNOTATE_WRITERLOCK_RELEASED(p);
|
||||
ANNOTATE_RWLOCK_RELEASED(p, 1);
|
||||
}
|
||||
assert(p->reader_count >= 0);
|
||||
assert(p->writer_count >= 0);
|
||||
assert(p->reader_count == 0 || p->writer_count == 0);
|
||||
(void) __sync_fetch_and_sub(&p->locked, 1);
|
||||
}
|
||||
|
||||
static void* thread_func(void* arg)
|
||||
{
|
||||
int i;
|
||||
int sum = 0;
|
||||
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
rwlock_rdlock(&s_rwlock);
|
||||
sum += s_counter;
|
||||
rwlock_unlock(&s_rwlock);
|
||||
rwlock_wrlock(&s_rwlock);
|
||||
s_counter++;
|
||||
rwlock_unlock(&s_rwlock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const int thread_count = 10;
|
||||
pthread_t tid[thread_count];
|
||||
int i;
|
||||
|
||||
rwlock_init(&s_rwlock);
|
||||
for (i = 0; i < thread_count; i++)
|
||||
{
|
||||
pthread_create(&tid[i], 0, thread_func, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < thread_count; i++)
|
||||
{
|
||||
pthread_join(tid[i], 0);
|
||||
}
|
||||
rwlock_destroy(&s_rwlock);
|
||||
|
||||
fprintf(stderr, "Finished.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
---Thread-Announcement------------------------------------------
|
||||
|
||||
Thread #x was created
|
||||
...
|
||||
by 0x........: pthread_create@* (hg_intercepts.c:...)
|
||||
by 0x........: main (annotate_rwlock.c:164)
|
||||
|
||||
---Thread-Announcement------------------------------------------
|
||||
|
||||
Thread #x was created
|
||||
...
|
||||
by 0x........: pthread_create@* (hg_intercepts.c:...)
|
||||
by 0x........: main (annotate_rwlock.c:164)
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Possible data race during read of size 4 at 0x........ by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_rdlock (annotate_rwlock.c:71)
|
||||
by 0x........: thread_func (annotate_rwlock.c:144)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
This conflicts with a previous write of size 4 by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_wrlock (annotate_rwlock.c:106)
|
||||
by 0x........: thread_func (annotate_rwlock.c:147)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 4 bytes inside data symbol "s_rwlock"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Possible data race during read of size 4 at 0x........ by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_rdlock (annotate_rwlock.c:81)
|
||||
by 0x........: thread_func (annotate_rwlock.c:144)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
This conflicts with a previous write of size 4 by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_rdlock (annotate_rwlock.c:81)
|
||||
by 0x........: thread_func (annotate_rwlock.c:144)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 8 bytes inside data symbol "s_rwlock"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Possible data race during write of size 4 at 0x........ by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_rdlock (annotate_rwlock.c:81)
|
||||
by 0x........: thread_func (annotate_rwlock.c:144)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
This conflicts with a previous read of size 4 by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_unlock (annotate_rwlock.c:131)
|
||||
by 0x........: thread_func (annotate_rwlock.c:149)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 8 bytes inside data symbol "s_rwlock"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Possible data race during write of size 4 at 0x........ by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_unlock (annotate_rwlock.c:121)
|
||||
by 0x........: thread_func (annotate_rwlock.c:146)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
This conflicts with a previous read of size 4 by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_unlock (annotate_rwlock.c:131)
|
||||
by 0x........: thread_func (annotate_rwlock.c:149)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 8 bytes inside data symbol "s_rwlock"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Possible data race during write of size 4 at 0x........ by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_wrlock (annotate_rwlock.c:106)
|
||||
by 0x........: thread_func (annotate_rwlock.c:147)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
This conflicts with a previous read of size 4 by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_unlock (annotate_rwlock.c:132)
|
||||
by 0x........: thread_func (annotate_rwlock.c:149)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 4 bytes inside data symbol "s_rwlock"
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Lock at 0x........ was first observed
|
||||
at 0x........: rwlock_init (annotate_rwlock.c:54)
|
||||
by 0x........: main (annotate_rwlock.c:161)
|
||||
Address 0x........ is 0 bytes inside data symbol "s_rwlock"
|
||||
|
||||
Possible data race during write of size 4 at 0x........ by thread #x
|
||||
Locks held: 1, at address 0x........
|
||||
at 0x........: rwlock_unlock (annotate_rwlock.c:127)
|
||||
by 0x........: thread_func (annotate_rwlock.c:149)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
This conflicts with a previous read of size 4 by thread #x
|
||||
Locks held: none
|
||||
at 0x........: rwlock_unlock (annotate_rwlock.c:132)
|
||||
by 0x........: thread_func (annotate_rwlock.c:149)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 4 bytes inside data symbol "s_rwlock"
|
||||
|
||||
Finished.
|
||||
@@ -0,0 +1,3 @@
|
||||
prereq: test -e annotate_rwlock
|
||||
vgopts: -q
|
||||
prog: annotate_rwlock
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
Done.
|
||||
|
||||
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1,3 @@
|
||||
prereq: test -e ../../drd/tests/annotate_smart_pointer
|
||||
prog: ../../drd/tests/annotate_smart_pointer
|
||||
args: 50 5
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
/* This program checks that Helgrind reports the five degenerate
|
||||
uses of the barrier functions shown. */
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
void* child1 ( void* arg )
|
||||
{
|
||||
pthread_barrier_wait( (pthread_barrier_t*)arg );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
pthread_barrier_t *bar1, *bar2, *bar3, *bar4, *bar5;
|
||||
pthread_t thr1, thr2;
|
||||
int r;
|
||||
|
||||
/* possibly set up a watchdog timer thread here. */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* initialise a barrier with a zero count */
|
||||
fprintf(stderr, "\ninitialise a barrier with zero count\n");
|
||||
bar1 = malloc(sizeof(pthread_barrier_t));
|
||||
pthread_barrier_init(bar1, NULL, 0);
|
||||
|
||||
/* initialise a barrier twice */
|
||||
fprintf(stderr, "\ninitialise a barrier twice\n");
|
||||
bar2 = malloc(sizeof(pthread_barrier_t));
|
||||
pthread_barrier_init(bar2, NULL, 1);
|
||||
pthread_barrier_init(bar2, NULL, 1);
|
||||
|
||||
/* initialise a barrier which has threads waiting on it.
|
||||
This isn't too simple. */
|
||||
fprintf(stderr, "\ninitialise a barrier which has threads waiting on it\n");
|
||||
bar3 = malloc(sizeof(pthread_barrier_t));
|
||||
pthread_barrier_init(bar3, NULL, 2);
|
||||
/* create a thread, whose only purpose is to block on the barrier */
|
||||
pthread_create(&thr1, NULL, child1, (void*)bar3);
|
||||
/* guarantee that it gets there first */
|
||||
sleep(1);
|
||||
/* and now reinitialise */
|
||||
pthread_barrier_init(bar3, NULL, 3);
|
||||
|
||||
/* destroy a barrier that has threads waiting at it */
|
||||
fprintf(stderr, "\ndestroy a barrier that has waiting threads\n");
|
||||
/* once again, create a thread, whose only purpose is to block. */
|
||||
bar4 = malloc(sizeof(pthread_barrier_t));
|
||||
pthread_barrier_init(bar4, NULL, 2);
|
||||
/* create a thread, whose only purpose is to block on the barrier */
|
||||
pthread_create(&thr2, NULL, child1, (void*)bar4);
|
||||
/* guarantee that it gets there first */
|
||||
sleep(1);
|
||||
/* and now destroy */
|
||||
pthread_barrier_destroy(bar4);
|
||||
|
||||
/* destroy a barrier that was never initialised. This is a bit
|
||||
tricky, in that we have to fill the barrier with bytes which
|
||||
ensure that the pthread_barrier_destroy call doesn't hang for
|
||||
some reason. Zero-fill seems to work ok on amd64-linux (glibc
|
||||
2.8). */
|
||||
fprintf(stderr, "\ndestroy a barrier that was never initialised\n");
|
||||
bar5 = malloc(sizeof(pthread_barrier_t));
|
||||
assert(bar5);
|
||||
memset(bar5, 0, sizeof(*bar5));
|
||||
pthread_barrier_destroy(bar5);
|
||||
|
||||
/* now we need to clean up the mess .. */
|
||||
r= pthread_cancel(thr1); assert(!r);
|
||||
r= pthread_cancel(thr2); assert(!r);
|
||||
|
||||
free(bar1); free(bar2); free(bar3); free(bar4); free(bar5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
initialise a barrier with zero count
|
||||
---Thread-Announcement------------------------------------------
|
||||
|
||||
Thread #x is the program's root thread
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Thread #x: pthread_barrier_init: 'count' argument is zero
|
||||
at 0x........: pthread_barrier_init (hg_intercepts.c:...)
|
||||
by 0x........: main (bar_bad.c:39)
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Thread #x's call to pthread_barrier_init failed
|
||||
with error code 22 (EINVAL: Invalid argument)
|
||||
at 0x........: pthread_barrier_init (hg_intercepts.c:...)
|
||||
by 0x........: main (bar_bad.c:39)
|
||||
|
||||
|
||||
initialise a barrier twice
|
||||
----------------------------------------------------------------
|
||||
|
||||
Thread #x: pthread_barrier_init: barrier is already initialised
|
||||
at 0x........: pthread_barrier_init (hg_intercepts.c:...)
|
||||
by 0x........: main (bar_bad.c:45)
|
||||
|
||||
|
||||
initialise a barrier which has threads waiting on it
|
||||
----------------------------------------------------------------
|
||||
|
||||
Thread #x: pthread_barrier_init: barrier is already initialised
|
||||
at 0x........: pthread_barrier_init (hg_intercepts.c:...)
|
||||
by 0x........: main (bar_bad.c:57)
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Thread #x: pthread_barrier_init: threads are waiting at barrier
|
||||
at 0x........: pthread_barrier_init (hg_intercepts.c:...)
|
||||
by 0x........: main (bar_bad.c:57)
|
||||
|
||||
|
||||
destroy a barrier that has waiting threads
|
||||
----------------------------------------------------------------
|
||||
|
||||
Thread #x: pthread_barrier_destroy: threads are waiting at barrier
|
||||
at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
|
||||
by 0x........: main (bar_bad.c:69)
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Thread #x's call to pthread_barrier_destroy failed
|
||||
with error code 16 (EBUSY: Device or resource busy)
|
||||
at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
|
||||
by 0x........: main (bar_bad.c:69)
|
||||
|
||||
|
||||
destroy a barrier that was never initialised
|
||||
----------------------------------------------------------------
|
||||
|
||||
Thread #x: pthread_barrier_destroy: barrier was never initialised
|
||||
at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
|
||||
by 0x........: main (bar_bad.c:80)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
prereq: test -e bar_bad
|
||||
prog: bar_bad
|
||||
vgopts: -q
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
/* This is the most trivial test I could think of that involves
|
||||
barriers. If H fails to notice the pthread_barrier_wait call then
|
||||
it will report a race. Correct behaviour is not to report a race
|
||||
(there isn't one.) */
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int x = 0;
|
||||
|
||||
pthread_barrier_t bar;
|
||||
|
||||
void* child_fn ( void* arg )
|
||||
{
|
||||
long r, n = (long)arg;
|
||||
|
||||
if (n == 1) x++;
|
||||
|
||||
r = pthread_barrier_wait(&bar);
|
||||
assert(r == 0 || r == PTHREAD_BARRIER_SERIAL_THREAD);
|
||||
|
||||
if (n == 0) x++;
|
||||
|
||||
sleep(1); /* ensure both threads get to this point before
|
||||
either exits. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define NTHR 2
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
long i, r;
|
||||
pthread_t thr[NTHR];
|
||||
|
||||
r = pthread_barrier_init(&bar, NULL, NTHR);
|
||||
assert(!r);
|
||||
|
||||
for (i = 0; i < NTHR; i++) {
|
||||
r = pthread_create(&thr[i], NULL, child_fn, (void*)i);
|
||||
assert(!r);
|
||||
}
|
||||
|
||||
for (i = 0; i < NTHR; i++) {
|
||||
r = pthread_join(thr[i], NULL);
|
||||
assert(!r);
|
||||
}
|
||||
|
||||
r = pthread_barrier_destroy(&bar); assert(!r);
|
||||
|
||||
printf("x = %d\n", x);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
x = 2
|
||||
@@ -0,0 +1,3 @@
|
||||
prereq: test -e bar_trivial
|
||||
prog: bar_trivial
|
||||
vgopts: -q
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <pthread.h>
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pthread_cond_t c;
|
||||
pthread_cond_init(& c, NULL);
|
||||
pthread_cond_destroy(& c);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1 @@
|
||||
prog: cond_init_destroy
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
struct timespec abstime;
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
|
||||
|
||||
|
||||
abstime.tv_sec = time(NULL) + 2;
|
||||
abstime.tv_nsec = 0;
|
||||
|
||||
abstime.tv_nsec += 1000000000;
|
||||
|
||||
assert(pthread_mutex_lock(&mutex)==0);
|
||||
assert(pthread_cond_timedwait(&cond, &mutex, &abstime)==EINVAL);
|
||||
assert(pthread_mutex_unlock(&mutex)==0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
---Thread-Announcement------------------------------------------
|
||||
|
||||
Thread #x is the program's root thread
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Thread #x's call to pthread_cond_timedwait failed
|
||||
with error code 22 (EINVAL: Invalid argument)
|
||||
at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
|
||||
by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
|
||||
by 0x........: main (cond_timedwait_invalid.c:22)
|
||||
|
||||
|
||||
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1,2 @@
|
||||
prog: cond_timedwait_invalid
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
int main() {
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
// This time has most definitely passed already. (Epoch)
|
||||
struct timespec now;
|
||||
memset(&now, 0, sizeof(now));
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_timedwait(&cond, &mutex, &now);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
pthread_cond_destroy(&cond);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1 @@
|
||||
prog: cond_timedwait_test
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# A list of files specific to the tool at hand. Line numbers in
|
||||
# these files will be removed from backtrace entries matching these files.
|
||||
#---------------------------------------------------------------------
|
||||
my @tool_files = ( "hg_intercepts.c", "vg_replace_malloc.c" );
|
||||
|
||||
|
||||
sub massage_backtrace_line ($$$) {
|
||||
my ($line, $tool_files, $cmdlin_files) = @_;
|
||||
my ($string, $qstring);
|
||||
|
||||
# If LINE matches any of the file names passed on the command line
|
||||
# (i.e. in CMDLIN_FILES) return LINE unmodified.
|
||||
|
||||
foreach $string (@$cmdlin_files) {
|
||||
$qstring = quotemeta($string);
|
||||
return $line if ($line =~ /$qstring/);
|
||||
}
|
||||
|
||||
# If LINE matches any of the file names in TOOL_FILES remove the line
|
||||
# number and return the so modified line.
|
||||
|
||||
foreach $string (@$tool_files) {
|
||||
$qstring = quotemeta($string);
|
||||
return $line if ($line =~ s/$qstring:[0-9]+/$string:.../m);
|
||||
# Special case for functions whose line numbers have been removed in
|
||||
# filter_stderr_basic. FIXME: filter_stderr_basic should not do that.
|
||||
return $line if ($line =~ s/$qstring:\.\.\./$string:.../m);
|
||||
}
|
||||
|
||||
# Did not match anything
|
||||
$line =~ s/[\w]+.*/.../m;
|
||||
|
||||
return "$line";
|
||||
}
|
||||
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Process lines. Two categories
|
||||
# (a) lines from back traces
|
||||
# pass through those lines that contain file names we're interested in
|
||||
# (b) everything else
|
||||
# pass through as is
|
||||
#---------------------------------------------------------------------
|
||||
my $prev_line = "";
|
||||
while (<STDIN>) {
|
||||
my $line = $_;
|
||||
chomp($line);
|
||||
if ($line =~ /^\s+(at |by )/) { # lines in a back trace
|
||||
$line = massage_backtrace_line($line, \@tool_files, \@ARGV);
|
||||
if ($line =~ /\s+\.\.\./) {
|
||||
print "$line\n" if ($prev_line !~ /\s+\.\.\./);
|
||||
} else {
|
||||
print "$line\n";
|
||||
}
|
||||
} else {
|
||||
print "$line\n"; # everything else
|
||||
}
|
||||
$prev_line = $line
|
||||
}
|
||||
|
||||
exit 0;
|
||||
@@ -0,0 +1,55 @@
|
||||
#! /bin/sh
|
||||
|
||||
dir=`dirname $0`
|
||||
|
||||
$dir/../../tests/filter_stderr_basic |
|
||||
|
||||
# Anonymise addresses
|
||||
$dir/../../tests/filter_addresses |
|
||||
|
||||
# Perform Solaris-specific filtering.
|
||||
if $dir/../../tests/os_test solaris; then
|
||||
perl -p $dir/filter_stderr_solaris
|
||||
else
|
||||
cat
|
||||
fi |
|
||||
|
||||
# get rid of the numbers in bits of text "Thread #n", "thread #n",
|
||||
# "Thread n" and "thread n", "tid n"
|
||||
# as these make some tests more scheduling sensitive -- those where
|
||||
# there are multiple threads which play interchangeable roles.
|
||||
sed \
|
||||
-e "s/tid [0-9][0-9]*/tid #x/g" \
|
||||
-e "s/hread #[0-9][0-9]*/hread #x/g" \
|
||||
-e "s/hread [0-9][0-9]*/hread x/g" |
|
||||
|
||||
# Likewise for frame numbers, which depend on compilation.
|
||||
sed -e "s/frame #[0-9][0-9]*/frame #x/g" | \
|
||||
|
||||
# Remove the message that more than hundred errors have been detected
|
||||
# (consists of two lines) and also the empty line above it.
|
||||
awk 'BEGIN{begin=1} {if ($0 == "More than 100 errors detected. Subsequent errors") { getline; getline; } else { if (begin) begin = 0; else print last_line; }; last_line = $0; } END { if (! begin) print last_line; }' |
|
||||
|
||||
# Merge sem_wait and sem_wait@*, as either could be used. Likewise for
|
||||
# sem_post.
|
||||
sed \
|
||||
-e "s/sem_wait@\*/sem_wait/" \
|
||||
-e "s/sem_post@\*/sem_post/" |
|
||||
|
||||
# Remove "Helgrind, ..." line and the following copyright line;
|
||||
# also the standard postamble (does such a word exist?)
|
||||
# And also remove pthread_create_WRK lines, as ppc64 stacktraces
|
||||
# do not contain them (at least on gcc110/fedora18).
|
||||
sed \
|
||||
-e "/^Helgrind, a thread error detector/ , /./ d" \
|
||||
-e "/^For counts of detected and suppressed errors, rerun with: -v$/d" \
|
||||
-e "/^Use --history-level=approx or =none to gain increased speed, at$/d" \
|
||||
-e "/^the cost of reduced accuracy of conflicting-access information$/d" \
|
||||
-e "/pthread_create_WRK (hg_intercepts.c:/d" |
|
||||
|
||||
# Some arches return ENOSYS instead of EINVAL for undefined futex operations.
|
||||
sed -e "s/with error code 38 (ENOSYS: Function not implemented)/with error code 22 (EINVAL: Invalid argument)/" |
|
||||
|
||||
$dir/../../helgrind/tests/filter_helgrind "$@"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# Replace pthread_create with pthread_create@* which is expected on Linux
|
||||
s/pthread_create \(hg_intercepts.c:/pthread_create@* \(hg_intercepts.c:/g;
|
||||
|
||||
# We need to remove stack frames containing redundant function
|
||||
# names from libc, for example
|
||||
# by 0x........: pthread_mutex_init (in /...libc...)
|
||||
my $check = join "|", ('pthread_mutex_init', 'pthread_cond_wait', 'pthread_cond_timedwait');
|
||||
s/^\s*by 0x........: (?:$check) \(in \/...libc...\)\s*//;
|
||||
|
||||
# We also need to replace Solaris threading and sychronization function
|
||||
# names with POSIX ones for hg_intercepts.c stack frame:
|
||||
# at 0x........: mutex_lock (hg_intercepts.c:1234)
|
||||
# See also comments in hg_intercepts.c.
|
||||
my %regex = (
|
||||
'cond_broadcast' => 'pthread_cond_broadcast@*',
|
||||
'cond_destroy' => 'pthread_cond_destroy@*',
|
||||
'cond_signal' => 'pthread_cond_signal@*',
|
||||
'cond_wait' => 'pthread_cond_wait@*',
|
||||
'cond_timedwait' => 'pthread_cond_timedwait@*',
|
||||
'mutex_destroy' => 'pthread_mutex_destroy',
|
||||
'mutex_init' => 'pthread_mutex_init',
|
||||
'mutex_lock' => 'pthread_mutex_lock',
|
||||
'mutex_trylock' => 'pthread_mutex_trylock',
|
||||
'mutex_unlock' => 'pthread_mutex_unlock',
|
||||
'rwlock_init' => 'pthread_rwlock_init',
|
||||
'rw_unlock' => 'pthread_rwlock_unlock'
|
||||
);
|
||||
my $check = join "|", keys %regex;
|
||||
if (! /: pthread_/ && ! /WRK/) {
|
||||
s/($check)(.*hg_intercepts.c)/$regex{$1}$2/g;
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# Quick and dirty program to filter helgrind's XML output.
|
||||
#
|
||||
# The script works line-by-line and is generally unaware of XML structure
|
||||
# and does not bother with issues of well-formedness.
|
||||
#
|
||||
# Consists of two parts
|
||||
# (1) Global match and replace (see PATTERNS below)
|
||||
# (2) Removal of stack frames
|
||||
# Stack frames whose associated file name does not match any name in
|
||||
# TOOL_FILES or in the list of files given on the command line
|
||||
# will be discarded. For a sequence of one or more discarded frames
|
||||
# a line <frame>...</frame> will be inserted.
|
||||
#
|
||||
#---------------------------------------------------------------------
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
#---------------------------------------------------------------------
|
||||
# A list of files specific to the tool at hand. Line numbers in
|
||||
# these files will be removed from stack frames matching these files.
|
||||
#---------------------------------------------------------------------
|
||||
my @tool_files = ( "hg_intercepts.c", "vg_replace_malloc.c" );
|
||||
|
||||
# List of patterns and replacement strings.
|
||||
# Each pattern must identify a substring which will be replaced.
|
||||
my %patterns = (
|
||||
"<pid>(.*)</pid>" => "...",
|
||||
"<ppid>(.*)</ppid>" => "...",
|
||||
"<time>(.*)</time>" => "...",
|
||||
"<obj>(.*)</obj>" => "...",
|
||||
"<dir>(.*)</dir>" => "...",
|
||||
"<exe>(.*)</exe>" => "...",
|
||||
"<tid>(.*)</tid>" => "...",
|
||||
"<unique>(.*)</unique>" => "...",
|
||||
"thread #([0-9]+)" => "x",
|
||||
"0x([0-9a-zA-Z]+)" => "........",
|
||||
"Using Valgrind-([^\\s]*)" => "X.Y.X",
|
||||
"Copyright \\(C\\) ([0-9]{4}-[0-9]{4}).*" => "XXXX-YYYY",
|
||||
'<fn>pthread_.*(@\*)</fn>' => ""
|
||||
);
|
||||
|
||||
# List of XML sections to be ignored.
|
||||
my %ignore_sections = (
|
||||
"<errorcounts>" => "</errorcounts>",
|
||||
"<suppcounts>" => "</suppcounts>"
|
||||
);
|
||||
|
||||
|
||||
# If FILE matches any of the FILES return 1
|
||||
sub file_matches ($$) {
|
||||
my ($file, $files) = @_;
|
||||
my ($string, $qstring);
|
||||
|
||||
foreach $string (@$files) {
|
||||
$qstring = quotemeta($string);
|
||||
return 1 if ($file =~ /$qstring/);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
my $frame_buf = "";
|
||||
my ($file, $lineno, $in_frame, $keep_frame, $num_discarded, $ignore_line);
|
||||
|
||||
$in_frame = $keep_frame = $num_discarded = $ignore_line = 0;
|
||||
|
||||
line:
|
||||
while (<STDIN>) {
|
||||
my $line = $_;
|
||||
chomp($line);
|
||||
|
||||
# Check whether we're ignoring this piece of XML..
|
||||
if ($ignore_line) {
|
||||
foreach my $tag (keys %ignore_sections) {
|
||||
if ($line =~ $ignore_sections{$tag}) {
|
||||
print "$tag...$ignore_sections{$tag}\n";
|
||||
$ignore_line = 0;
|
||||
next line;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach my $tag (keys %ignore_sections) {
|
||||
if ($line =~ $tag) {
|
||||
$ignore_line = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
next if ($ignore_line);
|
||||
|
||||
# OK. This line is not to be ignored.
|
||||
|
||||
# Massage line by applying PATTERNS.
|
||||
foreach my $key (keys %patterns) {
|
||||
if ($line =~ $key) {
|
||||
my $matched = quotemeta($1);
|
||||
$line =~ s/$matched/$patterns{$key}/g;
|
||||
}
|
||||
}
|
||||
|
||||
# Handle frames
|
||||
if ($in_frame) {
|
||||
if ($line =~ /<\/frame>/) {
|
||||
$frame_buf .= "$line\n";
|
||||
# The end of a frame
|
||||
if ($keep_frame) {
|
||||
# First: If there were any preceding frames that were discarded
|
||||
# print <frame>...</frame>
|
||||
if ($num_discarded) {
|
||||
print " <frame>...</frame>\n";
|
||||
$num_discarded = 0;
|
||||
}
|
||||
# Secondly: Write out the frame itself
|
||||
print "$frame_buf";
|
||||
} else {
|
||||
# We don't want to write this frame
|
||||
++$num_discarded;
|
||||
}
|
||||
$in_frame = $keep_frame = 0;
|
||||
$file = "";
|
||||
} elsif ($line =~ /<file>(.*)<\/file>/) {
|
||||
$frame_buf .= "$line\n";
|
||||
$file = $1;
|
||||
if (file_matches($file, \@tool_files) ||
|
||||
file_matches($file, \@ARGV)) {
|
||||
$keep_frame = 1;
|
||||
}
|
||||
} elsif ($line =~ /<line>(.*)<\/line>/) {
|
||||
# This code assumes that <file> always precedes <line>
|
||||
$lineno = $1;
|
||||
if (file_matches($file, \@tool_files)) {
|
||||
$line =~ s/$1/.../;
|
||||
}
|
||||
$frame_buf .= "$line\n";
|
||||
} else {
|
||||
$frame_buf .= "$line\n";
|
||||
}
|
||||
} else {
|
||||
# not within frame
|
||||
if ($line =~ /<\/stack>/) {
|
||||
print " <frame>...</frame>\n" if ($num_discarded);
|
||||
$num_discarded = 0;
|
||||
}
|
||||
if ($line =~ /<frame>/) {
|
||||
$in_frame = 1;
|
||||
$frame_buf = "$line\n";
|
||||
} else {
|
||||
print "$line\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit 0;
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static char* s_mem;
|
||||
|
||||
/* wait a second, so as to guarantee that the parent access
|
||||
the malloc'd area, then free it. */
|
||||
static void* thread_func(void* arg)
|
||||
{
|
||||
sleep(1);
|
||||
free(s_mem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
pthread_t tid;
|
||||
int quiet;
|
||||
|
||||
fprintf(stderr, "Start.\n");
|
||||
|
||||
quiet = argc > 1;
|
||||
|
||||
s_mem = malloc(10);
|
||||
if (0 && !quiet)
|
||||
fprintf(stderr, "Pointer to allocated memory: %p\n", s_mem);
|
||||
assert(s_mem);
|
||||
pthread_create(&tid, NULL, thread_func, NULL);
|
||||
|
||||
/* Write, which isn't coordinated with the free ==> a race
|
||||
should be reported. */
|
||||
char c = s_mem[5];
|
||||
__asm__ __volatile__("" : : "r"((long)c) );
|
||||
|
||||
pthread_join(tid, NULL);
|
||||
fprintf(stderr, "Done.\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
Start.
|
||||
---Thread-Announcement------------------------------------------
|
||||
|
||||
Thread #x was created
|
||||
...
|
||||
by 0x........: pthread_create@* (hg_intercepts.c:...)
|
||||
by 0x........: main (free_is_write.c:32)
|
||||
|
||||
---Thread-Announcement------------------------------------------
|
||||
|
||||
Thread #x is the program's root thread
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Possible data race during write of size 1 at 0x........ by thread #x
|
||||
Locks held: none
|
||||
at 0x........: free (vg_replace_malloc.c:...)
|
||||
by 0x........: thread_func (free_is_write.c:15)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
This conflicts with a previous read of size 1 by thread #x
|
||||
Locks held: none
|
||||
at 0x........: main (free_is_write.c:36)
|
||||
Address 0x........ is 5 bytes inside an unallocated block of size 16 in arena "client"
|
||||
|
||||
Done.
|
||||
|
||||
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1,2 @@
|
||||
prog: free_is_write
|
||||
vgopts: --free-is-write=yes
|
||||
@@ -0,0 +1,48 @@
|
||||
/* All OK */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int shared = 0;
|
||||
static char *ptr;
|
||||
|
||||
static void breakme(void)
|
||||
{
|
||||
if (shared == 1)
|
||||
memset (ptr, 0x55, 1000);
|
||||
}
|
||||
|
||||
static void *th(void *v)
|
||||
{
|
||||
pthread_mutex_lock(&mx);
|
||||
shared++;
|
||||
if (shared == 1) {
|
||||
ptr = malloc (1008);
|
||||
breakme();
|
||||
}
|
||||
if (shared == 2) {
|
||||
free (ptr);
|
||||
breakme();
|
||||
}
|
||||
pthread_mutex_unlock(&mx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t a, b;
|
||||
|
||||
pthread_mutex_lock(&mx);
|
||||
pthread_mutex_unlock(&mx);
|
||||
|
||||
pthread_create(&a, NULL, th, NULL);
|
||||
pthread_create(&b, NULL, th, NULL);
|
||||
|
||||
pthread_join(a, NULL);
|
||||
pthread_join(b, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1 @@
|
||||
prog: hg01_all_ok
|
||||
@@ -0,0 +1,43 @@
|
||||
/* Simple possible deadlock */
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void *t1(void *v)
|
||||
{
|
||||
pthread_mutex_lock(&m1);
|
||||
pthread_mutex_lock(&m2);
|
||||
pthread_mutex_unlock(&m1);
|
||||
pthread_mutex_unlock(&m2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *t2(void *v)
|
||||
{
|
||||
pthread_mutex_lock(&m2);
|
||||
pthread_mutex_lock(&m1);
|
||||
pthread_mutex_unlock(&m1);
|
||||
pthread_mutex_unlock(&m2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t a, b;
|
||||
|
||||
/* prevent spurious messages from the dynamic linker */
|
||||
pthread_mutex_lock(&m1);
|
||||
pthread_mutex_unlock(&m1);
|
||||
|
||||
pthread_create(&a, NULL, t1, NULL);
|
||||
pthread_create(&b, NULL, t2, NULL);
|
||||
|
||||
pthread_join(a, NULL);
|
||||
pthread_join(b, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
---Thread-Announcement------------------------------------------
|
||||
|
||||
Thread #x was created
|
||||
...
|
||||
by 0x........: pthread_create@* (hg_intercepts.c:...)
|
||||
by 0x........: main (hg02_deadlock.c:36)
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Thread #x: lock order "0x........ before 0x........" violated
|
||||
|
||||
Observed (incorrect) order is: acquisition of lock at 0x........
|
||||
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
|
||||
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
|
||||
by 0x........: t2 (hg02_deadlock.c:19)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
followed by a later acquisition of lock at 0x........
|
||||
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
|
||||
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
|
||||
by 0x........: t2 (hg02_deadlock.c:20)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Required order was established by acquisition of lock at 0x........
|
||||
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
|
||||
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
|
||||
by 0x........: t1 (hg02_deadlock.c:9)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
followed by a later acquisition of lock at 0x........
|
||||
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
|
||||
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
|
||||
by 0x........: t1 (hg02_deadlock.c:10)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
Lock at 0x........ was first observed
|
||||
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
|
||||
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
|
||||
by 0x........: main (hg02_deadlock.c:32)
|
||||
Address 0x........ is 0 bytes inside data symbol "m1"
|
||||
|
||||
Lock at 0x........ was first observed
|
||||
at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
|
||||
by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
|
||||
by 0x........: t1 (hg02_deadlock.c:10)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
Address 0x........ is 0 bytes inside data symbol "m2"
|
||||
|
||||
|
||||
|
||||
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1 @@
|
||||
prog: hg02_deadlock
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
/* I don't think this is a very good test .. all this
|
||||
sleepery is highly confusing. */
|
||||
|
||||
/* test child thread inheriting data */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static volatile int shared[2];
|
||||
|
||||
static void *t1(void *v)
|
||||
{
|
||||
volatile int *ip = (int *)v;
|
||||
if (0) printf("ta W\n");
|
||||
*ip += 44;
|
||||
*ip *= 2;
|
||||
sleep(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *t2(void *v)
|
||||
{
|
||||
volatile int *ip = (int *)v;
|
||||
sleep(2);
|
||||
if (0) printf("tb W\n");
|
||||
*ip += 88;
|
||||
*ip *= 3;
|
||||
sleep(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
pthread_t a, b;
|
||||
volatile int ret = 0;
|
||||
|
||||
sleep(0);
|
||||
|
||||
shared[0] = 22;
|
||||
shared[1] = 77;
|
||||
|
||||
pthread_create(&a, NULL, t1, (void *)&shared[0]);
|
||||
// a steals shared[0] from root thread, so is excl(a)
|
||||
pthread_create(&b, NULL, t2, (void *)&shared[1]);
|
||||
// b steals shared[1] from root thread, so is excl(b)
|
||||
|
||||
pthread_join(a, NULL);
|
||||
// b's stuff (shared[1]) still belongs to b, so is excl(b)
|
||||
|
||||
// ret is excl(root), and shared[0] is re-acquired as excl(root)
|
||||
// since a joined to root
|
||||
if (0) printf("r R1\n");
|
||||
ret += shared[0]; /* no error - a is finished */
|
||||
|
||||
// but shared[1] is excl(b); hence we're reading excl(b)
|
||||
// without a lock and without a dependency edge
|
||||
if (0) printf("r R2\n");
|
||||
ret += shared[1]; /* expect error - b has not finished,
|
||||
so we can't touch shared[1] yet */
|
||||
|
||||
pthread_join(b, NULL);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
---Thread-Announcement------------------------------------------
|
||||
|
||||
Thread #x was created
|
||||
...
|
||||
by 0x........: pthread_create@* (hg_intercepts.c:...)
|
||||
by 0x........: main (hg03_inherit.c:46)
|
||||
|
||||
---Thread-Announcement------------------------------------------
|
||||
|
||||
Thread #x is the program's root thread
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Possible data race during write of size 4 at 0x........ by thread #x
|
||||
Locks held: none
|
||||
at 0x........: t2 (hg03_inherit.c:28)
|
||||
by 0x........: mythread_wrapper (hg_intercepts.c:...)
|
||||
...
|
||||
|
||||
This conflicts with a previous read of size 4 by thread #x
|
||||
Locks held: none
|
||||
at 0x........: main (hg03_inherit.c:60)
|
||||
Location 0x........ is 0 bytes inside shared[1],
|
||||
a global variable declared at hg03_inherit.c:11
|
||||
|
||||
|
||||
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1,2 @@
|
||||
prog: hg03_inherit
|
||||
vgopts: --read-var-info=yes
|
||||
@@ -0,0 +1,27 @@
|
||||
/* A simple race */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int shared;
|
||||
|
||||
static void *th(void *v)
|
||||
{
|
||||
shared++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
pthread_t a, b;
|
||||
|
||||
pthread_create(&a, NULL, th, NULL);
|
||||
sleep(1); /* force ordering */
|
||||
pthread_create(&b, NULL, th, NULL);
|
||||
|
||||
pthread_join(a, NULL);
|
||||
pthread_join(b, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user