NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
lib/46367: broken semaphore with pthread_cancel
>Number: 46367
>Category: lib
>Synopsis: broken semaphore with pthread_cancel
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Apr 24 15:30:01 +0000 2012
>Originator: David Mandelberg
>Release: 5.99.63
>Organization:
>Environment:
NetBSD [redacted] 5.99.63 NetBSD 5.99.63 (GENERIC) #2: Fri Feb 3 04:53:44 EST
2012 [redacted]/netbsd-current/obj/sys/arch/i386/compile/GENERIC i386
>Description:
If thread A is in the middle of calling sem_wait() when thread B calls
pthread_cancel() on thread A, any other calls to sem_wait() on the same
semaphore can't be canceled with pthread_cancel() and the semaphore can't be
destroyed with sem_destroy().
>How-To-Repeat:
The below C code should complete and exit with return code EXIT_SUCCESS. With
NUM_THREADS set to 2 (as below), it hangs after calling pthread_cancel() on the
second non-main thread while the main thread is in pthread_join(). If you set
NUM_THREADS to 1, it hangs after calling pthread_join() while the main thread
is in sem_destroy().
#include <stdlib.h>
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#define NUM_THREADS 2
struct thread_data
{
int thread_num;
sem_t *sem;
};
void thread_cleanup(void * data_voidp)
{
struct thread_data * data = (struct thread_data *)data_voidp;
printf("thread %d in cleanup\n", data->thread_num);
}
void * thread_main(void * data_voidp)
{
struct thread_data * data = (struct thread_data *)data_voidp;
pthread_cleanup_push(thread_cleanup, data);
printf("thread %d before sem_wait\n", data->thread_num);
if (sem_wait(data->sem) != 0)
{
perror("sem_wait()");
}
printf("thread %d after sem_wait\n", data->thread_num);
pthread_cleanup_pop(1);
return NULL;
}
int main(void)
{
struct thread_data thread_data[NUM_THREADS];
pthread_t threads[NUM_THREADS];
sem_t sem;
int i;
if (sem_init(&sem, 0, 0) != 0)
{
perror("sem_init()");
return EXIT_FAILURE;
}
printf("creating %d threads...\n", NUM_THREADS);
for (i = 0; i < NUM_THREADS; ++i)
{
thread_data[i].thread_num = i;
thread_data[i].sem = &sem;
if (pthread_create(&threads[i], NULL, thread_main,
&thread_data[i]) != 0)
{
printf("error in pthread_create() for thread %d\n", i);
return EXIT_FAILURE;
}
sleep(1);
printf("thread %d created\n", i);
}
printf("all %d threads created, about to cancel and join threads\n",
NUM_THREADS);
for (i = 0; i < NUM_THREADS; ++i)
{
printf("before pthread_cancel() thread %d\n", i);
if (pthread_cancel(threads[i]) != 0)
{
printf("error in pthread_cancel() for thread %d\n", i);
return EXIT_FAILURE;
}
printf("after cancel, before pthread_join() thread %d\n", i);
if (pthread_join(threads[i], NULL) != 0)
{
printf("error in pthread_join() for thread %d\n", i);
return EXIT_FAILURE;
}
printf("thread %d joined\n", i);
}
printf("all %d threads joined, about to destroy semaphore\n",
NUM_THREADS);
if (sem_destroy(&sem) != 0)
{
perror("sem_destroy()");
return EXIT_FAILURE;
}
printf("semaphore destroyed\n");
return EXIT_SUCCESS;
}
>Fix:
Home |
Main Index |
Thread Index |
Old Index