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