Home | History | Annotate | Line # | Download | only in isc
      1 /*	$NetBSD: spinlock.h,v 1.2 2025/01/26 16:25:42 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #pragma once
     17 
     18 /*! \file */
     19 
     20 #include <pthread.h>
     21 #include <stdlib.h>
     22 
     23 #include <isc/atomic.h>
     24 #include <isc/lang.h>
     25 #include <isc/util.h>
     26 
     27 ISC_LANG_BEGINDECLS
     28 
     29 /*
     30  * We use macros instead of static inline functions so that the exact code
     31  * location can be reported when PTHREADS_RUNTIME_CHECK() fails or when mutrace
     32  * reports lock contention.
     33  */
     34 
     35 #ifdef ISC_TRACK_PTHREADS_OBJECTS
     36 
     37 #define isc_spinlock_init(sp)               \
     38 	{                                   \
     39 		*sp = malloc(sizeof(**sp)); \
     40 		isc__spinlock_init(*sp);    \
     41 	}
     42 #define isc_spinlock_lock(sp)	isc__spinlock_lock(*sp)
     43 #define isc_spinlock_unlock(sp) isc__spinlock_unlock(*sp)
     44 #define isc_spinlock_destroy(sp)            \
     45 	{                                   \
     46 		isc__spinlock_destroy(*sp); \
     47 		free((void *)*sp);          \
     48 	}
     49 
     50 #else /* ISC_TRACK_PTHREADS_OBJECTS */
     51 
     52 #define isc_spinlock_init(sp)	 isc__spinlock_init(sp)
     53 #define isc_spinlock_lock(sp)	 isc__spinlock_lock(sp)
     54 #define isc_spinlock_unlock(sp)	 isc__spinlock_unlock(sp)
     55 #define isc_spinlock_destroy(sp) isc__spinlock_destroy(sp)
     56 
     57 #endif /* ISC_TRACK_PTHREADS_OBJECTS */
     58 
     59 #if HAVE_PTHREAD_SPIN_INIT
     60 
     61 #if ISC_TRACK_PTHREADS_OBJECTS
     62 typedef pthread_spinlock_t *isc_spinlock_t;
     63 #else  /* ISC_TRACK_PTHREADS_OBJECTS */
     64 typedef pthread_spinlock_t isc_spinlock_t;
     65 #endif /* ISC_TRACK_PTHREADS_OBJECTS */
     66 
     67 #define isc__spinlock_init(sp)                                             \
     68 	{                                                                  \
     69 		int _ret = pthread_spin_init(sp, PTHREAD_PROCESS_PRIVATE); \
     70 		PTHREADS_RUNTIME_CHECK(pthread_spin_init, _ret);           \
     71 	}
     72 
     73 #define isc__spinlock_lock(sp)                                   \
     74 	{                                                        \
     75 		int _ret = pthread_spin_lock(sp);                \
     76 		PTHREADS_RUNTIME_CHECK(pthread_spin_lock, _ret); \
     77 	}
     78 
     79 #define isc__spinlock_unlock(sp)                                   \
     80 	{                                                          \
     81 		int _ret = pthread_spin_unlock(sp);                \
     82 		PTHREADS_RUNTIME_CHECK(pthread_spin_unlock, _ret); \
     83 	}
     84 
     85 #define isc__spinlock_destroy(sp)                                   \
     86 	{                                                           \
     87 		int _ret = pthread_spin_destroy(sp);                \
     88 		PTHREADS_RUNTIME_CHECK(pthread_spin_destroy, _ret); \
     89 	}
     90 
     91 #else /* HAVE_PTHREAD_SPIN_INIT */
     92 
     93 #if ISC_TRACK_PTHREADS_OBJECTS
     94 typedef atomic_uint_fast32_t *isc_spinlock_t;
     95 #else  /* ISC_TRACK_PTHREADS_OBJECTS */
     96 typedef atomic_uint_fast32_t isc_spinlock_t;
     97 #endif /* ISC_TRACK_PTHREADS_OBJECTS */
     98 
     99 #define isc__spinlock_init(sp)      \
    100 	{                           \
    101 		atomic_init(sp, 0); \
    102 	}
    103 
    104 #define isc__spinlock_lock(sp)                                  \
    105 	{                                                       \
    106 		while (!atomic_compare_exchange_weak_acq_rel(   \
    107 			sp, &(uint_fast32_t){ 0 }, 1))          \
    108 		{                                               \
    109 			do {                                    \
    110 				isc_pause();                    \
    111 			} while (atomic_load_relaxed(sp) != 0); \
    112 		}                                               \
    113 	}
    114 
    115 #define isc__spinlock_unlock(sp)             \
    116 	{                                    \
    117 		atomic_store_release(sp, 0); \
    118 	}
    119 
    120 #define isc__spinlock_destroy(sp)             \
    121 	{                                     \
    122 		INSIST(atomic_load(sp) == 0); \
    123 	}
    124 
    125 #endif
    126 
    127 ISC_LANG_ENDDECLS
    128