Path: blob/main/sys/contrib/ck/include/spinlock/anderson.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_ANDERSON_H27#define CK_SPINLOCK_ANDERSON_H2829#include <ck_cc.h>30#include <ck_limits.h>31#include <ck_md.h>32#include <ck_pr.h>33#include <ck_stdbool.h>3435#ifndef CK_F_SPINLOCK_ANDERSON36#define CK_F_SPINLOCK_ANDERSON37/*38* This is an implementation of Anderson's array-based queuing lock.39*/40struct ck_spinlock_anderson_thread {41unsigned int locked;42unsigned int position;43};44typedef struct ck_spinlock_anderson_thread ck_spinlock_anderson_thread_t;4546struct ck_spinlock_anderson {47struct ck_spinlock_anderson_thread *slots;48unsigned int count;49unsigned int wrap;50unsigned int mask;51char pad[CK_MD_CACHELINE - sizeof(unsigned int) * 3 - sizeof(void *)];52unsigned int next;53};54typedef struct ck_spinlock_anderson ck_spinlock_anderson_t;5556CK_CC_INLINE static void57ck_spinlock_anderson_init(struct ck_spinlock_anderson *lock,58struct ck_spinlock_anderson_thread *slots,59unsigned int count)60{61unsigned int i;6263slots[0].locked = false;64slots[0].position = 0;65for (i = 1; i < count; i++) {66slots[i].locked = true;67slots[i].position = i;68}6970lock->slots = slots;71lock->count = count;72lock->mask = count - 1;73lock->next = 0;7475/*76* If the number of threads is not a power of two then compute77* appropriate wrap-around value in the case of next slot counter78* overflow.79*/80if (count & (count - 1))81lock->wrap = (UINT_MAX % count) + 1;82else83lock->wrap = 0;8485ck_pr_barrier();86return;87}8889CK_CC_INLINE static bool90ck_spinlock_anderson_locked(struct ck_spinlock_anderson *lock)91{92unsigned int position;93bool r;9495position = ck_pr_load_uint(&lock->next) & lock->mask;96r = ck_pr_load_uint(&lock->slots[position].locked);97ck_pr_fence_acquire();98return r;99}100101CK_CC_INLINE static void102ck_spinlock_anderson_lock(struct ck_spinlock_anderson *lock,103struct ck_spinlock_anderson_thread **slot)104{105unsigned int position, next;106unsigned int count = lock->count;107108/*109* If count is not a power of 2, then it is possible for an overflow110* to reallocate beginning slots to more than one thread. To avoid this111* use a compare-and-swap.112*/113if (lock->wrap != 0) {114position = ck_pr_load_uint(&lock->next);115116do {117if (position == UINT_MAX)118next = lock->wrap;119else120next = position + 1;121} while (ck_pr_cas_uint_value(&lock->next, position,122next, &position) == false);123124position %= count;125} else {126position = ck_pr_faa_uint(&lock->next, 1);127position &= lock->mask;128}129130/* Serialize with respect to previous thread's store. */131ck_pr_fence_load();132133/*134* Spin until slot is marked as unlocked. First slot is initialized to135* false.136*/137while (ck_pr_load_uint(&lock->slots[position].locked) == true)138ck_pr_stall();139140/* Prepare slot for potential re-use by another thread. */141ck_pr_store_uint(&lock->slots[position].locked, true);142ck_pr_fence_lock();143144*slot = lock->slots + position;145return;146}147148CK_CC_INLINE static void149ck_spinlock_anderson_unlock(struct ck_spinlock_anderson *lock,150struct ck_spinlock_anderson_thread *slot)151{152unsigned int position;153154ck_pr_fence_unlock();155156/* Mark next slot as available. */157if (lock->wrap == 0)158position = (slot->position + 1) & lock->mask;159else160position = (slot->position + 1) % lock->count;161162ck_pr_store_uint(&lock->slots[position].locked, false);163return;164}165#endif /* CK_F_SPINLOCK_ANDERSON */166#endif /* CK_SPINLOCK_ANDERSON_H */167168169