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
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
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().
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)
        printf("thread %d after sem_wait\n", data->thread_num);


        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)
                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;


                printf("thread %d created\n", i);

        printf("all %d threads created, about to cancel and join threads\n", 

        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", 

        if (sem_destroy(&sem) != 0)
                return EXIT_FAILURE;

        printf("semaphore destroyed\n");

        return EXIT_SUCCESS;

Home | Main Index | Thread Index | Old Index