18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
4bb535300SJeff Roberson * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
5bb535300SJeff Roberson * All rights reserved.
6bb535300SJeff Roberson *
7bb535300SJeff Roberson * Redistribution and use in source and binary forms, with or without
8bb535300SJeff Roberson * modification, are permitted provided that the following conditions
9bb535300SJeff Roberson * are met:
10bb535300SJeff Roberson * 1. Redistributions of source code must retain the above copyright
11bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer.
12bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright
13bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the
14bb535300SJeff Roberson * documentation and/or other materials provided with the distribution.
15fed32d75SWarner Losh * 3. Neither the name of the author nor the names of any co-contributors
16bb535300SJeff Roberson * may be used to endorse or promote products derived from this software
17bb535300SJeff Roberson * without specific prior written permission.
18bb535300SJeff Roberson *
19bb535300SJeff Roberson * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
20bb535300SJeff Roberson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21bb535300SJeff Roberson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22bb535300SJeff Roberson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23bb535300SJeff Roberson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24bb535300SJeff Roberson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25bb535300SJeff Roberson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26bb535300SJeff Roberson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27bb535300SJeff Roberson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28bb535300SJeff Roberson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29bb535300SJeff Roberson * SUCH DAMAGE.
30bb535300SJeff Roberson */
31bb535300SJeff Roberson
32dec04f43SMike Makonnen #include <sys/types.h>
33bb535300SJeff Roberson #include <pthread.h>
34bb535300SJeff Roberson #include <libc_private.h>
35a091d823SDavid Xu #include <spinlock.h>
36bb535300SJeff Roberson
37bb535300SJeff Roberson #include "thr_private.h"
38bb535300SJeff Roberson
3990dc7952SJason Evans #define MAX_SPINLOCKS 72
40dec04f43SMike Makonnen
41dec04f43SMike Makonnen /*
42a091d823SDavid Xu * These data structures are used to trace all spinlocks
43a091d823SDavid Xu * in libc.
44dec04f43SMike Makonnen */
45a091d823SDavid Xu struct spinlock_extra {
46a091d823SDavid Xu spinlock_t *owner;
47bddd24cdSDavid Xu struct umutex lock;
48a091d823SDavid Xu };
49dec04f43SMike Makonnen
50bddd24cdSDavid Xu static struct umutex spinlock_static_lock = DEFAULT_UMUTEX;
51a091d823SDavid Xu static struct spinlock_extra extra[MAX_SPINLOCKS];
52a091d823SDavid Xu static int spinlock_count;
53a091d823SDavid Xu static int initialized;
54dec04f43SMike Makonnen
55a091d823SDavid Xu static void init_spinlock(spinlock_t *lck);
56a091d823SDavid Xu
57a091d823SDavid Xu /*
58*dbb1c64eSEric van Gyzen * These are for compatibility only. Spinlocks of this type
59a091d823SDavid Xu * are deprecated.
60a091d823SDavid Xu */
61dec04f43SMike Makonnen
62bb535300SJeff Roberson void
__thr_spinunlock(spinlock_t * lck)6345468c53SKonstantin Belousov __thr_spinunlock(spinlock_t *lck)
64bb535300SJeff Roberson {
65d0aa4fd3SXin LI struct spinlock_extra *_extra;
66bddd24cdSDavid Xu
6707f29d9fSEric van Gyzen _extra = lck->thr_extra;
68d0aa4fd3SXin LI THR_UMUTEX_UNLOCK(_get_curthread(), &_extra->lock);
69bb535300SJeff Roberson }
70bb535300SJeff Roberson
71bb535300SJeff Roberson void
__thr_spinlock(spinlock_t * lck)7245468c53SKonstantin Belousov __thr_spinlock(spinlock_t *lck)
73bb535300SJeff Roberson {
74d0aa4fd3SXin LI struct spinlock_extra *_extra;
75bddd24cdSDavid Xu
76*dbb1c64eSEric van Gyzen if (!_thr_isthreaded())
77a091d823SDavid Xu PANIC("Spinlock called when not threaded.");
78a091d823SDavid Xu if (!initialized)
79a091d823SDavid Xu PANIC("Spinlocks not initialized.");
8007f29d9fSEric van Gyzen if (lck->thr_extra == NULL)
81a091d823SDavid Xu init_spinlock(lck);
8207f29d9fSEric van Gyzen _extra = lck->thr_extra;
83d0aa4fd3SXin LI THR_UMUTEX_LOCK(_get_curthread(), &_extra->lock);
8459a47b31SMike Makonnen }
8559a47b31SMike Makonnen
86a091d823SDavid Xu static void
init_spinlock(spinlock_t * lck)87a091d823SDavid Xu init_spinlock(spinlock_t *lck)
88a091d823SDavid Xu {
89bddd24cdSDavid Xu struct pthread *curthread = _get_curthread();
90a091d823SDavid Xu
91bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &spinlock_static_lock);
9207f29d9fSEric van Gyzen if ((lck->thr_extra == NULL) && (spinlock_count < MAX_SPINLOCKS)) {
9307f29d9fSEric van Gyzen lck->thr_extra = &extra[spinlock_count];
94bddd24cdSDavid Xu _thr_umutex_init(&extra[spinlock_count].lock);
95a091d823SDavid Xu extra[spinlock_count].owner = lck;
96a091d823SDavid Xu spinlock_count++;
97a091d823SDavid Xu }
98bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &spinlock_static_lock);
9907f29d9fSEric van Gyzen if (lck->thr_extra == NULL)
100bddd24cdSDavid Xu PANIC("Warning: exceeded max spinlocks");
101a091d823SDavid Xu }
102a091d823SDavid Xu
103a091d823SDavid Xu void
_thr_spinlock_init(void)104a091d823SDavid Xu _thr_spinlock_init(void)
105a091d823SDavid Xu {
106a091d823SDavid Xu int i;
107a091d823SDavid Xu
108bddd24cdSDavid Xu _thr_umutex_init(&spinlock_static_lock);
109a091d823SDavid Xu if (initialized != 0) {
110a091d823SDavid Xu /*
111a091d823SDavid Xu * called after fork() to reset state of libc spin locks,
112a091d823SDavid Xu * it is not quite right since libc may be in inconsistent
113a091d823SDavid Xu * state, resetting the locks to allow current thread to be
114a091d823SDavid Xu * able to hold them may not help things too much, but
115a091d823SDavid Xu * anyway, we do our best.
116a091d823SDavid Xu * it is better to do pthread_atfork in libc.
117a091d823SDavid Xu */
118a091d823SDavid Xu for (i = 0; i < spinlock_count; i++)
119bddd24cdSDavid Xu _thr_umutex_init(&extra[i].lock);
120a091d823SDavid Xu } else {
121a091d823SDavid Xu initialized = 1;
122a091d823SDavid Xu }
123bb535300SJeff Roberson }
124