[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#342574: marked as done (pthread_cond_timedwait changes canceltype to ASYNCHRONOUS)



Your message dated Wed, 18 Apr 2007 18:57:54 +0200
with message-id <20070418165750.GA14044@amd64.aurel32.net>
and subject line pthread_cond_timedwait changes canceltype to ASYNCHRONOUS
has caused the attached Bug report to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what I am
talking about this indicates a serious mail system misconfiguration
somewhere.  Please contact me immediately.)

Debian bug tracking system administrator
(administrator, Debian Bugs database)

--- Begin Message ---
Package: libc6
Version: 2.3.2.ds1-22

The linuxthread's pthread_cond_timedwait force changes canceltype to
ASYNCHRONOUS if timeout occurred.  NPTL's one seems OK.

This is a test code.

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>

pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

void *func(void *arg)
{
	sleep(1);
	pthread_mutex_lock(&m);
	pthread_cond_broadcast(&cv);
	pthread_mutex_unlock(&m);
	return NULL;
}

int main(int argc, char **argv)
{
	pthread_t tid;
	struct timespec ts;
	struct timeval tv;
	int before, after;

	pthread_create(&tid, NULL, func, NULL);
	gettimeofday(&tv, NULL);
	ts.tv_sec = tv.tv_sec + 10;
	ts.tv_nsec = 0;
	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &before);
	pthread_mutex_lock(&m);
	pthread_cond_timedwait(&cv, &m, &ts);
	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &after);
	pthread_mutex_unlock(&m);
	pthread_join(tid, NULL);
	printf("before = %d, after = %d\n", before, after);
	return 0;
}

And results:

$ ./foo
before = 0, after = 0
$ LD_ASSUME_KERNEL=2.4.1 ./foo
before = 0, after = 1

The canceltype was 0 (DEFERRED) before pthread_cond_timedwait, and
becomes 1 (ASYNCHRONOUS) after timeout.

This is because pthread_cond_timedwait internally calls nanosleep
which is cancellation point.  The nanosleep temporarily changes
canceltype to ASYNCHRONOUS, and it was not reverted if timeout
occurred.

In glibc 2.3.5, it seems read_not_cancel, etc. are used to avoid such
an unexpected side-effects.  This was introduced by:

http://sources.redhat.com/ml/libc-hacker/2004-05/msg00003.html

But nanosleep was not replaced with *_not_cancel version.

Here is a proposal patch for 2.3.5-8.1

diff -ur glibc-2.3.5-8.1/sysdeps/unix/sysv/linux/not-cancel.h glibc-2.3.5/sysdeps/unix/sysv/linux/not-cancel.h
--- glibc-2.3.5-8.1/sysdeps/unix/sysv/linux/not-cancel.h	2003-09-04 23:05:12.000000000 +0900
+++ glibc-2.3.5/sysdeps/unix/sysv/linux/not-cancel.h	2005-12-09 01:42:02.593631864 +0900
@@ -58,3 +58,7 @@
 # define waitpid_not_cancel(pid, stat_loc, options) \
   INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL)
 #endif
+
+/* Uncancelable nanosleep.  */
+#define nanosleep_not_cancel(req, rem) \
+  INLINE_SYSCALL (nanosleep, 2, (req), (rem))
diff -ur glibc-2.3.5-8.1/linuxthreads/pthread.c glibc-2.3.5/linuxthreads/pthread.c
--- glibc-2.3.5-8.1/linuxthreads/pthread.c	2005-12-09 01:40:08.942909000 +0900
+++ glibc-2.3.5/linuxthreads/pthread.c	2005-12-09 01:42:02.594631712 +0900
@@ -1274,7 +1274,7 @@
 
 	/* Sleep for the required duration. If woken by a signal,
 	   resume waiting as required by Single Unix Specification.  */
-	if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
+	if (reltime.tv_sec < 0 || nanosleep_not_cancel(&reltime, NULL) == 0)
 	  break;
       }
 
@@ -1361,7 +1361,7 @@
 
       /* Sleep for the required duration. If woken by a signal,
 	 resume waiting as required by Single Unix Specification.  */
-      if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
+      if (reltime.tv_sec < 0 || nanosleep_not_cancel(&reltime, NULL) == 0)
 	break;
     }
 
diff -ur glibc-2.3.5-8.1/linuxthreads/spinlock.c glibc-2.3.5/linuxthreads/spinlock.c
--- glibc-2.3.5-8.1/linuxthreads/spinlock.c	2005-12-09 01:40:08.943909000 +0900
+++ glibc-2.3.5/linuxthreads/spinlock.c	2005-12-09 01:42:02.594631712 +0900
@@ -23,6 +23,7 @@
 #include "internals.h"
 #include "spinlock.h"
 #include "restart.h"
+#include <not-cancel.h>
 
 static void __pthread_acquire(__atomic_lock_t * spinlock);
 
@@ -713,7 +714,7 @@
     } else {
       tm.tv_sec = 0;
       tm.tv_nsec = SPIN_SLEEP_DURATION;
-      nanosleep(&tm, NULL);
+      nanosleep_not_cancel(&tm, NULL);
       cnt = 0;
     }
   }


--- End Message ---
--- Begin Message ---
Version: 2.5-1

On Fri, Dec 09, 2005 at 10:16:56AM +0900, Atsushi Nemoto wrote:
> anemo> The linuxthread's pthread_cond_timedwait force changes
> anemo> canceltype to ASYNCHRONOUS if timeout occurred.  NPTL's one
> anemo> seems OK.
> 
> Sorry, the condition in this statement was wrong.  "if timeout NOT
> occurred" is correct.
> 

glibc 2.5 which is now in unstable has switched to NPTL only, which
fixes this problem. Closing the bug.

-- 
  .''`.  Aurelien Jarno	            | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   aurel32@debian.org         | aurelien@aurel32.net
   `-    people.debian.org/~aurel32 | www.aurel32.net

--- End Message ---

Reply to: