/* * include/haproxy/thread-t.h * Definitions and types for thread support. * * Copyright (C) 2017 Christopher Faulet - cfaulet@haproxy.com * Copyright (C) 2020 Willy Tarreau - w@1wt.eu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, version 2.1 * exclusively. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _HAPROXY_THREAD_T_H #define _HAPROXY_THREAD_T_H #include /* Note: this file mainly contains 3 sections: * - one used solely when USE_THREAD is *not* set * - one used solely when USE_THREAD is set * - a common one. */ #ifndef USE_THREAD /********************** THREADS DISABLED ************************/ /* These macros allow to make some struct fields or local variables optional */ #define __decl_spinlock(lock) #define __decl_aligned_spinlock(lock) #define __decl_rwlock(lock) #define __decl_aligned_rwlock(lock) #elif !defined(DEBUG_THREAD) && !defined(DEBUG_FULL) /************** THREADS ENABLED WITHOUT DEBUGGING **************/ /* declare a self-initializing spinlock */ #define __decl_spinlock(lock) \ HA_SPINLOCK_T (lock) = 0; /* declare a self-initializing spinlock, aligned on a cache line */ #define __decl_aligned_spinlock(lock) \ HA_SPINLOCK_T (lock) __attribute__((aligned(64))) = 0; /* declare a self-initializing rwlock */ #define __decl_rwlock(lock) \ HA_RWLOCK_T (lock) = 0; /* declare a self-initializing rwlock, aligned on a cache line */ #define __decl_aligned_rwlock(lock) \ HA_RWLOCK_T (lock) __attribute__((aligned(64))) = 0; #else /* !USE_THREAD */ /**************** THREADS ENABLED WITH DEBUGGING ***************/ /* declare a self-initializing spinlock */ #define __decl_spinlock(lock) \ HA_SPINLOCK_T (lock); \ INITCALL1(STG_LOCK, ha_spin_init, &(lock)) /* declare a self-initializing spinlock, aligned on a cache line */ #define __decl_aligned_spinlock(lock) \ HA_SPINLOCK_T (lock) __attribute__((aligned(64))); \ INITCALL1(STG_LOCK, ha_spin_init, &(lock)) /* declare a self-initializing rwlock */ #define __decl_rwlock(lock) \ HA_RWLOCK_T (lock); \ INITCALL1(STG_LOCK, ha_rwlock_init, &(lock)) /* declare a self-initializing rwlock, aligned on a cache line */ #define __decl_aligned_rwlock(lock) \ HA_RWLOCK_T (lock) __attribute__((aligned(64))); \ INITCALL1(STG_LOCK, ha_rwlock_init, &(lock)) #endif /* USE_THREAD */ /*** Common parts below ***/ /* storage types used by spinlocks and RW locks */ #define __HA_SPINLOCK_T unsigned long #define __HA_RWLOCK_T unsigned long /* When thread debugging is enabled, we remap HA_SPINLOCK_T and HA_RWLOCK_T to * complex structures which embed debugging info. */ #if !defined(DEBUG_THREAD) && !defined(DEBUG_FULL) #define HA_SPINLOCK_T __HA_SPINLOCK_T #define HA_RWLOCK_T __HA_RWLOCK_T #else /* !DEBUG_THREAD */ #define HA_SPINLOCK_T struct ha_spinlock #define HA_RWLOCK_T struct ha_rwlock /* Debugging information that is only used when thread debugging is enabled */ struct lock_stat { uint64_t nsec_wait_for_write; uint64_t nsec_wait_for_read; uint64_t nsec_wait_for_seek; uint64_t num_write_locked; uint64_t num_write_unlocked; uint64_t num_read_locked; uint64_t num_read_unlocked; uint64_t num_seek_locked; uint64_t num_seek_unlocked; }; struct ha_spinlock_state { unsigned long owner; /* a bit is set to 1 << tid for the lock owner */ unsigned long waiters; /* a bit is set to 1 << tid for waiting threads */ }; struct ha_rwlock_state { unsigned long cur_writer; /* a bit is set to 1 << tid for the lock owner */ unsigned long wait_writers; /* a bit is set to 1 << tid for waiting writers */ unsigned long cur_readers; /* a bit is set to 1 << tid for current readers */ unsigned long wait_readers; /* a bit is set to 1 << tid for waiting waiters */ unsigned long cur_seeker; /* a bit is set to 1 << tid for the lock seekers */ unsigned long wait_seekers; /* a bit is set to 1 << tid for waiting seekers */ }; struct ha_spinlock { __HA_SPINLOCK_T lock; struct { struct ha_spinlock_state st[MAX_TGROUPS]; struct { const char *function; const char *file; int line; } last_location; /* location of the last owner */ } info; }; struct ha_rwlock { __HA_RWLOCK_T lock; struct { struct ha_rwlock_state st[MAX_TGROUPS]; struct { const char *function; const char *file; int line; } last_location; /* location of the last write owner */ } info; }; #endif /* DEBUG_THREAD */ #endif /* _HAPROXY_THREAD_T_H */