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, &param);
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