]>
Commit | Line | Data |
---|---|---|
ef400973 | 1 | /* pthread_spin_trylock -- trylock a spin lock. Generic version. |
2b778ceb | 2 | Copyright (C) 2012-2021 Free Software Foundation, Inc. |
02a9f771 DJ |
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 | |
ef400973 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
02a9f771 | 18 | |
1ba025a9 DJ |
19 | #include <errno.h> |
20 | #include <atomic.h> | |
21 | #include "pthreadP.h" | |
02a9f771 | 22 | |
1ba025a9 DJ |
23 | int |
24 | pthread_spin_trylock (pthread_spinlock_t *lock) | |
25 | { | |
12d2dd70 SL |
26 | /* For the spin try lock, we have the following possibilities: |
27 | ||
28 | 1) If we assume that trylock will most likely succeed in practice: | |
29 | * We just do an exchange. | |
30 | ||
31 | 2) If we want to bias towards cases where trylock succeeds, but don't | |
32 | rule out contention: | |
33 | * If exchange is not implemented by a CAS loop, and exchange is faster | |
34 | than CAS, do an exchange. | |
35 | * If exchange is implemented by a CAS loop, use a weak CAS and not an | |
36 | exchange so we bail out after the first failed attempt to change the state. | |
37 | ||
38 | 3) If we expect contention to be likely: | |
39 | * If CAS always brings the cache line into an exclusive state even if the | |
40 | spinlock is already acquired, then load the value first with | |
41 | atomic_load_relaxed and test if lock is not acquired. Then do 2). | |
42 | ||
43 | We assume that 2) is the common case, and that this won't be slower than | |
44 | 1) in the common case. | |
45 | ||
46 | We use acquire MO to synchronize-with the release MO store in | |
47 | pthread_spin_unlock, and thus ensure that prior critical sections | |
48 | happen-before this critical section. */ | |
49 | #if ! ATOMIC_EXCHANGE_USES_CAS | |
50 | /* Try to acquire the lock with an exchange instruction as this architecture | |
51 | has such an instruction and we assume it is faster than a CAS. | |
52 | The acquisition succeeds if the lock is not in an acquired state. */ | |
53 | if (atomic_exchange_acquire (lock, 1) == 0) | |
54 | return 0; | |
55 | #else | |
56 | /* Try to acquire the lock with a CAS instruction as this architecture | |
57 | has no exchange instruction. The acquisition succeeds if the lock is not | |
58 | acquired. */ | |
59 | do | |
60 | { | |
61 | int val = 0; | |
62 | if (atomic_compare_exchange_weak_acquire (lock, &val, 1)) | |
63 | return 0; | |
64 | } | |
65 | /* atomic_compare_exchange_weak_acquire can fail spuriously. Whereas | |
66 | C++11 and C11 make it clear that trylock operations can fail spuriously, | |
67 | POSIX does not explicitly specify this; it only specifies that failing | |
68 | synchronization operations do not need to have synchronization effects | |
69 | themselves, but a spurious failure is something that could contradict a | |
70 | happens-before established earlier (e.g., that we need to observe that | |
71 | the lock is acquired). Therefore, we emulate a strong CAS by simply | |
72 | checking with a relaxed MO load that the lock is really acquired before | |
73 | returning EBUSY; the additional overhead this may cause is on the slow | |
74 | path. */ | |
75 | while (atomic_load_relaxed (lock) == 0); | |
76 | #endif | |
77 | ||
78 | return EBUSY; | |
1ba025a9 | 79 | } |