1/*	$OpenBSD: rthread_spin_lock.c,v 1.5 2020/04/06 00:01:08 pirofti Exp $	*/
2/*
3 * Copyright (c) 2012 Paul Irofti <paul@irofti.net>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <errno.h>
19#include <stdlib.h>
20
21#include <pthread.h>
22
23#include "rthread.h"
24
25int
26pthread_spin_init(pthread_spinlock_t *lock, int pshared)
27{
28	pthread_spinlock_t l = NULL;
29
30	if (lock == NULL)
31		return (EINVAL);
32
33	if (pshared != PTHREAD_PROCESS_PRIVATE)
34		return (ENOTSUP);
35
36	l = calloc(1, sizeof *l);
37	if (l == NULL)
38		return (ENOMEM);
39
40	l->lock = _SPINLOCK_UNLOCKED;
41	*lock = l;
42	return (0);
43}
44
45int
46pthread_spin_destroy(pthread_spinlock_t *lock)
47{
48	if (lock == NULL || *lock == NULL)
49		return (EINVAL);
50
51	if ((*lock)->owner != NULL)
52		return (EBUSY);
53
54	free(*lock);
55	*lock = NULL;
56	return (0);
57}
58
59int
60pthread_spin_trylock(pthread_spinlock_t *lock)
61{
62	pthread_t self = pthread_self();
63	pthread_spinlock_t l;
64
65	if (lock == NULL || *lock == NULL)
66		return (EINVAL);
67
68	l = *lock;
69
70	if (l->owner == self)
71		return (EDEADLK);
72	if (!_spinlocktry(&l->lock))
73		return (EBUSY);
74
75	l->owner = self;
76	return (0);
77}
78
79int
80pthread_spin_lock(pthread_spinlock_t *lock)
81{
82	pthread_t self = pthread_self();
83	pthread_spinlock_t l;
84
85	if (lock == NULL || *lock == NULL)
86		return (EINVAL);
87
88	l = *lock;
89
90	if (l->owner == self)
91		return (EDEADLK);
92
93	_spinlock(&l->lock);
94	l->owner = self;
95	return (0);
96}
97
98int
99pthread_spin_unlock(pthread_spinlock_t *lock)
100{
101	pthread_t self = pthread_self();
102	pthread_spinlock_t l;
103
104	if (lock == NULL || *lock == NULL)
105		return (EINVAL);
106
107	l = *lock;
108
109	if (l->owner != self)
110		return (EPERM);
111
112	l->owner = NULL;
113	_spinunlock(&l->lock);
114	return (0);
115}
116