This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug nptl/4123] New: pthread cleanup handler not called
- From: "mkes at ra dot rockwell dot com" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sources dot redhat dot com
- Date: 2 Mar 2007 15:18:28 -0000
- Subject: [Bug nptl/4123] New: pthread cleanup handler not called
- Reply-to: sourceware-bugzilla at sourceware dot org
I use native or crosscompiler for arm-xscale-be gcc 4.1.1 and glibc 2.5. gcc
configuration:
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: /var/tmp/portage/gcc-4.1.1-r3/work/gcc-4.1.1/configure
--prefix=/usr --bindir=/usr/i686-pc-linux-gnu/gcc-bin/4.1.1
--includedir=/usr/lib/gcc/i686-pc-linux-gnu/4.1.1/include
--datadir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.1
--mandir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.1/man
--infodir=/usr/share/gcc-data/i686-pc-linux-gnu/4.1.1/info
--with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/4.1.1/include/g++-v4
--host=i686-pc-linux-gnu --build=i686-pc-linux-gnu --disable-altivec
--enable-nls --without-included-gettext --with-system-zlib --disable-checking
--disable-werror --enable-secureplt --disable-libunwind-exceptions
--disable-multilib --disable-libmudflap --disable-libssp --disable-libgcj
--enable-languages=c,c++,fortran --enable-shared --enable-threads=posix
--enable-__cxa_atexit --enable-clocale=gnu
Thread model: posix
gcc version 4.1.1 (Gentoo 4.1.1-r3)
or (the cross compiler)
Using built-in specs.
Target: armv5teb-softfloat-linux-gnueabi
Configured with: ../gcc-4.1.1/configure --prefix=/tmp/clfs/cross-tools
--host=i686-cross-linux-gnu --target=armv5teb-softfloat-linux-gnueabi
--disable-multilib --with-sysroot=/tmp/clfs --disable-nls --enable-shared
--enable-languages=c,c++ --enable-__cxa_atexit --enable-c99 --enable-long-long
--enable-threads=posix
Thread model: posix
gcc version 4.1.1
glibc on the x86 is:
GNU C Library stable release version 2.5, by Roland McGrath et al.
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.1.1 (Gentoo 4.1.1-r3).
Compiled on a Linux 2.6.17 system on 2007-02-09.
Available extensions:
C stubs add-on version 2.1.2
crypt add-on version 2.1 by Michael Glad and others
Gentoo patchset 1.3.1
GNU Libidn by Simon Josefsson
GNU libio by Per Bothner
NIS(YP)/NIS+ NSS modules 0.19 by Thorsten Kukuk
Native POSIX Threads Library by Ulrich Drepper et al
Support for some architectures added on, not maintained in glibc core.
BIND-8.2.3-T5B
Thread-local storage support included.
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.
Problem:
Pthread cleanup handlers do not get called on thread cancelation if the program
is compiled using g++. The same code, if compiled using gcc or using g++ with
the -fno-exceptions option, calls cleanup handlers OK.
Consequences in C++ application if the cleanup handler is (for example)
supposed to unlock a mutex are easy to guess.
Reproducible: Always
Steps to Reproduce:
Compile the code bellow using g++ and using gcc. Run both executables and
compare results.
Actual Results:
The executable compile using gcc prints out this:
Starting child thread.
Canceling child thread.
Cleanup handler called.
Child thread terminated.
while the executable compiled using g++ prints just this:
Starting child thread.
Canceling child thread.
Child thread terminated.
Expected Results:
The outputs should be the same regardless of compiler used.
--------------
/*
* Cleanup handler bug test program.
* Build using g++ -o cleanuphandlertest -l pthread cleanuphandlertest.cpp
* or using gcc -o cleanuphandlertest -l pthread cleanuphandlertest.c
*
* If the cleanup handler doesn't get called try the -fno-exceptions option.
*/
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
// Assertion which must always be true.
// If !(condition) then a fatal error will result.
//
#define ASSERT( condition, errCode ) ( ( void ) \
( (condition) ? ( ( void ) 0 ) : \
Assert( __FILE__, __LINE__, errCode ) ) )
void Assert( const char *file, int line, int err )
{
fprintf( stderr, "Error in file %s, line %d: error code %d\n", file,
line, err );
}
void ThreadCleanupHandler( void* arg )
{
printf( "Cleanup handler called.\n" );
}
void* ThreadBody( void* arg )
{
pthread_cleanup_push( ThreadCleanupHandler, arg );
while ( 1 )
{
pthread_testcancel();
sleep( 1 );
}
pthread_cleanup_pop( 0 );
}
int main( int argc, char **argv )
{
int status;
pthread_attr_t threadAttributes;
pthread_t threadId;
status = pthread_attr_init( &threadAttributes );
ASSERT( status == 0, status );
// Start the queue scanning thread
printf( "Starting child thread.\n" );
status = pthread_create( &threadId, &threadAttributes, ThreadBody, NULL );
ASSERT( status == 0, status );
status = pthread_attr_destroy( &threadAttributes );
ASSERT( status == 0, status );
sleep( 3 );
printf( "Canceling child thread.\n" );
status = pthread_cancel( threadId );
ASSERT( status == 0, status );
// wait until the thread really terminates
status = pthread_join( threadId, NULL );
ASSERT( status == 0, status );
printf( "Child thread terminated.\n" );
return 0;
}
--------------
After a bit more investigation ... If the compiler is stopped after the
preprocessor (i.e. g++ -E -o preprocess.cpp cleanuphandlertest.cpp), the code
that installs/deinstalls the cleanup hander looks like:
void* ThreadBody( void* arg )
{
do { __pthread_cleanup_class __clframe (ThreadCleanupHandler, arg);
while ( 1 )
{
pthread_testcancel();
sleep( 1 );
}
__clframe.__setdoit (0); } while (0);
}
where the __pthread_cleanup_class is defined as:
class __pthread_cleanup_class
{
void (*__cancel_routine) (void *);
void *__cancel_arg;
int __do_it;
int __cancel_type;
public:
__pthread_cleanup_class (void (*__fct) (void *), void *__arg)
: __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { }
~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); }
void __setdoit (int __newval) { __do_it = __newval; }
void __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED,
&__cancel_type); }
void __restore () const { pthread_setcanceltype (__cancel_type, 0); }
};
The actual execution of the cleanup handler when the thread is canceled should
happen in the destructor of the __clframe instance.
So it looks like if the cleanup handler setup/invocation is implemented using
the __pthread_cleanup_class the destructor of an instance created as local
variable doesn't get called on thread cancellation.
--
Summary: pthread cleanup handler not called
Product: glibc
Version: unspecified
Status: NEW
Severity: critical
Priority: P2
Component: nptl
AssignedTo: drepper at redhat dot com
ReportedBy: mkes at ra dot rockwell dot com
CC: glibc-bugs at sources dot redhat dot com
GCC build triplet: i686-pc-linux-gnu
GCC host triplet: i686-pc-linux-gnu
GCC target triplet: i686-pc-linux-gnu, arm-xscale-be
http://sourceware.org/bugzilla/show_bug.cgi?id=4123
------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.