1 /*
   2  * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include <stdio.h>
  26 #include <assert.h>
  27 #include "Monitor.hpp"
  28 
  29 Monitor::Monitor() {
  30   _lock_count = -1;       // No threads have entered the critical section
  31   _owner = NULL;
  32   _lock_event = CreateEvent(NULL, false, false, NULL);
  33   _wait_event = CreateEvent(NULL, true, false, NULL);
  34   _counter = 0;
  35   _tickets = 0;
  36   _waiters = 0;
  37 }
  38 
  39 Monitor::~Monitor() {
  40   assert(_owner == NULL);    // Otherwise, owned monitor being deleted
  41   assert(_lock_count == -1); // Otherwise, monitor being deleted with non -1 lock count
  42   CloseHandle(_lock_event);
  43   CloseHandle(_wait_event);
  44 }
  45 
  46 void
  47 Monitor::lock() {
  48   if (InterlockedIncrement(&_lock_count) == 0) {
  49     // Success, we now own the lock
  50   } else {
  51     DWORD dwRet = WaitForSingleObject((HANDLE)_lock_event,  INFINITE);
  52     assert(dwRet == WAIT_OBJECT_0); // Unexpected return value from WaitForSingleObject
  53   }
  54   assert(owner() == NULL); // Otherwise, lock count and owner are inconsistent
  55   setOwner(GetCurrentThread());
  56 }
  57 
  58 void
  59 Monitor::unlock() {
  60   setOwner(NULL);
  61   if (InterlockedDecrement(&_lock_count) >= 0) {
  62     // Wake a waiting thread up
  63     DWORD dwRet = SetEvent(_lock_event);
  64     assert(dwRet != 0); // Unexpected return value from SetEvent
  65   }
  66 }
  67 
  68 bool
  69 Monitor::wait(long timeout) {
  70   assert(owner() != NULL);
  71   assert(owner() == GetCurrentThread());
  72 
  73   // 0 means forever. Convert to Windows specific code.
  74   DWORD timeout_value = (timeout == 0) ? INFINITE : timeout;
  75   DWORD which;
  76 
  77   long c = _counter;
  78   bool retry = false;
  79 
  80   _waiters++;
  81   // Loop until condition variable is signaled.  The event object is
  82   // set whenever the condition variable is signaled, and tickets will
  83   // reflect the number of threads which have been notified. The counter
  84   // field is used to make sure we don't respond to notifications that
  85   // have occurred *before* we started waiting, and is incremented each
  86   // time the condition variable is signaled.
  87 
  88   while (true) {
  89 
  90     // Leave critical region
  91     unlock();
  92 
  93     // If this is a retry, let other low-priority threads have a chance
  94     // to run.  Make sure that we sleep outside of the critical section.
  95     if (retry) {
  96       Sleep(1);
  97     } else {
  98       retry = true;
  99     }
 100 
 101     which = WaitForSingleObject(_wait_event, timeout_value);
 102     // Enter critical section
 103     lock();
 104 
 105     if (_tickets != 0 && _counter != c) break;
 106 
 107     if (which == WAIT_TIMEOUT) {
 108       --_waiters;
 109       return true;
 110     }
 111   }
 112   _waiters--;
 113 
 114   // If this was the last thread to be notified, then we need to reset
 115   // the event object.
 116   if (--_tickets == 0) {
 117     ResetEvent(_wait_event);
 118   }
 119 
 120   return false;
 121 }
 122 
 123 // Notify a single thread waiting on this monitor
 124 bool
 125 Monitor::notify() {
 126   assert(ownedBySelf()); // Otherwise, notify on unknown thread
 127 
 128   if (_waiters > _tickets) {
 129     if (!SetEvent(_wait_event)) {
 130       return false;
 131     }
 132     _tickets++;
 133     _counter++;
 134   }
 135 
 136   return true;
 137 }
 138 
 139 // Notify all threads waiting on this monitor
 140 bool
 141 Monitor::notifyAll() {
 142   assert(ownedBySelf()); // Otherwise, notifyAll on unknown thread
 143 
 144   if (_waiters > 0) {
 145     if (!SetEvent(_wait_event)) {
 146       return false;
 147     }
 148     _tickets = _waiters;
 149     _counter++;
 150   }
 151 
 152   return true;
 153 }
 154 
 155 HANDLE
 156 Monitor::owner() {
 157   return _owner;
 158 }
 159 
 160 void
 161 Monitor::setOwner(HANDLE owner) {
 162   if (owner != NULL) {
 163     assert(_owner == NULL);                 // Setting owner thread of already owned monitor
 164     assert(owner == GetCurrentThread());    // Else should not be doing this
 165   } else {
 166     HANDLE oldOwner = _owner;
 167     assert(oldOwner != NULL);               // Removing the owner thread of an unowned mutex
 168     assert(oldOwner == GetCurrentThread());
 169   }
 170   _owner = owner;
 171 }
 172 
 173 bool
 174 Monitor::ownedBySelf() {
 175   return (_owner == GetCurrentThread());
 176 }