OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef MUTEX_H__ | |
6 #define MUTEX_H__ | |
7 | |
8 #include "sandbox_impl.h" | |
9 | |
10 namespace playground { | |
11 | |
12 class Mutex { | |
13 public: | |
14 typedef int mutex_t; | |
15 | |
16 enum { kInitValue = 0 }; | |
17 | |
18 static void initMutex(mutex_t* mutex) { | |
19 // Mutex is unlocked, and nobody is waiting for it | |
20 *mutex = kInitValue; | |
21 } | |
22 | |
23 static void unlockMutex(mutex_t* mutex) { | |
24 char status; | |
25 #if defined(__x86_64__) || defined(__i386__) | |
26 asm volatile( | |
27 "lock; addl %2, %0\n" | |
28 "setz %1" | |
29 : "=m"(*mutex), "=qm"(status) | |
30 : "ir"(0x80000000), "m"(*mutex)); | |
31 #else | |
32 #error Unsupported target platform | |
33 #endif | |
34 if (status) { | |
35 // Mutex is zero now. No other waiters. So, we can return. | |
36 return; | |
37 } | |
38 // We unlocked the mutex, but still need to wake up other waiters. | |
39 Sandbox::SysCalls sys; | |
40 sys.futex(mutex, FUTEX_WAKE, 1, NULL); | |
41 } | |
42 | |
43 static bool lockMutex(mutex_t* mutex, int timeout = 0) { | |
44 bool rc = true; | |
45 // Increment mutex to add ourselves to the list of waiters | |
46 #if defined(__x86_64__) || defined(__i386__) | |
47 asm volatile( | |
48 "lock; incl %0\n" | |
49 : "=m"(*mutex) | |
50 : "m"(*mutex)); | |
51 #else | |
52 #error Unsupported target platform | |
53 #endif | |
54 for (;;) { | |
55 // Atomically check whether the mutex is available and if so, acquire it | |
56 char status; | |
57 #if defined(__x86_64__) || defined(__i386__) | |
58 asm volatile( | |
59 "lock; btsl %3, %1\n" | |
60 "setc %0" | |
61 : "=q"(status), "=m"(*mutex) | |
62 : "m"(*mutex), "ir"(31)); | |
63 #else | |
64 #error Unsupported target platform | |
65 #endif | |
66 if (!status) { | |
67 done: | |
68 // If the mutex was available, remove ourselves from list of waiters | |
69 #if defined(__x86_64__) || defined(__i386__) | |
70 asm volatile( | |
71 "lock; decl %0\n" | |
72 : "=m"(*mutex) | |
73 : "m"(*mutex)); | |
74 #else | |
75 #error Unsupported target platform | |
76 #endif | |
77 return rc; | |
78 } | |
79 int value = *mutex; | |
80 if (value >= 0) { | |
81 // Mutex has just become available, no need to call kernel | |
82 continue; | |
83 } | |
84 Sandbox::SysCalls sys; | |
85 Sandbox::SysCalls::kernel_timespec tm; | |
86 if (timeout) { | |
87 tm.tv_sec = timeout / 1000; | |
88 tm.tv_nsec = (timeout % 1000) * 1000 * 1000; | |
89 } else { | |
90 tm.tv_sec = 0; | |
91 tm.tv_nsec = 0; | |
92 } | |
93 if (NOINTR_SYS(sys.futex(mutex, FUTEX_WAIT, value, &tm)) && | |
94 sys.my_errno == ETIMEDOUT) { | |
95 rc = false; | |
96 goto done; | |
97 } | |
98 } | |
99 } | |
100 | |
101 static bool waitForUnlock(mutex_t* mutex, int timeout = 0) { | |
102 bool rc = true; | |
103 // Increment mutex to add ourselves to the list of waiters | |
104 #if defined(__x86_64__) || defined(__i386__) | |
105 asm volatile( | |
106 "lock; incl %0\n" | |
107 : "=m"(*mutex) | |
108 : "m"(*mutex)); | |
109 #else | |
110 #error Unsupported target platform | |
111 #endif | |
112 Sandbox::SysCalls sys; | |
113 for (;;) { | |
114 mutex_t value = *mutex; | |
115 if (value >= 0) { | |
116 done: | |
117 // Mutex was not locked. Remove ourselves from list of waiters, notify | |
118 // any other waiters (if any), and return. | |
119 #if defined(__x86_64__) || defined(__i386__) | |
120 asm volatile( | |
121 "lock; decl %0\n" | |
122 : "=m"(*mutex) | |
123 : "m"(*mutex)); | |
124 #else | |
125 #error Unsupported target platform | |
126 #endif | |
127 NOINTR_SYS(sys.futex(mutex, FUTEX_WAKE, 1, 0)); | |
128 return rc; | |
129 } | |
130 | |
131 // Wait for mutex to become unlocked | |
132 Sandbox::SysCalls::kernel_timespec tm; | |
133 if (timeout) { | |
134 tm.tv_sec = timeout / 1000; | |
135 tm.tv_nsec = (timeout % 1000) * 1000 * 1000; | |
136 } else { | |
137 tm.tv_sec = 0; | |
138 tm.tv_nsec = 0; | |
139 } | |
140 | |
141 if (NOINTR_SYS(sys.futex(mutex, FUTEX_WAIT, value, &tm)) && | |
142 sys.my_errno == ETIMEDOUT) { | |
143 rc = false; | |
144 goto done; | |
145 } | |
146 } | |
147 } | |
148 | |
149 }; | |
150 | |
151 } // namespace | |
152 | |
153 #endif // MUTEX_H__ | |
OLD | NEW |