|
From: David H. <dw...@ov...> - 2004-04-14 21:43:54
|
Hi,
I just learned about valgrind today, so went to put
it to the test.
With the following test file:
/*--------------------------------------------------------------------------
* two_threads.c
*
* A simple test of two threads (main and another).
*
* The purpose of this test was to see whether valgrind complains.
*
* gcc -o two_threads two_threads.c -lpthread
* valgrind --tool=memcheck --leak-check=yes --show-reachable=yes
two_threads
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
/* Threads */
void *another_thread(void *arg);
/* Main thread */
int main()
{
pthread_t thread_id;
int status;
/* start another thread */
printf("Main: Creating another thread.\n");
status = pthread_create(&thread_id, NULL, another_thread, NULL);
if (status) {
fprintf(stderr, "Main: Thread creation failed!");
return 1;
}
/* Stop the other thread */
printf("Main: Waiting for the other thread\n");
pthread_join(thread_id, NULL);
if (status) {
fprintf(stderr, "Main: Thread join failed!");
return 1;
}
printf("Main: Joined ok\n");
return 0;
}
void* another_thread(void *arg)
{
printf("Thread: Started\n");
printf("Thread: Sleeping for 2s\n");
sleep(2);
printf("Thread: Exiting\n");
return NULL;
}
/*--------------------------------------------------------------------------
*/
The output of Valgrind is:
==21781== Memcheck, a memory error detector for x86-linux.
==21781== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward.
==21781== Using valgrind-2.1.1, a program supervision framework for
x86-linux.
==21781== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward.
==21781== For more details, rerun with: -v
==21781==
Main: Creating another thread.
Main: Waiting for the other thread
Thread: Started
Thread: Sleeping for 2s
Thread: Exiting
Main: Joined ok
==21781==
==21781== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 1)
==21781== malloc/free: in use at exit: 216 bytes in 2 blocks.
==21781== malloc/free: 5 allocs, 3 frees, 2004 bytes allocated.
==21781== For counts of detected errors, rerun with: -v
==21781== searching for pointers to 2 not-freed blocks.
==21781== checked 1597296 bytes.
==21781==
==21781== 16 bytes in 1 blocks are still reachable in loss record 1 of 2
==21781== at 0x3C01E9D3: calloc (vg_replace_malloc.c:141)
==21781== by 0x3C063360: _dlerror_run (in /lib/libdl-2.3.2.so)
==21781== by 0x3C063023: dlsym (in /lib/libdl-2.3.2.so)
==21781== by 0x3C026F9C: pthread_create (vg_libpthread.c:906)
==21781==
==21781==
==21781== 200 bytes in 1 blocks are definitely lost in loss record 2 of 2
==21781== at 0x3C01E250: malloc (vg_replace_malloc.c:105)
==21781== by 0x3C025DF6: my_malloc (vg_libpthread.c:334)
==21781== by 0x3C028AAA: get_or_allocate_specifics_ptr
(vg_libpthread.c:1591)
==21781== by 0x3C028C33: pthread_key_create (vg_libpthread.c:1628)
==21781==
==21781== LEAK SUMMARY:
==21781== definitely lost: 200 bytes in 1 blocks.
==21781== possibly lost: 0 bytes in 0 blocks.
==21781== still reachable: 16 bytes in 1 blocks.
==21781== suppressed: 0 bytes in 0 blocks.
Which points to the leak in pthread_create() etc.
I looked on the mailing list archive and saw a comment about
the same error posted last month. However, their example code
did not use pthread_join() so I thought perhaps that might
be the issue. However, here the thread is joined successfully
before main exits, so the thread resources should have been
reclaimed.
I'd like to start using Valgrind on more thread-based code.
What are my options here?
Regards
Dave Hawkins
Caltech.
|
|
From: David H. <dw...@ov...> - 2004-04-14 23:35:55
|
Hi,
I just learned about valgrind today, so went to put
it to the test.
I used the helgrind option to see what race conditions
it could catch ... here's an example of what I believe
is thread-safe, yet generates valgrind errors.
/*
* two_threads_stdio.c
*
* A simple test of two threads (main and another) both
* accessing stderr through a thread-safe function.
*
* valgrind was complaining about race conditions in some of
* my other code. So here is a minimal version that uses a
* protected printf in two threads - lets see if helgrind
* complains.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
/* Threads */
void *another_thread(void *arg);
/* Thread-safe debug */
static pthread_mutex_t stdio_mutex = PTHREAD_MUTEX_INITIALIZER;
static void debug(const char *format, ...);
/* Main thread */
int main()
{
pthread_t thread_id;
int status;
/* Start another thread */
debug("Main: Creating another thread.\n");
status = pthread_create(&thread_id, NULL, another_thread, NULL);
if (status) {
debug("Main: Thread creation failed!");
return 1;
}
/* Stop the other thread */
debug("Main: Waiting for the other thread\n");
pthread_join(thread_id, NULL);
if (status) {
debug("Main: Thread join failed!");
return 1;
}
debug("Main: Joined ok\n");
return 0;
}
void* another_thread(void *arg)
{
debug("Thread: Started\n");
debug("Thread: Sleeping for 2s\n");
sleep(2);
debug("Thread: Exiting\n");
return NULL;
}
/* Thread-safe printf */
static void debug(const char *format, ...)
{
va_list arg;
pthread_mutex_lock(&stdio_mutex);
va_start(arg, format);
vfprintf(stderr, format, arg);
va_end(arg);
(void)pthread_mutex_unlock(&stdio_mutex);
return;
}
==22213== Helgrind, a data race detector for x86-linux.
==22213== Copyright (C) 2002-2004, and GNU GPL'd, by Nicholas Nethercote.
==22213== Using valgrind-2.1.1, a program supervision framework for
x86-linux.
==22213== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward.
==22213== For more details, rerun with: -v
==22213==
Main: Creating another thread.
Main: Waiting for the other thread
Thread: Started
Thread: Sleeping for 2s
Thread: Exiting
Main: Joined ok
==22213== Possible data race reading variable at 0x4212E150
(_IO_stdfile_2_lock+8)
==22213== at 0x420701A4: _IO_flush_all_lockp (in /lib/tls/libc-2.3.2.so)
==22213== by 0x4207031F: _IO_flush_all_internal (in
/lib/tls/libc-2.3.2.so)
==22213== by 0x42070518: _IO_cleanup (in /lib/tls/libc-2.3.2.so)
==22213== by 0x42029C61: exit (in /lib/tls/libc-2.3.2.so)
==22213== Address 0x4212E150 is in data section of /lib/tls/libc-2.3.2.so
==22213== Previous state: shared RW, locked by:0x80497DC(stdio_mutex)
==22213==
==22213== Possible data race reading variable at 0x4212E14C
(_IO_stdfile_2_lock+4)
==22213== at 0x420701C0: _IO_flush_all_lockp (in /lib/tls/libc-2.3.2.so)
==22213== by 0x4207031F: _IO_flush_all_internal (in
/lib/tls/libc-2.3.2.so)
==22213== by 0x42070518: _IO_cleanup (in /lib/tls/libc-2.3.2.so)
==22213== by 0x42029C61: exit (in /lib/tls/libc-2.3.2.so)
==22213== Address 0x4212E14C is in data section of /lib/tls/libc-2.3.2.so
==22213== Previous state: shared RW, locked by:0x80497DC(stdio_mutex)
==22213==
==22213== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)
==22213== 4 possible data races found; 0 lock order problems
I believe all of these complains are caused by code encapsulated
in the locked mutex, hence they are thread-safe. Any reason why
this mutex locking is not being detected.
Cheers
Dave Hawkins
Caltech.
|
|
From: Nicholas N. <nj...@ca...> - 2004-04-15 07:51:44
|
On Wed, 14 Apr 2004, David Hawkins wrote: > I just learned about valgrind today, so went to put > it to the test. > > I used the helgrind option to see what race conditions > it could catch ... here's an example of what I believe > is thread-safe, yet generates valgrind errors. Helgrind is quite fallible, unfortunately, and generates a lot of false positives. N |
|
From: Nicholas N. <nj...@ca...> - 2004-04-15 07:55:55
|
On Wed, 14 Apr 2004, David Hawkins wrote:
> I just learned about valgrind today, so went to put
> it to the test.
>
> ==21781== 16 bytes in 1 blocks are still reachable in loss record 1 of 2
> ==21781== at 0x3C01E9D3: calloc (vg_replace_malloc.c:141)
> ==21781== by 0x3C063360: _dlerror_run (in /lib/libdl-2.3.2.so)
> ==21781== by 0x3C063023: dlsym (in /lib/libdl-2.3.2.so)
> ==21781== by 0x3C026F9C: pthread_create (vg_libpthread.c:906)
This block is still reachable, and so isn't a problem. If you don't want
to hear about it, don't use --show-reachable=yes.
> ==21781== 200 bytes in 1 blocks are definitely lost in loss record 2 of 2
> ==21781== at 0x3C01E250: malloc (vg_replace_malloc.c:105)
> ==21781== by 0x3C025DF6: my_malloc (vg_libpthread.c:334)
> ==21781== by 0x3C028AAA: get_or_allocate_specifics_ptr
> (vg_libpthread.c:1591)
> ==21781== by 0x3C028C33: pthread_key_create (vg_libpthread.c:1628)
This is an leak in Valgrind's libpthread; there's meant to be a
suppression for it (the leak is in our code, not yours) but it doesn't
seem to be working. In default.supp (should be wherever Valgrind is
installed), change this suppression:
{
my_malloc/get_or_allocate_specifics_ptr/pthread_key_create(Leak)
Memcheck:Leak
fun:my_malloc
fun:get_or_allocate_specifics_ptr
fun:pthread_key_create
}
to this:
{
my_malloc/get_or_allocate_specifics_ptr/pthread_key_create(Leak)
Memcheck:Leak
fun:malloc
fun:my_malloc
fun:get_or_allocate_specifics_ptr
fun:pthread_key_create
}
which should get rid of it.
> I'd like to start using Valgrind on more thread-based code.
> What are my options here?
Is that enough to get you going?
N
|