summaryrefslogtreecommitdiffstats
path: root/sandbox/linux/seccomp/mutex.h
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/linux/seccomp/mutex.h')
-rw-r--r--sandbox/linux/seccomp/mutex.h153
1 files changed, 153 insertions, 0 deletions
diff --git a/sandbox/linux/seccomp/mutex.h b/sandbox/linux/seccomp/mutex.h
new file mode 100644
index 0000000..d7e1c5d
--- /dev/null
+++ b/sandbox/linux/seccomp/mutex.h
@@ -0,0 +1,153 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MUTEX_H__
+#define MUTEX_H__
+
+#include "sandbox_impl.h"
+
+namespace playground {
+
+class Mutex {
+ public:
+ typedef int mutex_t;
+
+ enum { kInitValue = 0 };
+
+ static void initMutex(mutex_t* mutex) {
+ // Mutex is unlocked, and nobody is waiting for it
+ *mutex = kInitValue;
+ }
+
+ static void unlockMutex(mutex_t* mutex) {
+ char status;
+ #if defined(__x86_64__) || defined(__i386__)
+ asm volatile(
+ "lock; addl %2, %0\n"
+ "setz %1"
+ : "=m"(*mutex), "=qm"(status)
+ : "ir"(0x80000000), "m"(*mutex));
+ #else
+ #error Unsupported target platform
+ #endif
+ if (status) {
+ // Mutex is zero now. No other waiters. So, we can return.
+ return;
+ }
+ // We unlocked the mutex, but still need to wake up other waiters.
+ Sandbox::SysCalls sys;
+ sys.futex(mutex, FUTEX_WAKE, 1, NULL);
+ }
+
+ static bool lockMutex(mutex_t* mutex, int timeout = 0) {
+ bool rc = true;
+ // Increment mutex to add ourselves to the list of waiters
+ #if defined(__x86_64__) || defined(__i386__)
+ asm volatile(
+ "lock; incl %0\n"
+ : "=m"(*mutex)
+ : "m"(*mutex));
+ #else
+ #error Unsupported target platform
+ #endif
+ for (;;) {
+ // Atomically check whether the mutex is available and if so, acquire it
+ char status;
+ #if defined(__x86_64__) || defined(__i386__)
+ asm volatile(
+ "lock; btsl %3, %1\n"
+ "setc %0"
+ : "=q"(status), "=m"(*mutex)
+ : "m"(*mutex), "ir"(31));
+ #else
+ #error Unsupported target platform
+ #endif
+ if (!status) {
+ done:
+ // If the mutex was available, remove ourselves from list of waiters
+ #if defined(__x86_64__) || defined(__i386__)
+ asm volatile(
+ "lock; decl %0\n"
+ : "=m"(*mutex)
+ : "m"(*mutex));
+ #else
+ #error Unsupported target platform
+ #endif
+ return rc;
+ }
+ int value = *mutex;
+ if (value >= 0) {
+ // Mutex has just become available, no need to call kernel
+ continue;
+ }
+ Sandbox::SysCalls sys;
+ Sandbox::SysCalls::kernel_timespec tm;
+ if (timeout) {
+ tm.tv_sec = timeout / 1000;
+ tm.tv_nsec = (timeout % 1000) * 1000 * 1000;
+ } else {
+ tm.tv_sec = 0;
+ tm.tv_nsec = 0;
+ }
+ if (NOINTR_SYS(sys.futex(mutex, FUTEX_WAIT, value, &tm)) &&
+ sys.my_errno == ETIMEDOUT) {
+ rc = false;
+ goto done;
+ }
+ }
+ }
+
+ static bool waitForUnlock(mutex_t* mutex, int timeout = 0) {
+ bool rc = true;
+ // Increment mutex to add ourselves to the list of waiters
+ #if defined(__x86_64__) || defined(__i386__)
+ asm volatile(
+ "lock; incl %0\n"
+ : "=m"(*mutex)
+ : "m"(*mutex));
+ #else
+ #error Unsupported target platform
+ #endif
+ Sandbox::SysCalls sys;
+ for (;;) {
+ mutex_t value = *mutex;
+ if (value >= 0) {
+ done:
+ // Mutex was not locked. Remove ourselves from list of waiters, notify
+ // any other waiters (if any), and return.
+ #if defined(__x86_64__) || defined(__i386__)
+ asm volatile(
+ "lock; decl %0\n"
+ : "=m"(*mutex)
+ : "m"(*mutex));
+ #else
+ #error Unsupported target platform
+ #endif
+ NOINTR_SYS(sys.futex(mutex, FUTEX_WAKE, 1, 0));
+ return rc;
+ }
+
+ // Wait for mutex to become unlocked
+ Sandbox::SysCalls::kernel_timespec tm;
+ if (timeout) {
+ tm.tv_sec = timeout / 1000;
+ tm.tv_nsec = (timeout % 1000) * 1000 * 1000;
+ } else {
+ tm.tv_sec = 0;
+ tm.tv_nsec = 0;
+ }
+
+ if (NOINTR_SYS(sys.futex(mutex, FUTEX_WAIT, value, &tm)) &&
+ sys.my_errno == ETIMEDOUT) {
+ rc = false;
+ goto done;
+ }
+ }
+ }
+
+};
+
+} // namespace
+
+#endif // MUTEX_H__