1#!/bin/sh
2
3# The program is a test case by Eric which demonstrates the
4# bug, unkillable spinning thread, owning a spinlock.
5
6# "panic: spin lock held too long" seen.
7# Fixed in r277970.
8
9. ../default.cfg
10
11here=`pwd`
12cd /tmp
13sed '1,/^EOF/d' < $here/$0 > kern_umtx_inf_loop.c
14mycc -o kern_umtx_inf_loop -Wall -Wextra -O0 -g kern_umtx_inf_loop.c \
15    -lpthread || exit 1
16rm -f kern_umtx_inf_loop.c
17
18/tmp/kern_umtx_inf_loop
19
20rm -f /tmp/kern_umtx_inf_loop
21exit 0
22EOF
23/*-
24 * Copyright (c) 2015 Eric van Gyzen
25 * All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 *    notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 *    notice, this list of conditions and the following disclaimer in the
34 *    documentation and/or other materials provided with the distribution.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
37 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
40 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 */
48
49#include <sys/cdefs.h>
50#include <sys/types.h>
51
52#include <machine/cpufunc.h>
53#include <machine/cpu.h>
54
55#include <err.h>
56#include <pthread.h>
57#include <pthread_np.h>
58#include <signal.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <unistd.h>
62
63pthread_mutex_t the_mutex = PTHREAD_MUTEX_INITIALIZER;
64
65pthread_t contender;
66
67static void *
68contender_func(void *arg)
69{
70    int error;
71
72    (void) arg;
73
74    error = pthread_mutex_lock(&the_mutex);
75    if (error) errc(1, error, "pthread_mutex_lock contender");
76
77    fprintf(stderr, "contender lock succeeded\n");
78
79    error = pthread_mutex_unlock(&the_mutex);
80    if (error) errc(1, error, "pthread_mutex_unlock contender");
81
82    fprintf(stderr, "contender unlock succeeded; exiting\n");
83
84    return (NULL);
85}
86
87static void *
88signaler_func(void *arg __unused)
89{
90    int error;
91
92    // Wait for the main thread to sleep.
93    usleep(100000);
94
95    error = pthread_kill(contender, SIGHUP);
96    if (error) errc(1, error, "pthread_kill");
97
98    // Wait for the contender to lock umtx_lock
99    // in umtx_repropagate_priority.
100    usleep(100000);
101
102    error = pthread_mutex_lock(&the_mutex);
103    if (error) errc(1, error, "pthread_mutex_lock signaler");
104
105    return (NULL);
106}
107
108int
109main(void)
110{
111    int error;
112
113    pthread_mutexattr_t mattr;
114
115    error = pthread_mutexattr_init(&mattr);
116    if (error) errc(1, error, "pthread_mutexattr_init");
117
118    error = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
119    if (error) errc(1, error, "pthread_mutexattr_setprotocol");
120
121    error = pthread_mutex_init(&the_mutex, &mattr);
122    if (error) errc(1, error, "pthread_mutex_init");
123
124    error = pthread_mutexattr_destroy(&mattr);
125    if (error) errc(1, error, "pthread_mutexattr_destroy");
126
127    //error = pthread_mutex_lock(&the_mutex);
128    //if (error) errc(1, error, "pthread_mutex_lock");
129
130    // Hack lock.
131    *(int *)the_mutex = pthread_getthreadid_np();
132
133    error = pthread_create(&contender, NULL, contender_func, NULL);
134    if (error) errc(1, error, "pthread_create");
135
136    // Wait for the contender to sleep.
137    usleep(100000);
138
139    pthread_t signaler;
140    error = pthread_create(&signaler, NULL, signaler_func, NULL);
141    if (error) errc(1, error, "pthread_create");
142
143    error = pthread_mutex_lock(&the_mutex);
144    if (error) errc(1, error, "pthread_mutex_lock recurse");
145
146    return (0);
147}
148
149