1/*
2 * Copyright (c) 2004, QUALCOMM Inc. All rights reserved.
3 * Created by:  abisain REMOVE-THIS AT qualcomm DOT com
4 * This file is licensed under the GPL license.  For the full content
5 * of this license, see the COPYING file at the top level of this
6 * source tree.
7
8 * Test pthread_cancel()
9 *
10 * Any destructors for thread_specific data will be called after
11 * all cleanup handlers return
12 *
13 * Steps:
14 * 1.  Create a new thread.
15 * 2.  Create a thread specific object in the thread with a destructor
16 * 3.  Add a cleanup function in the thread
17 * 4.  Call pthread_cancel on the thread.
18 * 5.  Make sure that the destructor was called after the cleanup handler
19 *
20 */
21
22#include <pthread.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include "posixtest.h"
27
28#define TEST "2-3"
29#define FUNCTION "pthread_cancel"
30#define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": "
31
32int cleanup_flag = 0;
33int destructor_flag = 0;
34int sem = 0;				/* manual semaphore */
35struct timespec destructor_time, cleanup_time;
36
37/*
38   Destructor for the Thread Specific Data
39 */
40void destructor(void *tmp)
41{
42	clock_gettime(CLOCK_REALTIME, &destructor_time);
43	destructor_flag = 1;
44}
45
46/*
47   Cleanup Handler for the Thread
48 */
49void cleanup_function()
50{
51	clock_gettime(CLOCK_REALTIME, &cleanup_time);
52	cleanup_flag = 1;
53}
54
55/* Thread's function. */
56void *a_thread_func(void *tmp)
57{
58	pthread_key_t key;
59	int           value = 1;
60	int           rc = 0;
61
62	/* To enable thread immediate cancelation, since the default
63	 * is PTHREAD_CANCEL_DEFERRED. */
64	rc = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
65	if (rc != 0) {
66		printf(ERROR_PREFIX "pthread_setcanceltype\n");
67		exit(PTS_UNRESOLVED);
68	}
69
70	rc = pthread_key_create(&key, destructor);
71	if (rc != 0) {
72		printf(ERROR_PREFIX "pthread_key_create\n");
73		exit(PTS_UNRESOLVED);
74	}
75
76	rc = pthread_setspecific(key, &value);
77	if (rc != 0) {
78		printf(ERROR_PREFIX "pthread_setspecific\n");
79		exit(PTS_UNRESOLVED);
80	}
81
82	pthread_cleanup_push(cleanup_function, NULL);
83
84	/* Tell main that the key is created */
85	sem = 1;
86
87	/* Sleep forever */
88	while(1)
89		sleep(5);
90
91	pthread_cleanup_pop(0);
92	return NULL;
93}
94
95int main()
96{
97	pthread_t new_th;
98	int       rc = 0;
99	double     diff;
100	sem = 0;
101
102	/* Create a new thread. */
103	rc = pthread_create(&new_th, NULL, a_thread_func, NULL);
104	if(rc != 0) {
105		printf(ERROR_PREFIX "pthread_create\n");
106		exit(PTS_UNRESOLVED);
107	}
108
109	/* Wait for the thread to be ready */
110	while(sem == 0)
111		sleep(1);
112
113	/* Cancel the thread. */
114	rc = pthread_cancel(new_th);
115	if(rc != 0) {
116		printf(ERROR_PREFIX "pthread_cancel\n");
117		exit(PTS_UNRESOLVED);
118	}
119
120	/* Delay enough so that the destructor must have been called */
121	sleep(5);
122
123	if(cleanup_flag != 1) {
124		printf(ERROR_PREFIX "Test FAIL: Cleanup handler was not executed.\n");
125		exit(PTS_FAIL);
126	}
127
128	if(destructor_flag != 1) {
129		printf(ERROR_PREFIX "Test FAIL: Destructor was not executed.\n");
130		exit(PTS_FAIL);
131	}
132
133	diff = destructor_time.tv_sec - cleanup_time.tv_sec;
134	diff += (double)(destructor_time.tv_nsec - cleanup_time.tv_nsec)/1000000000.0;
135	if(diff < 0) {
136		printf(ERROR_PREFIX "Test FAIL: Destructor called before Cleanup Handler\n");
137		exit(PTS_FAIL);
138	}
139
140	printf("Test PASS\n");
141	exit(PTS_PASS);
142}
143
144
145