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