xref: /freebsd/tools/test/stress2/misc/signal.sh (revision 4d846d26)
1#!/bin/sh
2
3#
4# Copyright (c) 2013 EMC Corp.
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28
29# Regression test for kern/150138: signal sent to stopped, traced process
30# not immediately handled on continue.
31# Fixed in r212047.
32
33# Test scenario by Dan McNulty <dkmcnulty gmail.com>
34
35. ../default.cfg
36
37here=`pwd`
38wd=/tmp/signal.dir
39rm -rf $wd
40mkdir -p $wd
41cd $wd
42cat > waitthread.c <<EOF
43#include <unistd.h>
44#include <stdlib.h>
45#include <pthread.h>
46#include <stdio.h>
47#include <assert.h>
48#include <signal.h>
49#include <time.h>
50#include <sys/syscall.h>
51#include <string.h>
52#include <fcntl.h>
53#include <sys/types.h>
54#include <sys/stat.h>
55#include <errno.h>
56
57struct threadArg {
58    int id;
59    pthread_mutex_t *mutex;
60};
61
62void *entry(void *arg) {
63    struct threadArg *thisArg = (struct threadArg *)arg;
64
65    long lwp_id = thisArg->id;
66    if( syscall(SYS_thr_self, &lwp_id) ) {
67        perror("syscall");
68    }
69
70    printf("%ld waiting on lock\n", lwp_id);
71
72    if( pthread_mutex_lock(thisArg->mutex) != 0 ) {
73        perror("pthread_mutex_lock");
74        return NULL;
75    }
76
77    printf("%ld obtained lock\n", lwp_id);
78
79    if( pthread_mutex_unlock(thisArg->mutex) != 0 ) {
80        perror("pthread_mutex_unlock");
81        return NULL;
82    }
83
84    printf("%ld released lock\n", lwp_id);
85
86    return NULL;
87}
88
89int main(int argc, char **argv) {
90    if( 2 != argc ) {
91        printf("Usage: %s <num. of threads>\n", argv[0]);
92        return EXIT_FAILURE;
93    }
94
95    printf("%d\n", getpid());
96
97    int numThreads;
98    sscanf(argv[1], "%d", &numThreads);
99    if( numThreads < 1 ) numThreads = 1;
100
101    pthread_t *threads = (pthread_t *)malloc(sizeof(pthread_t)*numThreads);
102
103    pthread_mutex_t *mutex = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t));
104
105    if( pthread_mutex_init(mutex, NULL) != 0 ) {
106        perror("pthread_mutex_init");
107        return EXIT_FAILURE;
108    }
109
110    if( pthread_mutex_lock(mutex) != 0 ) {
111        perror("pthread_mutex_lock");
112        return EXIT_FAILURE;
113    }
114
115    int i;
116    for(i = 0; i < numThreads; ++i) {
117        struct threadArg *arg = (struct threadArg *)malloc(sizeof(struct threadArg));
118        arg->id = i;
119        arg->mutex = mutex;
120        assert( !pthread_create(&threads[i], NULL, &entry, (void *)arg) );
121    }
122
123    // Wait on the named pipe
124    unlink("/tmp/waitthread");
125    if( mkfifo("/tmp/waitthread", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) ) {
126        perror("mkfifo");
127        return EXIT_FAILURE;
128    }
129
130    FILE *fifo;
131    do {
132        if( (fifo = fopen("/tmp/waitthread", "r")) == NULL ) {
133            if( errno == EINTR ) continue;
134
135            perror("fopen");
136            return EXIT_FAILURE;
137        }
138        break;
139    }while(1);
140
141    unsigned char byte;
142    if( fread(&byte, sizeof(unsigned char), 1, fifo) != 1 ) {
143        perror("fread");
144    }
145
146    fclose(fifo);
147
148    unlink("/tmp/waitthread");
149
150    printf("Received notification\n");
151
152    if( pthread_mutex_unlock(mutex) != 0 ) {
153        perror("pthread_mutex_unlock");
154        return EXIT_FAILURE;
155    }
156
157    printf("Unlocked mutex, joining\n");
158
159    for(i = 0; i < numThreads; ++i ) {
160        assert( !pthread_join(threads[i], NULL) );
161    }
162
163    return EXIT_SUCCESS;
164}
165EOF
166cat > tkill.c <<EOF
167#include <sys/syscall.h>
168#include <unistd.h>
169#include <stdio.h>
170#include <errno.h>
171#include <stdlib.h>
172#include <signal.h>
173
174int main(int argc, char *argv[]) {
175    if( argc != 4 ) {
176        printf("Usage: %s <pid> <lwp_id> <sig>\n", argv[0]);
177        return EXIT_FAILURE;
178    }
179
180    pid_t pid;
181    sscanf(argv[1], "%d", &pid);
182
183    long id;
184    sscanf(argv[2], "%ld", &id);
185
186    int sig;
187    sscanf(argv[3], "%d", &sig);
188
189    if( syscall(SYS_thr_kill2, pid, id, sig) ) {
190        perror("syscall");
191    }
192
193    return EXIT_SUCCESS;
194}
195EOF
196mycc -o waitthread -Wall -Wextra waitthread.c -lpthread || exit
197mycc -o tkill -Wall -Wextra tkill.c || exit
198rm -f waitthread.c tkill.c
199
200rm -f gdbfifo gdbout pstat /tmp/waitthread
201pkill -9 waitthread
202pgrep -q waitthread && { pgrep waitthread | xargs ps -lHp; exit 1; }
203mkfifo gdbfifo
204trap "rm -f gdbfifo" EXIT INT
205sleep 300 > gdbfifo &	# Keep the fifo open
206sleep .5
207fifopid=$!
208
209(trap - INT; gdb ./waitthread < gdbfifo > gdbout 2>&1) &
210sleep .8
211gdbpid=$!
212echo "set args 8" > gdbfifo
213echo "run"        > gdbfifo
214sleep .8
215
216for i in `jot 5`; do
217	pid=`ps -x | grep -v grep | grep "waitthread 8" |
218	    sed 's/^ *//;s/ .*//'`
219	[ -n "$pid" ] && break
220	sleep 1
221done
222s=0
223if [ -n "$pid" ]; then
224	procstat -t $pid > pstat
225
226	t1=`grep fifo  pstat | awk '{print $2}'`
227	t2=`grep umtxn pstat | awk '{print $2}' | tail -1`
228
229	set -e
230	./tkill $pid $t1 5	# SIGTRAP
231	./tkill $pid $t2 2	# SIGINT
232	set +e
233
234	echo "c"    > gdbfifo
235	echo "quit" > gdbfifo
236	sleep 1
237	grep -q "signal SIGINT" gdbout || { echo FAIL; cat gdbout; s=1; }
238else
239	echo "Did not find pid for test program waitthread"
240	s=2
241fi
242
243kill -9 $fifopid $gdbpid > /dev/null 2>&1
244pgrep -q waitthread && pkill -9 waitthread
245cd $here
246rm -rf $wd /tmp/waitthread
247exit $s
248