/* * Copyright (c) 2004, QUALCOMM Inc. All rights reserved. * Created by: abisain REMOVE-THIS AT qualcomm DOT com * This file is licensed under the GPL license. For the full content * of this license, see the COPYING file at the top level of this * source tree. * Test pthread_cancel() * * Any destructors for thread_specific data will be called after * all cleanup handlers return * * Steps: * 1. Create a new thread. * 2. Create a thread specific object in the thread with a destructor * 3. Add a cleanup function in the thread * 4. Call pthread_cancel on the thread. * 5. Make sure that the destructor was called after the cleanup handler * */ #include #include #include #include #include "posixtest.h" #define TEST "2-3" #define FUNCTION "pthread_cancel" #define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": " int cleanup_flag = 0; int destructor_flag = 0; int sem = 0; /* manual semaphore */ struct timespec destructor_time, cleanup_time; /* Destructor for the Thread Specific Data */ void destructor(void *tmp) { clock_gettime(CLOCK_REALTIME, &destructor_time); destructor_flag = 1; } /* Cleanup Handler for the Thread */ void cleanup_function() { clock_gettime(CLOCK_REALTIME, &cleanup_time); cleanup_flag = 1; } /* Thread's function. */ void *a_thread_func(void *tmp) { pthread_key_t key; int value = 1; int rc = 0; /* To enable thread immediate cancelation, since the default * is PTHREAD_CANCEL_DEFERRED. */ rc = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); if (rc != 0) { printf(ERROR_PREFIX "pthread_setcanceltype\n"); exit(PTS_UNRESOLVED); } rc = pthread_key_create(&key, destructor); if (rc != 0) { printf(ERROR_PREFIX "pthread_key_create\n"); exit(PTS_UNRESOLVED); } rc = pthread_setspecific(key, &value); if (rc != 0) { printf(ERROR_PREFIX "pthread_setspecific\n"); exit(PTS_UNRESOLVED); } pthread_cleanup_push(cleanup_function, NULL); /* Tell main that the key is created */ sem = 1; /* Sleep forever */ while(1) sleep(5); pthread_cleanup_pop(0); return NULL; } int main() { pthread_t new_th; int rc = 0; double diff; sem = 0; /* Create a new thread. */ rc = pthread_create(&new_th, NULL, a_thread_func, NULL); if(rc != 0) { printf(ERROR_PREFIX "pthread_create\n"); exit(PTS_UNRESOLVED); } /* Wait for the thread to be ready */ while(sem == 0) sleep(1); /* Cancel the thread. */ rc = pthread_cancel(new_th); if(rc != 0) { printf(ERROR_PREFIX "pthread_cancel\n"); exit(PTS_UNRESOLVED); } /* Delay enough so that the destructor must have been called */ sleep(5); if(cleanup_flag != 1) { printf(ERROR_PREFIX "Test FAIL: Cleanup handler was not executed.\n"); exit(PTS_FAIL); } if(destructor_flag != 1) { printf(ERROR_PREFIX "Test FAIL: Destructor was not executed.\n"); exit(PTS_FAIL); } diff = destructor_time.tv_sec - cleanup_time.tv_sec; diff += (double)(destructor_time.tv_nsec - cleanup_time.tv_nsec)/1000000000.0; if(diff < 0) { printf(ERROR_PREFIX "Test FAIL: Destructor called before Cleanup Handler\n"); exit(PTS_FAIL); } printf("Test PASS\n"); exit(PTS_PASS); }