Path: blob/main/sys/contrib/ck/include/spinlock/mcs.h
48375 views
/*1* Copyright 2010-2015 Samy Al Bahra.2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#ifndef CK_SPINLOCK_MCS_H27#define CK_SPINLOCK_MCS_H2829#include <ck_cc.h>30#include <ck_pr.h>31#include <ck_stdbool.h>32#include <ck_stddef.h>3334#ifndef CK_F_SPINLOCK_MCS35#define CK_F_SPINLOCK_MCS3637struct ck_spinlock_mcs {38unsigned int locked;39struct ck_spinlock_mcs *next;40};41typedef struct ck_spinlock_mcs * ck_spinlock_mcs_t;42typedef struct ck_spinlock_mcs ck_spinlock_mcs_context_t;4344#define CK_SPINLOCK_MCS_INITIALIZER (NULL)4546CK_CC_INLINE static void47ck_spinlock_mcs_init(struct ck_spinlock_mcs **queue)48{4950*queue = NULL;51ck_pr_barrier();52return;53}5455CK_CC_INLINE static bool56ck_spinlock_mcs_trylock(struct ck_spinlock_mcs **queue,57struct ck_spinlock_mcs *node)58{59bool r;6061node->locked = true;62node->next = NULL;63ck_pr_fence_store_atomic();6465r = ck_pr_cas_ptr(queue, NULL, node);66ck_pr_fence_lock();67return r;68}6970CK_CC_INLINE static bool71ck_spinlock_mcs_locked(struct ck_spinlock_mcs **queue)72{73bool r;7475r = ck_pr_load_ptr(queue) != NULL;76ck_pr_fence_acquire();77return r;78}7980CK_CC_INLINE static void81ck_spinlock_mcs_lock(struct ck_spinlock_mcs **queue,82struct ck_spinlock_mcs *node)83{84struct ck_spinlock_mcs *previous;8586/*87* In the case that there is a successor, let them know they must88* wait for us to unlock.89*/90node->locked = true;91node->next = NULL;92ck_pr_fence_store_atomic();9394/*95* Swap current tail with current lock request. If the swap operation96* returns NULL, it means the queue was empty. If the queue was empty,97* then the operation is complete.98*/99previous = ck_pr_fas_ptr(queue, node);100if (previous != NULL) {101/*102* Let the previous lock holder know that we are waiting on103* them.104*/105ck_pr_store_ptr(&previous->next, node);106while (ck_pr_load_uint(&node->locked) == true)107ck_pr_stall();108}109110ck_pr_fence_lock();111return;112}113114CK_CC_INLINE static void115ck_spinlock_mcs_unlock(struct ck_spinlock_mcs **queue,116struct ck_spinlock_mcs *node)117{118struct ck_spinlock_mcs *next;119120ck_pr_fence_unlock();121122next = ck_pr_load_ptr(&node->next);123if (next == NULL) {124/*125* If there is no request following us then it is a possibilty126* that we are the current tail. In this case, we may just127* mark the spinlock queue as empty.128*/129if (ck_pr_load_ptr(queue) == node &&130ck_pr_cas_ptr(queue, node, NULL) == true) {131return;132}133134/*135* If the node is not the current tail then a lock operation136* is in-progress. In this case, busy-wait until the queue is137* in a consistent state to wake up the incoming lock138* request.139*/140for (;;) {141next = ck_pr_load_ptr(&node->next);142if (next != NULL)143break;144145ck_pr_stall();146}147}148149/* Allow the next lock operation to complete. */150ck_pr_store_uint(&next->locked, false);151return;152}153#endif /* CK_F_SPINLOCK_MCS */154#endif /* CK_SPINLOCK_MCS_H */155156157