1 | /* Commit an elided pthread lock. |
2 | Copyright (C) 2014-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 | #include <pthreadP.h> |
20 | #include <lowlevellock.h> |
21 | #include <htm.h> |
22 | |
23 | int |
24 | __lll_unlock_elision(int *futex, short *adapt_count, int private) |
25 | { |
26 | /* If the lock is free, we elided the lock earlier. This does not |
27 | necessarily mean that we are in a transaction, because the user code may |
28 | have closed the transaction, but that is impossible to detect reliably. |
29 | Relaxed MO access to futex is sufficient because a correct program |
30 | will only release a lock it has acquired; therefore, it must either |
31 | changed the futex word's value to something !=0 or it must have used |
32 | elision; these are actions by the same thread, so these actions are |
33 | sequenced-before the relaxed load (and thus also happens-before the |
34 | relaxed load). Therefore, relaxed MO is sufficient. */ |
35 | if (atomic_load_relaxed (futex) == 0) |
36 | { |
37 | __libc_tend (); |
38 | } |
39 | else |
40 | { |
41 | /* Update the adapt_count while unlocking before completing the critical |
42 | section. adapt_count is accessed concurrently outside of a |
43 | transaction or a critical section (e.g. in elision-lock.c). So we need |
44 | to use atomic accesses. However, the value of adapt_count is just a |
45 | hint, so relaxed MO accesses are sufficient. |
46 | If adapt_count would be decremented while locking, multiple |
47 | CPUs, trying to lock the acquired mutex, will decrement adapt_count to |
48 | zero and another CPU will try to start a transaction, which will be |
49 | immediately aborted as the mutex is locked. |
50 | The update of adapt_count is done before releasing the lock as POSIX' |
51 | mutex destruction requirements disallow accesses to the mutex after it |
52 | has been released and thus could have been acquired or destroyed by |
53 | another thread. */ |
54 | short adapt_count_val = atomic_load_relaxed (adapt_count); |
55 | if (adapt_count_val > 0) |
56 | atomic_store_relaxed (adapt_count, adapt_count_val - 1); |
57 | |
58 | lll_unlock ((*futex), private); |
59 | } |
60 | return 0; |
61 | } |
62 | libc_hidden_def (__lll_unlock_elision) |
63 | |