text: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
   * vim: set ts=8 sts=4 et sw=4 tw=99:
   * 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/. */
  
  #ifndef vm_Monitor_h
  #define vm_Monitor_h
  
  #include "mozilla/DebugOnly.h"
  
  #include <stddef.h>
  
  #include "jslock.h"
  
  #include "js/Utility.h"
  
  namespace js {
  
  // A base class used for types intended to be used in a parallel
  // fashion.  Combines a lock and a condition variable.  You can
  // acquire the lock or signal the condition variable using the
  // |AutoLockMonitor| type.
  
  class Monitor
  {
    protected:
      friend class AutoLockMonitor;
      friend class AutoUnlockMonitor;
  
      PRLock* lock_;
      PRCondVar* condVar_;
  
    public:
      Monitor()
        : lock_(nullptr),
          condVar_(nullptr)
      { }
  
      ~Monitor() {
          if (lock_)
              PR_DestroyLock(lock_);
          if (condVar_)
              PR_DestroyCondVar(condVar_);
      }
  
      bool init();
  };
  
  class AutoLockMonitor
  {
    private:
      Monitor& monitor;
  
    public:
      explicit AutoLockMonitor(Monitor& monitor)
        : monitor(monitor)
      {
          PR_Lock(monitor.lock_);
      }
  
      ~AutoLockMonitor() {
          PR_Unlock(monitor.lock_);
      }
  
      bool isFor(Monitor& other) const {
          return monitor.lock_ == other.lock_;
      }
  
      void wait(PRCondVar* condVar) {
          mozilla::DebugOnly<PRStatus> status =
            PR_WaitCondVar(condVar, PR_INTERVAL_NO_TIMEOUT);
          MOZ_ASSERT(status == PR_SUCCESS);
      }
  
      void wait() {
          wait(monitor.condVar_);
      }
  
      void notify(PRCondVar* condVar) {
          mozilla::DebugOnly<PRStatus> status = PR_NotifyCondVar(condVar);
          MOZ_ASSERT(status == PR_SUCCESS);
      }
  
      void notify() {
          notify(monitor.condVar_);
      }
  
      void notifyAll(PRCondVar* condVar) {
          mozilla::DebugOnly<PRStatus> status = PR_NotifyAllCondVar(monitor.condVar_);
          MOZ_ASSERT(status == PR_SUCCESS);
      }
  
      void notifyAll() {
          notifyAll(monitor.condVar_);
      }
  };
  
  class AutoUnlockMonitor
  {
    private:
      Monitor& monitor;
  
    public:
      explicit AutoUnlockMonitor(Monitor& monitor)
        : monitor(monitor)
      {
          PR_Unlock(monitor.lock_);
      }
  
      ~AutoUnlockMonitor() {
          PR_Lock(monitor.lock_);
      }
  
      bool isFor(Monitor& other) const {
          return monitor.lock_ == other.lock_;
      }
  };
  
  } // namespace js
  
  #endif /* vm_Monitor_h */
  