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 */
38int sem;
39
40/* Made global so that the cleanup function
41 * can manipulate the value as well.
42 */
43int cleanup_flag;
44struct 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 */
49void 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 */
63void *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
92int main()
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 += (double)(cleanup_time.tv_nsec - main_time.tv_nsec)/1000000000.0;
151	if(diff < 0) {
152		printf(ERROR_PREFIX "Cleanup function was called before main continued\n");
153		exit(PTS_FAIL);
154	}
155	printf("Test PASS\n");
156	exit(PTS_PASS);
157}
158