1#!/bin/sh 2 3# Original test scenario by nabijaczleweli@nabijaczleweli.xyz: 4# Bug 283101 - pthread_cancel() doesn't cancel a thread that's currently in pause() 5# Fixed by: 9f78c837d94f check_cancel: when in_sigsuspend, send SIGCANCEL unconditionally 6 7. ../default.cfg 8set -u 9prog=$(basename "$0" .sh) 10cat > /tmp/$prog.c <<EOF 11#include <pthread.h> 12#include <stdio.h> 13#include <stdlib.h> 14#include <unistd.h> 15 16static void * 17thread(void *arg __unused) 18{ 19 for(;;) { 20 pause(); 21 printf("woke up from pause\n"); 22 } 23} 24 25static void 26thread_cancel_and_join(pthread_t ptid) 27{ 28 void *status = NULL; 29 30 if (pthread_cancel(ptid)) { 31 printf("pthread_cancel() failed\n"); 32 exit(1); 33 } 34 35 (void) pthread_join(ptid, &status); 36 int error = (int)(uintptr_t)status; 37 38 if (error) { 39 if (status == PTHREAD_CANCELED) { 40 printf("pthread_cancel() succeeded\n"); 41 } else { 42 printf("pthread_join() error (not PTHREAD_CANCELED)\n"); 43 exit(1); 44 } 45 } 46} 47 48int 49main(void) 50{ 51 // Empirically, I've noticed that either the hang occurs somewhere between 52 // 10 and 500 iterations, or it runs infinitely without ever hanging. 53 // Therefore, stopping at 500th iteration, and looping from a shell script. 54 55 // For quick results (usually under 10 minutes), invoke "./run" from a dozen 56 // consoles or GNU screen windows in parallel. 57 58 pid_t pid = getpid(); 59 60 for (uint64_t iteration = 1; iteration <= 500; ++iteration) { 61 printf("PID %d, iteration %lu...", pid, iteration); 62 63 pthread_t ptid; 64 int err; 65 66 err = pthread_create(&ptid, NULL, thread, NULL); 67 68 if (err) { 69 printf("pthread_create() failed with error: %d\n", err); 70 return 1; 71 } 72 73 thread_cancel_and_join(ptid); 74 75 printf("OK\n"); 76 77 // Tiny sleep 78 usleep(20000); 79 } 80} 81EOF 82mycc -o /tmp/$prog -Wall -Wextra -O2 /tmp/$prog.c -lpthread || exit 1 83(cd ../testcases/swap; ./swap -t 3m -i 20 > /dev/null) & 84sleep 5 85start=`date +%s` 86while [ $((`date +%s` - start)) -lt 180 ]; do 87 /tmp/$prog > /dev/null & pid=$! 88 t1=`date +%s` 89 while kill -0 $pid 2> /dev/null; do 90 if [ $((`date +%s` - t1)) -gt 180 ]; then 91 ps -lH $pid 92# exit 1 # For DEBUG 93 kill -9 $pid; s=1 94 echo fail 95 break 2 96 else 97 sleep 1 98 fi 99 done 100 wait $pid; s=$? 101 [ $s -ne 0 ] && break 102done 103while pkill swap; do :; done 104wait 105rm -f /tmp/$prog /tmp/$prog.c 106exit $s 107