mirror of
https://github.com/ioacademy-jikim/debugging
synced 2026-08-31 09:49:38 +00:00
first commit
This commit is contained in:
@@ -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,54 @@
|
||||
helgrind_x86_linux-hg_addrdescr.o: hg_addrdescr.c \
|
||||
/usr/include/stdc-predef.h ../include/pub_tool_basics.h \
|
||||
../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_libcbase.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcprint.h ../include/pub_tool_libcassert.h \
|
||||
../include/pub_tool_wordfm.h ../include/pub_tool_xarray.h \
|
||||
../include/pub_tool_execontext.h ../include/pub_tool_debuginfo.h \
|
||||
../include/pub_tool_xarray.h ../include/pub_tool_threadstate.h \
|
||||
../include/pub_tool_aspacemgr.h ../include/pub_tool_addrinfo.h \
|
||||
../include/pub_tool_aspacemgr.h hg_basics.h hg_wordset.h \
|
||||
hg_lock_n_thread.h hg_addrdescr.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_libcbase.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcprint.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_wordfm.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../include/pub_tool_debuginfo.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_threadstate.h:
|
||||
|
||||
../include/pub_tool_aspacemgr.h:
|
||||
|
||||
../include/pub_tool_addrinfo.h:
|
||||
|
||||
../include/pub_tool_aspacemgr.h:
|
||||
|
||||
hg_basics.h:
|
||||
|
||||
hg_wordset.h:
|
||||
|
||||
hg_lock_n_thread.h:
|
||||
|
||||
hg_addrdescr.h:
|
||||
@@ -0,0 +1,26 @@
|
||||
helgrind_x86_linux-hg_basics.o: hg_basics.c /usr/include/stdc-predef.h \
|
||||
../include/pub_tool_basics.h ../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_libcbase.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcassert.h ../include/pub_tool_mallocfree.h \
|
||||
../include/pub_tool_threadstate.h hg_basics.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_libcbase.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_mallocfree.h:
|
||||
|
||||
../include/pub_tool_threadstate.h:
|
||||
|
||||
hg_basics.h:
|
||||
@@ -0,0 +1,75 @@
|
||||
helgrind_x86_linux-hg_errors.o: hg_errors.c /usr/include/stdc-predef.h \
|
||||
../include/pub_tool_basics.h ../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_libcbase.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcassert.h ../include/pub_tool_libcprint.h \
|
||||
../include/pub_tool_stacktrace.h ../include/pub_tool_execontext.h \
|
||||
../include/pub_tool_errormgr.h ../include/pub_tool_execontext.h \
|
||||
../include/pub_tool_wordfm.h ../include/pub_tool_xarray.h \
|
||||
../include/pub_tool_debuginfo.h ../include/pub_tool_xarray.h \
|
||||
../include/pub_tool_threadstate.h ../include/pub_tool_options.h \
|
||||
../VEX/pub/libvex.h ../VEX/pub/libvex_basictypes.h \
|
||||
../VEX/pub/libvex_ir.h ../include/pub_tool_aspacemgr.h \
|
||||
../include/pub_tool_addrinfo.h ../include/pub_tool_aspacemgr.h \
|
||||
hg_basics.h hg_addrdescr.h hg_wordset.h hg_lock_n_thread.h libhb.h \
|
||||
hg_errors.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_libcbase.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_libcprint.h:
|
||||
|
||||
../include/pub_tool_stacktrace.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../include/pub_tool_errormgr.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../include/pub_tool_wordfm.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_debuginfo.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_threadstate.h:
|
||||
|
||||
../include/pub_tool_options.h:
|
||||
|
||||
../VEX/pub/libvex.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
../VEX/pub/libvex_ir.h:
|
||||
|
||||
../include/pub_tool_aspacemgr.h:
|
||||
|
||||
../include/pub_tool_addrinfo.h:
|
||||
|
||||
../include/pub_tool_aspacemgr.h:
|
||||
|
||||
hg_basics.h:
|
||||
|
||||
hg_addrdescr.h:
|
||||
|
||||
hg_wordset.h:
|
||||
|
||||
hg_lock_n_thread.h:
|
||||
|
||||
libhb.h:
|
||||
|
||||
hg_errors.h:
|
||||
@@ -0,0 +1,34 @@
|
||||
helgrind_x86_linux-hg_lock_n_thread.o: hg_lock_n_thread.c \
|
||||
/usr/include/stdc-predef.h ../include/pub_tool_basics.h \
|
||||
../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_libcbase.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcassert.h ../include/pub_tool_execontext.h \
|
||||
../include/pub_tool_threadstate.h ../include/pub_tool_wordfm.h \
|
||||
hg_basics.h hg_wordset.h hg_lock_n_thread.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_libcbase.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../include/pub_tool_threadstate.h:
|
||||
|
||||
../include/pub_tool_wordfm.h:
|
||||
|
||||
hg_basics.h:
|
||||
|
||||
hg_wordset.h:
|
||||
|
||||
hg_lock_n_thread.h:
|
||||
@@ -0,0 +1,148 @@
|
||||
helgrind_x86_linux-hg_main.o: hg_main.c /usr/include/stdc-predef.h \
|
||||
../include/pub_tool_basics.h ../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_gdbserver.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcassert.h ../include/pub_tool_libcbase.h \
|
||||
../include/pub_tool_libcprint.h ../include/pub_tool_threadstate.h \
|
||||
../include/pub_tool_tooliface.h ../include/pub_tool_errormgr.h \
|
||||
../include/pub_tool_execontext.h ../VEX/pub/libvex.h \
|
||||
../VEX/pub/libvex_basictypes.h ../VEX/pub/libvex_ir.h \
|
||||
../include/pub_tool_hashtable.h ../include/pub_tool_replacemalloc.h \
|
||||
../include/pub_tool_machine.h ../include/pub_tool_options.h \
|
||||
../include/pub_tool_xarray.h ../include/pub_tool_stacktrace.h \
|
||||
../include/pub_tool_wordfm.h ../include/pub_tool_debuginfo.h \
|
||||
../include/pub_tool_xarray.h ../include/pub_tool_redir.h ../config.h \
|
||||
../include/pub_tool_vki.h ../include/vki/vki-linux.h \
|
||||
../include/vki/vki-posixtypes-x86-linux.h ../include/vki/vki-x86-linux.h \
|
||||
../include/vki/vki-linux-drm.h ../include/vki/vki-xen.h \
|
||||
../include/vki/vki-xen-x86.h ../include/vki/vki-xen-domctl.h \
|
||||
../include/vki/vki-xen-sysctl.h ../include/vki/vki-xen-mmuext.h \
|
||||
../include/vki/vki-xen-schedop.h ../include/vki/vki-xen-memory.h \
|
||||
../include/vki/vki-xen-evtchn.h ../include/vki/vki-xen-gnttab.h \
|
||||
../include/vki/vki-xen-version.h ../include/vki/vki-xen-hvm.h \
|
||||
../include/vki/vki-xen-tmem.h ../include/vki/vki-xen-xsm.h \
|
||||
../include/vki/vki-xen-physdev.h ../include/pub_tool_libcproc.h \
|
||||
../include/pub_tool_vki.h ../include/pub_tool_aspacemgr.h \
|
||||
../include/pub_tool_poolalloc.h ../include/pub_tool_addrinfo.h \
|
||||
../include/pub_tool_aspacemgr.h hg_basics.h hg_wordset.h hg_addrdescr.h \
|
||||
hg_lock_n_thread.h hg_errors.h libhb.h helgrind.h ../include/valgrind.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_gdbserver.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_libcbase.h:
|
||||
|
||||
../include/pub_tool_libcprint.h:
|
||||
|
||||
../include/pub_tool_threadstate.h:
|
||||
|
||||
../include/pub_tool_tooliface.h:
|
||||
|
||||
../include/pub_tool_errormgr.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../VEX/pub/libvex.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
../VEX/pub/libvex_ir.h:
|
||||
|
||||
../include/pub_tool_hashtable.h:
|
||||
|
||||
../include/pub_tool_replacemalloc.h:
|
||||
|
||||
../include/pub_tool_machine.h:
|
||||
|
||||
../include/pub_tool_options.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_stacktrace.h:
|
||||
|
||||
../include/pub_tool_wordfm.h:
|
||||
|
||||
../include/pub_tool_debuginfo.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_redir.h:
|
||||
|
||||
../config.h:
|
||||
|
||||
../include/pub_tool_vki.h:
|
||||
|
||||
../include/vki/vki-linux.h:
|
||||
|
||||
../include/vki/vki-posixtypes-x86-linux.h:
|
||||
|
||||
../include/vki/vki-x86-linux.h:
|
||||
|
||||
../include/vki/vki-linux-drm.h:
|
||||
|
||||
../include/vki/vki-xen.h:
|
||||
|
||||
../include/vki/vki-xen-x86.h:
|
||||
|
||||
../include/vki/vki-xen-domctl.h:
|
||||
|
||||
../include/vki/vki-xen-sysctl.h:
|
||||
|
||||
../include/vki/vki-xen-mmuext.h:
|
||||
|
||||
../include/vki/vki-xen-schedop.h:
|
||||
|
||||
../include/vki/vki-xen-memory.h:
|
||||
|
||||
../include/vki/vki-xen-evtchn.h:
|
||||
|
||||
../include/vki/vki-xen-gnttab.h:
|
||||
|
||||
../include/vki/vki-xen-version.h:
|
||||
|
||||
../include/vki/vki-xen-hvm.h:
|
||||
|
||||
../include/vki/vki-xen-tmem.h:
|
||||
|
||||
../include/vki/vki-xen-xsm.h:
|
||||
|
||||
../include/vki/vki-xen-physdev.h:
|
||||
|
||||
../include/pub_tool_libcproc.h:
|
||||
|
||||
../include/pub_tool_vki.h:
|
||||
|
||||
../include/pub_tool_aspacemgr.h:
|
||||
|
||||
../include/pub_tool_poolalloc.h:
|
||||
|
||||
../include/pub_tool_addrinfo.h:
|
||||
|
||||
../include/pub_tool_aspacemgr.h:
|
||||
|
||||
hg_basics.h:
|
||||
|
||||
hg_wordset.h:
|
||||
|
||||
hg_addrdescr.h:
|
||||
|
||||
hg_lock_n_thread.h:
|
||||
|
||||
hg_errors.h:
|
||||
|
||||
libhb.h:
|
||||
|
||||
helgrind.h:
|
||||
|
||||
../include/valgrind.h:
|
||||
@@ -0,0 +1,31 @@
|
||||
helgrind_x86_linux-hg_wordset.o: hg_wordset.c /usr/include/stdc-predef.h \
|
||||
../include/pub_tool_basics.h ../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_libcassert.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcbase.h ../include/pub_tool_libcprint.h \
|
||||
../include/pub_tool_threadstate.h ../include/pub_tool_wordfm.h \
|
||||
hg_basics.h hg_wordset.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcbase.h:
|
||||
|
||||
../include/pub_tool_libcprint.h:
|
||||
|
||||
../include/pub_tool_threadstate.h:
|
||||
|
||||
../include/pub_tool_wordfm.h:
|
||||
|
||||
hg_basics.h:
|
||||
|
||||
hg_wordset.h:
|
||||
@@ -0,0 +1,72 @@
|
||||
helgrind_x86_linux-libhb_core.o: libhb_core.c /usr/include/stdc-predef.h \
|
||||
../include/pub_tool_basics.h ../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_poolalloc.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcassert.h ../include/pub_tool_libcbase.h \
|
||||
../include/pub_tool_libcprint.h ../include/pub_tool_mallocfree.h \
|
||||
../include/pub_tool_wordfm.h ../include/pub_tool_hashtable.h \
|
||||
../include/pub_tool_xarray.h ../include/pub_tool_oset.h \
|
||||
../include/pub_tool_threadstate.h ../include/pub_tool_aspacemgr.h \
|
||||
../include/pub_tool_stacktrace.h ../include/pub_tool_execontext.h \
|
||||
../include/pub_tool_errormgr.h ../include/pub_tool_execontext.h \
|
||||
../include/pub_tool_options.h ../VEX/pub/libvex.h \
|
||||
../VEX/pub/libvex_basictypes.h ../VEX/pub/libvex_ir.h hg_basics.h \
|
||||
hg_wordset.h hg_lock_n_thread.h hg_errors.h libhb.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_poolalloc.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_libcbase.h:
|
||||
|
||||
../include/pub_tool_libcprint.h:
|
||||
|
||||
../include/pub_tool_mallocfree.h:
|
||||
|
||||
../include/pub_tool_wordfm.h:
|
||||
|
||||
../include/pub_tool_hashtable.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_oset.h:
|
||||
|
||||
../include/pub_tool_threadstate.h:
|
||||
|
||||
../include/pub_tool_aspacemgr.h:
|
||||
|
||||
../include/pub_tool_stacktrace.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../include/pub_tool_errormgr.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../include/pub_tool_options.h:
|
||||
|
||||
../VEX/pub/libvex.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
../VEX/pub/libvex_ir.h:
|
||||
|
||||
hg_basics.h:
|
||||
|
||||
hg_wordset.h:
|
||||
|
||||
hg_lock_n_thread.h:
|
||||
|
||||
hg_errors.h:
|
||||
|
||||
libhb.h:
|
||||
+1
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
vgpreload_helgrind_x86_linux_so-hg_intercepts.o: hg_intercepts.c \
|
||||
/usr/include/stdc-predef.h ../include/pub_tool_basics.h \
|
||||
../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_redir.h ../config.h ../include/pub_tool_clreq.h \
|
||||
../include/valgrind.h helgrind.h ../include/valgrind.h \
|
||||
/usr/include/stdio.h /usr/include/features.h \
|
||||
/usr/include/i386-linux-gnu/sys/cdefs.h \
|
||||
/usr/include/i386-linux-gnu/bits/wordsize.h \
|
||||
/usr/include/i386-linux-gnu/gnu/stubs.h \
|
||||
/usr/include/i386-linux-gnu/gnu/stubs-32.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stddef.h \
|
||||
/usr/include/i386-linux-gnu/bits/types.h \
|
||||
/usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/libio.h \
|
||||
/usr/include/_G_config.h /usr/include/wchar.h \
|
||||
/usr/include/i386-linux-gnu/bits/stdio_lim.h \
|
||||
/usr/include/i386-linux-gnu/bits/sys_errlist.h \
|
||||
/usr/include/i386-linux-gnu/bits/stdio.h \
|
||||
/usr/include/i386-linux-gnu/bits/stdio2.h /usr/include/assert.h \
|
||||
/usr/include/errno.h /usr/include/i386-linux-gnu/bits/errno.h \
|
||||
/usr/include/linux/errno.h /usr/include/i386-linux-gnu/asm/errno.h \
|
||||
/usr/include/asm-generic/errno.h /usr/include/asm-generic/errno-base.h \
|
||||
/usr/include/pthread.h /usr/include/endian.h \
|
||||
/usr/include/i386-linux-gnu/bits/endian.h \
|
||||
/usr/include/i386-linux-gnu/bits/byteswap.h \
|
||||
/usr/include/i386-linux-gnu/bits/byteswap-16.h /usr/include/sched.h \
|
||||
/usr/include/time.h /usr/include/i386-linux-gnu/bits/sched.h \
|
||||
/usr/include/i386-linux-gnu/bits/time.h \
|
||||
/usr/include/i386-linux-gnu/bits/timex.h /usr/include/xlocale.h \
|
||||
/usr/include/i386-linux-gnu/bits/pthreadtypes.h \
|
||||
/usr/include/i386-linux-gnu/bits/setjmp.h /usr/include/semaphore.h \
|
||||
/usr/include/i386-linux-gnu/sys/types.h \
|
||||
/usr/include/i386-linux-gnu/sys/select.h \
|
||||
/usr/include/i386-linux-gnu/bits/select.h \
|
||||
/usr/include/i386-linux-gnu/bits/sigset.h \
|
||||
/usr/include/i386-linux-gnu/bits/select2.h \
|
||||
/usr/include/i386-linux-gnu/sys/sysmacros.h \
|
||||
/usr/include/i386-linux-gnu/bits/semaphore.h /usr/include/fcntl.h \
|
||||
/usr/include/i386-linux-gnu/bits/fcntl.h \
|
||||
/usr/include/i386-linux-gnu/bits/fcntl-linux.h \
|
||||
/usr/include/i386-linux-gnu/bits/uio.h \
|
||||
/usr/include/i386-linux-gnu/bits/stat.h \
|
||||
/usr/include/i386-linux-gnu/bits/fcntl2.h ../shared/vg_replace_strmem.c \
|
||||
../include/pub_tool_poolalloc.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_hashtable.h ../include/pub_tool_tooliface.h \
|
||||
../include/pub_tool_errormgr.h ../include/pub_tool_execontext.h \
|
||||
../VEX/pub/libvex.h ../VEX/pub/libvex_basictypes.h \
|
||||
../VEX/pub/libvex_ir.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_redir.h:
|
||||
|
||||
../config.h:
|
||||
|
||||
../include/pub_tool_clreq.h:
|
||||
|
||||
../include/valgrind.h:
|
||||
|
||||
helgrind.h:
|
||||
|
||||
../include/valgrind.h:
|
||||
|
||||
/usr/include/stdio.h:
|
||||
|
||||
/usr/include/features.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/sys/cdefs.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/wordsize.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/gnu/stubs.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/gnu/stubs-32.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stddef.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/types.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/typesizes.h:
|
||||
|
||||
/usr/include/libio.h:
|
||||
|
||||
/usr/include/_G_config.h:
|
||||
|
||||
/usr/include/wchar.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/stdio_lim.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/sys_errlist.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/stdio.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/stdio2.h:
|
||||
|
||||
/usr/include/assert.h:
|
||||
|
||||
/usr/include/errno.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/errno.h:
|
||||
|
||||
/usr/include/linux/errno.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/asm/errno.h:
|
||||
|
||||
/usr/include/asm-generic/errno.h:
|
||||
|
||||
/usr/include/asm-generic/errno-base.h:
|
||||
|
||||
/usr/include/pthread.h:
|
||||
|
||||
/usr/include/endian.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/endian.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/byteswap.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/byteswap-16.h:
|
||||
|
||||
/usr/include/sched.h:
|
||||
|
||||
/usr/include/time.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/sched.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/time.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/timex.h:
|
||||
|
||||
/usr/include/xlocale.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/pthreadtypes.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/setjmp.h:
|
||||
|
||||
/usr/include/semaphore.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/sys/types.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/sys/select.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/select.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/sigset.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/select2.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/sys/sysmacros.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/semaphore.h:
|
||||
|
||||
/usr/include/fcntl.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/fcntl.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/fcntl-linux.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/uio.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/stat.h:
|
||||
|
||||
/usr/include/i386-linux-gnu/bits/fcntl2.h:
|
||||
|
||||
../shared/vg_replace_strmem.c:
|
||||
|
||||
../include/pub_tool_poolalloc.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_hashtable.h:
|
||||
|
||||
../include/pub_tool_tooliface.h:
|
||||
|
||||
../include/pub_tool_errormgr.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../VEX/pub/libvex.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
../VEX/pub/libvex_ir.h:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,120 @@
|
||||
include $(top_srcdir)/Makefile.tool.am
|
||||
|
||||
EXTRA_DIST = \
|
||||
docs/hg-manual.xml \
|
||||
README_MSMProp2.txt \
|
||||
README_YARD.txt
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Headers, etc
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
pkginclude_HEADERS = helgrind.h
|
||||
|
||||
noinst_HEADERS = \
|
||||
hg_addrdescr.h \
|
||||
hg_basics.h \
|
||||
hg_errors.h \
|
||||
hg_lock_n_thread.h \
|
||||
hg_wordset.h \
|
||||
libhb.h
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# helgrind-<platform>
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
noinst_PROGRAMS = helgrind-@VGCONF_ARCH_PRI@-@VGCONF_OS@
|
||||
if VGCONF_HAVE_PLATFORM_SEC
|
||||
noinst_PROGRAMS += helgrind-@VGCONF_ARCH_SEC@-@VGCONF_OS@
|
||||
endif
|
||||
|
||||
HELGRIND_SOURCES_COMMON = \
|
||||
hg_addrdescr.c \
|
||||
hg_basics.c \
|
||||
hg_errors.c \
|
||||
hg_lock_n_thread.c \
|
||||
hg_main.c \
|
||||
hg_wordset.c \
|
||||
libhb_core.c
|
||||
|
||||
helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_SOURCES = \
|
||||
$(HELGRIND_SOURCES_COMMON)
|
||||
helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS = \
|
||||
$(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) -O2
|
||||
helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_DEPENDENCIES = \
|
||||
$(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDADD = \
|
||||
$(TOOL_LDADD_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS = \
|
||||
$(TOOL_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LINK = \
|
||||
$(top_builddir)/coregrind/link_tool_exe_@VGCONF_OS@ \
|
||||
@VALT_LOAD_ADDRESS_PRI@ \
|
||||
$(LINK) \
|
||||
$(helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS) \
|
||||
$(helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS)
|
||||
|
||||
if VGCONF_HAVE_PLATFORM_SEC
|
||||
helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_SOURCES = \
|
||||
$(HELGRIND_SOURCES_COMMON)
|
||||
helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS = \
|
||||
$(AM_CFLAGS_@VGCONF_PLATFORM_SEC_CAPS@) -O2
|
||||
helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_DEPENDENCIES = \
|
||||
$(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDADD = \
|
||||
$(TOOL_LDADD_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDFLAGS = \
|
||||
$(TOOL_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LINK = \
|
||||
$(top_builddir)/coregrind/link_tool_exe_@VGCONF_OS@ \
|
||||
@VALT_LOAD_ADDRESS_SEC@ \
|
||||
$(LINK) \
|
||||
$(helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS) \
|
||||
$(helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDFLAGS)
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# vgpreload_helgrind-<platform>.so
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
noinst_PROGRAMS += vgpreload_helgrind-@VGCONF_ARCH_PRI@-@VGCONF_OS@.so
|
||||
if VGCONF_HAVE_PLATFORM_SEC
|
||||
noinst_PROGRAMS += vgpreload_helgrind-@VGCONF_ARCH_SEC@-@VGCONF_OS@.so
|
||||
endif
|
||||
|
||||
if VGCONF_OS_IS_DARWIN
|
||||
noinst_DSYMS = $(noinst_PROGRAMS)
|
||||
endif
|
||||
|
||||
VGPRELOAD_HELGRIND_SOURCES_COMMON = hg_intercepts.c
|
||||
|
||||
vgpreload_helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_SOURCES = \
|
||||
$(VGPRELOAD_HELGRIND_SOURCES_COMMON)
|
||||
vgpreload_helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
vgpreload_helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_CFLAGS = \
|
||||
$(AM_CFLAGS_PSO_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
vgpreload_helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_DEPENDENCIES = \
|
||||
$(LIBREPLACEMALLOC_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
vgpreload_helgrind_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_LDFLAGS = \
|
||||
$(PRELOAD_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) \
|
||||
$(LIBREPLACEMALLOC_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
|
||||
if VGCONF_HAVE_PLATFORM_SEC
|
||||
vgpreload_helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_SOURCES = \
|
||||
$(VGPRELOAD_HELGRIND_SOURCES_COMMON)
|
||||
vgpreload_helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
vgpreload_helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_CFLAGS = \
|
||||
$(AM_CFLAGS_PSO_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
vgpreload_helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_DEPENDENCIES = \
|
||||
$(LIBREPLACEMALLOC_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
vgpreload_helgrind_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_LDFLAGS = \
|
||||
$(PRELOAD_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@) \
|
||||
$(LIBREPLACEMALLOC_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,156 @@
|
||||
|
||||
MSMProp2, a simplified but functionally equivalent version of MSMProp1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Julian Seward, OpenWorks Ltd, 19 August 2008
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Note that this file does NOT describe the state machine used in the
|
||||
svn://svn.valgrind.org/branches/YARD version of Helgrind. That state
|
||||
machine is different again from any previously described machine.
|
||||
|
||||
See the file README_YARD.txt for more details on YARD.
|
||||
|
||||
----------------------
|
||||
|
||||
In early 2008 Konstantin Serebryany proposed "MSMProp1", a memory
|
||||
state machine for data race detection. It is described at
|
||||
http://code.google.com/p/data-race-test/wiki/MSMProp1
|
||||
|
||||
Implementation experiences show MSMProp1 is useful, but difficult to
|
||||
implement efficiently. In particular keeping the memory usage under
|
||||
control is complex and difficult.
|
||||
|
||||
This note points out a key simplification of MSMProp1, which makes it
|
||||
easier to implement without changing the functionality.
|
||||
|
||||
|
||||
The idea
|
||||
~~~~~~~~
|
||||
|
||||
The core of the idea pertains to the "Condition" entry for MSMProp1
|
||||
state machine rules E5 and E6(r). These are, respectively:
|
||||
|
||||
HB(SS, currS) and its negation
|
||||
! HB(SS, currS).
|
||||
|
||||
Here, SS is a set of segments, and currS is a single segment. Each
|
||||
segment contains a vector timestamp. The expression "HB(SS, currS)"
|
||||
is intended to denote
|
||||
|
||||
for each segment S in SS . happens_before(S,currS)
|
||||
|
||||
where happens_before(S,T) means that S's vector timestamp is ordered
|
||||
before-or-equal to T's vector timestamp.
|
||||
|
||||
In words, the expression
|
||||
|
||||
for each segment S in SS . happens_before(S,currS)
|
||||
|
||||
is equivalent to saying that currS has a timestamp which is
|
||||
greater-than-equal to the timestamps of all the segments in SS.
|
||||
|
||||
The key observation is that this is equivalent to
|
||||
|
||||
happens_before( JOIN(SS), currS )
|
||||
|
||||
where JOIN is the lattice-theoretic "max" or "least upper bound"
|
||||
operation on vector clocks. Given the definition of HB,
|
||||
happens_before and (binary) JOIN, this is easy to prove.
|
||||
|
||||
|
||||
The consequences
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
With that observation in place, it is a short step to observe that
|
||||
storing segment sets in MSMProp1 is unnecessary. Instead of
|
||||
storing a segment set in each shadow value, just store and
|
||||
update a single vector timestamp. The following two equivalences
|
||||
hold:
|
||||
|
||||
MSMProp1 MSMProp2
|
||||
|
||||
adding a segment S join-ing S's vector timestamp
|
||||
to the segment-set to the current vector timestamp
|
||||
|
||||
HB(SS,currS) happens_before(
|
||||
currS's timestamp,
|
||||
current vector timestamp )
|
||||
|
||||
Once it is no longer necessary to represent segment sets, it then
|
||||
also becomes unnecessary to represent segments. This constitutes
|
||||
a significant simplication to the implementation.
|
||||
|
||||
|
||||
The resulting state machine, MSMProp2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
MSMProp2 is isomorphic to MSMProp1, with the following changes:
|
||||
|
||||
States are New, Read(VTS,LS), Write(VTS,LS)
|
||||
|
||||
where LS is a lockset (as before) and VTS is a vector timestamp.
|
||||
|
||||
For a thread T with current lockset 'currLS' and current VTS 'currVTS'
|
||||
making a memory access, the new rules are
|
||||
|
||||
Name Old-State Op Guard New-State Race-If
|
||||
|
||||
E1 New rd True Read(currVTS,currLS) False
|
||||
|
||||
E2 New wr True Write(currVTS,currLS) False
|
||||
|
||||
E3 Read(oldVTS,oldLS) rd True Read(newVTS,newLS) False
|
||||
|
||||
E4 Read(oldVTS,oldLS) wr True Write(newVTS,newLS) #newLS == 0
|
||||
&& !hb(oldVTS,currVTS)
|
||||
|
||||
E5 Write(oldVTS,oldLS) rd hb(oldVTS, Read(currVTS,currLS) False
|
||||
currVTS)
|
||||
|
||||
E6r Write(oldVTS,oldLS) rd !hb(oldVTS, Write(newVTS,newLS) #newLS == 0
|
||||
currVTS) && !hb(oldVTS,currVTS)
|
||||
|
||||
E6w Write(oldVTS,oldLS) wr True Write(newVTS,newLS) #newLS == 0
|
||||
&& !hb(oldVTS,currVTS)
|
||||
|
||||
where newVTS = join2(oldVTS,currVTS)
|
||||
|
||||
newLS = if hb(oldVTS,currVTS)
|
||||
then currLS
|
||||
else intersect(oldLS,currLS)
|
||||
|
||||
hb(vts1, vts2) = vts1 happens before or is equal to vts2
|
||||
|
||||
|
||||
Interpretation of the states
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
I always found the state names in MSMProp1 confusing. Both MSMProp1
|
||||
and MSMProp2 are easier to understand if the states Read and Write are
|
||||
renamed, like this:
|
||||
|
||||
old name new name
|
||||
|
||||
Read WriteConstraint
|
||||
Write AllConstraint
|
||||
|
||||
The effect of a state Read(VTS,LS) is to constrain all later-observed
|
||||
writes so that either (1) the writing thread holds at least one lock
|
||||
in common with LS, or (2) those writes must happen-after VTS. If
|
||||
neither of those two conditions hold, a race is reported.
|
||||
|
||||
Hence a Read state places a constraint on writes.
|
||||
|
||||
The effect of a state Write(VTS,LS) is similar, but it applies to all
|
||||
later-observed accesses: either (1) the accessing thread holds at
|
||||
least one lock in common with LS, or (2) those accesses must
|
||||
happen-after VTS. If neither of those two conditions hold, a race is
|
||||
reported.
|
||||
|
||||
Hence a Write state places a constraint on all accesses.
|
||||
|
||||
If we ignore the LS component of these states, the intuitive
|
||||
interpretation of the VTS component is that it states the earliest
|
||||
vector-time that the next write / access may safely happen.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
YARD, Yet Another Race Detector, built on the Helgrind framework
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Julian Seward, OpenWorks Ltd, 19 August 2008
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The YARD race detector lives in svn://svn.valgrind.org/branches/YARD.
|
||||
|
||||
It uses a new and relatively simple race detection engine, based on
|
||||
the idea of shadowing each memory location with two vector timestamps,
|
||||
indicating respectively the "earliest safe read point" and "earliest
|
||||
safe write point". As far as I know this is a novel approach. Some
|
||||
features of the implementation:
|
||||
|
||||
* Modularity. The entire race detection engine is placed in a
|
||||
standalone library (libhb_core.c) with a simple interface (libhb.h).
|
||||
This makes it easier to debug and verify the engine; indeed it can
|
||||
be built as a standalone executable with test harness using "make -f
|
||||
Makefile_sa".
|
||||
|
||||
* Simplified and scalable storage management, so that large programs,
|
||||
with many synchronisation events, can be handled.
|
||||
|
||||
* Ability to report both call stacks involved in a race, without
|
||||
excessive time or space overhead.
|
||||
|
||||
* Pure happens before operation, so as not to give any false
|
||||
positives.
|
||||
|
||||
To use, build as usual and run as "--tool=helgrind".
|
||||
|
||||
You can disable lock order checking with --track-lockorders=no, as it
|
||||
sometimes produces an annoying amount of output.
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,798 @@
|
||||
/*
|
||||
----------------------------------------------------------------
|
||||
|
||||
Notice that the above BSD-style license applies to this one file
|
||||
(helgrind.h) only. The entire rest of Valgrind is licensed under
|
||||
the terms of the GNU General Public License, version 2. See the
|
||||
COPYING file in the source distribution for details.
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
This file is part of Helgrind, a Valgrind tool for detecting errors
|
||||
in threaded programs.
|
||||
|
||||
Copyright (C) 2007-2015 OpenWorks LLP
|
||||
info@open-works.co.uk
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
3. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
Notice that the above BSD-style license applies to this one file
|
||||
(helgrind.h) only. The entire rest of Valgrind is licensed under
|
||||
the terms of the GNU General Public License, version 2. See the
|
||||
COPYING file in the source distribution for details.
|
||||
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __HELGRIND_H
|
||||
#define __HELGRIND_H
|
||||
|
||||
#include "valgrind.h"
|
||||
|
||||
/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !!
|
||||
This enum comprises an ABI exported by Valgrind to programs
|
||||
which use client requests. DO NOT CHANGE THE ORDER OF THESE
|
||||
ENTRIES, NOR DELETE ANY -- add new ones at the end. */
|
||||
typedef
|
||||
enum {
|
||||
VG_USERREQ__HG_CLEAN_MEMORY = VG_USERREQ_TOOL_BASE('H','G'),
|
||||
|
||||
/* The rest are for Helgrind's internal use. Not for end-user
|
||||
use. Do not use them unless you are a Valgrind developer. */
|
||||
|
||||
/* Notify the tool what this thread's pthread_t is. */
|
||||
_VG_USERREQ__HG_SET_MY_PTHREAD_T = VG_USERREQ_TOOL_BASE('H','G')
|
||||
+ 256,
|
||||
_VG_USERREQ__HG_PTH_API_ERROR, /* char*, int */
|
||||
_VG_USERREQ__HG_PTHREAD_JOIN_POST, /* pthread_t of quitter */
|
||||
_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST, /* pth_mx_t*, long mbRec */
|
||||
_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE, /* pth_mx_t*, long isInit */
|
||||
_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, /* pth_mx_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST, /* pth_mx_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_PRE, /* void*, long isTryLock */
|
||||
_VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_POST, /* void* */
|
||||
_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE, /* pth_cond_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE, /* pth_cond_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE, /* pth_cond_t*, pth_mx_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST, /* pth_cond_t*, pth_mx_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE, /* pth_cond_t*, long isInit */
|
||||
_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST, /* pth_rwlk_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE, /* pth_rwlk_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE, /* pth_rwlk_t*, long isW */
|
||||
_VG_USERREQ__HG_PTHREAD_RWLOCK_ACQUIRED, /* void*, long isW */
|
||||
_VG_USERREQ__HG_PTHREAD_RWLOCK_RELEASED, /* void* */
|
||||
_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST, /* pth_rwlk_t* */
|
||||
_VG_USERREQ__HG_POSIX_SEM_INIT_POST, /* sem_t*, ulong value */
|
||||
_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, /* sem_t* */
|
||||
_VG_USERREQ__HG_POSIX_SEM_RELEASED, /* void* */
|
||||
_VG_USERREQ__HG_POSIX_SEM_ACQUIRED, /* void* */
|
||||
_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE, /* pth_bar_t*, ulong, ulong */
|
||||
_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE, /* pth_bar_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE, /* pth_bar_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE, /* pth_slk_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST, /* pth_slk_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE, /* pth_slk_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST, /* pth_slk_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE, /* pth_slk_t* */
|
||||
_VG_USERREQ__HG_CLIENTREQ_UNIMP, /* char* */
|
||||
_VG_USERREQ__HG_USERSO_SEND_PRE, /* arbitrary UWord SO-tag */
|
||||
_VG_USERREQ__HG_USERSO_RECV_POST, /* arbitrary UWord SO-tag */
|
||||
_VG_USERREQ__HG_USERSO_FORGET_ALL, /* arbitrary UWord SO-tag */
|
||||
_VG_USERREQ__HG_RESERVED2, /* Do not use */
|
||||
_VG_USERREQ__HG_RESERVED3, /* Do not use */
|
||||
_VG_USERREQ__HG_RESERVED4, /* Do not use */
|
||||
_VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED, /* Addr a, ulong len */
|
||||
_VG_USERREQ__HG_ARANGE_MAKE_TRACKED, /* Addr a, ulong len */
|
||||
_VG_USERREQ__HG_PTHREAD_BARRIER_RESIZE_PRE, /* pth_bar_t*, ulong */
|
||||
_VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK, /* Addr start_of_block */
|
||||
_VG_USERREQ__HG_PTHREAD_COND_INIT_POST, /* pth_cond_t*, pth_cond_attr_t*/
|
||||
_VG_USERREQ__HG_GNAT_MASTER_HOOK, /* void*d,void*m,Word ml */
|
||||
_VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK, /* void*s,Word ml */
|
||||
_VG_USERREQ__HG_GET_ABITS, /* Addr a,Addr abits, ulong len */
|
||||
_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
|
||||
_VG_USERREQ__HG_PTHREAD_CREATE_END,
|
||||
_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, /* pth_mx_t*,long isTryLock */
|
||||
_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST, /* pth_mx_t *,long tookLock */
|
||||
_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST, /* pth_rwlk_t*,long isW,long */
|
||||
_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE, /* pth_rwlk_t* */
|
||||
_VG_USERREQ__HG_POSIX_SEM_POST_PRE, /* sem_t* */
|
||||
_VG_USERREQ__HG_POSIX_SEM_POST_POST, /* sem_t* */
|
||||
_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, /* sem_t* */
|
||||
_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, /* sem_t*, long tookLock */
|
||||
_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST, /* pth_cond_t* */
|
||||
_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,/* pth_cond_t* */
|
||||
_VG_USERREQ__HG_RTLD_BIND_GUARD, /* int flags */
|
||||
_VG_USERREQ__HG_RTLD_BIND_CLEAR /* int flags */
|
||||
} Vg_TCheckClientRequest;
|
||||
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- ---*/
|
||||
/*--- Implementation-only facilities. Not for end-user use. ---*/
|
||||
/*--- For end-user facilities see below (the next section in ---*/
|
||||
/*--- this file.) ---*/
|
||||
/*--- ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/* Do a client request. These are macros rather than a functions so
|
||||
as to avoid having an extra frame in stack traces.
|
||||
|
||||
NB: these duplicate definitions in hg_intercepts.c. But here, we
|
||||
have to make do with weaker typing (no definition of Word etc) and
|
||||
no assertions, whereas in helgrind.h we can use those facilities.
|
||||
Obviously it's important the two sets of definitions are kept in
|
||||
sync.
|
||||
|
||||
The commented-out asserts should actually hold, but unfortunately
|
||||
they can't be allowed to be visible here, because that would
|
||||
require the end-user code to #include <assert.h>.
|
||||
*/
|
||||
|
||||
#define DO_CREQ_v_W(_creqF, _ty1F,_arg1F) \
|
||||
do { \
|
||||
long int _arg1; \
|
||||
/* assert(sizeof(_ty1F) == sizeof(long int)); */ \
|
||||
_arg1 = (long int)(_arg1F); \
|
||||
VALGRIND_DO_CLIENT_REQUEST_STMT( \
|
||||
(_creqF), \
|
||||
_arg1, 0,0,0,0); \
|
||||
} while (0)
|
||||
|
||||
#define DO_CREQ_W_W(_resF, _dfltF, _creqF, _ty1F,_arg1F) \
|
||||
do { \
|
||||
long int _arg1; \
|
||||
/* assert(sizeof(_ty1F) == sizeof(long int)); */ \
|
||||
_arg1 = (long int)(_arg1F); \
|
||||
_qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR( \
|
||||
(_dfltF), \
|
||||
(_creqF), \
|
||||
_arg1, 0,0,0,0); \
|
||||
_resF = _qzz_res; \
|
||||
} while (0)
|
||||
|
||||
#define DO_CREQ_v_WW(_creqF, _ty1F,_arg1F, _ty2F,_arg2F) \
|
||||
do { \
|
||||
long int _arg1, _arg2; \
|
||||
/* assert(sizeof(_ty1F) == sizeof(long int)); */ \
|
||||
/* assert(sizeof(_ty2F) == sizeof(long int)); */ \
|
||||
_arg1 = (long int)(_arg1F); \
|
||||
_arg2 = (long int)(_arg2F); \
|
||||
VALGRIND_DO_CLIENT_REQUEST_STMT( \
|
||||
(_creqF), \
|
||||
_arg1,_arg2,0,0,0); \
|
||||
} while (0)
|
||||
|
||||
#define DO_CREQ_v_WWW(_creqF, _ty1F,_arg1F, \
|
||||
_ty2F,_arg2F, _ty3F, _arg3F) \
|
||||
do { \
|
||||
long int _arg1, _arg2, _arg3; \
|
||||
/* assert(sizeof(_ty1F) == sizeof(long int)); */ \
|
||||
/* assert(sizeof(_ty2F) == sizeof(long int)); */ \
|
||||
/* assert(sizeof(_ty3F) == sizeof(long int)); */ \
|
||||
_arg1 = (long int)(_arg1F); \
|
||||
_arg2 = (long int)(_arg2F); \
|
||||
_arg3 = (long int)(_arg3F); \
|
||||
VALGRIND_DO_CLIENT_REQUEST_STMT( \
|
||||
(_creqF), \
|
||||
_arg1,_arg2,_arg3,0,0); \
|
||||
} while (0)
|
||||
|
||||
#define DO_CREQ_W_WWW(_resF, _dfltF, _creqF, _ty1F,_arg1F, \
|
||||
_ty2F,_arg2F, _ty3F, _arg3F) \
|
||||
do { \
|
||||
long int _qzz_res; \
|
||||
long int _arg1, _arg2, _arg3; \
|
||||
/* assert(sizeof(_ty1F) == sizeof(long int)); */ \
|
||||
_arg1 = (long int)(_arg1F); \
|
||||
_arg2 = (long int)(_arg2F); \
|
||||
_arg3 = (long int)(_arg3F); \
|
||||
_qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR( \
|
||||
(_dfltF), \
|
||||
(_creqF), \
|
||||
_arg1,_arg2,_arg3,0,0); \
|
||||
_resF = _qzz_res; \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
#define _HG_CLIENTREQ_UNIMP(_qzz_str) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_CLIENTREQ_UNIMP, \
|
||||
(char*),(_qzz_str))
|
||||
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- ---*/
|
||||
/*--- Helgrind-native requests. These allow access to ---*/
|
||||
/*--- the same set of annotation primitives that are used ---*/
|
||||
/*--- to build the POSIX pthread wrappers. ---*/
|
||||
/*--- ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/* ----------------------------------------------------------
|
||||
For describing ordinary mutexes (non-rwlocks). For rwlock
|
||||
descriptions see ANNOTATE_RWLOCK_* below.
|
||||
---------------------------------------------------------- */
|
||||
|
||||
/* Notify here immediately after mutex creation. _mbRec == 0 for a
|
||||
non-recursive mutex, 1 for a recursive mutex. */
|
||||
#define VALGRIND_HG_MUTEX_INIT_POST(_mutex, _mbRec) \
|
||||
DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST, \
|
||||
void*,(_mutex), long,(_mbRec))
|
||||
|
||||
/* Notify here immediately before mutex acquisition. _isTryLock == 0
|
||||
for a normal acquisition, 1 for a "try" style acquisition. */
|
||||
#define VALGRIND_HG_MUTEX_LOCK_PRE(_mutex, _isTryLock) \
|
||||
DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_PRE, \
|
||||
void*,(_mutex), long,(_isTryLock))
|
||||
|
||||
/* Notify here immediately after a successful mutex acquisition. */
|
||||
#define VALGRIND_HG_MUTEX_LOCK_POST(_mutex) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_POST, \
|
||||
void*,(_mutex))
|
||||
|
||||
/* Notify here immediately before a mutex release. */
|
||||
#define VALGRIND_HG_MUTEX_UNLOCK_PRE(_mutex) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE, \
|
||||
void*,(_mutex))
|
||||
|
||||
/* Notify here immediately after a mutex release. */
|
||||
#define VALGRIND_HG_MUTEX_UNLOCK_POST(_mutex) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST, \
|
||||
void*,(_mutex))
|
||||
|
||||
/* Notify here immediately before mutex destruction. */
|
||||
#define VALGRIND_HG_MUTEX_DESTROY_PRE(_mutex) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE, \
|
||||
void*,(_mutex))
|
||||
|
||||
/* ----------------------------------------------------------
|
||||
For describing semaphores.
|
||||
---------------------------------------------------------- */
|
||||
|
||||
/* Notify here immediately after semaphore creation. */
|
||||
#define VALGRIND_HG_SEM_INIT_POST(_sem, _value) \
|
||||
DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST, \
|
||||
void*, (_sem), unsigned long, (_value))
|
||||
|
||||
/* Notify here immediately after a semaphore wait (an acquire-style
|
||||
operation) */
|
||||
#define VALGRIND_HG_SEM_WAIT_POST(_sem) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_ACQUIRED, \
|
||||
void*,(_sem))
|
||||
|
||||
/* Notify here immediately before semaphore post (a release-style
|
||||
operation) */
|
||||
#define VALGRIND_HG_SEM_POST_PRE(_sem) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_RELEASED, \
|
||||
void*,(_sem))
|
||||
|
||||
/* Notify here immediately before semaphore destruction. */
|
||||
#define VALGRIND_HG_SEM_DESTROY_PRE(_sem) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE, \
|
||||
void*, (_sem))
|
||||
|
||||
/* ----------------------------------------------------------
|
||||
For describing barriers.
|
||||
---------------------------------------------------------- */
|
||||
|
||||
/* Notify here immediately before barrier creation. _count is the
|
||||
capacity. _resizable == 0 means the barrier may not be resized, 1
|
||||
means it may be. */
|
||||
#define VALGRIND_HG_BARRIER_INIT_PRE(_bar, _count, _resizable) \
|
||||
DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE, \
|
||||
void*,(_bar), \
|
||||
unsigned long,(_count), \
|
||||
unsigned long,(_resizable))
|
||||
|
||||
/* Notify here immediately before arrival at a barrier. */
|
||||
#define VALGRIND_HG_BARRIER_WAIT_PRE(_bar) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE, \
|
||||
void*,(_bar))
|
||||
|
||||
/* Notify here immediately before a resize (change of barrier
|
||||
capacity). If _newcount >= the existing capacity, then there is no
|
||||
change in the state of any threads waiting at the barrier. If
|
||||
_newcount < the existing capacity, and >= _newcount threads are
|
||||
currently waiting at the barrier, then this notification is
|
||||
considered to also have the effect of telling the checker that all
|
||||
waiting threads have now moved past the barrier. (I can't think of
|
||||
any other sane semantics.) */
|
||||
#define VALGRIND_HG_BARRIER_RESIZE_PRE(_bar, _newcount) \
|
||||
DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_BARRIER_RESIZE_PRE, \
|
||||
void*,(_bar), \
|
||||
unsigned long,(_newcount))
|
||||
|
||||
/* Notify here immediately before barrier destruction. */
|
||||
#define VALGRIND_HG_BARRIER_DESTROY_PRE(_bar) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE, \
|
||||
void*,(_bar))
|
||||
|
||||
/* ----------------------------------------------------------
|
||||
For describing memory ownership changes.
|
||||
---------------------------------------------------------- */
|
||||
|
||||
/* Clean memory state. This makes Helgrind forget everything it knew
|
||||
about the specified memory range. Effectively this announces that
|
||||
the specified memory range now "belongs" to the calling thread, so
|
||||
that: (1) the calling thread can access it safely without
|
||||
synchronisation, and (2) all other threads must sync with this one
|
||||
to access it safely. This is particularly useful for memory
|
||||
allocators that wish to recycle memory. */
|
||||
#define VALGRIND_HG_CLEAN_MEMORY(_qzz_start, _qzz_len) \
|
||||
DO_CREQ_v_WW(VG_USERREQ__HG_CLEAN_MEMORY, \
|
||||
void*,(_qzz_start), \
|
||||
unsigned long,(_qzz_len))
|
||||
|
||||
/* The same, but for the heap block starting at _qzz_blockstart. This
|
||||
allows painting when we only know the address of an object, but not
|
||||
its size, which is sometimes the case in C++ code involving
|
||||
inheritance, and in which RTTI is not, for whatever reason,
|
||||
available. Returns the number of bytes painted, which can be zero
|
||||
for a zero-sized block. Hence, return values >= 0 indicate success
|
||||
(the block was found), and the value -1 indicates block not
|
||||
found, and -2 is returned when not running on Helgrind. */
|
||||
#define VALGRIND_HG_CLEAN_MEMORY_HEAPBLOCK(_qzz_blockstart) \
|
||||
(__extension__ \
|
||||
({long int _npainted; \
|
||||
DO_CREQ_W_W(_npainted, (-2)/*default*/, \
|
||||
_VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK, \
|
||||
void*,(_qzz_blockstart)); \
|
||||
_npainted; \
|
||||
}))
|
||||
|
||||
/* ----------------------------------------------------------
|
||||
For error control.
|
||||
---------------------------------------------------------- */
|
||||
|
||||
/* Tell H that an address range is not to be "tracked" until further
|
||||
notice. This puts it in the NOACCESS state, in which case we
|
||||
ignore all reads and writes to it. Useful for ignoring ranges of
|
||||
memory where there might be races we don't want to see. If the
|
||||
memory is subsequently reallocated via malloc/new/stack allocation,
|
||||
then it is put back in the trackable state. Hence it is safe in
|
||||
the situation where checking is disabled, the containing area is
|
||||
deallocated and later reallocated for some other purpose. */
|
||||
#define VALGRIND_HG_DISABLE_CHECKING(_qzz_start, _qzz_len) \
|
||||
DO_CREQ_v_WW(_VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED, \
|
||||
void*,(_qzz_start), \
|
||||
unsigned long,(_qzz_len))
|
||||
|
||||
/* And put it back into the normal "tracked" state, that is, make it
|
||||
once again subject to the normal race-checking machinery. This
|
||||
puts it in the same state as new memory allocated by this thread --
|
||||
that is, basically owned exclusively by this thread. */
|
||||
#define VALGRIND_HG_ENABLE_CHECKING(_qzz_start, _qzz_len) \
|
||||
DO_CREQ_v_WW(_VG_USERREQ__HG_ARANGE_MAKE_TRACKED, \
|
||||
void*,(_qzz_start), \
|
||||
unsigned long,(_qzz_len))
|
||||
|
||||
|
||||
/* Checks the accessibility bits for addresses [zza..zza+zznbytes-1].
|
||||
If zzabits array is provided, copy the accessibility bits in zzabits.
|
||||
Return values:
|
||||
-2 if not running on helgrind
|
||||
-1 if any parts of zzabits is not addressable
|
||||
>= 0 : success.
|
||||
When success, it returns the nr of addressable bytes found.
|
||||
So, to check that a whole range is addressable, check
|
||||
VALGRIND_HG_GET_ABITS(addr,NULL,len) == len
|
||||
In addition, if you want to examine the addressability of each
|
||||
byte of the range, you need to provide a non NULL ptr as
|
||||
second argument, pointing to an array of unsigned char
|
||||
of length len.
|
||||
Addressable bytes are indicated with 0xff.
|
||||
Non-addressable bytes are indicated with 0x00.
|
||||
*/
|
||||
#define VALGRIND_HG_GET_ABITS(zza,zzabits,zznbytes) \
|
||||
(__extension__ \
|
||||
({long int _res; \
|
||||
DO_CREQ_W_WWW(_res, (-2)/*default*/, \
|
||||
_VG_USERREQ__HG_GET_ABITS, \
|
||||
void*,(zza), void*,(zzabits), \
|
||||
unsigned long,(zznbytes)); \
|
||||
_res; \
|
||||
}))
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- ---*/
|
||||
/*--- ThreadSanitizer-compatible requests ---*/
|
||||
/*--- (mostly unimplemented) ---*/
|
||||
/*--- ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/* A quite-broad set of annotations, as used in the ThreadSanitizer
|
||||
project. This implementation aims to be a (source-level)
|
||||
compatible implementation of the macros defined in:
|
||||
|
||||
http://code.google.com/p/data-race-test/source
|
||||
/browse/trunk/dynamic_annotations/dynamic_annotations.h
|
||||
|
||||
(some of the comments below are taken from the above file)
|
||||
|
||||
The implementation here is very incomplete, and intended as a
|
||||
starting point. Many of the macros are unimplemented. Rather than
|
||||
allowing unimplemented macros to silently do nothing, they cause an
|
||||
assertion. Intention is to implement them on demand.
|
||||
|
||||
The major use of these macros is to make visible to race detectors,
|
||||
the behaviour (effects) of user-implemented synchronisation
|
||||
primitives, that the detectors could not otherwise deduce from the
|
||||
normal observation of pthread etc calls.
|
||||
|
||||
Some of the macros are no-ops in Helgrind. That's because Helgrind
|
||||
is a pure happens-before detector, whereas ThreadSanitizer uses a
|
||||
hybrid lockset and happens-before scheme, which requires more
|
||||
accurate annotations for correct operation.
|
||||
|
||||
The macros are listed in the same order as in dynamic_annotations.h
|
||||
(URL just above).
|
||||
|
||||
I should point out that I am less than clear about the intended
|
||||
semantics of quite a number of them. Comments and clarifications
|
||||
welcomed!
|
||||
*/
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
These four allow description of user-level condition variables,
|
||||
apparently in the style of POSIX's pthread_cond_t. Currently
|
||||
unimplemented and will assert.
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
/* Report that wait on the condition variable at address CV has
|
||||
succeeded and the lock at address LOCK is now held. CV and LOCK
|
||||
are completely arbitrary memory addresses which presumably mean
|
||||
something to the application, but are meaningless to Helgrind. */
|
||||
#define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_CONDVAR_LOCK_WAIT")
|
||||
|
||||
/* Report that wait on the condition variable at CV has succeeded.
|
||||
Variant w/o lock. */
|
||||
#define ANNOTATE_CONDVAR_WAIT(cv) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_CONDVAR_WAIT")
|
||||
|
||||
/* Report that we are about to signal on the condition variable at
|
||||
address CV. */
|
||||
#define ANNOTATE_CONDVAR_SIGNAL(cv) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_CONDVAR_SIGNAL")
|
||||
|
||||
/* Report that we are about to signal_all on the condition variable at
|
||||
CV. */
|
||||
#define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_CONDVAR_SIGNAL_ALL")
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Create completely arbitrary happens-before edges between threads.
|
||||
|
||||
If threads T1 .. Tn all do ANNOTATE_HAPPENS_BEFORE(obj) and later
|
||||
(w.r.t. some notional global clock for the computation) thread Tm
|
||||
does ANNOTATE_HAPPENS_AFTER(obj), then Helgrind will regard all
|
||||
memory accesses done by T1 .. Tn before the ..BEFORE.. call as
|
||||
happening-before all memory accesses done by Tm after the
|
||||
..AFTER.. call. Hence Helgrind won't complain about races if Tm's
|
||||
accesses afterwards are to the same locations as accesses before by
|
||||
any of T1 .. Tn.
|
||||
|
||||
OBJ is a machine word (unsigned long, or void*), is completely
|
||||
arbitrary, and denotes the identity of some synchronisation object
|
||||
you're modelling.
|
||||
|
||||
You must do the _BEFORE call just before the real sync event on the
|
||||
signaller's side, and _AFTER just after the real sync event on the
|
||||
waiter's side.
|
||||
|
||||
If none of the rest of these macros make sense to you, at least
|
||||
take the time to understand these two. They form the very essence
|
||||
of describing arbitrary inter-thread synchronisation events to
|
||||
Helgrind. You can get a long way just with them alone.
|
||||
|
||||
See also, extensive discussion on semantics of this in
|
||||
https://bugs.kde.org/show_bug.cgi?id=243935
|
||||
|
||||
ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(obj) is interim until such time
|
||||
as bug 243935 is fully resolved. It instructs Helgrind to forget
|
||||
about any ANNOTATE_HAPPENS_BEFORE calls on the specified object, in
|
||||
effect putting it back in its original state. Once in that state,
|
||||
a use of ANNOTATE_HAPPENS_AFTER on it has no effect on the calling
|
||||
thread.
|
||||
|
||||
An implementation may optionally release resources it has
|
||||
associated with 'obj' when ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(obj)
|
||||
happens. Users are recommended to use
|
||||
ANNOTATE_HAPPENS_BEFORE_FORGET_ALL to indicate when a
|
||||
synchronisation object is no longer needed, so as to avoid
|
||||
potential indefinite resource leaks.
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
#define ANNOTATE_HAPPENS_BEFORE(obj) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_USERSO_SEND_PRE, void*,(obj))
|
||||
|
||||
#define ANNOTATE_HAPPENS_AFTER(obj) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_USERSO_RECV_POST, void*,(obj))
|
||||
|
||||
#define ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(obj) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_USERSO_FORGET_ALL, void*,(obj))
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Memory publishing. The TSan sources say:
|
||||
|
||||
Report that the bytes in the range [pointer, pointer+size) are about
|
||||
to be published safely. The race checker will create a happens-before
|
||||
arc from the call ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) to
|
||||
subsequent accesses to this memory.
|
||||
|
||||
I'm not sure I understand what this means exactly, nor whether it
|
||||
is relevant for a pure h-b detector. Leaving unimplemented for
|
||||
now.
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
#define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_PUBLISH_MEMORY_RANGE")
|
||||
|
||||
/* DEPRECATED. Don't use it. */
|
||||
/* #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) */
|
||||
|
||||
/* DEPRECATED. Don't use it. */
|
||||
/* #define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size) */
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
TSan sources say:
|
||||
|
||||
Instruct the tool to create a happens-before arc between
|
||||
MU->Unlock() and MU->Lock(). This annotation may slow down the
|
||||
race detector; normally it is used only when it would be
|
||||
difficult to annotate each of the mutex's critical sections
|
||||
individually using the annotations above.
|
||||
|
||||
If MU is a posix pthread_mutex_t then Helgrind will do this anyway.
|
||||
In any case, leave as unimp for now. I'm unsure about the intended
|
||||
behaviour.
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
#define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX")
|
||||
|
||||
/* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */
|
||||
/* #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) */
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
TSan sources say:
|
||||
|
||||
Annotations useful when defining memory allocators, or when
|
||||
memory that was protected in one way starts to be protected in
|
||||
another.
|
||||
|
||||
Report that a new memory at "address" of size "size" has been
|
||||
allocated. This might be used when the memory has been retrieved
|
||||
from a free list and is about to be reused, or when a the locking
|
||||
discipline for a variable changes.
|
||||
|
||||
AFAICS this is the same as VALGRIND_HG_CLEAN_MEMORY.
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
#define ANNOTATE_NEW_MEMORY(address, size) \
|
||||
VALGRIND_HG_CLEAN_MEMORY((address), (size))
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
TSan sources say:
|
||||
|
||||
Annotations useful when defining FIFO queues that transfer data
|
||||
between threads.
|
||||
|
||||
All unimplemented. Am not claiming to understand this (yet).
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Report that the producer-consumer queue object at address PCQ has
|
||||
been created. The ANNOTATE_PCQ_* annotations should be used only
|
||||
for FIFO queues. For non-FIFO queues use ANNOTATE_HAPPENS_BEFORE
|
||||
(for put) and ANNOTATE_HAPPENS_AFTER (for get). */
|
||||
#define ANNOTATE_PCQ_CREATE(pcq) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_PCQ_CREATE")
|
||||
|
||||
/* Report that the queue at address PCQ is about to be destroyed. */
|
||||
#define ANNOTATE_PCQ_DESTROY(pcq) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_PCQ_DESTROY")
|
||||
|
||||
/* Report that we are about to put an element into a FIFO queue at
|
||||
address PCQ. */
|
||||
#define ANNOTATE_PCQ_PUT(pcq) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_PCQ_PUT")
|
||||
|
||||
/* Report that we've just got an element from a FIFO queue at address
|
||||
PCQ. */
|
||||
#define ANNOTATE_PCQ_GET(pcq) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_PCQ_GET")
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Annotations that suppress errors. It is usually better to express
|
||||
the program's synchronization using the other annotations, but
|
||||
these can be used when all else fails.
|
||||
|
||||
Currently these are all unimplemented. I can't think of a simple
|
||||
way to implement them without at least some performance overhead.
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Report that we may have a benign race at "pointer", with size
|
||||
"sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the
|
||||
point where "pointer" has been allocated, preferably close to the point
|
||||
where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC.
|
||||
|
||||
XXX: what's this actually supposed to do? And what's the type of
|
||||
DESCRIPTION? When does the annotation stop having an effect?
|
||||
*/
|
||||
#define ANNOTATE_BENIGN_RACE(pointer, description) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_BENIGN_RACE")
|
||||
|
||||
/* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to
|
||||
the memory range [address, address+size). */
|
||||
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
|
||||
VALGRIND_HG_DISABLE_CHECKING(address, size)
|
||||
|
||||
/* Request the analysis tool to ignore all reads in the current thread
|
||||
until ANNOTATE_IGNORE_READS_END is called. Useful to ignore
|
||||
intentional racey reads, while still checking other reads and all
|
||||
writes. */
|
||||
#define ANNOTATE_IGNORE_READS_BEGIN() \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_IGNORE_READS_BEGIN")
|
||||
|
||||
/* Stop ignoring reads. */
|
||||
#define ANNOTATE_IGNORE_READS_END() \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_IGNORE_READS_END")
|
||||
|
||||
/* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */
|
||||
#define ANNOTATE_IGNORE_WRITES_BEGIN() \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_IGNORE_WRITES_BEGIN")
|
||||
|
||||
/* Stop ignoring writes. */
|
||||
#define ANNOTATE_IGNORE_WRITES_END() \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_IGNORE_WRITES_END")
|
||||
|
||||
/* Start ignoring all memory accesses (reads and writes). */
|
||||
#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
|
||||
do { \
|
||||
ANNOTATE_IGNORE_READS_BEGIN(); \
|
||||
ANNOTATE_IGNORE_WRITES_BEGIN(); \
|
||||
} while (0)
|
||||
|
||||
/* Stop ignoring all memory accesses. */
|
||||
#define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
|
||||
do { \
|
||||
ANNOTATE_IGNORE_WRITES_END(); \
|
||||
ANNOTATE_IGNORE_READS_END(); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Annotations useful for debugging.
|
||||
|
||||
Again, so for unimplemented, partly for performance reasons.
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Request to trace every access to ADDRESS. */
|
||||
#define ANNOTATE_TRACE_MEMORY(address) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_TRACE_MEMORY")
|
||||
|
||||
/* Report the current thread name to a race detector. */
|
||||
#define ANNOTATE_THREAD_NAME(name) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_THREAD_NAME")
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Annotations for describing behaviour of user-implemented lock
|
||||
primitives. In all cases, the LOCK argument is a completely
|
||||
arbitrary machine word (unsigned long, or void*) and can be any
|
||||
value which gives a unique identity to the lock objects being
|
||||
modelled.
|
||||
|
||||
We just pretend they're ordinary posix rwlocks. That'll probably
|
||||
give some rather confusing wording in error messages, claiming that
|
||||
the arbitrary LOCK values are pthread_rwlock_t*'s, when in fact
|
||||
they are not. Ah well.
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
/* Report that a lock has just been created at address LOCK. */
|
||||
#define ANNOTATE_RWLOCK_CREATE(lock) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST, \
|
||||
void*,(lock))
|
||||
|
||||
/* Report that the lock at address LOCK is about to be destroyed. */
|
||||
#define ANNOTATE_RWLOCK_DESTROY(lock) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE, \
|
||||
void*,(lock))
|
||||
|
||||
/* Report that the lock at address LOCK has just been acquired.
|
||||
is_w=1 for writer lock, is_w=0 for reader lock. */
|
||||
#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
|
||||
DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_ACQUIRED, \
|
||||
void*,(lock), unsigned long,(is_w))
|
||||
|
||||
/* Report that the lock at address LOCK is about to be released. */
|
||||
#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
|
||||
DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_RELEASED, \
|
||||
void*,(lock)) /* is_w is ignored */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------
|
||||
Annotations useful when implementing barriers. They are not
|
||||
normally needed by modules that merely use barriers.
|
||||
The "barrier" argument is a pointer to the barrier object.
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Report that the "barrier" has been initialized with initial
|
||||
"count". If 'reinitialization_allowed' is true, initialization is
|
||||
allowed to happen multiple times w/o calling barrier_destroy() */
|
||||
#define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_BARRIER_INIT")
|
||||
|
||||
/* Report that we are about to enter barrier_wait("barrier"). */
|
||||
#define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_BARRIER_DESTROY")
|
||||
|
||||
/* Report that we just exited barrier_wait("barrier"). */
|
||||
#define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_BARRIER_DESTROY")
|
||||
|
||||
/* Report that the "barrier" has been destroyed. */
|
||||
#define ANNOTATE_BARRIER_DESTROY(barrier) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_BARRIER_DESTROY")
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
Annotations useful for testing race detectors.
|
||||
----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Report that we expect a race on the variable at ADDRESS. Use only
|
||||
in unit tests for a race detector. */
|
||||
#define ANNOTATE_EXPECT_RACE(address, description) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_EXPECT_RACE")
|
||||
|
||||
/* A no-op. Insert where you like to test the interceptors. */
|
||||
#define ANNOTATE_NO_OP(arg) \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_NO_OP")
|
||||
|
||||
/* Force the race detector to flush its state. The actual effect depends on
|
||||
* the implementation of the detector. */
|
||||
#define ANNOTATE_FLUSH_STATE() \
|
||||
_HG_CLIENTREQ_UNIMP("ANNOTATE_FLUSH_STATE")
|
||||
|
||||
#endif /* __HELGRIND_H */
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,121 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Address Description. ---*/
|
||||
/*--- hg_addrdescr.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Helgrind, a Valgrind tool for detecting errors
|
||||
in threaded programs.
|
||||
|
||||
Copyright (C) 2007-2015 OpenWorks Ltd
|
||||
info@open-works.co.uk
|
||||
|
||||
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.
|
||||
*/
|
||||
#include "pub_tool_basics.h"
|
||||
#include "pub_tool_libcbase.h"
|
||||
#include "pub_tool_libcprint.h"
|
||||
#include "pub_tool_libcassert.h"
|
||||
#include "pub_tool_wordfm.h"
|
||||
#include "pub_tool_xarray.h"
|
||||
#include "pub_tool_execontext.h"
|
||||
#include "pub_tool_debuginfo.h"
|
||||
#include "pub_tool_threadstate.h"
|
||||
#include "pub_tool_aspacemgr.h"
|
||||
#include "pub_tool_addrinfo.h"
|
||||
|
||||
#include "hg_basics.h"
|
||||
#include "hg_wordset.h"
|
||||
#include "hg_lock_n_thread.h"
|
||||
#include "hg_addrdescr.h" /* self */
|
||||
|
||||
void HG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai )
|
||||
{
|
||||
tl_assert(ai->tag == Addr_Undescribed);
|
||||
|
||||
/* hctxt/tnr/haddr/hszB describe the addr if it is a heap block. */
|
||||
ExeContext* hctxt;
|
||||
UInt tnr;
|
||||
Addr haddr;
|
||||
SizeT hszB;
|
||||
|
||||
/* First, see if it's in any heap block. Unfortunately this
|
||||
means a linear search through all allocated heap blocks. The
|
||||
assertion says that if it's detected as a heap block, then we
|
||||
must have an allocation context for it, since all heap blocks
|
||||
should have an allocation context. */
|
||||
Bool is_heapblock
|
||||
= HG_(mm_find_containing_block)(
|
||||
&hctxt,
|
||||
&tnr,
|
||||
&haddr,
|
||||
&hszB,
|
||||
a
|
||||
);
|
||||
if (is_heapblock) {
|
||||
tl_assert(is_heapblock == (hctxt != NULL));
|
||||
ai->tag = Addr_Block;
|
||||
ai->Addr.Block.block_kind = Block_Mallocd;
|
||||
ai->Addr.Block.block_desc = "block";
|
||||
ai->Addr.Block.block_szB = hszB;
|
||||
ai->Addr.Block.rwoffset = (Word)(a) - (Word)(haddr);
|
||||
ai->Addr.Block.allocated_at = hctxt;
|
||||
VG_(initThreadInfo) (&ai->Addr.Block.alloc_tinfo);
|
||||
ai->Addr.Block.alloc_tinfo.tnr = tnr;
|
||||
ai->Addr.Block.freed_at = VG_(null_ExeContext)();;
|
||||
} else {
|
||||
/* No block found. Search a non-heap block description. */
|
||||
VG_(describe_addr) (a, ai);
|
||||
|
||||
/* In case ai contains a tid, set tnr to the corresponding helgrind
|
||||
thread number. */
|
||||
if (ai->tag == Addr_Stack) {
|
||||
Thread* thr = get_admin_threads();
|
||||
|
||||
tl_assert(ai->Addr.Stack.tinfo.tid);
|
||||
while (thr) {
|
||||
if (thr->coretid == ai->Addr.Stack.tinfo.tid) {
|
||||
ai->Addr.Stack.tinfo.tnr = thr->errmsg_index;
|
||||
break;
|
||||
}
|
||||
thr = thr->admin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bool HG_(get_and_pp_addrdescr) (Addr addr)
|
||||
{
|
||||
|
||||
Bool ret;
|
||||
AddrInfo glai;
|
||||
|
||||
glai.tag = Addr_Undescribed;
|
||||
HG_(describe_addr) (addr, &glai);
|
||||
VG_(pp_addrinfo) (addr, &glai);
|
||||
ret = glai.tag != Addr_Unknown;
|
||||
|
||||
VG_(clear_addrinfo) (&glai);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end hg_addrdescr.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
/*--- Address Description, used e.g. to describe addresses involved ---*/
|
||||
/*--- in race conditions, locks. ---*/
|
||||
/*--- hg_addrdescr.h ---*/
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Helgrind, a Valgrind tool for detecting errors
|
||||
in threaded programs.
|
||||
|
||||
Copyright (C) 2007-2015 OpenWorks Ltd
|
||||
info@open-works.co.uk
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __HG_ADDRDESCR_H
|
||||
#define __HG_ADDRDESCR_H
|
||||
|
||||
/* Describe an address as best you can, for error messages or
|
||||
lock description, putting the result in ai.
|
||||
This might allocate some memory in ai, to be cleared with
|
||||
VG_(clear_addrinfo). */
|
||||
extern void HG_(describe_addr) ( Addr a, /*OUT*/AddrInfo* ai );
|
||||
|
||||
/* Get a readable description of addr, then print it using HG_(pp_addrdescr)
|
||||
using xml False and VG_(printf) to emit the characters.
|
||||
Returns True if a description was found/printed, False otherwise. */
|
||||
extern Bool HG_(get_and_pp_addrdescr) (Addr a);
|
||||
|
||||
/* For error creation/address description:
|
||||
map 'data_addr' to a malloc'd chunk, if any.
|
||||
Slow linear search accelerated in some special cases normal hash
|
||||
search of the mallocmeta table. This is an abuse of the normal file
|
||||
structure since this is exported by hg_main.c, not hg_addrdesc.c. Oh
|
||||
Well. Returns True if found, False if not. Zero-sized blocks are
|
||||
considered to contain the searched-for address if they equal that
|
||||
address. */
|
||||
Bool HG_(mm_find_containing_block)( /*OUT*/ExeContext** where,
|
||||
/*OUT*/UInt* tnr,
|
||||
/*OUT*/Addr* payload,
|
||||
/*OUT*/SizeT* szB,
|
||||
Addr data_addr );
|
||||
|
||||
|
||||
#endif /* ! __HG_ADDRDESCR_H */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end hg_addrdescr.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Basic definitions for all of Helgrind. ---*/
|
||||
/*--- hg_basics.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Helgrind, a Valgrind tool for detecting errors
|
||||
in threaded programs.
|
||||
|
||||
Copyright (C) 2007-2015 OpenWorks Ltd
|
||||
info@open-works.co.uk
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "pub_tool_basics.h"
|
||||
#include "pub_tool_libcbase.h"
|
||||
#include "pub_tool_libcassert.h"
|
||||
#include "pub_tool_mallocfree.h"
|
||||
#include "pub_tool_threadstate.h"
|
||||
|
||||
#include "hg_basics.h" /* self */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- Very basic stuff ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
void* HG_(zalloc) ( const HChar* cc, SizeT n )
|
||||
{
|
||||
void* p;
|
||||
tl_assert(n > 0);
|
||||
p = VG_(malloc)( cc, n );
|
||||
VG_(memset)(p, 0, n);
|
||||
return p;
|
||||
}
|
||||
|
||||
void HG_(free) ( void* p )
|
||||
{
|
||||
tl_assert(p);
|
||||
VG_(free)(p);
|
||||
}
|
||||
|
||||
HChar* HG_(strdup) ( const HChar* cc, const HChar* s )
|
||||
{
|
||||
return VG_(strdup)( cc, s );
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- Command line options ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/* Description of these flags is in hg_basics.h. */
|
||||
|
||||
Bool HG_(clo_track_lockorders) = True;
|
||||
|
||||
Bool HG_(clo_cmp_race_err_addrs) = False;
|
||||
|
||||
UWord HG_(clo_history_level) = 2;
|
||||
|
||||
UWord HG_(clo_conflict_cache_size) = 2000000;
|
||||
|
||||
UWord HG_(clo_sanity_flags) = 0;
|
||||
|
||||
Bool HG_(clo_free_is_write) = False;
|
||||
|
||||
UWord HG_(clo_vts_pruning) = 1;
|
||||
|
||||
Bool HG_(clo_check_stack_refs) = True;
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end hg_basics.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,133 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Basic definitions for all of Helgrind. ---*/
|
||||
/*--- hg_basics.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Helgrind, a Valgrind tool for detecting errors
|
||||
in threaded programs.
|
||||
|
||||
Copyright (C) 2007-2015 OpenWorks Ltd
|
||||
info@open-works.co.uk
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __HG_BASICS_H
|
||||
#define __HG_BASICS_H
|
||||
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- Very basic stuff ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#define HG_(str) VGAPPEND(vgHelgrind_,str)
|
||||
|
||||
void* HG_(zalloc) ( const HChar* cc, SizeT n );
|
||||
void HG_(free) ( void* p );
|
||||
HChar* HG_(strdup) ( const HChar* cc, const HChar* s );
|
||||
|
||||
static inline Bool HG_(is_sane_ThreadId) ( ThreadId coretid ) {
|
||||
return coretid >= 0 && coretid < VG_N_THREADS;
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- Command line options ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/* Flags for controlling for which events sanity checking is done */
|
||||
#define SCE_THREADS (1<<0) // Sanity check at thread create/join
|
||||
#define SCE_LOCKS (1<<1) // Sanity check at lock events
|
||||
#define SCE_BIGRANGE (1<<2) // Sanity check at big mem range events
|
||||
#define SCE_ACCESS (1<<3) // Sanity check at mem accesses
|
||||
#define SCE_LAOG (1<<4) // Sanity check at significant LAOG events
|
||||
|
||||
#define SCE_BIGRANGE_T 256 // big mem range minimum size
|
||||
|
||||
|
||||
/* Enable/disable lock order checking. Sometimes it produces a lot of
|
||||
errors, possibly genuine, which nevertheless can be very
|
||||
annoying. */
|
||||
extern Bool HG_(clo_track_lockorders);
|
||||
|
||||
/* When comparing race errors for equality, should the race address be
|
||||
taken into account? For users, no, but for verification purposes
|
||||
(regtesting) this is sometimes important. */
|
||||
extern Bool HG_(clo_cmp_race_err_addrs);
|
||||
|
||||
/* Controls how much history to collect, in order to show conflicting
|
||||
accesses. There are three levels:
|
||||
|
||||
0: "none": don't collect any history. Fastest, but means we can
|
||||
only show one of the two stacks in a race.
|
||||
|
||||
1: "approx": collect one stack trace per (notional) segment, that
|
||||
is, collect a stack trace for a thread every time its vector
|
||||
clock changes. This facilitates showing the bounds of the
|
||||
conflicting segment(s), with relatively small overhead.
|
||||
|
||||
2: "full": collect a stack trace every time the constraints for a
|
||||
location change. This facilitates showing both stack traces in
|
||||
a race, although can be very expensive in time and space
|
||||
(depends on the rate that threads "drag" locations across
|
||||
vector-clock-change boundaries ("dragovers"). This involves
|
||||
collecting and storing large numbers of call stacks just in case
|
||||
we might need to show them later, and so is expensive (although
|
||||
very useful). */
|
||||
extern UWord HG_(clo_history_level);
|
||||
|
||||
/* When doing "full" history collection, this determines the size of
|
||||
the conflicting-access cache, measured in terms of maximum possible
|
||||
number of elements in the previous-access map. Must be between 10k
|
||||
amd 10 million. Default is 1 million. */
|
||||
extern UWord HG_(clo_conflict_cache_size);
|
||||
|
||||
/* Sanity check level. This is an or-ing of
|
||||
SCE_{THREADS,LOCKS,BIGRANGE,ACCESS,LAOG}. */
|
||||
extern UWord HG_(clo_sanity_flags);
|
||||
|
||||
/* Treat heap frees as if the memory was written immediately prior to
|
||||
the free. This shakes out races in which memory is referenced by
|
||||
one thread, and freed by another, and there's no observable
|
||||
synchronisation event to guarantee that the reference happens
|
||||
before the free. */
|
||||
extern Bool HG_(clo_free_is_write);
|
||||
|
||||
/* Controls the application of VTS pruning. There are three levels:
|
||||
|
||||
0: "never": VTS pruning is never done
|
||||
|
||||
1: "auto": (the default): VTS pruning is sometimes done after VTS
|
||||
GCs, just frequently enough to keep space use under control, as
|
||||
determined by heuristics in libhb_core.c.
|
||||
|
||||
2: "always": VTS pruning is done after every VTS GC. This is
|
||||
mostly a big time waster, but minimises space use. */
|
||||
extern UWord HG_(clo_vts_pruning);
|
||||
|
||||
/* When False, race checking ignores memory references which are to
|
||||
the stack, which speeds things up a bit. Default: True. */
|
||||
extern Bool HG_(clo_check_stack_refs);
|
||||
|
||||
#endif /* ! __HG_BASICS_H */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end hg_basics.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,94 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Error management for Helgrind. ---*/
|
||||
/*--- hg_errors.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Helgrind, a Valgrind tool for detecting errors
|
||||
in threaded programs.
|
||||
|
||||
Copyright (C) 2007-2015 OpenWorks Ltd
|
||||
info@open-works.co.uk
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __HG_ERRORS_H
|
||||
#define __HG_ERRORS_H
|
||||
|
||||
|
||||
/* The standard bundle of error management functions that we are
|
||||
required to present to the core/tool interface at startup. */
|
||||
Bool HG_(eq_Error) ( VgRes not_used, const Error* e1, const Error* e2 );
|
||||
void HG_(before_pp_Error) ( const Error* err );
|
||||
void HG_(pp_Error) ( const Error* err );
|
||||
UInt HG_(update_extra) ( const Error* err );
|
||||
Bool HG_(recognised_suppression) ( const HChar* name, Supp *su );
|
||||
Bool HG_(read_extra_suppression_info) ( Int fd, HChar** bufpp, SizeT* nBufp,
|
||||
Int* lineno, Supp* su );
|
||||
Bool HG_(error_matches_suppression) ( const Error* err, const Supp* su );
|
||||
const HChar* HG_(get_error_name) ( const Error* err );
|
||||
SizeT HG_(get_extra_suppression_info) ( const Error* err,
|
||||
/*OUT*/HChar* buf, Int nBuf );
|
||||
SizeT HG_(print_extra_suppression_use) ( const Supp* su,
|
||||
/*OUT*/HChar* buf, Int nBuf );
|
||||
void HG_(update_extra_suppression_use) ( const Error* err, const Supp* su );
|
||||
|
||||
/* Functions for recording various kinds of errors. */
|
||||
void HG_(record_error_Race) ( Thread* thr,
|
||||
Addr data_addr, Int szB, Bool isWrite,
|
||||
Thread* h1_confthr,
|
||||
ExeContext* h1_ct_segstart,
|
||||
ExeContext* h1_ct_mbsegend );
|
||||
void HG_(record_error_UnlockUnlocked) ( Thread*, Lock* );
|
||||
void HG_(record_error_UnlockForeign) ( Thread*, Thread*, Lock* );
|
||||
void HG_(record_error_UnlockBogus) ( Thread*, Addr );
|
||||
void HG_(record_error_PthAPIerror) ( Thread*, const HChar*, Word,
|
||||
const HChar* );
|
||||
|
||||
/* Function for printing the details about an access */
|
||||
void HG_(print_access) (StackTrace ips, UInt n_ips,
|
||||
Thr* thr_a,
|
||||
Addr ga,
|
||||
SizeT SzB,
|
||||
Bool isW,
|
||||
WordSetID locksHeldW );
|
||||
|
||||
/* see the implementation for meaning of these params */
|
||||
void HG_(record_error_LockOrder) ( Thread*, Lock*, Lock*,
|
||||
ExeContext*, ExeContext*,
|
||||
ExeContext* );
|
||||
|
||||
void HG_(record_error_Misc_w_aux) ( Thread*, const HChar* errstr,
|
||||
const HChar* auxstr,
|
||||
ExeContext* auxctx );
|
||||
void HG_(record_error_Misc) ( Thread* thr, const HChar* errstr );
|
||||
|
||||
|
||||
/* Statistics pertaining to error management. */
|
||||
extern ULong HG_(stats__LockN_to_P_queries);
|
||||
extern ULong HG_(stats__LockN_to_P_get_map_size) ( void );
|
||||
extern ULong HG_(stats__string_table_queries);
|
||||
extern ULong HG_(stats__string_table_get_map_size) ( void );
|
||||
|
||||
#endif /* ! __HG_ERRORS_H */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end hg_errors.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,123 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Definitions for Locks and Threads. ---*/
|
||||
/*--- hg_lock_n_thread.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Helgrind, a Valgrind tool for detecting errors
|
||||
in threaded programs.
|
||||
|
||||
Copyright (C) 2007-2015 OpenWorks Ltd
|
||||
info@open-works.co.uk
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "pub_tool_basics.h"
|
||||
#include "pub_tool_libcbase.h"
|
||||
#include "pub_tool_libcassert.h"
|
||||
#include "pub_tool_execontext.h"
|
||||
#include "pub_tool_threadstate.h"
|
||||
#include "pub_tool_wordfm.h"
|
||||
|
||||
#include "hg_basics.h"
|
||||
#include "hg_wordset.h"
|
||||
#include "hg_lock_n_thread.h" /* self */
|
||||
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- Sanity checking ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
inline Bool HG_(is_sane_Thread) ( Thread* thr ) {
|
||||
return thr != NULL && thr->magic == Thread_MAGIC;
|
||||
}
|
||||
|
||||
static Bool is_sane_Bag_of_Threads ( WordBag* bag )
|
||||
{
|
||||
Thread* thr;
|
||||
UWord count;
|
||||
VG_(initIterBag)( bag );
|
||||
while (VG_(nextIterBag)( bag, (UWord*)&thr, &count )) {
|
||||
if (count < 1) return False;
|
||||
if (!HG_(is_sane_Thread)(thr)) return False;
|
||||
}
|
||||
VG_(doneIterBag)( bag );
|
||||
return True;
|
||||
}
|
||||
|
||||
static Bool is_sane_Lock_BASE ( Lock* lock )
|
||||
{
|
||||
if (lock == NULL
|
||||
|| (lock->magic != LockN_MAGIC && lock->magic != LockP_MAGIC))
|
||||
return False;
|
||||
switch (lock->kind) {
|
||||
case LK_mbRec: case LK_nonRec: case LK_rdwr: break;
|
||||
default: return False;
|
||||
}
|
||||
if (lock->heldBy == NULL) {
|
||||
if (lock->acquired_at != NULL) return False;
|
||||
/* Unheld. We arbitrarily require heldW to be False. */
|
||||
return !lock->heldW;
|
||||
} else {
|
||||
if (lock->acquired_at == NULL) return False;
|
||||
}
|
||||
|
||||
/* If heldBy is non-NULL, we require it to contain at least one
|
||||
thread. */
|
||||
if (VG_(isEmptyBag)(lock->heldBy))
|
||||
return False;
|
||||
|
||||
/* Lock is either r- or w-held. */
|
||||
if (!is_sane_Bag_of_Threads(lock->heldBy))
|
||||
return False;
|
||||
if (lock->heldW) {
|
||||
/* Held in write-mode */
|
||||
if ((lock->kind == LK_nonRec || lock->kind == LK_rdwr)
|
||||
&& !VG_(isSingletonTotalBag)(lock->heldBy))
|
||||
return False;
|
||||
} else {
|
||||
/* Held in read-mode */
|
||||
if (lock->kind != LK_rdwr) return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
Bool HG_(is_sane_LockP) ( Lock* lock ) {
|
||||
return lock != NULL
|
||||
&& lock->magic == LockP_MAGIC
|
||||
&& lock->hbso == NULL
|
||||
&& is_sane_Lock_BASE(lock);
|
||||
}
|
||||
|
||||
Bool HG_(is_sane_LockN) ( Lock* lock ) {
|
||||
return lock != NULL
|
||||
&& lock->magic == LockN_MAGIC
|
||||
&& lock->hbso != NULL
|
||||
&& is_sane_Lock_BASE(lock);
|
||||
}
|
||||
|
||||
Bool HG_(is_sane_LockNorP) ( Lock* lock ) {
|
||||
return is_sane_Lock_BASE(lock);
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end hg_lock_n_thread.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,198 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Definitions for Locks and Threads. ---*/
|
||||
/*--- hg_lock_n_thread.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Helgrind, a Valgrind tool for detecting errors
|
||||
in threaded programs.
|
||||
|
||||
Copyright (C) 2007-2015 OpenWorks Ltd
|
||||
info@open-works.co.uk
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __HG_LOCK_N_THREAD_H
|
||||
#define __HG_LOCK_N_THREAD_H
|
||||
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- Primary data definitions ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/* Magic numbers, for doing assertions that structures really are of
|
||||
the right type. Useful as some of the code can get a bit
|
||||
complex. */
|
||||
#define Thread_MAGIC 0x504fc5e5
|
||||
#define LockN_MAGIC 0x6545b557 /* normal nonpersistent locks */
|
||||
#define LockP_MAGIC 0x755b5456 /* persistent (copied) locks */
|
||||
|
||||
|
||||
/* These are handles for Word sets. CONSTRAINTS: must be small ints
|
||||
numbered from zero, since 32-bit versions of them are used to
|
||||
encode lock-sets in libhb's history records (Thr_n_RCEC). */
|
||||
typedef WordSet WordSetID;
|
||||
|
||||
|
||||
/* Synchronisation Objects, exported abstractly by libhb. */
|
||||
typedef struct _SO SO;
|
||||
|
||||
/* Thr, libhb's private thread record, exported abstractly. Thr's are
|
||||
allocated and never deallocated (simply leaked). Also ThrID, which
|
||||
is a small integer which uniquely identifies a Thr and which is
|
||||
used in ScalarTS because it is smaller than a Thr*. There is a 1-1
|
||||
mapping between Thr's and ThrIDs. */
|
||||
typedef struct _Thr Thr;
|
||||
typedef UInt ThrID;
|
||||
|
||||
|
||||
/* Stores information about a thread. Addresses of these also serve
|
||||
as unique thread identifiers and so are never freed, so they should
|
||||
be as small as possible. Freeing Thread structures makes the
|
||||
storage management just too complex, and most programs don't create
|
||||
many threads, so tolerating this leak seems like a not-bad
|
||||
tradeoff.
|
||||
|
||||
Since these are never freed, the .coretid field only indicates the
|
||||
core's ThreadId associated with this Thread whilst it is alive.
|
||||
Once the thread finishes, the ThreadId is set to
|
||||
VG_INVALID_THREADID.
|
||||
|
||||
The core may later re-use the same ThreadId for what is a logically
|
||||
completely different thread, which of course must have a different
|
||||
Thread structure. */
|
||||
typedef
|
||||
struct _Thread {
|
||||
/* ADMIN */
|
||||
struct _Thread* admin;
|
||||
UInt magic;
|
||||
Thr* hbthr; /* which in turn points back here .. */
|
||||
ThreadId coretid; /* .. via its hgthread field */
|
||||
/* USEFUL */
|
||||
WordSetID locksetA; /* WordSet of Lock* currently held by thread */
|
||||
WordSetID locksetW; /* subset of locksetA held in w-mode */
|
||||
/* EXPOSITION */
|
||||
/* Place where parent was when this thread was created. */
|
||||
ExeContext* created_at;
|
||||
Bool announced;
|
||||
/* Index for generating references in error messages. */
|
||||
Int errmsg_index;
|
||||
|
||||
/* Nesting level of pthread_create(). New memory allocated is untracked
|
||||
when this value is > 0: race reporting is suppressed there. DRD does
|
||||
the same thing implicitly. This is necessary because for example
|
||||
Solaris libc caches many objects and reuses them for different threads
|
||||
and that confuses Helgrind. With libvki it would be possible to
|
||||
explictly use VG_USERREQ__HG_CLEAN_MEMORY on such objects.
|
||||
Also mutex activity is ignored so that they do not impose false
|
||||
ordering between creator and created thread. */
|
||||
Int pthread_create_nesting_level;
|
||||
|
||||
/* Nesting level of synchronization functions called by the client.
|
||||
Loads and stores are ignored when its value > 0.
|
||||
Currently this is used solely for suppressing races of primitive
|
||||
synchronization objects themselves - mutexes, condition variables,
|
||||
read-write locks and their associated sleep queues.
|
||||
See also documentation for command line option
|
||||
--ignore-thread-creation. */
|
||||
Int synchr_nesting;
|
||||
|
||||
#if defined(VGO_solaris)
|
||||
Int bind_guard_flag; /* Bind flag from the runtime linker. */
|
||||
#endif /* VGO_solaris */
|
||||
}
|
||||
Thread;
|
||||
|
||||
/* Get hg's admin_threads value, so libhb can visit all of them. */
|
||||
Thread* get_admin_threads ( void );
|
||||
|
||||
/* Stores information about a lock's current state. These are
|
||||
allocated and later freed (when the containing memory becomes
|
||||
NoAccess). This gives a problem for the XError type, which
|
||||
contains Lock*s. Solution is to copy any Lock which is to be
|
||||
incorporated into an XErrors, so as to make it independent from the
|
||||
'normal' collection of Locks, which can come and go. When the lock
|
||||
is copied, its .magic is changed from LockN_Magic to
|
||||
LockP_Magic. */
|
||||
|
||||
/* Lock kinds. */
|
||||
typedef
|
||||
enum {
|
||||
LK_mbRec=1001, /* normal mutex, possibly recursive */
|
||||
LK_nonRec, /* normal mutex, definitely non recursive */
|
||||
LK_rdwr /* reader-writer lock */
|
||||
}
|
||||
LockKind;
|
||||
|
||||
typedef
|
||||
struct _Lock {
|
||||
/* ADMIN */
|
||||
struct _Lock* admin_next; /* fields for a double linked */
|
||||
struct _Lock* admin_prev; /* list of these locks */
|
||||
ULong unique; /* used for persistence-hashing */
|
||||
UInt magic; /* LockN_MAGIC or LockP_MAGIC */
|
||||
/* EXPOSITION */
|
||||
/* Place where lock first came to the attention of Helgrind. */
|
||||
ExeContext* appeared_at;
|
||||
/* If the lock is held, place where the lock most recently made
|
||||
an unlocked->locked transition. Must be sync'd with .heldBy:
|
||||
either both NULL or both non-NULL. */
|
||||
ExeContext* acquired_at;
|
||||
/* USEFUL-STATIC */
|
||||
SO* hbso; /* associated SO */
|
||||
Addr guestaddr; /* Guest address of lock */
|
||||
LockKind kind; /* what kind of lock this is */
|
||||
/* USEFUL-DYNAMIC */
|
||||
Bool heldW;
|
||||
WordBag* heldBy; /* bag of threads that hold this lock */
|
||||
/* .heldBy is NULL: lock is unheld, and .heldW is meaningless
|
||||
but arbitrarily set to False
|
||||
.heldBy is non-NULL:
|
||||
.heldW is True: lock is w-held by threads in heldBy
|
||||
.heldW is False: lock is r-held by threads in heldBy
|
||||
Either way, heldBy may not validly be an empty Bag.
|
||||
|
||||
for LK_nonRec, r-holdings are not allowed, and w-holdings may
|
||||
only have sizeTotal(heldBy) == 1
|
||||
|
||||
for LK_mbRec, r-holdings are not allowed, and w-holdings may
|
||||
only have sizeUnique(heldBy) == 1
|
||||
|
||||
for LK_rdwr, w-holdings may only have sizeTotal(heldBy) == 1 */
|
||||
}
|
||||
Lock;
|
||||
|
||||
#define Lock_INVALID ((Lock*)1UL)
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
/*--- Sanity checking ---*/
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
Bool HG_(is_sane_Thread) ( Thread* thr );
|
||||
Bool HG_(is_sane_LockP) ( Lock* lock );
|
||||
Bool HG_(is_sane_LockN) ( Lock* lock );
|
||||
Bool HG_(is_sane_LockNorP) ( Lock* lock );
|
||||
|
||||
|
||||
#endif /* ! __HG_LOCK_N_THREAD_H */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end hg_lock_n_thread.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,945 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Sets of words, with unique set identifiers. ---*/
|
||||
/*--- hg_wordset.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Helgrind, a Valgrind tool for detecting errors
|
||||
in threaded programs.
|
||||
|
||||
Copyright (C) 2007-2015 OpenWorks LLP
|
||||
info@open-works.co.uk
|
||||
|
||||
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.
|
||||
|
||||
Neither the names of the U.S. Department of Energy nor the
|
||||
University of California nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software
|
||||
without prior written permission.
|
||||
*/
|
||||
|
||||
#include "pub_tool_basics.h"
|
||||
#include "pub_tool_libcassert.h"
|
||||
#include "pub_tool_libcbase.h"
|
||||
#include "pub_tool_libcprint.h"
|
||||
#include "pub_tool_threadstate.h"
|
||||
#include "pub_tool_wordfm.h"
|
||||
|
||||
#include "hg_basics.h"
|
||||
#include "hg_wordset.h" /* self */
|
||||
|
||||
// define to 1 to have (a lot of) debugging of add/re-use/die WSU entries.
|
||||
#define HG_DEBUG 0
|
||||
|
||||
//------------------------------------------------------------------//
|
||||
//--- Word Cache ---//
|
||||
//------------------------------------------------------------------//
|
||||
|
||||
typedef
|
||||
struct { UWord arg1; UWord arg2; UWord res; }
|
||||
WCacheEnt;
|
||||
|
||||
/* Each cache is a fixed sized array of N_WCACHE_STAT_MAX entries.
|
||||
However only the first .dynMax are used. This is because at some
|
||||
point, expanding the cache further overall gives a slowdown because
|
||||
searching more entries more than negates any performance advantage
|
||||
from caching those entries in the first place. Hence use .dynMax
|
||||
to allow the size of the cache(s) to be set differently for each
|
||||
different WordSetU. */
|
||||
#define N_WCACHE_STAT_MAX 32
|
||||
typedef
|
||||
struct {
|
||||
WCacheEnt ent[N_WCACHE_STAT_MAX];
|
||||
UWord dynMax; /* 1 .. N_WCACHE_STAT_MAX inclusive */
|
||||
UWord inUse; /* 0 .. dynMax inclusive */
|
||||
}
|
||||
WCache;
|
||||
|
||||
#define WCache_INIT(_zzcache,_zzdynmax) \
|
||||
do { \
|
||||
tl_assert((_zzdynmax) >= 1); \
|
||||
tl_assert((_zzdynmax) <= N_WCACHE_STAT_MAX); \
|
||||
(_zzcache).dynMax = (_zzdynmax); \
|
||||
(_zzcache).inUse = 0; \
|
||||
} while (0)
|
||||
|
||||
#define WCache_LOOKUP_AND_RETURN(_retty,_zzcache,_zzarg1,_zzarg2) \
|
||||
do { \
|
||||
UWord _i; \
|
||||
UWord _arg1 = (UWord)(_zzarg1); \
|
||||
UWord _arg2 = (UWord)(_zzarg2); \
|
||||
WCache* _cache = &(_zzcache); \
|
||||
tl_assert(_cache->dynMax >= 1); \
|
||||
tl_assert(_cache->dynMax <= N_WCACHE_STAT_MAX); \
|
||||
tl_assert(_cache->inUse >= 0); \
|
||||
tl_assert(_cache->inUse <= _cache->dynMax); \
|
||||
if (_cache->inUse > 0) { \
|
||||
if (_cache->ent[0].arg1 == _arg1 \
|
||||
&& _cache->ent[0].arg2 == _arg2) \
|
||||
return (_retty)_cache->ent[0].res; \
|
||||
for (_i = 1; _i < _cache->inUse; _i++) { \
|
||||
if (_cache->ent[_i].arg1 == _arg1 \
|
||||
&& _cache->ent[_i].arg2 == _arg2) { \
|
||||
WCacheEnt tmp = _cache->ent[_i-1]; \
|
||||
_cache->ent[_i-1] = _cache->ent[_i]; \
|
||||
_cache->ent[_i] = tmp; \
|
||||
return (_retty)_cache->ent[_i-1].res; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define WCache_UPDATE(_zzcache,_zzarg1,_zzarg2,_zzresult) \
|
||||
do { \
|
||||
Word _i; \
|
||||
UWord _arg1 = (UWord)(_zzarg1); \
|
||||
UWord _arg2 = (UWord)(_zzarg2); \
|
||||
UWord _res = (UWord)(_zzresult); \
|
||||
WCache* _cache = &(_zzcache); \
|
||||
tl_assert(_cache->dynMax >= 1); \
|
||||
tl_assert(_cache->dynMax <= N_WCACHE_STAT_MAX); \
|
||||
tl_assert(_cache->inUse >= 0); \
|
||||
tl_assert(_cache->inUse <= _cache->dynMax); \
|
||||
if (_cache->inUse < _cache->dynMax) \
|
||||
_cache->inUse++; \
|
||||
for (_i = _cache->inUse-1; _i >= 1; _i--) \
|
||||
_cache->ent[_i] = _cache->ent[_i-1]; \
|
||||
_cache->ent[0].arg1 = _arg1; \
|
||||
_cache->ent[0].arg2 = _arg2; \
|
||||
_cache->ent[0].res = _res; \
|
||||
} while (0)
|
||||
|
||||
|
||||
//------------------------------------------------------------------//
|
||||
//--- WordSet ---//
|
||||
//--- Implementation ---//
|
||||
//------------------------------------------------------------------//
|
||||
|
||||
typedef
|
||||
struct {
|
||||
WordSetU* owner; /* for sanity checking */
|
||||
UWord* words;
|
||||
UWord size; /* Really this should be SizeT */
|
||||
}
|
||||
WordVec;
|
||||
|
||||
/* ix2vec[0 .. ix2vec_used-1] are pointers to the lock sets (WordVecs)
|
||||
really. vec2ix is the inverse mapping, mapping WordVec* to the
|
||||
corresponding ix2vec entry number. The two mappings are mutually
|
||||
redundant.
|
||||
|
||||
If a WordVec WV is marked as dead by HG(dieWS), WV is removed from
|
||||
vec2ix. The entry of the dead WVs in ix2vec are used to maintain a
|
||||
linked list of free (to be re-used) ix2vec entries. */
|
||||
struct _WordSetU {
|
||||
void* (*alloc)(const HChar*,SizeT);
|
||||
const HChar* cc;
|
||||
void (*dealloc)(void*);
|
||||
WordFM* vec2ix; /* WordVec-to-WordSet mapping tree */
|
||||
WordVec** ix2vec; /* WordSet-to-WordVec mapping array */
|
||||
UWord ix2vec_size;
|
||||
UWord ix2vec_used;
|
||||
WordVec** ix2vec_free;
|
||||
WordSet empty; /* cached, for speed */
|
||||
/* Caches for some operations */
|
||||
WCache cache_addTo;
|
||||
WCache cache_delFrom;
|
||||
WCache cache_intersect;
|
||||
WCache cache_minus;
|
||||
/* Stats */
|
||||
UWord n_add;
|
||||
UWord n_add_uncached;
|
||||
UWord n_del;
|
||||
UWord n_del_uncached;
|
||||
UWord n_die;
|
||||
UWord n_union;
|
||||
UWord n_intersect;
|
||||
UWord n_intersect_uncached;
|
||||
UWord n_minus;
|
||||
UWord n_minus_uncached;
|
||||
UWord n_elem;
|
||||
UWord n_doubleton;
|
||||
UWord n_isEmpty;
|
||||
UWord n_isSingleton;
|
||||
UWord n_anyElementOf;
|
||||
UWord n_isSubsetOf;
|
||||
};
|
||||
|
||||
/* Create a new WordVec of the given size. */
|
||||
|
||||
static WordVec* new_WV_of_size ( WordSetU* wsu, UWord sz )
|
||||
{
|
||||
WordVec* wv;
|
||||
tl_assert(sz >= 0);
|
||||
wv = wsu->alloc( wsu->cc, sizeof(WordVec) );
|
||||
wv->owner = wsu;
|
||||
wv->words = NULL;
|
||||
wv->size = sz;
|
||||
if (sz > 0) {
|
||||
wv->words = wsu->alloc( wsu->cc, (SizeT)sz * sizeof(UWord) );
|
||||
}
|
||||
return wv;
|
||||
}
|
||||
|
||||
static void delete_WV ( WordVec* wv )
|
||||
{
|
||||
void (*dealloc)(void*) = wv->owner->dealloc;
|
||||
if (wv->words) {
|
||||
dealloc(wv->words);
|
||||
}
|
||||
dealloc(wv);
|
||||
}
|
||||
static void delete_WV_for_FM ( UWord wv ) {
|
||||
delete_WV( (WordVec*)wv );
|
||||
}
|
||||
|
||||
static Word cmp_WordVecs_for_FM ( UWord wv1W, UWord wv2W )
|
||||
{
|
||||
UWord i;
|
||||
WordVec* wv1 = (WordVec*)wv1W;
|
||||
WordVec* wv2 = (WordVec*)wv2W;
|
||||
|
||||
// WordVecs with smaller size are smaller.
|
||||
if (wv1->size < wv2->size) {
|
||||
return -1;
|
||||
}
|
||||
if (wv1->size > wv2->size) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Sizes are equal => order based on content.
|
||||
for (i = 0; i < wv1->size; i++) {
|
||||
if (wv1->words[i] == wv2->words[i])
|
||||
continue;
|
||||
if (wv1->words[i] < wv2->words[i])
|
||||
return -1;
|
||||
if (wv1->words[i] > wv2->words[i])
|
||||
return 1;
|
||||
tl_assert(0);
|
||||
}
|
||||
return 0; /* identical */
|
||||
}
|
||||
|
||||
static void ensure_ix2vec_space ( WordSetU* wsu )
|
||||
{
|
||||
UInt i, new_sz;
|
||||
WordVec** new_vec;
|
||||
tl_assert(wsu->ix2vec_used <= wsu->ix2vec_size);
|
||||
if (wsu->ix2vec_used < wsu->ix2vec_size)
|
||||
return;
|
||||
new_sz = 2 * wsu->ix2vec_size;
|
||||
if (new_sz == 0) new_sz = 1;
|
||||
new_vec = wsu->alloc( wsu->cc, new_sz * sizeof(WordVec*) );
|
||||
tl_assert(new_vec);
|
||||
for (i = 0; i < wsu->ix2vec_size; i++)
|
||||
new_vec[i] = wsu->ix2vec[i];
|
||||
if (wsu->ix2vec)
|
||||
wsu->dealloc(wsu->ix2vec);
|
||||
wsu->ix2vec = new_vec;
|
||||
wsu->ix2vec_size = new_sz;
|
||||
}
|
||||
|
||||
/* True if wv is a dead entry (i.e. is in the linked list of free to be re-used
|
||||
entries in ix2vec). */
|
||||
static inline Bool is_dead ( WordSetU* wsu, WordVec* wv )
|
||||
{
|
||||
if (wv == NULL) /* last element in free linked list in ix2vec */
|
||||
return True;
|
||||
else
|
||||
return (WordVec**)wv >= &(wsu->ix2vec[1])
|
||||
&& (WordVec**)wv < &(wsu->ix2vec[wsu->ix2vec_size]);
|
||||
}
|
||||
/* Index into a WordSetU, doing the obvious range check. Failure of
|
||||
the assertions marked XXX and YYY is an indication of passing the
|
||||
wrong WordSetU* in the public API of this module.
|
||||
Accessing a dead ws will assert. */
|
||||
static WordVec* do_ix2vec ( WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
WordVec* wv;
|
||||
tl_assert(wsu->ix2vec_used <= wsu->ix2vec_size);
|
||||
if (wsu->ix2vec_used > 0)
|
||||
tl_assert(wsu->ix2vec);
|
||||
/* If this assertion fails, it may mean you supplied a 'ws'
|
||||
that does not come from the 'wsu' universe. */
|
||||
tl_assert(ws < wsu->ix2vec_used); /* XXX */
|
||||
wv = wsu->ix2vec[ws];
|
||||
/* Make absolutely sure that 'ws' is a non dead member of 'wsu'. */
|
||||
tl_assert(wv);
|
||||
tl_assert(!is_dead(wsu,wv));
|
||||
tl_assert(wv->owner == wsu); /* YYY */
|
||||
return wv;
|
||||
}
|
||||
|
||||
/* Same as do_ix2vec but returns NULL for a dead ws. */
|
||||
static WordVec* do_ix2vec_with_dead ( WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
WordVec* wv;
|
||||
tl_assert(wsu->ix2vec_used <= wsu->ix2vec_size);
|
||||
if (wsu->ix2vec_used > 0)
|
||||
tl_assert(wsu->ix2vec);
|
||||
/* If this assertion fails, it may mean you supplied a 'ws'
|
||||
that does not come from the 'wsu' universe. */
|
||||
tl_assert(ws < wsu->ix2vec_used); /* XXX */
|
||||
wv = wsu->ix2vec[ws];
|
||||
/* Make absolutely sure that 'ws' is either dead or a member of 'wsu'. */
|
||||
if (is_dead(wsu,wv))
|
||||
wv = NULL;
|
||||
else
|
||||
tl_assert(wv->owner == wsu); /* YYY */
|
||||
return wv;
|
||||
}
|
||||
|
||||
/* See if wv is contained within wsu. If so, deallocate wv and return
|
||||
the index of the already-present copy. If not, add wv to both the
|
||||
vec2ix and ix2vec mappings and return its index.
|
||||
*/
|
||||
static WordSet add_or_dealloc_WordVec( WordSetU* wsu, WordVec* wv_new )
|
||||
{
|
||||
Bool have;
|
||||
WordVec* wv_old;
|
||||
UWord/*Set*/ ix_old = -1;
|
||||
/* Really WordSet, but need something that can safely be casted to
|
||||
a Word* in the lookupFM. Making it WordSet (which is 32 bits)
|
||||
causes failures on a 64-bit platform. */
|
||||
tl_assert(wv_new->owner == wsu);
|
||||
have = VG_(lookupFM)( wsu->vec2ix,
|
||||
(UWord*)&wv_old, (UWord*)&ix_old,
|
||||
(UWord)wv_new );
|
||||
if (have) {
|
||||
tl_assert(wv_old != wv_new);
|
||||
tl_assert(wv_old);
|
||||
tl_assert(wv_old->owner == wsu);
|
||||
tl_assert(ix_old < wsu->ix2vec_used);
|
||||
tl_assert(wsu->ix2vec[ix_old] == wv_old);
|
||||
delete_WV( wv_new );
|
||||
return (WordSet)ix_old;
|
||||
} else if (wsu->ix2vec_free) {
|
||||
WordSet ws;
|
||||
tl_assert(is_dead(wsu,(WordVec*)wsu->ix2vec_free));
|
||||
ws = wsu->ix2vec_free - &(wsu->ix2vec[0]);
|
||||
tl_assert(wsu->ix2vec[ws] == NULL || is_dead(wsu,wsu->ix2vec[ws]));
|
||||
wsu->ix2vec_free = (WordVec **) wsu->ix2vec[ws];
|
||||
wsu->ix2vec[ws] = wv_new;
|
||||
VG_(addToFM)( wsu->vec2ix, (UWord)wv_new, ws );
|
||||
if (HG_DEBUG) VG_(printf)("aodW %s re-use free %d %p\n", wsu->cc, (Int)ws, wv_new );
|
||||
return ws;
|
||||
} else {
|
||||
ensure_ix2vec_space( wsu );
|
||||
tl_assert(wsu->ix2vec);
|
||||
tl_assert(wsu->ix2vec_used < wsu->ix2vec_size);
|
||||
wsu->ix2vec[wsu->ix2vec_used] = wv_new;
|
||||
VG_(addToFM)( wsu->vec2ix, (Word)wv_new, (Word)wsu->ix2vec_used );
|
||||
if (HG_DEBUG) VG_(printf)("aodW %s %d %p\n", wsu->cc, (Int)wsu->ix2vec_used, wv_new );
|
||||
wsu->ix2vec_used++;
|
||||
tl_assert(wsu->ix2vec_used <= wsu->ix2vec_size);
|
||||
return (WordSet)(wsu->ix2vec_used - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WordSetU* HG_(newWordSetU) ( void* (*alloc_nofail)( const HChar*, SizeT ),
|
||||
const HChar* cc,
|
||||
void (*dealloc)(void*),
|
||||
Word cacheSize )
|
||||
{
|
||||
WordSetU* wsu;
|
||||
WordVec* empty;
|
||||
|
||||
wsu = alloc_nofail( cc, sizeof(WordSetU) );
|
||||
VG_(memset)( wsu, 0, sizeof(WordSetU) );
|
||||
wsu->alloc = alloc_nofail;
|
||||
wsu->cc = cc;
|
||||
wsu->dealloc = dealloc;
|
||||
wsu->vec2ix = VG_(newFM)( alloc_nofail, cc,
|
||||
dealloc, cmp_WordVecs_for_FM );
|
||||
wsu->ix2vec_used = 0;
|
||||
wsu->ix2vec_size = 0;
|
||||
wsu->ix2vec = NULL;
|
||||
wsu->ix2vec_free = NULL;
|
||||
WCache_INIT(wsu->cache_addTo, cacheSize);
|
||||
WCache_INIT(wsu->cache_delFrom, cacheSize);
|
||||
WCache_INIT(wsu->cache_intersect, cacheSize);
|
||||
WCache_INIT(wsu->cache_minus, cacheSize);
|
||||
empty = new_WV_of_size( wsu, 0 );
|
||||
wsu->empty = add_or_dealloc_WordVec( wsu, empty );
|
||||
|
||||
return wsu;
|
||||
}
|
||||
|
||||
void HG_(deleteWordSetU) ( WordSetU* wsu )
|
||||
{
|
||||
void (*dealloc)(void*) = wsu->dealloc;
|
||||
tl_assert(wsu->vec2ix);
|
||||
VG_(deleteFM)( wsu->vec2ix, delete_WV_for_FM, NULL/*val-finalizer*/ );
|
||||
if (wsu->ix2vec)
|
||||
dealloc(wsu->ix2vec);
|
||||
dealloc(wsu);
|
||||
}
|
||||
|
||||
WordSet HG_(emptyWS) ( WordSetU* wsu )
|
||||
{
|
||||
return wsu->empty;
|
||||
}
|
||||
|
||||
Bool HG_(isEmptyWS) ( WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
WordVec* wv = do_ix2vec( wsu, ws );
|
||||
wsu->n_isEmpty++;
|
||||
if (wv->size == 0) {
|
||||
tl_assert(ws == wsu->empty);
|
||||
return True;
|
||||
} else {
|
||||
tl_assert(ws != wsu->empty);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
Bool HG_(isSingletonWS) ( WordSetU* wsu, WordSet ws, UWord w )
|
||||
{
|
||||
WordVec* wv;
|
||||
tl_assert(wsu);
|
||||
wsu->n_isSingleton++;
|
||||
wv = do_ix2vec( wsu, ws );
|
||||
return (Bool)(wv->size == 1 && wv->words[0] == w);
|
||||
}
|
||||
|
||||
UWord HG_(cardinalityWS) ( WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
WordVec* wv;
|
||||
tl_assert(wsu);
|
||||
wv = do_ix2vec( wsu, ws );
|
||||
tl_assert(wv->size >= 0);
|
||||
return wv->size;
|
||||
}
|
||||
|
||||
UWord HG_(anyElementOfWS) ( WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
WordVec* wv;
|
||||
tl_assert(wsu);
|
||||
wsu->n_anyElementOf++;
|
||||
wv = do_ix2vec( wsu, ws );
|
||||
tl_assert(wv->size >= 1);
|
||||
return wv->words[0];
|
||||
}
|
||||
|
||||
UWord HG_(cardinalityWSU) ( WordSetU* wsu )
|
||||
{
|
||||
tl_assert(wsu);
|
||||
return wsu->ix2vec_used;
|
||||
}
|
||||
|
||||
void HG_(getPayloadWS) ( /*OUT*/UWord** words, /*OUT*/UWord* nWords,
|
||||
WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
WordVec* wv;
|
||||
if (HG_DEBUG) VG_(printf)("getPayloadWS %s %d\n", wsu->cc, (Int)ws);
|
||||
tl_assert(wsu);
|
||||
wv = do_ix2vec( wsu, ws );
|
||||
tl_assert(wv->size >= 0);
|
||||
*nWords = wv->size;
|
||||
*words = wv->words;
|
||||
}
|
||||
|
||||
void HG_(dieWS) ( WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
WordVec* wv = do_ix2vec_with_dead( wsu, ws );
|
||||
WordVec* wv_in_vec2ix;
|
||||
UWord/*Set*/ wv_ix = -1;
|
||||
|
||||
if (HG_DEBUG) VG_(printf)("dieWS %s %d %p\n", wsu->cc, (Int)ws, wv);
|
||||
|
||||
if (ws == 0)
|
||||
return; // we never die the empty set.
|
||||
|
||||
if (!wv)
|
||||
return; // already dead. (or a bug ?).
|
||||
|
||||
wsu->n_die++;
|
||||
|
||||
|
||||
wsu->ix2vec[ws] = (WordVec*) wsu->ix2vec_free;
|
||||
wsu->ix2vec_free = &wsu->ix2vec[ws];
|
||||
|
||||
VG_(delFromFM) ( wsu->vec2ix,
|
||||
(UWord*)&wv_in_vec2ix, (UWord*)&wv_ix,
|
||||
(UWord)wv );
|
||||
|
||||
if (HG_DEBUG) VG_(printf)("dieWS wv_ix %d\n", (Int)wv_ix);
|
||||
tl_assert (wv_ix);
|
||||
tl_assert (wv_ix == ws);
|
||||
|
||||
delete_WV( wv );
|
||||
|
||||
wsu->cache_addTo.inUse = 0;
|
||||
wsu->cache_delFrom.inUse = 0;
|
||||
wsu->cache_intersect.inUse = 0;
|
||||
wsu->cache_minus.inUse = 0;
|
||||
}
|
||||
|
||||
Bool HG_(plausibleWS) ( WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
if (wsu == NULL) return False;
|
||||
if (ws < 0 || ws >= wsu->ix2vec_used)
|
||||
return False;
|
||||
return True;
|
||||
}
|
||||
|
||||
Bool HG_(saneWS_SLOW) ( WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
WordVec* wv;
|
||||
UWord i;
|
||||
if (wsu == NULL) return False;
|
||||
if (ws < 0 || ws >= wsu->ix2vec_used)
|
||||
return False;
|
||||
wv = do_ix2vec( wsu, ws );
|
||||
/* can never happen .. do_ix2vec will assert instead. Oh well. */
|
||||
if (wv->owner != wsu) return False;
|
||||
if (wv->size < 0) return False;
|
||||
if (wv->size > 0) {
|
||||
for (i = 0; i < wv->size-1; i++) {
|
||||
if (wv->words[i] >= wv->words[i+1])
|
||||
return False;
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
Bool HG_(elemWS) ( WordSetU* wsu, WordSet ws, UWord w )
|
||||
{
|
||||
UWord i;
|
||||
WordVec* wv = do_ix2vec( wsu, ws );
|
||||
wsu->n_elem++;
|
||||
for (i = 0; i < wv->size; i++) {
|
||||
if (wv->words[i] == w)
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
WordSet HG_(doubletonWS) ( WordSetU* wsu, UWord w1, UWord w2 )
|
||||
{
|
||||
WordVec* wv;
|
||||
wsu->n_doubleton++;
|
||||
if (w1 == w2) {
|
||||
wv = new_WV_of_size(wsu, 1);
|
||||
wv->words[0] = w1;
|
||||
}
|
||||
else if (w1 < w2) {
|
||||
wv = new_WV_of_size(wsu, 2);
|
||||
wv->words[0] = w1;
|
||||
wv->words[1] = w2;
|
||||
}
|
||||
else {
|
||||
tl_assert(w1 > w2);
|
||||
wv = new_WV_of_size(wsu, 2);
|
||||
wv->words[0] = w2;
|
||||
wv->words[1] = w1;
|
||||
}
|
||||
return add_or_dealloc_WordVec( wsu, wv );
|
||||
}
|
||||
|
||||
WordSet HG_(singletonWS) ( WordSetU* wsu, UWord w )
|
||||
{
|
||||
return HG_(doubletonWS)( wsu, w, w );
|
||||
}
|
||||
|
||||
WordSet HG_(isSubsetOf) ( WordSetU* wsu, WordSet small, WordSet big )
|
||||
{
|
||||
wsu->n_isSubsetOf++;
|
||||
return small == HG_(intersectWS)( wsu, small, big );
|
||||
}
|
||||
|
||||
void HG_(ppWS) ( WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
UWord i;
|
||||
WordVec* wv;
|
||||
tl_assert(wsu);
|
||||
wv = do_ix2vec( wsu, ws );
|
||||
VG_(printf)("{");
|
||||
for (i = 0; i < wv->size; i++) {
|
||||
VG_(printf)("%p", (void*)wv->words[i]);
|
||||
if (i < wv->size-1)
|
||||
VG_(printf)(",");
|
||||
}
|
||||
VG_(printf)("}");
|
||||
}
|
||||
|
||||
void HG_(ppWSUstats) ( WordSetU* wsu, const HChar* name )
|
||||
{
|
||||
VG_(printf)(" WordSet \"%s\":\n", name);
|
||||
VG_(printf)(" addTo %10lu (%lu uncached)\n",
|
||||
wsu->n_add, wsu->n_add_uncached);
|
||||
VG_(printf)(" delFrom %10lu (%lu uncached)\n",
|
||||
wsu->n_del, wsu->n_del_uncached);
|
||||
VG_(printf)(" union %10lu\n", wsu->n_union);
|
||||
VG_(printf)(" intersect %10lu (%lu uncached) "
|
||||
"[nb. incl isSubsetOf]\n",
|
||||
wsu->n_intersect, wsu->n_intersect_uncached);
|
||||
VG_(printf)(" minus %10lu (%lu uncached)\n",
|
||||
wsu->n_minus, wsu->n_minus_uncached);
|
||||
VG_(printf)(" elem %10lu\n", wsu->n_elem);
|
||||
VG_(printf)(" doubleton %10lu\n", wsu->n_doubleton);
|
||||
VG_(printf)(" isEmpty %10lu\n", wsu->n_isEmpty);
|
||||
VG_(printf)(" isSingleton %10lu\n", wsu->n_isSingleton);
|
||||
VG_(printf)(" anyElementOf %10lu\n", wsu->n_anyElementOf);
|
||||
VG_(printf)(" isSubsetOf %10lu\n", wsu->n_isSubsetOf);
|
||||
VG_(printf)(" dieWS %10lu\n", wsu->n_die);
|
||||
}
|
||||
|
||||
WordSet HG_(addToWS) ( WordSetU* wsu, WordSet ws, UWord w )
|
||||
{
|
||||
UWord k, j;
|
||||
WordVec* wv_new;
|
||||
WordVec* wv;
|
||||
WordSet result = (WordSet)(-1); /* bogus */
|
||||
|
||||
wsu->n_add++;
|
||||
WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_addTo, ws, w);
|
||||
wsu->n_add_uncached++;
|
||||
|
||||
/* If already present, this is a no-op. */
|
||||
wv = do_ix2vec( wsu, ws );
|
||||
for (k = 0; k < wv->size; k++) {
|
||||
if (wv->words[k] == w) {
|
||||
result = ws;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* Ok, not present. Build a new one ... */
|
||||
wv_new = new_WV_of_size( wsu, wv->size + 1 );
|
||||
k = j = 0;
|
||||
for (; k < wv->size && wv->words[k] < w; k++) {
|
||||
wv_new->words[j++] = wv->words[k];
|
||||
}
|
||||
wv_new->words[j++] = w;
|
||||
for (; k < wv->size; k++) {
|
||||
tl_assert(wv->words[k] > w);
|
||||
wv_new->words[j++] = wv->words[k];
|
||||
}
|
||||
tl_assert(j == wv_new->size);
|
||||
|
||||
/* Find any existing copy, or add the new one. */
|
||||
result = add_or_dealloc_WordVec( wsu, wv_new );
|
||||
tl_assert(result != (WordSet)(-1));
|
||||
|
||||
out:
|
||||
WCache_UPDATE(wsu->cache_addTo, ws, w, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
WordSet HG_(delFromWS) ( WordSetU* wsu, WordSet ws, UWord w )
|
||||
{
|
||||
UWord i, j, k;
|
||||
WordVec* wv_new;
|
||||
WordSet result = (WordSet)(-1); /* bogus */
|
||||
WordVec* wv = do_ix2vec( wsu, ws );
|
||||
|
||||
wsu->n_del++;
|
||||
|
||||
/* special case empty set */
|
||||
if (wv->size == 0) {
|
||||
tl_assert(ws == wsu->empty);
|
||||
return ws;
|
||||
}
|
||||
|
||||
WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_delFrom, ws, w);
|
||||
wsu->n_del_uncached++;
|
||||
|
||||
/* If not already present, this is a no-op. */
|
||||
for (i = 0; i < wv->size; i++) {
|
||||
if (wv->words[i] == w)
|
||||
break;
|
||||
}
|
||||
if (i == wv->size) {
|
||||
result = ws;
|
||||
goto out;
|
||||
}
|
||||
/* So w is present in ws, and the new set will be one element
|
||||
smaller. */
|
||||
tl_assert(i >= 0 && i < wv->size);
|
||||
tl_assert(wv->size > 0);
|
||||
|
||||
wv_new = new_WV_of_size( wsu, wv->size - 1 );
|
||||
j = k = 0;
|
||||
for (; j < wv->size; j++) {
|
||||
if (j == i)
|
||||
continue;
|
||||
wv_new->words[k++] = wv->words[j];
|
||||
}
|
||||
tl_assert(k == wv_new->size);
|
||||
|
||||
result = add_or_dealloc_WordVec( wsu, wv_new );
|
||||
if (wv->size == 1) {
|
||||
tl_assert(result == wsu->empty);
|
||||
}
|
||||
|
||||
out:
|
||||
WCache_UPDATE(wsu->cache_delFrom, ws, w, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
WordSet HG_(unionWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 )
|
||||
{
|
||||
UWord i1, i2, k, sz;
|
||||
WordVec* wv_new;
|
||||
WordVec* wv1 = do_ix2vec( wsu, ws1 );
|
||||
WordVec* wv2 = do_ix2vec( wsu, ws2 );
|
||||
wsu->n_union++;
|
||||
sz = 0;
|
||||
i1 = i2 = 0;
|
||||
while (1) {
|
||||
if (i1 >= wv1->size || i2 >= wv2->size)
|
||||
break;
|
||||
sz++;
|
||||
if (wv1->words[i1] < wv2->words[i2]) {
|
||||
i1++;
|
||||
} else
|
||||
if (wv1->words[i1] > wv2->words[i2]) {
|
||||
i2++;
|
||||
} else {
|
||||
i1++;
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
tl_assert(i1 <= wv1->size);
|
||||
tl_assert(i2 <= wv2->size);
|
||||
tl_assert(i1 == wv1->size || i2 == wv2->size);
|
||||
if (i1 == wv1->size && i2 < wv2->size) {
|
||||
sz += (wv2->size - i2);
|
||||
}
|
||||
if (i2 == wv2->size && i1 < wv1->size) {
|
||||
sz += (wv1->size - i1);
|
||||
}
|
||||
|
||||
wv_new = new_WV_of_size( wsu, sz );
|
||||
k = 0;
|
||||
|
||||
i1 = i2 = 0;
|
||||
while (1) {
|
||||
if (i1 >= wv1->size || i2 >= wv2->size)
|
||||
break;
|
||||
if (wv1->words[i1] < wv2->words[i2]) {
|
||||
wv_new->words[k++] = wv1->words[i1];
|
||||
i1++;
|
||||
} else
|
||||
if (wv1->words[i1] > wv2->words[i2]) {
|
||||
wv_new->words[k++] = wv2->words[i2];
|
||||
i2++;
|
||||
} else {
|
||||
wv_new->words[k++] = wv1->words[i1];
|
||||
i1++;
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
tl_assert(i1 <= wv1->size);
|
||||
tl_assert(i2 <= wv2->size);
|
||||
tl_assert(i1 == wv1->size || i2 == wv2->size);
|
||||
if (i1 == wv1->size && i2 < wv2->size) {
|
||||
while (i2 < wv2->size)
|
||||
wv_new->words[k++] = wv2->words[i2++];
|
||||
}
|
||||
if (i2 == wv2->size && i1 < wv1->size) {
|
||||
while (i1 < wv1->size)
|
||||
wv_new->words[k++] = wv1->words[i1++];
|
||||
}
|
||||
|
||||
tl_assert(k == sz);
|
||||
|
||||
return add_or_dealloc_WordVec( wsu, wv_new );
|
||||
}
|
||||
|
||||
WordSet HG_(intersectWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 )
|
||||
{
|
||||
UWord i1, i2, k, sz;
|
||||
WordSet ws_new = (WordSet)(-1); /* bogus */
|
||||
WordVec* wv_new;
|
||||
WordVec* wv1;
|
||||
WordVec* wv2;
|
||||
|
||||
wsu->n_intersect++;
|
||||
|
||||
/* Deal with an obvious case fast. */
|
||||
if (ws1 == ws2)
|
||||
return ws1;
|
||||
|
||||
/* Since intersect(x,y) == intersect(y,x), convert both variants to
|
||||
the same query. This reduces the number of variants the cache
|
||||
has to deal with. */
|
||||
if (ws1 > ws2) {
|
||||
WordSet wst = ws1; ws1 = ws2; ws2 = wst;
|
||||
}
|
||||
|
||||
WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_intersect, ws1, ws2);
|
||||
wsu->n_intersect_uncached++;
|
||||
|
||||
wv1 = do_ix2vec( wsu, ws1 );
|
||||
wv2 = do_ix2vec( wsu, ws2 );
|
||||
sz = 0;
|
||||
i1 = i2 = 0;
|
||||
while (1) {
|
||||
if (i1 >= wv1->size || i2 >= wv2->size)
|
||||
break;
|
||||
if (wv1->words[i1] < wv2->words[i2]) {
|
||||
i1++;
|
||||
} else
|
||||
if (wv1->words[i1] > wv2->words[i2]) {
|
||||
i2++;
|
||||
} else {
|
||||
sz++;
|
||||
i1++;
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
tl_assert(i1 <= wv1->size);
|
||||
tl_assert(i2 <= wv2->size);
|
||||
tl_assert(i1 == wv1->size || i2 == wv2->size);
|
||||
|
||||
wv_new = new_WV_of_size( wsu, sz );
|
||||
k = 0;
|
||||
|
||||
i1 = i2 = 0;
|
||||
while (1) {
|
||||
if (i1 >= wv1->size || i2 >= wv2->size)
|
||||
break;
|
||||
if (wv1->words[i1] < wv2->words[i2]) {
|
||||
i1++;
|
||||
} else
|
||||
if (wv1->words[i1] > wv2->words[i2]) {
|
||||
i2++;
|
||||
} else {
|
||||
wv_new->words[k++] = wv1->words[i1];
|
||||
i1++;
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
tl_assert(i1 <= wv1->size);
|
||||
tl_assert(i2 <= wv2->size);
|
||||
tl_assert(i1 == wv1->size || i2 == wv2->size);
|
||||
|
||||
tl_assert(k == sz);
|
||||
|
||||
ws_new = add_or_dealloc_WordVec( wsu, wv_new );
|
||||
if (sz == 0) {
|
||||
tl_assert(ws_new == wsu->empty);
|
||||
}
|
||||
|
||||
tl_assert(ws_new != (WordSet)(-1));
|
||||
WCache_UPDATE(wsu->cache_intersect, ws1, ws2, ws_new);
|
||||
|
||||
return ws_new;
|
||||
}
|
||||
|
||||
WordSet HG_(minusWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 )
|
||||
{
|
||||
UWord i1, i2, k, sz;
|
||||
WordSet ws_new = (WordSet)(-1); /* bogus */
|
||||
WordVec* wv_new;
|
||||
WordVec* wv1;
|
||||
WordVec* wv2;
|
||||
|
||||
wsu->n_minus++;
|
||||
WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_minus, ws1, ws2);
|
||||
wsu->n_minus_uncached++;
|
||||
|
||||
wv1 = do_ix2vec( wsu, ws1 );
|
||||
wv2 = do_ix2vec( wsu, ws2 );
|
||||
sz = 0;
|
||||
i1 = i2 = 0;
|
||||
while (1) {
|
||||
if (i1 >= wv1->size || i2 >= wv2->size)
|
||||
break;
|
||||
if (wv1->words[i1] < wv2->words[i2]) {
|
||||
sz++;
|
||||
i1++;
|
||||
} else
|
||||
if (wv1->words[i1] > wv2->words[i2]) {
|
||||
i2++;
|
||||
} else {
|
||||
i1++;
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
tl_assert(i1 <= wv1->size);
|
||||
tl_assert(i2 <= wv2->size);
|
||||
tl_assert(i1 == wv1->size || i2 == wv2->size);
|
||||
if (i2 == wv2->size && i1 < wv1->size) {
|
||||
sz += (wv1->size - i1);
|
||||
}
|
||||
|
||||
wv_new = new_WV_of_size( wsu, sz );
|
||||
k = 0;
|
||||
|
||||
i1 = i2 = 0;
|
||||
while (1) {
|
||||
if (i1 >= wv1->size || i2 >= wv2->size)
|
||||
break;
|
||||
if (wv1->words[i1] < wv2->words[i2]) {
|
||||
wv_new->words[k++] = wv1->words[i1];
|
||||
i1++;
|
||||
} else
|
||||
if (wv1->words[i1] > wv2->words[i2]) {
|
||||
i2++;
|
||||
} else {
|
||||
i1++;
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
tl_assert(i1 <= wv1->size);
|
||||
tl_assert(i2 <= wv2->size);
|
||||
tl_assert(i1 == wv1->size || i2 == wv2->size);
|
||||
if (i2 == wv2->size && i1 < wv1->size) {
|
||||
while (i1 < wv1->size)
|
||||
wv_new->words[k++] = wv1->words[i1++];
|
||||
}
|
||||
|
||||
tl_assert(k == sz);
|
||||
|
||||
ws_new = add_or_dealloc_WordVec( wsu, wv_new );
|
||||
if (sz == 0) {
|
||||
tl_assert(ws_new == wsu->empty);
|
||||
}
|
||||
|
||||
tl_assert(ws_new != (WordSet)(-1));
|
||||
WCache_UPDATE(wsu->cache_minus, ws1, ws2, ws_new);
|
||||
|
||||
return ws_new;
|
||||
}
|
||||
|
||||
static __attribute__((unused))
|
||||
void show_WS ( WordSetU* wsu, WordSet ws )
|
||||
{
|
||||
UWord i;
|
||||
WordVec* wv = do_ix2vec( wsu, ws );
|
||||
VG_(printf)("#%u{", ws);
|
||||
for (i = 0; i < wv->size; i++) {
|
||||
VG_(printf)("%lu", wv->words[i]);
|
||||
if (i < wv->size-1)
|
||||
VG_(printf)(",");
|
||||
}
|
||||
VG_(printf)("}\n");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------//
|
||||
//--- end WordSet ---//
|
||||
//--- Implementation ---//
|
||||
//------------------------------------------------------------------//
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end hg_wordset.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,126 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Sets of words, with unique set identifiers. ---*/
|
||||
/*--- hg_wordset.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Helgrind, a Valgrind tool for detecting errors
|
||||
in threaded programs.
|
||||
|
||||
Copyright (C) 2007-2015 OpenWorks LLP
|
||||
info@open-works.co.uk
|
||||
|
||||
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.
|
||||
|
||||
Neither the names of the U.S. Department of Energy nor the
|
||||
University of California nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software
|
||||
without prior written permission.
|
||||
*/
|
||||
|
||||
#ifndef __HG_WORDSET_H
|
||||
#define __HG_WORDSET_H
|
||||
|
||||
//------------------------------------------------------------------//
|
||||
//--- WordSet ---//
|
||||
//--- Public Interface ---//
|
||||
//------------------------------------------------------------------//
|
||||
|
||||
typedef struct _WordSetU WordSetU; /* opaque */
|
||||
|
||||
typedef UInt WordSet; /* opaque, small int index */
|
||||
|
||||
/* Allocate and initialise a WordSetU */
|
||||
WordSetU* HG_(newWordSetU) ( void* (*alloc_nofail)( const HChar*, SizeT ),
|
||||
const HChar* cc,
|
||||
void (*dealloc)(void*),
|
||||
Word cacheSize );
|
||||
|
||||
/* Free up the WordSetU. */
|
||||
void HG_(deleteWordSetU) ( WordSetU* );
|
||||
|
||||
/* Get the number of elements in this WordSetU. Note that the dead
|
||||
WordSet are included in the WordSetU number of elements. */
|
||||
UWord HG_(cardinalityWSU) ( WordSetU* );
|
||||
|
||||
/* Show performance stats for this WordSetU. */
|
||||
void HG_(ppWSUstats) ( WordSetU* wsu, const HChar* name );
|
||||
|
||||
|
||||
/* Element-level operations on WordSets. Note that the WordSet
|
||||
numbers given out are 0, 1, 2, 3, etc, and as it happens 0 always
|
||||
represents the empty set. */
|
||||
|
||||
WordSet HG_(emptyWS) ( WordSetU* );
|
||||
WordSet HG_(addToWS) ( WordSetU*, WordSet, UWord );
|
||||
WordSet HG_(delFromWS) ( WordSetU*, WordSet, UWord );
|
||||
WordSet HG_(unionWS) ( WordSetU*, WordSet, WordSet );
|
||||
WordSet HG_(intersectWS) ( WordSetU*, WordSet, WordSet );
|
||||
WordSet HG_(minusWS) ( WordSetU*, WordSet, WordSet );
|
||||
Bool HG_(isEmptyWS) ( WordSetU*, WordSet );
|
||||
Bool HG_(isSingletonWS) ( WordSetU*, WordSet, UWord );
|
||||
UWord HG_(anyElementOfWS) ( WordSetU*, WordSet );
|
||||
UWord HG_(cardinalityWS) ( WordSetU*, WordSet );
|
||||
Bool HG_(elemWS) ( WordSetU*, WordSet, UWord );
|
||||
WordSet HG_(doubletonWS) ( WordSetU*, UWord, UWord );
|
||||
WordSet HG_(singletonWS) ( WordSetU*, UWord );
|
||||
WordSet HG_(isSubsetOf) ( WordSetU*, WordSet, WordSet );
|
||||
|
||||
Bool HG_(plausibleWS) ( WordSetU*, WordSet );
|
||||
|
||||
|
||||
Bool HG_(saneWS_SLOW) ( WordSetU*, WordSet );
|
||||
|
||||
void HG_(ppWS) ( WordSetU*, WordSet );
|
||||
|
||||
void HG_(getPayloadWS) ( /*OUT*/UWord** words, /*OUT*/UWord* nWords,
|
||||
WordSetU*, WordSet );
|
||||
|
||||
/* HG_(dieWS) indicates WordSet is not used/not referenced anymore,
|
||||
and its memory can be reclaimed.
|
||||
If ever a WordSet with the same content would be needed again,
|
||||
a new WordSet will be reallocated.
|
||||
|
||||
BUG ALERT: !!! Using HG_(dieWS) on a WSU introduces a risk of
|
||||
dangling references. Dangling references can be created by keeping
|
||||
a ws after having marked it dead. This ws (just an index in
|
||||
reality) will be re-cycled : a newly created wv can get the same
|
||||
index. This implies that the wrong wv will be used if the
|
||||
"old" ws has been kept.
|
||||
Re-using a "dead" ws will be detected if the index has not been
|
||||
re-cycled yet.
|
||||
|
||||
Another possibility of bug is to ask for the payload of a ws, and
|
||||
then have this ws marked dead while the payload is still being
|
||||
examined. This is a real dangling reference in free or re-allocated
|
||||
memory. */
|
||||
void HG_(dieWS) ( WordSetU*, WordSet );
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------//
|
||||
//--- end WordSet ---//
|
||||
//--- Public Interface ---//
|
||||
//------------------------------------------------------------------//
|
||||
|
||||
#endif /* ! __HG_WORDSET_H */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end hg_wordset.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,186 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- LibHB: a library for implementing and checking ---*/
|
||||
/*--- the happens-before relationship in concurrent programs. ---*/
|
||||
/*--- libhb_main.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of LibHB, a library for implementing and checking
|
||||
the happens-before relationship in concurrent programs.
|
||||
|
||||
Copyright (C) 2008-2015 OpenWorks Ltd
|
||||
info@open-works.co.uk
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __LIBHB_H
|
||||
#define __LIBHB_H
|
||||
|
||||
/* Abstract to user: thread identifiers */
|
||||
/* typedef struct _Thr Thr; */ /* now in hg_lock_n_thread.h */
|
||||
|
||||
/* Abstract to user: synchronisation objects */
|
||||
/* typedef struct _SO SO; */ /* now in hg_lock_n_thread.h */
|
||||
|
||||
/* Initialise library; returns Thr* for root thread. 'shadow_alloc'
|
||||
should never return NULL, instead it should simply not return if
|
||||
they encounter an out-of-memory condition. */
|
||||
Thr* libhb_init (
|
||||
void (*get_stacktrace)( Thr*, Addr*, UWord ),
|
||||
ExeContext* (*get_EC)( Thr* )
|
||||
);
|
||||
|
||||
/* Shut down the library, and print stats (in fact that's _all_
|
||||
this is for.) */
|
||||
void libhb_shutdown ( Bool show_stats );
|
||||
|
||||
/* Thread creation: returns Thr* for new thread */
|
||||
Thr* libhb_create ( Thr* parent );
|
||||
|
||||
/* Thread async exit */
|
||||
void libhb_async_exit ( Thr* exitter );
|
||||
void libhb_joinedwith_done ( Thr* exitter );
|
||||
|
||||
/* Synchronisation objects (abstract to caller) */
|
||||
|
||||
/* Allocate a new one (alloc'd by library) */
|
||||
SO* libhb_so_alloc ( void );
|
||||
|
||||
/* Dealloc one */
|
||||
void libhb_so_dealloc ( SO* so );
|
||||
|
||||
/* Send a message via a sync object. If strong_send is true, the
|
||||
resulting inter-thread dependency seen by a future receiver of this
|
||||
message will be a dependency on this thread only. That is, in a
|
||||
strong send, the VC inside the SO is replaced by the clock of the
|
||||
sending thread. For a weak send, the sender's VC is joined into
|
||||
that already in the SO, if any. This subtlety is needed to model
|
||||
rwlocks: a strong send corresponds to releasing a rwlock that had
|
||||
been w-held (or releasing a standard mutex). A weak send
|
||||
corresponds to releasing a rwlock that has been r-held.
|
||||
|
||||
(rationale): Since in general many threads may hold a rwlock in
|
||||
r-mode, a weak send facility is necessary in order that the final
|
||||
SO reflects the join of the VCs of all the threads releasing the
|
||||
rwlock, rather than merely holding the VC of the most recent thread
|
||||
to release it. */
|
||||
void libhb_so_send ( Thr* thr, SO* so, Bool strong_send );
|
||||
|
||||
/* Recv a message from a sync object. If strong_recv is True, the
|
||||
resulting inter-thread dependency is considered adequate to induce
|
||||
a h-b ordering on both reads and writes. If it is False, the
|
||||
implied h-b ordering exists only for reads, not writes. This is
|
||||
subtlety is required in order to support reader-writer locks: a
|
||||
thread doing a write-acquire of a rwlock (or acquiring a normal
|
||||
mutex) models this by doing a strong receive. A thread doing a
|
||||
read-acquire of a rwlock models this by doing a !strong_recv. */
|
||||
void libhb_so_recv ( Thr* thr, SO* so, Bool strong_recv );
|
||||
|
||||
/* Has this SO ever been sent on? */
|
||||
Bool libhb_so_everSent ( SO* so );
|
||||
|
||||
/* Memory accesses (1/2/4/8 byte size). They report a race if one is
|
||||
found. */
|
||||
#define LIBHB_CWRITE_1(_thr,_a) zsm_sapply08_f__msmcwrite((_thr),(_a))
|
||||
#define LIBHB_CWRITE_2(_thr,_a) zsm_sapply16_f__msmcwrite((_thr),(_a))
|
||||
#define LIBHB_CWRITE_4(_thr,_a) zsm_sapply32_f__msmcwrite((_thr),(_a))
|
||||
#define LIBHB_CWRITE_8(_thr,_a) zsm_sapply64_f__msmcwrite((_thr),(_a))
|
||||
#define LIBHB_CWRITE_N(_thr,_a,_n) zsm_sapplyNN_f__msmcwrite((_thr),(_a),(_n))
|
||||
|
||||
#define LIBHB_CREAD_1(_thr,_a) zsm_sapply08_f__msmcread((_thr),(_a))
|
||||
#define LIBHB_CREAD_2(_thr,_a) zsm_sapply16_f__msmcread((_thr),(_a))
|
||||
#define LIBHB_CREAD_4(_thr,_a) zsm_sapply32_f__msmcread((_thr),(_a))
|
||||
#define LIBHB_CREAD_8(_thr,_a) zsm_sapply64_f__msmcread((_thr),(_a))
|
||||
#define LIBHB_CREAD_N(_thr,_a,_n) zsm_sapplyNN_f__msmcread((_thr),(_a),(_n))
|
||||
|
||||
void zsm_sapply08_f__msmcwrite ( Thr* thr, Addr a );
|
||||
void zsm_sapply16_f__msmcwrite ( Thr* thr, Addr a );
|
||||
void zsm_sapply32_f__msmcwrite ( Thr* thr, Addr a );
|
||||
void zsm_sapply64_f__msmcwrite ( Thr* thr, Addr a );
|
||||
void zsm_sapplyNN_f__msmcwrite ( Thr* thr, Addr a, SizeT len );
|
||||
|
||||
void zsm_sapply08_f__msmcread ( Thr* thr, Addr a );
|
||||
void zsm_sapply16_f__msmcread ( Thr* thr, Addr a );
|
||||
void zsm_sapply32_f__msmcread ( Thr* thr, Addr a );
|
||||
void zsm_sapply64_f__msmcread ( Thr* thr, Addr a );
|
||||
void zsm_sapplyNN_f__msmcread ( Thr* thr, Addr a, SizeT len );
|
||||
|
||||
void libhb_Thr_resumes ( Thr* thr );
|
||||
|
||||
/* Set memory address ranges to new (freshly allocated), or noaccess
|
||||
(no longer accessible). NB: "AHAE" == "Actually Has An Effect" :-) */
|
||||
void libhb_srange_new ( Thr*, Addr, SizeT );
|
||||
void libhb_srange_untrack ( Thr*, Addr, SizeT );
|
||||
void libhb_srange_noaccess_NoFX ( Thr*, Addr, SizeT ); /* IS IGNORED */
|
||||
void libhb_srange_noaccess_AHAE ( Thr*, Addr, SizeT ); /* IS NOT IGNORED */
|
||||
|
||||
/* Counts the nr of bytes addressable in the range [a, a+len[
|
||||
(so a+len excluded) and returns the nr of addressable bytes found.
|
||||
If abits /= NULL, abits must point to a block of memory of length len.
|
||||
In this array, each addressable byte will be indicated with 0xff.
|
||||
Non-addressable bytes are indicated with 0x00. */
|
||||
UWord libhb_srange_get_abits (Addr a, /*OUT*/UChar *abits, SizeT len);
|
||||
|
||||
/* Get and set the hgthread (pointer to corresponding Thread
|
||||
structure). */
|
||||
Thread* libhb_get_Thr_hgthread ( Thr* );
|
||||
void libhb_set_Thr_hgthread ( Thr*, Thread* );
|
||||
|
||||
/* Low level copy of shadow state from [src,src+len) to [dst,dst+len).
|
||||
Overlapping moves are checked for and asserted against. */
|
||||
void libhb_copy_shadow_state ( Thr* thr, Addr src, Addr dst, SizeT len );
|
||||
|
||||
/* Call this periodically to give libhb the opportunity to
|
||||
garbage-collect its internal data structures. */
|
||||
void libhb_maybe_GC ( void );
|
||||
|
||||
/* Extract info from the conflicting-access machinery. */
|
||||
Bool libhb_event_map_lookup ( /*OUT*/ExeContext** resEC,
|
||||
/*OUT*/Thr** resThr,
|
||||
/*OUT*/SizeT* resSzB,
|
||||
/*OUT*/Bool* resIsW,
|
||||
/*OUT*/WordSetID* locksHeldW,
|
||||
Thr* thr, Addr a, SizeT szB, Bool isW );
|
||||
|
||||
typedef void (*Access_t) (StackTrace ips, UInt n_ips,
|
||||
Thr* Thr_a,
|
||||
Addr ga,
|
||||
SizeT SzB,
|
||||
Bool isW,
|
||||
WordSetID locksHeldW );
|
||||
/* Call fn for each recorded access history that overlaps with range [a, a+szB[.
|
||||
fn is first called for oldest access.*/
|
||||
void libhb_event_map_access_history ( Addr a, SizeT szB, Access_t fn );
|
||||
|
||||
/* ------ Exported from hg_main.c ------ */
|
||||
/* Yes, this is a horrible tangle. Sigh. */
|
||||
|
||||
/* Get the univ_lset (universe for locksets) from hg_main.c. Sigh. */
|
||||
WordSetU* HG_(get_univ_lsets) ( void );
|
||||
|
||||
/* Get the the header pointer for the double linked list of locks
|
||||
(admin_locks). */
|
||||
Lock* HG_(get_admin_locks) ( void );
|
||||
|
||||
#endif /* __LIBHB_H */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end libhb.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
+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.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user