Path: blob/main/sys/contrib/ck/include/ck_cohort.h
48255 views
/*1* Copyright 2013-2015 Samy Al Bahra.2* Copyright 2013 Brendon Scheinman.3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#ifndef CK_COHORT_H28#define CK_COHORT_H2930/*31* This is an implementation of lock cohorts as described in:32* Dice, D.; Marathe, V.; and Shavit, N. 2012.33* Lock Cohorting: A General Technique for Designing NUMA Locks34*/3536#include <ck_cc.h>37#include <ck_pr.h>38#include <ck_stddef.h>3940enum ck_cohort_state {41CK_COHORT_STATE_GLOBAL = 0,42CK_COHORT_STATE_LOCAL = 143};4445#define CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT 104647#define CK_COHORT_NAME(N) ck_cohort_##N48#define CK_COHORT_INSTANCE(N) struct CK_COHORT_NAME(N)49#define CK_COHORT_INIT(N, C, GL, LL, P) ck_cohort_##N##_init(C, GL, LL, P)50#define CK_COHORT_LOCK(N, C, GC, LC) ck_cohort_##N##_lock(C, GC, LC)51#define CK_COHORT_UNLOCK(N, C, GC, LC) ck_cohort_##N##_unlock(C, GC, LC)52#define CK_COHORT_TRYLOCK(N, C, GLC, LLC, LUC) ck_cohort_##N##_trylock(C, GLC, LLC, LUC)53#define CK_COHORT_LOCKED(N, C, GC, LC) ck_cohort_##N##_locked(C, GC, LC)5455#define CK_COHORT_PROTOTYPE(N, GL, GU, GI, LL, LU, LI) \56CK_COHORT_INSTANCE(N) { \57void *global_lock; \58void *local_lock; \59enum ck_cohort_state release_state; \60unsigned int waiting_threads; \61unsigned int acquire_count; \62unsigned int local_pass_limit; \63}; \64\65CK_CC_INLINE static void \66ck_cohort_##N##_init(struct ck_cohort_##N *cohort, \67void *global_lock, void *local_lock, unsigned int pass_limit) \68{ \69cohort->global_lock = global_lock; \70cohort->local_lock = local_lock; \71cohort->release_state = CK_COHORT_STATE_GLOBAL; \72cohort->waiting_threads = 0; \73cohort->acquire_count = 0; \74cohort->local_pass_limit = pass_limit; \75ck_pr_barrier(); \76return; \77} \78\79CK_CC_INLINE static void \80ck_cohort_##N##_lock(CK_COHORT_INSTANCE(N) *cohort, \81void *global_context, void *local_context) \82{ \83\84ck_pr_inc_uint(&cohort->waiting_threads); \85LL(cohort->local_lock, local_context); \86ck_pr_dec_uint(&cohort->waiting_threads); \87\88if (cohort->release_state == CK_COHORT_STATE_GLOBAL) { \89GL(cohort->global_lock, global_context); \90} \91\92++cohort->acquire_count; \93return; \94} \95\96CK_CC_INLINE static void \97ck_cohort_##N##_unlock(CK_COHORT_INSTANCE(N) *cohort, \98void *global_context, void *local_context) \99{ \100\101if (ck_pr_load_uint(&cohort->waiting_threads) > 0 \102&& cohort->acquire_count < cohort->local_pass_limit) { \103cohort->release_state = CK_COHORT_STATE_LOCAL; \104} else { \105GU(cohort->global_lock, global_context); \106cohort->release_state = CK_COHORT_STATE_GLOBAL; \107cohort->acquire_count = 0; \108} \109\110ck_pr_fence_release(); \111LU(cohort->local_lock, local_context); \112\113return; \114} \115\116CK_CC_INLINE static bool \117ck_cohort_##N##_locked(CK_COHORT_INSTANCE(N) *cohort, \118void *global_context, void *local_context) \119{ \120return GI(cohort->local_lock, local_context) || \121LI(cohort->global_lock, global_context); \122}123124#define CK_COHORT_TRYLOCK_PROTOTYPE(N, GL, GU, GI, GTL, LL, LU, LI, LTL) \125CK_COHORT_PROTOTYPE(N, GL, GU, GI, LL, LU, LI) \126CK_CC_INLINE static bool \127ck_cohort_##N##_trylock(CK_COHORT_INSTANCE(N) *cohort, \128void *global_context, void *local_context, \129void *local_unlock_context) \130{ \131\132bool trylock_result; \133\134ck_pr_inc_uint(&cohort->waiting_threads); \135trylock_result = LTL(cohort->local_lock, local_context); \136ck_pr_dec_uint(&cohort->waiting_threads); \137if (trylock_result == false) { \138return false; \139} \140\141if (cohort->release_state == CK_COHORT_STATE_GLOBAL && \142GTL(cohort->global_lock, global_context) == false) { \143LU(cohort->local_lock, local_unlock_context); \144return false; \145} \146\147++cohort->acquire_count; \148return true; \149}150151#define CK_COHORT_INITIALIZER { \152.global_lock = NULL, \153.local_lock = NULL, \154.release_state = CK_COHORT_STATE_GLOBAL, \155.waiting_threads = 0, \156.acquire_count = 0, \157.local_pass_limit = CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT \158}159160#endif /* CK_COHORT_H */161162163