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/types.h>
50
51#include <machine/cpufunc.h>
52#include <machine/cpu.h>
53
54#include <err.h>
55#include <pthread.h>
56#include <pthread_np.h>
57#include <signal.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <unistd.h>
61
62pthread_mutex_t the_mutex = PTHREAD_MUTEX_INITIALIZER;
63
64pthread_t contender;
65
66static void *
67contender_func(void *arg)
68{
69    int error;
70
71    (void) arg;
72
73    error = pthread_mutex_lock(&the_mutex);
74    if (error) errc(1, error, "pthread_mutex_lock contender");
75
76    fprintf(stderr, "contender lock succeeded\n");
77
78    error = pthread_mutex_unlock(&the_mutex);
79    if (error) errc(1, error, "pthread_mutex_unlock contender");
80
81    fprintf(stderr, "contender unlock succeeded; exiting\n");
82
83    return (NULL);
84}
85
86static void *
87signaler_func(void *arg __unused)
88{
89    int error;
90
91    // Wait for the main thread to sleep.
92    usleep(100000);
93
94    error = pthread_kill(contender, SIGHUP);
95    if (error) errc(1, error, "pthread_kill");
96
97    // Wait for the contender to lock umtx_lock
98    // in umtx_repropagate_priority.
99    usleep(100000);
100
101    error = pthread_mutex_lock(&the_mutex);
102    if (error) errc(1, error, "pthread_mutex_lock signaler");
103
104    return (NULL);
105}
106
107int
108main(void)
109{
110    int error;
111
112    pthread_mutexattr_t mattr;
113
114    error = pthread_mutexattr_init(&mattr);
115    if (error) errc(1, error, "pthread_mutexattr_init");
116
117    error = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
118    if (error) errc(1, error, "pthread_mutexattr_setprotocol");
119
120    error = pthread_mutex_init(&the_mutex, &mattr);
121    if (error) errc(1, error, "pthread_mutex_init");
122
123    error = pthread_mutexattr_destroy(&mattr);
124    if (error) errc(1, error, "pthread_mutexattr_destroy");
125
126    //error = pthread_mutex_lock(&the_mutex);
127    //if (error) errc(1, error, "pthread_mutex_lock");
128
129    // Hack lock.
130    *(int *)the_mutex = pthread_getthreadid_np();
131
132    error = pthread_create(&contender, NULL, contender_func, NULL);
133    if (error) errc(1, error, "pthread_create");
134
135    // Wait for the contender to sleep.
136    usleep(100000);
137
138    pthread_t signaler;
139    error = pthread_create(&signaler, NULL, signaler_func, NULL);
140    if (error) errc(1, error, "pthread_create");
141
142    error = pthread_mutex_lock(&the_mutex);
143    if (error) errc(1, error, "pthread_mutex_lock recurse");
144
145    return (0);
146}
147
148