1*49714e86SBryan Cantrill#
2*49714e86SBryan Cantrill# This file and its contents are supplied under the terms of the
3*49714e86SBryan Cantrill# Common Development and Distribution License ("CDDL"), version 1.0.
4*49714e86SBryan Cantrill# You may only use this file in accordance with the terms of version
5*49714e86SBryan Cantrill# 1.0 of the CDDL.
6*49714e86SBryan Cantrill#
7*49714e86SBryan Cantrill# A full copy of the text of the CDDL should have accompanied this
8*49714e86SBryan Cantrill# source.  A copy of the CDDL is also available via the Internet at
9*49714e86SBryan Cantrill# http://www.illumos.org/license/CDDL.
10*49714e86SBryan Cantrill#
11*49714e86SBryan Cantrill
12*49714e86SBryan Cantrill#
13*49714e86SBryan Cantrill# Copyright (c) 2017, Joyent, Inc. All rights reserved.
14*49714e86SBryan Cantrill#
15*49714e86SBryan Cantrill
16*49714e86SBryan Cantrill#
17*49714e86SBryan Cantrill# This test attempts to reproduce a three-way deadlock between mod_lock,
18*49714e86SBryan Cantrill# dtrace_lock and P_PR_LOCK that is induced by shmsys having to go through
19*49714e86SBryan Cantrill# mod_hold_stub.
20*49714e86SBryan Cantrill#
21*49714e86SBryan Cantrillif [ $# != 1 ]; then
22*49714e86SBryan Cantrill	echo expected one argument: '<'dtrace-path'>'
23*49714e86SBryan Cantrill	exit 2
24*49714e86SBryan Cantrillfi
25*49714e86SBryan Cantrill
26*49714e86SBryan Cantrilldtrace=$1
27*49714e86SBryan CantrillDIR=/var/tmp/dtest.$$
28*49714e86SBryan Cantrill
29*49714e86SBryan Cantrillmkdir $DIR
30*49714e86SBryan Cantrillcd $DIR
31*49714e86SBryan Cantrill
32*49714e86SBryan Cantrillcat > prov.d <<EOF
33*49714e86SBryan Cantrillprovider test_prov {
34*49714e86SBryan Cantrill	probe ripraf();
35*49714e86SBryan Cantrill};
36*49714e86SBryan CantrillEOF
37*49714e86SBryan Cantrill
38*49714e86SBryan Cantrill$dtrace -h -s prov.d
39*49714e86SBryan Cantrillif [ $? -ne 0 ]; then
40*49714e86SBryan Cantrill	print -u2 "failed to generate header file"
41*49714e86SBryan Cantrill	exit 1
42*49714e86SBryan Cantrillfi
43*49714e86SBryan Cantrill
44*49714e86SBryan Cantrillcat > test.c <<EOF
45*49714e86SBryan Cantrill#include <unistd.h>
46*49714e86SBryan Cantrill#include <stdlib.h>
47*49714e86SBryan Cantrill#include <sys/types.h>
48*49714e86SBryan Cantrill#include <sys/ipc.h>
49*49714e86SBryan Cantrill#include <sys/shm.h>
50*49714e86SBryan Cantrill#include <stdio.h>
51*49714e86SBryan Cantrill#include <stdlib.h>
52*49714e86SBryan Cantrill#include "prov.h"
53*49714e86SBryan Cantrill
54*49714e86SBryan Cantrillvoid
55*49714e86SBryan Cantrillmain(int argc)
56*49714e86SBryan Cantrill{
57*49714e86SBryan Cantrill	void *addr;
58*49714e86SBryan Cantrill	int shmid;
59*49714e86SBryan Cantrill
60*49714e86SBryan Cantrill	if (argc > 1) {
61*49714e86SBryan Cantrill		TEST_PROV_RIPRAF();
62*49714e86SBryan Cantrill		exit(0);
63*49714e86SBryan Cantrill	}
64*49714e86SBryan Cantrill
65*49714e86SBryan Cantrill	shmid = shmget(IPC_PRIVATE, sizeof (int), IPC_CREAT | 0666);
66*49714e86SBryan Cantrill
67*49714e86SBryan Cantrill	if (shmid == -1) {
68*49714e86SBryan Cantrill		perror("shmget: ");
69*49714e86SBryan Cantrill		exit(1);
70*49714e86SBryan Cantrill	}
71*49714e86SBryan Cantrill
72*49714e86SBryan Cantrill	if ((addr = shmat(shmid, NULL, 0)) == (void *)-1) {
73*49714e86SBryan Cantrill		perror("shmat: ");
74*49714e86SBryan Cantrill		exit(1);
75*49714e86SBryan Cantrill	}
76*49714e86SBryan Cantrill
77*49714e86SBryan Cantrill	printf("%p\n", addr);
78*49714e86SBryan Cantrill
79*49714e86SBryan Cantrill	for (;;) {
80*49714e86SBryan Cantrill		TEST_PROV_RIPRAF();
81*49714e86SBryan Cantrill		sleep(1);
82*49714e86SBryan Cantrill	}
83*49714e86SBryan Cantrill}
84*49714e86SBryan CantrillEOF
85*49714e86SBryan Cantrill
86*49714e86SBryan Cantrillgcc -m32 -c test.c
87*49714e86SBryan Cantrillif [ $? -ne 0 ]; then
88*49714e86SBryan Cantrill	print -u2 "failed to compile test.c"
89*49714e86SBryan Cantrill	exit 1
90*49714e86SBryan Cantrillfi
91*49714e86SBryan Cantrill
92*49714e86SBryan Cantrill$dtrace -G -32 -s prov.d test.o
93*49714e86SBryan Cantrill
94*49714e86SBryan Cantrillif [ $? -ne 0 ]; then
95*49714e86SBryan Cantrill	print -u2 "failed to create DOF"
96*49714e86SBryan Cantrill	exit 1
97*49714e86SBryan Cantrillfi
98*49714e86SBryan Cantrill
99*49714e86SBryan Cantrillgcc -m32 -o test test.o prov.o
100*49714e86SBryan Cantrill
101*49714e86SBryan Cantrillif [ $? -ne 0 ]; then
102*49714e86SBryan Cantrill	print -u2 "failed to link final executable"
103*49714e86SBryan Cantrill	exit 1
104*49714e86SBryan Cantrillfi
105*49714e86SBryan Cantrill
106*49714e86SBryan Cantrill#
107*49714e86SBryan Cantrill# Kick off the victim program.
108*49714e86SBryan Cantrill#
109*49714e86SBryan Cantrill./test &
110*49714e86SBryan Cantrill
111*49714e86SBryan Cantrillvictim=$!
112*49714e86SBryan Cantrill
113*49714e86SBryan Cantrill#
114*49714e86SBryan Cantrill# Kick off a shell that will do nothing but read our victim's /proc map
115*49714e86SBryan Cantrill#
116*49714e86SBryan Cantrill( while true ; do read foo < /proc/$victim/map ; done ) &
117*49714e86SBryan Cantrillstubby=$!
118*49714e86SBryan Cantrill
119*49714e86SBryan Cantrill#
120*49714e86SBryan Cantrill# Kick off a shell that will do nothing but instrument (and de-instrument)
121*49714e86SBryan Cantrill# the victim
122*49714e86SBryan Cantrill#
123*49714e86SBryan Cantrill( while true; do \
124*49714e86SBryan Cantrill    $dtrace -q -P test_prov$victim -n BEGIN'{exit(0)}' > /dev/null ; done ) &
125*49714e86SBryan Cantrillinst=$!
126*49714e86SBryan Cantrill
127*49714e86SBryan Cantrill#
128*49714e86SBryan Cantrill# Finally, kick off a shell that will cause lots of provider registration and
129*49714e86SBryan Cantrill# (importantly) de-registration
130*49714e86SBryan Cantrill#
131*49714e86SBryan Cantrill( while true; do ./test foo ; done) &
132*49714e86SBryan Cantrillreg=$!
133*49714e86SBryan Cantrill
134*49714e86SBryan Cantrillecho $DIR
135*49714e86SBryan Cantrillecho victim: $victim
136*49714e86SBryan Cantrillecho stubby: $stubby
137*49714e86SBryan Cantrillecho inst: $inst
138*49714e86SBryan Cantrillecho reg: $reg
139*49714e86SBryan Cantrill
140*49714e86SBryan Cantrillsleep 120
141*49714e86SBryan Cantrill
142*49714e86SBryan Cantrillkill $reg
143*49714e86SBryan Cantrillsleep 1
144*49714e86SBryan Cantrillkill $inst
145*49714e86SBryan Cantrillsleep 1
146*49714e86SBryan Cantrillkill $stubby
147*49714e86SBryan Cantrillsleep 1
148*49714e86SBryan Cantrillkill $victim
149*49714e86SBryan Cantrill
150*49714e86SBryan Cantrill#
151*49714e86SBryan Cantrill# If we're deadlocked, this DTrace enabling won't work (if we even make it this
152*49714e86SBryan Cantrill# far, which seems unlikely).  In the spirit of the deadlock, we denote our
153*49714e86SBryan Cantrill# success by emiting a classic Faulknerism.
154*49714e86SBryan Cantrill#
155*49714e86SBryan Cantrillraf="Maybe you're not so worthless!"
156*49714e86SBryan Cantrilldtrace -qn BEGIN"{printf(\"$raf\"); exit(0)}"
157*49714e86SBryan Cantrill
158*49714e86SBryan Cantrillcd /
159*49714e86SBryan Cantrill/usr/bin/rm -rf $DIR
160*49714e86SBryan Cantrill
161*49714e86SBryan Cantrillexit 0
162