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
32 int cleanup_flag = 0;
33 int destructor_flag = 0;
34 int sem = 0; /* manual semaphore */
35 struct timespec destructor_time, cleanup_time;
36
37 /*
38 Destructor for the Thread Specific Data
39 */
destructor(void * tmp)40 void 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 */
cleanup_function()49 void cleanup_function()
50 {
51 clock_gettime(CLOCK_REALTIME, &cleanup_time);
52 cleanup_flag = 1;
53 }
54
55 /* Thread's function. */
a_thread_func(void * tmp)56 void *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
main(void)95 int main(void)
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
125 "Test FAIL: Cleanup handler was not executed.\n");
126 exit(PTS_FAIL);
127 }
128
129 if (destructor_flag != 1) {
130 printf(ERROR_PREFIX
131 "Test FAIL: Destructor was not executed.\n");
132 exit(PTS_FAIL);
133 }
134
135 diff = destructor_time.tv_sec - cleanup_time.tv_sec;
136 diff +=
137 (double)(destructor_time.tv_nsec -
138 cleanup_time.tv_nsec) / 1000000000.0;
139 if (diff < 0) {
140 printf(ERROR_PREFIX
141 "Test FAIL: Destructor called before Cleanup Handler\n");
142 exit(PTS_FAIL);
143 }
144
145 printf("Test PASSED\n");
146 exit(PTS_PASS);
147 }
148