summaryrefslogtreecommitdiffstats
path: root/js/src/gc/GCLock.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/gc/GCLock.h110
1 files changed, 110 insertions, 0 deletions
diff --git a/js/src/gc/GCLock.h b/js/src/gc/GCLock.h
new file mode 100644
index 0000000000..64c28ac544
--- /dev/null
+++ b/js/src/gc/GCLock.h
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * GC-internal classes for acquiring and releasing the GC lock.
+ */
+
+#ifndef gc_GCLock_h
+#define gc_GCLock_h
+
+#include "vm/Runtime.h"
+
+namespace js {
+
+class AutoUnlockGC;
+
+/*
+ * RAII class that takes the GC lock while it is live.
+ *
+ * Usually functions will pass const references of this class. However
+ * non-const references can be used to either temporarily release the lock by
+ * use of AutoUnlockGC or to start background allocation when the lock is
+ * released.
+ */
+class MOZ_RAII AutoLockGC {
+ public:
+ explicit AutoLockGC(gc::GCRuntime* gc) : gc(gc) { lock(); }
+ explicit AutoLockGC(JSRuntime* rt) : AutoLockGC(&rt->gc) {}
+
+ ~AutoLockGC() { lockGuard_.reset(); }
+
+ js::LockGuard<js::Mutex>& guard() { return lockGuard_.ref(); }
+
+ protected:
+ void lock() {
+ MOZ_ASSERT(lockGuard_.isNothing());
+ lockGuard_.emplace(gc->lock);
+ }
+
+ void unlock() {
+ MOZ_ASSERT(lockGuard_.isSome());
+ lockGuard_.reset();
+ }
+
+ gc::GCRuntime* const gc;
+
+ private:
+ mozilla::Maybe<js::LockGuard<js::Mutex>> lockGuard_;
+
+ AutoLockGC(const AutoLockGC&) = delete;
+ AutoLockGC& operator=(const AutoLockGC&) = delete;
+
+ friend class AutoUnlockGC; // For lock/unlock.
+};
+
+/*
+ * Same as AutoLockGC except it can optionally start a background chunk
+ * allocation task when the lock is released.
+ */
+class MOZ_RAII AutoLockGCBgAlloc : public AutoLockGC {
+ public:
+ explicit AutoLockGCBgAlloc(gc::GCRuntime* gc) : AutoLockGC(gc) {}
+ explicit AutoLockGCBgAlloc(JSRuntime* rt) : AutoLockGCBgAlloc(&rt->gc) {}
+
+ ~AutoLockGCBgAlloc() {
+ unlock();
+
+ /*
+ * We have to do this after releasing the lock because it may acquire
+ * the helper lock which could cause lock inversion if we still held
+ * the GC lock.
+ */
+ if (startBgAlloc) {
+ gc->startBackgroundAllocTaskIfIdle();
+ }
+ }
+
+ /*
+ * This can be used to start a background allocation task (if one isn't
+ * already running) that allocates chunks and makes them available in the
+ * free chunks list. This happens after the lock is released in order to
+ * avoid lock inversion.
+ */
+ void tryToStartBackgroundAllocation() { startBgAlloc = true; }
+
+ private:
+ // true if we should start a background chunk allocation task after the
+ // lock is released.
+ bool startBgAlloc = false;
+};
+
+class MOZ_RAII AutoUnlockGC {
+ public:
+ explicit AutoUnlockGC(AutoLockGC& lock) : lock(lock) { lock.unlock(); }
+
+ ~AutoUnlockGC() { lock.lock(); }
+
+ private:
+ AutoLockGC& lock;
+
+ AutoUnlockGC(const AutoUnlockGC&) = delete;
+ AutoUnlockGC& operator=(const AutoUnlockGC&) = delete;
+};
+
+} // namespace js
+
+#endif /* gc_GCLock_h */