Date: Fri, 6 Aug 2010 14:40:49 GMT From: Fernando Lemos <fernando@netfilter.com.br> To: freebsd-gnats-submit@FreeBSD.org Subject: misc/149366: pthread_cleanup_pop never runs the configured routine Message-ID: <201008061440.o76Een1G012895@www.freebsd.org> Resent-Message-ID: <201008061450.o76Eo2tQ015363@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 149366 >Category: misc >Synopsis: pthread_cleanup_pop never runs the configured routine >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Aug 06 14:50:02 UTC 2010 >Closed-Date: >Last-Modified: >Originator: Fernando Lemos >Release: 7.2-p8 >Organization: NetFilter >Environment: FreeBSD iron.netfilter.com.br 7.2-RELEASE-p8 FreeBSD 7.2-RELEASE-p8 #0: Wed May 26 03:08:50 UTC 2010 root@i386-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC i386 >Description: The pthread_cleanup_pop docs say: "The pthread_cleanup_pop() function shall remove the routine at the top of the calling thread's cancellation cleanup stack and optionally invoke it (if execute is non-zero)." However, in the attached sample, we invoke pthread_cleanup_pop with execute non-zero and still the routine isn't called. I got to reproduce it consistently in FreeBSD 7.2 and also in one FreeBSD 7.0-PRERELEASE box, so I think it might even affect newer versions (I don't have access to a box running 7.3 or 8.x). If pthread_cleanup_pop doesn't work properly, all sorts of deadlocks and races are possible, not to mention resource leaks, so this is kind of important (although I don't think pthread_cleanup_pop is widely used). TIA, >How-To-Repeat: The attached sample C file can be used. To compile it, run "gcc -O0 -ggdb -o test main.c", for example. Run it with "gdb test". Break on release_update_lock. You'll see that it never gets called. Compare the outputs, first a Linux machine: Init Res: 0 Locking read Res: 0 Unlocking Res: 0 Locking write Res: 0 Unlocking Res: 0 Locking read Res: 0 Unlocking with cleanup pop release_update_rwlock: 0 Locking write Res: 0 Unlocking Res: 0 Now a FreeBSD 7.2-p8 machine: Init Res: 0 Locking read Res: 0 Unlocking Res: 0 Locking write Res: 0 Unlocking Res: 0 Locking read Res: 0 Unlocking with cleanup pop Locking write Res: 0 Unlocking Res: 0 Note how release_update_rwlock is never called (and gdb confirms it). >Fix: Patch attached with submission follows: #include <pthread.h> #include <stdio.h> static pthread_rwlock_t trava; static void release_update_rwlock(void *dummy) { int res = pthread_rwlock_unlock(&trava); printf("release_update_rwlock: %d\n", res); } int main(int argc, char **argv) { printf("Init\n"); int res = pthread_rwlock_init(&trava, NULL); printf("Res: %d\n", res); printf("Locking read\n"); res = pthread_rwlock_rdlock(&trava); printf("Res: %d\n", res); printf("Unlocking\n"); res = pthread_rwlock_unlock(&trava); printf("Res: %d\n", res); printf("Locking write\n"); res = pthread_rwlock_wrlock(&trava); printf("Res: %d\n", res); printf("Unlocking\n"); res = pthread_rwlock_unlock(&trava); printf("Res: %d\n", res); printf("Locking read\n"); res = pthread_rwlock_rdlock(&trava); printf("Res: %d\n", res); printf("Unlocking with cleanup pop\n"); pthread_cleanup_push(&release_update_rwlock, NULL); pthread_cleanup_pop(1); printf("Locking write\n"); res = pthread_rwlock_wrlock(&trava); printf("Res: %d\n", res); printf("Unlocking\n"); res = pthread_rwlock_unlock(&trava); printf("Res: %d\n", res); return 0; } >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201008061440.o76Een1G012895>