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

Bug#281775: PTHREAD_CANCEL_DISABLE broken for NPTL



Package: libc6
Version: 2.3.2.ds1-18
Severity: normal

Thread cancellation can't be disabled when running a 2.6.x kernel (i.e. when using the new NPTL threading).

Effect: A thread T1 will be cancelled if another thread T2 requests the cancellation via pthread_cancel(), even if T1 has cancellation disabled via pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0).

Workaround: Force libc6 to use the old LinuxThreads implementation by setting LD_ASSUME_KERNEL=2.4.19

The bug is already listed (and solved) in redhat's bugtracking system, see bug #112512 on bugzilla.redhat.com.

Demonstration:
--------
#include <stdio.h>
#include <pthread.h>

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *thread_fn(void *self)
{
  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
  pthread_mutex_lock(&lock);
  pthread_cond_signal(&cond);
  puts("checkpoint 1");
  /* The main thread will try to cancel the following call. */
  pthread_cond_wait(&cond, &lock);
  puts("checkpoint 3");
  pthread_cond_signal(&cond);
  pthread_mutex_unlock(&lock);
  return 0;
}

int main(void)
{
  pthread_t thread;
  pthread_mutex_lock(&lock);
  pthread_create(&thread, 0, thread_fn, 0);
  /* Wait for 'thread' to reach checkpoint 1. */
  pthread_cond_wait(&cond, &lock);
  /* Cancel the thread.  Note: 'thread' has disabled cancellation. */
  pthread_cancel(thread);
  puts("checkpoint 2");
  /* If the cancellation went through, then 'thread' will be cancelled
   * in a call to 'pthread_cond_wait()', i.e. it will re-acquire the
   * lock and terminate as soon as we release the lock in the main
   * thread -- which will happen with the following
   * 'pthread_cond_wait()'. */
  pthread_cond_signal(&cond);
  /* In case of the demonstrated bug, we will wait forever. */
  pthread_cond_wait(&cond, &lock);
  puts("checkpoint 4");
  pthread_mutex_unlock(&lock);
  pthread_join(thread, 0);
  puts("OK");
  return 0;
}
--------

/tmp $ gcc test.c -lpthread
/tmp $ LD_ASSUME_KERNEL=2.4.19 ./a.out
checkpoint 1
checkpoint 2
checkpoint 3
checkpoint 4
OK
/tmp $ ./a.out
checkpoint 1
checkpoint 2
(Program hangs.)

Tested on/with:
  Debian unstable
  Linux-2.6.8.1 ('Linus' kernel)
  glibc-2.3.2.ds1-18
  GCC 3.3.2



Reply to: