From a35a48f96ee2e51ebe6fab5be14c14f882131dc1 Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Sun, 21 Dec 2008 23:11:14 +0000 Subject: [PATCH] More documentation updates. Urr. I knew there was a reason I'd been putting this off. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@8859 --- helgrind/docs/hg-manual.xml | 265 ++++++++++++++++-------------------- 1 file changed, 117 insertions(+), 148 deletions(-) diff --git a/helgrind/docs/hg-manual.xml b/helgrind/docs/hg-manual.xml index 6efa739bab..079afbcbae 100644 --- a/helgrind/docs/hg-manual.xml +++ b/helgrind/docs/hg-manual.xml @@ -362,17 +362,6 @@ algorithm in more detail. - - - - - - - - - - - Helgrind's Race Detection Algorithm @@ -573,10 +562,6 @@ to the other, then it complains of a race. - - - - Interpreting Race Error Messages @@ -586,112 +571,98 @@ detected. Here's an example: Helgrind first announces the creation points of any threads referenced in the error message. This is so it can speak concisely -about threads and sets of threads without repeatedly printing their -creation point call stacks. Each thread is only ever announced once, -the first time it appears in any Helgrind error message. +about threads without repeatedly printing their creation point call +stacks. Each thread is only ever announced once, the first time it +appears in any Helgrind error message. The main error message begins at the text -"Possible data race during read". -At the start is information you would expect to see -- address and -size of the racing access, whether a read or a write, and the call -stack at the point it was detected. - -More interesting is the state transition caused by this access. -This memory is already in the shared-modified state, and up to now has -been consistently protected by at least one lock. However, the thread -making the access in question (thread #2, here) does not hold any -locks in common with those held during all previous accesses to the -location -- "no consistent locks", in other words. - -Finally, Helgrind shows the lock which has protected this -location in all previous accesses. (If there is more than one, only -one is shown). This can be a useful hint, because it typically shows -the lock that the programmers intended to use to protect the location, -but in this case forgot. - -Here are some more examples of race reports. This not an -exhaustive list of combinations, but should give you some insight into -how to interpret the output. - - - -The location is shared by 3 threads, all of which have been -reading it without locking ("has never been protected by any lock"). -Now one of them is writing it. Regardless of whether the writer has a -lock or not, this is still an error, because the write races against -the previously observed reads. +"Possible data race during read". At +the start is information you would expect to see -- address and size +of the racing access, whether a read or a write, and the call stack at +the point it was detected. + +A second call stack is presented starting at the text +"This conflicts with a previous +write". This shows a previous access which also +accessed the stated address, and which is believed to be racing +against the access in the first call stack. + +Finally, Helgrind may attempt to give a description of the +raced-on address in source level terms. In this example, it +identifies it as a local variable, shows its name, declaration point, +and in which frame (of the first call stack) it lives. Note that this +information is only shown when --read-var-info=yes +is specified on the command line. That's because reading the DWARF3 +debug information in enough detail to capture variable type and +location information makes Helgrind much slower at startup, and also +requires considerable amounts of memory, for large programs. + - +Once you have your two call stacks, how do you begin to get to +the root problem? -The location is shared by 3 threads, all of which have been -reading and writing it while (as required) holding at least one lock -in common. Now it is being read without that lock being held. In the -"Last consistently used lock" part, Helgrind offers its best guess as -to the identity of the lock that should have been used. +The first thing to do is examine the source locations referred +to by each call stack. They should both show an access to the same +location, or variable. - +Now figure out how how that location should have been made +thread-safe: -A location that has so far been accessed exclusively by thread -#4 has now been written by thread #5, without use of any lock. This -can be a sign that the programmer did not consider the possibility of -the location being shared between threads, or, alternatively, forgot -to use the appropriate lock. - -Note that thread #4 exclusively owns the location, and so has -the right to access it without holding a lock. However, this message -does not say that thread #4 is not using a lock for this location. -Indeed, it could be using a lock for the location because it intends -to make it available to other threads, one of which is thread #5 -- -and thread #5 has forgotten to use the lock. - -Also, this message implies that Helgrind did not see any -synchronisation event between threads #4 and #5 that would have -allowed #5 to acquire exclusive ownership from #4. See -above -for a discussion of transfers of exclusive ownership states between -threads. + + Perhaps the location was intended to be protected by + a mutex? If so, you need to lock and unlock the mutex at both + access points, even if one of the accesses is reported to be a read. + Did you perhaps forget the locking at one or other of the + accesses? + + Alternatively, you intended to use a some other + scheme to make it safe, such as signalling on a condition variable. + In all such cases, try to find a synchronisation event (or a chain + thereof) which separates the earlier-observed access (as shown in the + second call stack) from the later-observed access (as shown in the + first call stack). In other words, try to find evidence that the + earlier access "happens-before" the later access. See the previous + subsection for an explanation of the happens-before + relationship. + + The fact that Helgrind is reporting a race means it did not observe + any happens-before relationship between the two accesses. If + Helgrind is working correctly, it should also be the case that you + also cannot find any such relationship, even on detailed inspection + of the source code. Hopefully, though, your inspection of the code + will show where the missing synchronisation operation(s) should have + been. + + @@ -731,9 +702,9 @@ of false data-race errors. pthread_ functions. Do not roll your own threading primitives (mutexes, etc) - from combinations of the Linux futex syscall, counters and wotnot. - These throw Helgrind's internal what's-going-on models way off - course and will give bogus results. + from combinations of the Linux futex syscall, atomic counters and + wotnot. These throw Helgrind's internal what's-going-on models + way off course and will give bogus results. Also, do not reimplement existing POSIX abstractions using other POSIX abstractions. For example, don't build your own @@ -743,26 +714,39 @@ of false data-race errors. Helgrind directly supports the following POSIX threading abstractions: mutexes, reader-writer locks, condition variables - (but see below), and semaphores. Currently spinlocks and barriers - are not supported, although they could be in future. A prototype - "safe" implementation of barriers, based on semaphores, is - available: please contact the Valgrind authors for details. + (but see below), semaphores and barriers. Currently spinlocks + are not supported, although they could be in future. At the time of writing, the following popular Linux packages are known to implement their own threading primitives: - Qt version 4.X. Qt 3.X is fine, but not 4.X. - Helgrind contains partial direct support for Qt 4.X threading, - but this is not yet in a usable state. Assistance from folks - knowledgeable in Qt 4 threading internals would be - appreciated. - - Runtime support library for GNU OpenMP (part of - GCC), at least GCC versions 4.2 and 4.3. With some minor effort - of modifying the GNU OpenMP runtime support sources, it is - possible to use Helgrind on GNU OpenMP compiled codes. Please - contact the Valgrind authors for details. + Qt version 4.X. Qt 3.X is harmless in that it + only uses POSIX pthreads primitives. Unfortunately Qt 4.X + has its own implementation of mutexes (QMutex) and thread reaping. + Helgrind 3.4.x contains direct support + for Qt 4.X threading, which is experimental but is believed to + work fairly well. A side effect of supporting Qt 4 directly is + that Helgrind can be used to debug KDE4 applications. As this + is an experimental feature, we would particularly appreciate + feedback from folks who have used Helgrind to successfully debug + Qt 4 and/or KDE4 applications. + + Runtime support library for GNU OpenMP (part of + GCC), at least GCC versions 4.2 and 4.3. The GNU OpenMP runtime + library (libgomp.so) constructs its own synchronisation + primitives using combinations of atomic memory instructions and + the futex syscall, which causes total chaos since in Helgrind + since it cannot "see" those. + Fortunately, this can be solved using a configuration-time + flag (for gcc). Rebuild gcc from source, and configure using + --disable-linux-futex. + This makes libgomp.so use the standard + POSIX threading primitives instead. Note that this was tested + using gcc-4.2.3 and has not been re-tested using more recent gcc + versions. We would appreciate hearing about any successes or + failures with more recent versions. + @@ -810,10 +794,7 @@ of false data-race errors. The result of Helgrind missing some inter-thread synchronisation events is to cause it to report false positives. - That's because missing such events reduces the extent to which it - can transfer exclusive memory ownership between threads. So - memory may end up in a shared-modified state when that was not - intended by the application programmers. + The root cause of this synchronisation lossage is particularly hard to understand, so an example is helpful. It was @@ -862,16 +843,10 @@ unlock(mx) unlock(mx) Make sure you are using a supported Linux distribution. At - present, Helgrind only properly supports x86-linux and amd64-linux - with glibc-2.3 or later. The latter restriction means we only - support glibc's NPTL threading implementation. The old - LinuxThreads implementation is not supported. - - Unsupported targets may work to varying degrees. In - particular ppc32-linux and ppc64-linux running NPTL should work, - but you will get false race errors because Helgrind does not know - how to properly handle atomic instruction sequences created using - the lwarx/stwcx instructions. + present, Helgrind only properly supports glibc-2.3 or later. This + in turn means we only support glibc's NPTL threading + implementation. The old LinuxThreads implementation is not + supported. @@ -881,13 +856,7 @@ unlock(mx) unlock(mx) Using pthread_join to round up finished threads provides a clear synchronisation point that both Helgrind and programmers can - see. This synchronisation point allows Helgrind to adjust its - memory ownership - models as described - extensively above, which helps Helgrind produce more - accurate error reports. - - If you don't call pthread_join on a thread, Helgrind has no + see. If you don't call pthread_join on a thread, Helgrind has no way to know when it finishes, relative to any significant synchronisation points for other threads in the program. So it assumes that the thread lingers indefinitely and can potentially -- 2.47.2