1 /* Low-level lock implementation. Mach gsync-based version. 2 Copyright (C) 1994-2022 Free Software Foundation, Inc. 3 This file is part of the GNU C Library. 4 5 The GNU C Library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 The GNU C Library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with the GNU C Library; if not, see 17 <https://www.gnu.org/licenses/>. */ 18 19 #ifndef _MACH_LOWLEVELLOCK_H 20 #define _MACH_LOWLEVELLOCK_H 1 21 22 #include <mach/gnumach.h> 23 #include <atomic.h> 24 25 /* Gsync flags. */ 26 #ifndef GSYNC_SHARED 27 # define GSYNC_SHARED 0x01 28 # define GSYNC_QUAD 0x02 29 # define GSYNC_TIMED 0x04 30 # define GSYNC_BROADCAST 0x08 31 # define GSYNC_MUTATE 0x10 32 #endif 33 34 /* Static initializer for low-level locks. */ 35 #define LLL_LOCK_INITIALIZER 0 36 37 #define LLL_PRIVATE 0 38 #define LLL_SHARED GSYNC_SHARED 39 40 /* Interruptible version of __gsync_wait. */ 41 extern kern_return_t __gsync_wait_intr 42 ( 43 mach_port_t task, 44 vm_offset_t addr, 45 unsigned val1, 46 unsigned val2, 47 natural_t msec, 48 int flags 49 ); 50 51 /* Wait on address PTR, without blocking if its contents 52 * are different from VAL. */ 53 #define __lll_wait(ptr, val, flags) \ 54 __gsync_wait (__mach_task_self (), \ 55 (vm_offset_t)(ptr), (val), 0, 0, (flags)) 56 #define lll_wait(var, val, flags) \ 57 __lll_wait (&(var), val, flags) 58 59 /* Interruptible version. */ 60 #define __lll_wait_intr(ptr, val, flags) \ 61 __gsync_wait_intr (__mach_task_self (), \ 62 (vm_offset_t)(ptr), (val), 0, 0, (flags)) 63 #define lll_wait_intr(var, val, flags) \ 64 __lll_wait_intr ((&var), val, flags) 65 66 /* Wake one or more threads waiting on address PTR. */ 67 #define __lll_wake(ptr, flags) \ 68 __gsync_wake (__mach_task_self (), (vm_offset_t)(ptr), 0, (flags)) 69 #define lll_wake(var, flags) \ 70 __lll_wake (&(var), flags) 71 72 /* Acquire the lock at PTR. */ 73 #define __lll_lock(ptr, flags) \ 74 ({ \ 75 int *__iptr = (int *)(ptr); \ 76 int __flags = (flags); \ 77 if (*__iptr != 0 \ 78 || atomic_compare_and_exchange_bool_acq (__iptr, 1, 0) != 0) \ 79 while (1) \ 80 { \ 81 if (atomic_exchange_acq (__iptr, 2) == 0) \ 82 break; \ 83 __lll_wait (__iptr, 2, __flags); \ 84 } \ 85 (void)0; \ 86 }) 87 #define lll_lock(var, flags) \ 88 __lll_lock (&(var), flags) 89 90 /* Try to acquire the lock at PTR, without blocking. 91 Evaluates to zero on success. */ 92 #define __lll_trylock(ptr) \ 93 ({ \ 94 int *__iptr = (int *)(ptr); \ 95 *__iptr == 0 \ 96 && atomic_compare_and_exchange_bool_acq (__iptr, 1, 0) == 0 ? 0 : -1; \ 97 }) 98 #define lll_trylock(var) \ 99 __lll_trylock (&(var)) 100 101 /* Release the lock at PTR. */ 102 #define __lll_unlock(ptr, flags) \ 103 ({ \ 104 int *__iptr = (int *)(ptr); \ 105 if (atomic_exchange_rel (__iptr, 0) == 2) \ 106 __lll_wake (__iptr, (flags)); \ 107 (void)0; \ 108 }) 109 #define lll_unlock(var, flags) \ 110 __lll_unlock (&(var), flags) 111 112 #endif 113