1234353Sdim/*
2198090Srdivacky * Copyright 2010-2015 Samy Al Bahra.
3198090Srdivacky * All rights reserved.
4198090Srdivacky *
5198090Srdivacky * Redistribution and use in source and binary forms, with or without
6198090Srdivacky * modification, are permitted provided that the following conditions
7198090Srdivacky * are met:
8198090Srdivacky * 1. Redistributions of source code must retain the above copyright
9198090Srdivacky *    notice, this list of conditions and the following disclaimer.
10198090Srdivacky * 2. Redistributions in binary form must reproduce the above copyright
11198090Srdivacky *    notice, this list of conditions and the following disclaimer in the
12198090Srdivacky *    documentation and/or other materials provided with the distribution.
13249423Sdim *
14249423Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15249423Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16198090Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17198090Srdivacky * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18234353Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19198090Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20198090Srdivacky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21276479Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22276479Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23210299Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24210299Sed * SUCH DAMAGE.
25198090Srdivacky */
26198090Srdivacky
27210299Sed#ifndef CK_SPINLOCK_FAS_H
28210299Sed#define CK_SPINLOCK_FAS_H
29198090Srdivacky
30212904Sdim#include <ck_backoff.h>
31198090Srdivacky#include <ck_cc.h>
32261991Sdim#include <ck_elide.h>
33198090Srdivacky#include <ck_pr.h>
34210299Sed#include <ck_stdbool.h>
35198090Srdivacky
36198090Srdivacky#ifndef CK_F_SPINLOCK_FAS
37276479Sdim#define CK_F_SPINLOCK_FAS
38198090Srdivacky
39276479Sdimstruct ck_spinlock_fas {
40198090Srdivacky	unsigned int value;
41198090Srdivacky};
42198090Srdivackytypedef struct ck_spinlock_fas ck_spinlock_fas_t;
43198090Srdivacky
44210299Sed#define CK_SPINLOCK_FAS_INITIALIZER {false}
45210299Sed
46210299SedCK_CC_INLINE static void
47210299Sedck_spinlock_fas_init(struct ck_spinlock_fas *lock)
48210299Sed{
49198090Srdivacky
50198090Srdivacky	lock->value = false;
51198090Srdivacky	ck_pr_barrier();
52198090Srdivacky	return;
53210299Sed}
54210299Sed
55210299SedCK_CC_INLINE static bool
56210299Sedck_spinlock_fas_trylock(struct ck_spinlock_fas *lock)
57210299Sed{
58210299Sed	bool value;
59210299Sed
60210299Sed	value = ck_pr_fas_uint(&lock->value, true);
61210299Sed	ck_pr_fence_lock();
62210299Sed
63210299Sed	return !value;
64210299Sed}
65210299Sed
66210299SedCK_CC_INLINE static bool
67210299Sedck_spinlock_fas_locked(struct ck_spinlock_fas *lock)
68210299Sed{
69210299Sed	bool r;
70210299Sed
71210299Sed	r = ck_pr_load_uint(&lock->value);
72210299Sed	ck_pr_fence_acquire();
73210299Sed	return r;
74210299Sed}
75210299Sed
76210299SedCK_CC_INLINE static void
77210299Sedck_spinlock_fas_lock(struct ck_spinlock_fas *lock)
78261991Sdim{
79261991Sdim
80210299Sed        while (CK_CC_UNLIKELY(ck_pr_fas_uint(&lock->value, true) == true)) {
81210299Sed                do {
82210299Sed                        ck_pr_stall();
83210299Sed                } while (ck_pr_load_uint(&lock->value) == true);
84210299Sed        }
85261991Sdim
86261991Sdim	ck_pr_fence_lock();
87210299Sed	return;
88210299Sed}
89210299Sed
90210299SedCK_CC_INLINE static void
91198090Srdivackyck_spinlock_fas_lock_eb(struct ck_spinlock_fas *lock)
92198090Srdivacky{
93288943Sdim	ck_backoff_t backoff = CK_BACKOFF_INITIALIZER;
94288943Sdim
95288943Sdim	while (ck_pr_fas_uint(&lock->value, true) == true)
96288943Sdim		ck_backoff_eb(&backoff);
97288943Sdim
98288943Sdim	ck_pr_fence_lock();
99288943Sdim	return;
100288943Sdim}
101288943Sdim
102288943SdimCK_CC_INLINE static void
103288943Sdimck_spinlock_fas_unlock(struct ck_spinlock_fas *lock)
104288943Sdim{
105288943Sdim
106212904Sdim	ck_pr_fence_unlock();
107212904Sdim	ck_pr_store_uint(&lock->value, false);
108212904Sdim	return;
109212904Sdim}
110212904Sdim
111212904SdimCK_ELIDE_PROTOTYPE(ck_spinlock_fas, ck_spinlock_fas_t,
112212904Sdim    ck_spinlock_fas_locked, ck_spinlock_fas_lock,
113212904Sdim    ck_spinlock_fas_locked, ck_spinlock_fas_unlock)
114212904Sdim
115212904SdimCK_ELIDE_TRYLOCK_PROTOTYPE(ck_spinlock_fas, ck_spinlock_fas_t,
116212904Sdim    ck_spinlock_fas_locked, ck_spinlock_fas_trylock)
117212904Sdim
118210299Sed#endif /* CK_F_SPINLOCK_FAS */
119210299Sed#endif /* CK_SPINLOCK_FAS_H */
120210299Sed