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