| 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 |