• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2018, Linux Test Project
3  * This file is licensed under the GPL license.  For the full content
4  * of this license, see the COPYING file at the top level of this
5  * source tree.
6  *
7  * Cancellation steps happen asynchronously with respect to
8  * the pthread_cancel(). The return status of pthread_cancel()
9  * merely informs the caller whether the cancellation request
10  * was successfully queued.
11  */
12 
13 #include <pthread.h>
14 #include <semaphore.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include "posixtest.h"
20 #include "safe_helpers.h"
21 
22 #define TIMEOUT_MS 5000
23 #define SLEEP_MS 1
24 
25 static volatile int after_cancel;
26 static volatile int thread_sleep_time;
27 static sem_t sem;
28 
cleanup_func(LTP_ATTRIBUTE_UNUSED void * unused)29 static void cleanup_func(LTP_ATTRIBUTE_UNUSED void *unused)
30 {
31 	struct timespec cleanup_ts = {0, SLEEP_MS*1000000};
32 	do {
33 		nanosleep(&cleanup_ts, NULL);
34 		thread_sleep_time += SLEEP_MS;
35 	} while (after_cancel == 0 && thread_sleep_time < TIMEOUT_MS);
36 }
37 
thread_func(LTP_ATTRIBUTE_UNUSED void * unused)38 static void *thread_func(LTP_ATTRIBUTE_UNUSED void *unused)
39 {
40 	int waited_for_cancel_ms = 0;
41 	struct timespec cancel_wait_ts = {0, SLEEP_MS*1000000};
42 
43 	SAFE_PFUNC(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL));
44 	pthread_cleanup_push(cleanup_func, NULL);
45 
46 	SAFE_FUNC(sem_post(&sem));
47 	while (waited_for_cancel_ms < TIMEOUT_MS) {
48 		nanosleep(&cancel_wait_ts, NULL);
49 		waited_for_cancel_ms += SLEEP_MS;
50 	}
51 
52 	/* shouldn't be reached */
53 	printf("Error: cancel never arrived\n");
54 	pthread_cleanup_pop(0);
55 	exit(PTS_FAIL);
56 	return NULL;
57 }
58 
main(void)59 int main(void)
60 {
61 	pthread_t th;
62 
63 	SAFE_FUNC(sem_init(&sem, 0, 0));
64 	SAFE_PFUNC(pthread_create(&th, NULL, thread_func, NULL));
65 
66 	/* wait for thread to start */
67 	SAFE_FUNC(sem_wait(&sem));
68 	SAFE_PFUNC(pthread_cancel(th));
69 
70 	/*
71 	 * if cancel action would run synchronously then
72 	 * thread will sleep for too long, because it
73 	 * would never see after_cancel == 1
74 	 */
75 	after_cancel = 1;
76 
77 	SAFE_PFUNC(pthread_join(th, NULL));
78 
79 	if (thread_sleep_time >= TIMEOUT_MS) {
80 		printf("Error: cleanup_func hit timeout\n");
81 		exit(PTS_FAIL);
82 	}
83 
84 	if (thread_sleep_time == 0) {
85 		printf("Error: cleanup_func never called\n");
86 		exit(PTS_FAIL);
87 	}
88 
89 	printf("Thread cancelled after %d ms.\n", thread_sleep_time);
90 	printf("Test PASSED\n");
91 	exit(PTS_PASS);
92 }
93