171b3fa15SDavid Xu /*
271b3fa15SDavid Xu * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
371b3fa15SDavid Xu * All rights reserved.
471b3fa15SDavid Xu *
571b3fa15SDavid Xu * Redistribution and use in source and binary forms, with or without
671b3fa15SDavid Xu * modification, are permitted provided that the following conditions
771b3fa15SDavid Xu * are met:
871b3fa15SDavid Xu * 1. Redistributions of source code must retain the above copyright
971b3fa15SDavid Xu * notice, this list of conditions and the following disclaimer.
1071b3fa15SDavid Xu * 2. Redistributions in binary form must reproduce the above copyright
1171b3fa15SDavid Xu * notice, this list of conditions and the following disclaimer in the
1271b3fa15SDavid Xu * documentation and/or other materials provided with the distribution.
13d3b15642Szrj * 3. Neither the name of the author nor the names of any co-contributors
1471b3fa15SDavid Xu * may be used to endorse or promote products derived from this software
1571b3fa15SDavid Xu * without specific prior written permission.
1671b3fa15SDavid Xu *
1771b3fa15SDavid Xu * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
1871b3fa15SDavid Xu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1971b3fa15SDavid Xu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2071b3fa15SDavid Xu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2171b3fa15SDavid Xu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2271b3fa15SDavid Xu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2371b3fa15SDavid Xu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2471b3fa15SDavid Xu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2571b3fa15SDavid Xu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2671b3fa15SDavid Xu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2771b3fa15SDavid Xu * SUCH DAMAGE.
2871b3fa15SDavid Xu *
2971b3fa15SDavid Xu */
3071b3fa15SDavid Xu
3171b3fa15SDavid Xu #include <sys/types.h>
3271b3fa15SDavid Xu #include <machine/atomic.h>
339e2ee207SJoerg Sonnenberger #include <machine/tls.h>
3471b3fa15SDavid Xu #include <pthread.h>
3571b3fa15SDavid Xu #include <libc_private.h>
3671b3fa15SDavid Xu #include "spinlock.h"
37fc71f871SDavid Xu
3871b3fa15SDavid Xu #include "thr_private.h"
3971b3fa15SDavid Xu
40ebe0d361SMatthew Dillon #define MAX_SPINLOCKS 256
4171b3fa15SDavid Xu
4271b3fa15SDavid Xu /*
4371b3fa15SDavid Xu * These data structures are used to trace all spinlocks
4471b3fa15SDavid Xu * in libc.
4571b3fa15SDavid Xu */
4671b3fa15SDavid Xu struct spinlock_extra {
4771b3fa15SDavid Xu spinlock_t *owner;
4871b3fa15SDavid Xu };
4971b3fa15SDavid Xu
5071b3fa15SDavid Xu static umtx_t spinlock_static_lock;
5171b3fa15SDavid Xu static struct spinlock_extra extra[MAX_SPINLOCKS];
5271b3fa15SDavid Xu static int spinlock_count;
5371b3fa15SDavid Xu static int initialized;
5471b3fa15SDavid Xu
5571b3fa15SDavid Xu static void init_spinlock(spinlock_t *lck);
5671b3fa15SDavid Xu
5771b3fa15SDavid Xu /*
58721505deSMatthew Dillon * These functions implement temporary spinlocks as used by libc.
59721505deSMatthew Dillon * these are not persistent spinlocks, so we use the API for
60721505deSMatthew Dillon * temporary locks which block all signals for the duration.
6171b3fa15SDavid Xu */
6271b3fa15SDavid Xu void
_spinunlock(spinlock_t * lck)6371b3fa15SDavid Xu _spinunlock(spinlock_t *lck)
6471b3fa15SDavid Xu {
65*940be950Szrj pthread_t curthread = tls_get_curthread();
669e2ee207SJoerg Sonnenberger
67fc71f871SDavid Xu THR_UMTX_UNLOCK(curthread, (volatile umtx_t *)&lck->access_lock);
6871b3fa15SDavid Xu }
6971b3fa15SDavid Xu
7071b3fa15SDavid Xu void
_spinlock(spinlock_t * lck)7171b3fa15SDavid Xu _spinlock(spinlock_t *lck)
7271b3fa15SDavid Xu {
73*940be950Szrj pthread_t curthread;
749e2ee207SJoerg Sonnenberger
7571b3fa15SDavid Xu if (!__isthreaded)
7671b3fa15SDavid Xu PANIC("Spinlock called when not threaded.");
7771b3fa15SDavid Xu if (!initialized)
7871b3fa15SDavid Xu PANIC("Spinlocks not initialized.");
7971b3fa15SDavid Xu if (lck->fname == NULL)
8071b3fa15SDavid Xu init_spinlock(lck);
819e2ee207SJoerg Sonnenberger
829e2ee207SJoerg Sonnenberger curthread = tls_get_curthread();
83fc71f871SDavid Xu THR_UMTX_LOCK(curthread, (volatile umtx_t *)&lck->access_lock);
8471b3fa15SDavid Xu }
8571b3fa15SDavid Xu
8682949828SMatthew Dillon /*
8782949828SMatthew Dillon * Returns 0 on success, else EBUSY
8882949828SMatthew Dillon */
8982949828SMatthew Dillon int
_spintrylock(spinlock_t * lck)9082949828SMatthew Dillon _spintrylock(spinlock_t *lck)
9182949828SMatthew Dillon {
92*940be950Szrj pthread_t curthread;
9382949828SMatthew Dillon
9482949828SMatthew Dillon if (!__isthreaded)
9582949828SMatthew Dillon PANIC("Spinlock called when not threaded.");
9682949828SMatthew Dillon if (!initialized)
9782949828SMatthew Dillon PANIC("Spinlocks not initialized.");
9882949828SMatthew Dillon if (lck->fname == NULL)
9982949828SMatthew Dillon init_spinlock(lck);
10082949828SMatthew Dillon
10182949828SMatthew Dillon curthread = tls_get_curthread();
10282949828SMatthew Dillon return(THR_UMTX_TRYLOCK(curthread,
10382949828SMatthew Dillon (volatile umtx_t *)&lck->access_lock));
10482949828SMatthew Dillon }
10582949828SMatthew Dillon
10671b3fa15SDavid Xu void
_spinlock_debug(spinlock_t * lck,char * fname __unused,int lineno __unused)107fc71f871SDavid Xu _spinlock_debug(spinlock_t *lck, char *fname __unused, int lineno __unused)
10871b3fa15SDavid Xu {
10971b3fa15SDavid Xu _spinlock(lck);
11071b3fa15SDavid Xu }
11171b3fa15SDavid Xu
11271b3fa15SDavid Xu static void
init_spinlock(spinlock_t * lck)11371b3fa15SDavid Xu init_spinlock(spinlock_t *lck)
11471b3fa15SDavid Xu {
11571b3fa15SDavid Xu static int count = 0;
116*940be950Szrj pthread_t curthread = tls_get_curthread();
11771b3fa15SDavid Xu
1189e2ee207SJoerg Sonnenberger THR_UMTX_LOCK(curthread, &spinlock_static_lock);
11971b3fa15SDavid Xu if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) {
12071b3fa15SDavid Xu lck->fname = (char *)&extra[spinlock_count];
12171b3fa15SDavid Xu extra[spinlock_count].owner = lck;
12271b3fa15SDavid Xu spinlock_count++;
12371b3fa15SDavid Xu }
1249e2ee207SJoerg Sonnenberger THR_UMTX_UNLOCK(curthread, &spinlock_static_lock);
12571b3fa15SDavid Xu if (lck->fname == NULL && ++count < 5)
12671b3fa15SDavid Xu stderr_debug("Warning: exceeded max spinlocks");
12771b3fa15SDavid Xu }
12871b3fa15SDavid Xu
12971b3fa15SDavid Xu void
_thr_spinlock_init(void)13071b3fa15SDavid Xu _thr_spinlock_init(void)
13171b3fa15SDavid Xu {
13271b3fa15SDavid Xu int i;
13371b3fa15SDavid Xu
13471b3fa15SDavid Xu _thr_umtx_init(&spinlock_static_lock);
13571b3fa15SDavid Xu if (initialized != 0) {
13671b3fa15SDavid Xu /*
13771b3fa15SDavid Xu * called after fork() to reset state of libc spin locks,
13871b3fa15SDavid Xu * it is not quite right since libc may be in inconsistent
13971b3fa15SDavid Xu * state, resetting the locks to allow current thread to be
14071b3fa15SDavid Xu * able to hold them may not help things too much, but
14171b3fa15SDavid Xu * anyway, we do our best.
14271b3fa15SDavid Xu * it is better to do pthread_atfork in libc.
14371b3fa15SDavid Xu */
14471b3fa15SDavid Xu for (i = 0; i < spinlock_count; i++)
145fc71f871SDavid Xu _thr_umtx_init((volatile umtx_t *)
146fc71f871SDavid Xu &extra[i].owner->access_lock);
14771b3fa15SDavid Xu } else {
14871b3fa15SDavid Xu initialized = 1;
14971b3fa15SDavid Xu }
15071b3fa15SDavid Xu }
151