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 * When the cancelation is acted on, the cancelation cleanup handlers for
10 * 'thread' shall be called "asynchronously"
11 *
12 * STEPS:
13 * 1. Change main thread to a real-time thread with a high priority
14 * 1. Create a lower priority thread
15 * 2. In the thread function, push a cleanup function onto the stack
16 * 3. Cancel the thread from main and get timestamp, then block.
17 * 4. The cleanup function should be automatically
18 * executed, else the test will fail.
19 */
20
21 #include <pthread.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include "posixtest.h"
27 #include <time.h>
28
29 #define TEST "3-1"
30 #define FUNCTION "pthread_cancel"
31 #define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": "
32
33 #define FIFOPOLICY SCHED_FIFO
34 #define MAIN_PRIORITY 30
35 #define TIMEOUT_IN_SECS 10
36
37 /* Manual semaphore */
38 int sem;
39
40 /* Made global so that the cleanup function
41 * can manipulate the value as well.
42 */
43 int cleanup_flag;
44 struct timespec main_time, cleanup_time;
45
46 /* A cleanup function that sets the cleanup_flag to 1, meaning that the
47 * cleanup function was reached.
48 */
a_cleanup_func()49 void a_cleanup_func()
50 {
51 clock_gettime(CLOCK_REALTIME, &cleanup_time);
52 cleanup_flag = 1;
53 sem = 0;
54 return;
55 }
56
57 /* A thread function called at the creation of the thread. It will push
58 * the cleanup function onto it's stack, then go into a continuous 'while'
59 * loop, never reaching the cleanup_pop function. So the only way the cleanup
60 * function can be called is when the thread is canceled and all the cleanup
61 * functions are supposed to be popped.
62 */
a_thread_func()63 void *a_thread_func()
64 {
65 int rc = 0;
66
67 /* To enable thread immediate cancelation, since the default
68 * is PTHREAD_CANCEL_DEFERRED.
69 */
70 rc = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
71 if (rc != 0) {
72 printf(ERROR_PREFIX "pthread_setcanceltype\n");
73 exit(PTS_UNRESOLVED);
74 }
75 pthread_cleanup_push(a_cleanup_func, NULL);
76
77 sem = 1;
78 while (sem == 1)
79 sleep(1);
80 sleep(5);
81 sem = 0;
82
83 /* Should never be reached, but is required to be in the code
84 * since pthread_cleanup_push is in the code. Else a compile error
85 * will result.
86 */
87 pthread_cleanup_pop(0);
88 pthread_exit(0);
89 return NULL;
90 }
91
main(void)92 int main(void)
93 {
94 pthread_t new_th;
95 int i;
96 double diff;
97 struct sched_param param;
98 int rc = 0;
99
100 /* Initializing the cleanup flag. */
101 cleanup_flag = 0;
102 sem = 0;
103 param.sched_priority = MAIN_PRIORITY;
104
105 /* Increase priority of main, so the new thread doesn't get to run */
106 rc = pthread_setschedparam(pthread_self(), FIFOPOLICY, ¶m);
107 if (rc != 0) {
108 printf(ERROR_PREFIX "pthread_setschedparam\n");
109 exit(PTS_UNRESOLVED);
110 }
111
112 /* Create a new thread. */
113 rc = pthread_create(&new_th, NULL, a_thread_func, NULL);
114 if (rc != 0) {
115 printf(ERROR_PREFIX "pthread_create\n");
116 return PTS_UNRESOLVED;
117 }
118
119 /* Make sure thread is created and executed before we cancel it. */
120 while (sem == 0)
121 sleep(1);
122
123 rc = pthread_cancel(new_th);
124 if (rc != 0) {
125 printf(ERROR_PREFIX "pthread_cancel\n");
126 exit(PTS_FAIL);
127 }
128
129 /* Get the time after canceling the thread */
130 clock_gettime(CLOCK_REALTIME, &main_time);
131 i = 0;
132 while (sem == 1) {
133 sleep(1);
134 if (i == TIMEOUT_IN_SECS) {
135 printf(ERROR_PREFIX "Cleanup handler was not called\n");
136 exit(PTS_FAIL);
137 }
138 i++;
139 }
140
141 /* If the cleanup function was not reached by calling the
142 * pthread_cancel function, then the test fails.
143 */
144 if (cleanup_flag != 1) {
145 printf(ERROR_PREFIX "Cleanup handler was not called\n");
146 exit(PTS_FAIL);
147 }
148
149 diff = cleanup_time.tv_sec - main_time.tv_sec;
150 diff +=
151 (double)(cleanup_time.tv_nsec - main_time.tv_nsec) / 1000000000.0;
152 if (diff < 0) {
153 printf(ERROR_PREFIX
154 "Cleanup function was called before main continued\n");
155 exit(PTS_FAIL);
156 }
157 printf("Test PASSED\n");
158 exit(PTS_PASS);
159 }
160