001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.scheduler;
014
015import static org.jikesrvm.runtime.SysCall.sysCall;
016import org.jikesrvm.VM;
017
018import org.vmmagic.pragma.Uninterruptible;
019import org.vmmagic.pragma.Unpreemptible;
020import org.vmmagic.pragma.NonMoving;
021import org.vmmagic.pragma.NoInline;
022import org.vmmagic.pragma.NoOptCompile;
023import org.vmmagic.pragma.BaselineSaveLSRegisters;
024import org.vmmagic.unboxed.Word;
025
026/**
027 * Implementation of a heavy lock and condition variable implemented using
028 * the primitives available from the operating system.  Currently we use
029 * a pthread_mutex_t and pthread_cond_it.  When instantiated, the mutex
030 * and cond are allocated.  There is currently no way to destroy either
031 * (thus, pool and reuse accordingly).
032 * <p>
033 * It is perfectly safe to use this throughout the VM for locking.  It is
034 * meant to provide roughly the same functionality as Java monitors,
035 * except:
036 * <ul>
037 * <li>This class provides a faster slow path than Java monitors.</li>
038 * <li>This class provides a slower fast path than Java monitors.</li>
039 * <li>This class does not have any interaction with Thread.interrupt()
040 *     or Thread.stop().  Thus, if you block on a lock or a wait and the
041 *     calling thread is stopped or interrupted, nothing will happen
042 *     until the lock is acquired or the wait is notified.</li>
043 * <li>This class will work in the inner guts of the RVM runtime because
044 *     it gives you the ability to lock and unlock, as well as wait and
045 *     notify, without using any other VM runtime functionality.</li>
046 * <li>This class allows you to optionally block without letting the thread
047 *     system know that you are blocked.  The benefit is that you can
048 *     perform synchronization without depending on RVM thread subsystem functionality.
049 *     However, most of the time, you should use the methods that inform
050 *     the thread system that you are blocking.  Methods that have the
051 *     "WithHandshake" suffix will inform the thread system if you are blocked,
052 *     while methods that do not have the suffix will either not block
053 *     (as is the case with {@link #unlock()} and {@link #broadcast()})
054 *     or will block without letting anyone know (like {@link #lockNoHandshake()}
055 *     and {@link #waitNoHandshake()}). Not letting the threading
056 *     system know that you are blocked may cause things like GC to stall
057 *     until you unblock.</li>
058 * </ul>
059 */
060@Uninterruptible
061@NonMoving
062public class Monitor {
063  Word monitor;
064  int holderSlot = -1; // use the slot so that we're even more GC safe
065  int recCount;
066  public int acquireCount;
067  /**
068   * Allocate a heavy condition variable and lock.  This involves
069   * allocating stuff in C that gets deallocated only when the finalizer
070   * is run. Thus, don't instantiate too many of these.
071   */
072  public Monitor() {
073    monitor = sysCall.sysMonitorCreate();
074  }
075
076  /**
077   * Frees the data structures that were allocated in C code
078   * when the object was created.
079   */
080  @Override
081  protected void finalize() throws Throwable {
082    sysCall.sysMonitorDestroy(monitor);
083  }
084
085  /**
086   * Wait until it is possible to acquire the lock and then acquire it.
087   * There is no bound on how long you might wait, if someone else is
088   * holding the lock and there is no bound on how long they will hold it.
089   * As well, even if there is a bound on how long a thread might hold a
090   * lock but there are multiple threads contending on its acquisition,
091   * there will not necessarily be a bound on how long any particular
092   * thread will wait until it gets its turn.
093   * <p>
094   * This blocking method method does not notify the threading subsystem
095   * that it is blocking.  Thus, if someone (like, say, the GC) requests
096   * that the thread is blocked then their request will block until this
097   * method unblocks.  If this sounds like it might be undesirable, call
098   * {@link #lockWithHandshake()} instead.
099   */
100  @NoInline
101  @NoOptCompile
102  public void lockNoHandshake() {
103    int mySlot = RVMThread.getCurrentThreadSlot();
104    if (mySlot != holderSlot) {
105      sysCall.sysMonitorEnter(monitor);
106      if (VM.VerifyAssertions) VM._assert(holderSlot == -1);
107      if (VM.VerifyAssertions) VM._assert(recCount == 0);
108      holderSlot = mySlot;
109    }
110    recCount++;
111    acquireCount++;
112  }
113  /**
114   * Relocks the mutex after using {@link #unlockCompletely()}.
115   *
116   * @param recCount the recursion count
117   */
118  @NoInline
119  @NoOptCompile
120  public void relockNoHandshake(int recCount) {
121    sysCall.sysMonitorEnter(monitor);
122    if (VM.VerifyAssertions) VM._assert(holderSlot == -1);
123    if (VM.VerifyAssertions) VM._assert(this.recCount == 0);
124    holderSlot = RVMThread.getCurrentThreadSlot();
125    this.recCount = recCount;
126    acquireCount++;
127  }
128  /**
129   * Wait until it is possible to acquire the lock and then acquire it.
130   * There is no bound on how long you might wait, if someone else is
131   * holding the lock and there is no bound on how long they will hold it.
132   * As well, even if there is a bound on how long a thread might hold a
133   * lock but there are multiple threads contending on its acquisition,
134   * there will not necessarily be a bound on how long any particular
135   * thread will wait until it gets its turn.
136   * <p>
137   * This blocking method method notifies the threading subsystem that it
138   * is blocking.  Thus, it may be safer than calling lock.  But,
139   * its reliance on threading subsystem accounting methods may mean that
140   * it cannot be used in certain contexts (say, the threading subsystem
141   * itself).
142   * <p>
143   * This method will ensure that if it blocks, it does so with the
144   * mutex not held.  This is useful for cases where the subsystem that
145   * requested you to block needs to acquire the lock you were trying to
146   * acquire when the blocking request came.
147   * <p>
148   * It is usually not necessary to call this method instead of
149   * {@link #lockNoHandshake()} since most VM locks are held for short
150   * periods of time.
151   */
152  @Unpreemptible("If the lock cannot be acquired, this method will allow the thread to be asynchronously blocked")
153  @NoInline
154  @NoOptCompile
155  public void lockWithHandshake() {
156    int mySlot = RVMThread.getCurrentThreadSlot();
157    if (mySlot != holderSlot) {
158      lockWithHandshakeNoRec();
159      if (VM.VerifyAssertions) VM._assert(holderSlot == -1);
160      if (VM.VerifyAssertions) VM._assert(recCount == 0);
161      holderSlot = mySlot;
162    }
163    recCount++;
164    acquireCount++;
165  }
166  @NoInline
167  @NoOptCompile
168  @BaselineSaveLSRegisters
169  @Unpreemptible
170  private void lockWithHandshakeNoRec() {
171    RVMThread.saveThreadState();
172    lockWithHandshakeNoRecImpl();
173  }
174  @NoInline
175  @Unpreemptible
176  @NoOptCompile
177  private void lockWithHandshakeNoRecImpl() {
178    for (;;) {
179      RVMThread.enterNative();
180      sysCall.sysMonitorEnter(monitor);
181      if (RVMThread.attemptLeaveNativeNoBlock()) {
182        return;
183      } else {
184        sysCall.sysMonitorExit(monitor);
185        RVMThread.leaveNative();
186      }
187    }
188  }
189  /**
190   * Relocks the mutex after using {@link #unlockCompletely()} and notify
191   * the threading subsystem.
192   *
193   * @param recCount the recursion count
194   */
195  @NoInline
196  @NoOptCompile
197  @BaselineSaveLSRegisters
198  @Unpreemptible("If the lock cannot be reacquired, this method may allow the thread to be asynchronously blocked")
199  public void relockWithHandshake(int recCount) {
200    RVMThread.saveThreadState();
201    relockWithHandshakeImpl(recCount);
202  }
203  @NoInline
204  @Unpreemptible
205  @NoOptCompile
206  private void relockWithHandshakeImpl(int recCount) {
207    for (;;) {
208      RVMThread.enterNative();
209      sysCall.sysMonitorEnter(monitor);
210      if (RVMThread.attemptLeaveNativeNoBlock()) {
211        break;
212      } else {
213        sysCall.sysMonitorExit(monitor);
214        RVMThread.leaveNative();
215      }
216    }
217    if (VM.VerifyAssertions) VM._assert(holderSlot == -1);
218    if (VM.VerifyAssertions) VM._assert(this.recCount == 0);
219    holderSlot = RVMThread.getCurrentThreadSlot();
220    this.recCount = recCount;
221  }
222  /**
223   * Release the lock.  This method should (in principle) be non-blocking,
224   * and, as such, it does not notify the threading subsystem that it is
225   * blocking.
226   */
227  @NoInline
228  @NoOptCompile
229  public void unlock() {
230    if (--recCount == 0) {
231      holderSlot = -1;
232      sysCall.sysMonitorExit(monitor);
233    }
234  }
235
236  /**
237   * Completely releases the lock, ignoring recursion.
238   *
239   * @return the recursion count
240   */
241  @NoInline
242  @NoOptCompile
243  public int unlockCompletely() {
244    int result = recCount;
245    recCount = 0;
246    holderSlot = -1;
247    sysCall.sysMonitorExit(monitor);
248    return result;
249  }
250  /**
251   * Wait until someone calls {@link #broadcast()}.
252   * <p>
253   * This blocking method method does not notify the threading subsystem
254   * that it is blocking.  Thus, if someone (like, say, the GC) requests
255   * that the thread is blocked then their request will block until this
256   * method unblocks.  If this sounds like it might be undesirable, call
257   * {@link #waitWithHandshake()} instead.
258   */
259  @NoInline
260  @NoOptCompile
261  public void waitNoHandshake() {
262    int recCount = this.recCount;
263    this.recCount = 0;
264    holderSlot = -1;
265    sysCall.sysMonitorWait(monitor);
266    if (VM.VerifyAssertions) VM._assert(holderSlot == -1);
267    if (VM.VerifyAssertions) VM._assert(this.recCount == 0);
268    this.recCount = recCount;
269    holderSlot = RVMThread.getCurrentThreadSlot();
270  }
271  /**
272   * Wait until someone calls {@link #broadcast()}, or until the clock
273   * reaches the given time.
274   * <p>
275   * This blocking method method does not notify the threading subsystem
276   * that it is blocking.  Thus, if someone (like, say, the GC) requests
277   * that the thread is blocked then their request will block until this
278   * method unblocks.  If this sounds like it might be undesirable, call
279   * {@link #timedWaitAbsoluteWithHandshake(long)} instead.
280   *
281   * @param whenWakeupNanos the absolute time point that must be reached
282   *  before the wait is over when no call to {@link #broadcast()} occurs
283   *  in the meantime
284   */
285  @NoInline
286  @NoOptCompile
287  public void timedWaitAbsoluteNoHandshake(long whenWakeupNanos) {
288    int recCount = this.recCount;
289    this.recCount = 0;
290    holderSlot = -1;
291    sysCall.sysMonitorTimedWaitAbsolute(monitor, whenWakeupNanos);
292    if (VM.VerifyAssertions) VM._assert(holderSlot == -1);
293    if (VM.VerifyAssertions) VM._assert(this.recCount == 0);
294    this.recCount = recCount;
295    holderSlot = RVMThread.getCurrentThreadSlot();
296  }
297  /**
298   * Wait until someone calls {@link #broadcast()}, or until at least
299   * the given number of nanoseconds pass.
300   * <p>
301   * This blocking method method does not notify the threading subsystem
302   * that it is blocking.  Thus, if someone (like, say, the GC) requests
303   * that the thread is blocked then their request will block until this
304   * method unblocks.  If this sounds like it might be undesirable, call
305   * {@link #timedWaitRelativeWithHandshake(long)} instead.
306   *
307   * @param delayNanos the number of nanoseconds that need to pass
308   *  from the call of this method until the wait is over when no call
309   *  to {@link #broadcast()} occurs in the meantime
310   */
311  @NoInline
312  @NoOptCompile
313  public void timedWaitRelativeNoHandshake(long delayNanos) {
314    long now = sysCall.sysNanoTime();
315    timedWaitAbsoluteNoHandshake(now + delayNanos);
316  }
317  /**
318   * Wait until someone calls {@link #broadcast()}.
319   * <p>
320   * This blocking method notifies the threading subsystem that it
321   * is blocking.  Thus, it is generally safer than calling
322   * {@link #waitNoHandshake()}.  But, its reliance on threading subsystem
323   * accounting methods may mean that it cannot be used in certain contexts
324   * (say, the threading subsystem itself).
325   * <p>
326   * This method will ensure that if it blocks, it does so with the
327   * mutex not held.  This is useful for cases where the subsystem that
328   * requested you to block needs to acquire the lock you were trying to
329   * acquire when the blocking request came.
330   */
331  @NoInline
332  @NoOptCompile
333  @BaselineSaveLSRegisters
334  @Unpreemptible("While the thread is waiting, this method may allow the thread to be asynchronously blocked")
335  public void waitWithHandshake() {
336    RVMThread.saveThreadState();
337    waitWithHandshakeImpl();
338  }
339  @NoInline
340  @Unpreemptible
341  @NoOptCompile
342  private void waitWithHandshakeImpl() {
343    RVMThread.enterNative();
344    waitNoHandshake();
345    int recCount = unlockCompletely();
346    RVMThread.leaveNative();
347    relockWithHandshakeImpl(recCount);
348  }
349  /**
350   * Wait until someone calls {@link #broadcast()}, or until the clock
351   * reaches the given time.
352   * <p>
353   * This blocking method method notifies the threading subsystem that it
354   * is blocking.  Thus, it is generally safer than calling
355   * {@link #timedWaitAbsoluteNoHandshake(long)}. But, its reliance on
356   * threading subsystem accounting methods may mean that it cannot be
357   * used in certain contexts (say, the threading subsystem itself).
358   * <p>
359   * This method will ensure that if it blocks, it does so with the
360   * mutex not held.  This is useful for cases where the subsystem that
361   * requested you to block needs to acquire the lock you were trying to
362   * acquire when the blocking request came.
363   *
364   * @param whenWakeupNanos the absolute time point that must be reached
365   *  before the wait is over when no call to {@link #broadcast()} occurs
366   *  in the meantime
367   */
368  @NoInline
369  @NoOptCompile
370  @BaselineSaveLSRegisters
371  @Unpreemptible("While the thread is waiting, this method may allow the thread to be asynchronously blocked")
372  public void timedWaitAbsoluteWithHandshake(long whenWakeupNanos) {
373    RVMThread.saveThreadState();
374    timedWaitAbsoluteWithHandshakeImpl(whenWakeupNanos);
375  }
376  @NoInline
377  @Unpreemptible
378  @NoOptCompile
379  private void timedWaitAbsoluteWithHandshakeImpl(long whenWakeupNanos) {
380    RVMThread.enterNative();
381    timedWaitAbsoluteNoHandshake(whenWakeupNanos);
382    int recCount = unlockCompletely();
383    RVMThread.leaveNative();
384    relockWithHandshakeImpl(recCount);
385  }
386  /**
387   * Wait until someone calls {@link #broadcast()}, or until at least the given
388   * number of nanoseconds pass.
389   * <p>
390   * This blocking method method notifies the threading subsystem that it
391   * is blocking.  Thus, it is generally safer than calling
392   * {@link #timedWaitRelativeWithHandshake(long)}.  But, its reliance on
393   * threading subsystem accounting methods may mean that it cannot be used
394   * in certain contexts (say, the threading subsystem itself).
395   * <p>
396   * This method will ensure that if it blocks, it does so with the
397   * mutex not held.  This is useful for cases where the subsystem that
398   * requested you to block needs to acquire the lock you were trying to
399   * acquire when the blocking request came.
400   *
401   * @param delayNanos the number of nanoseconds that need to pass
402   *  from the call of this method until the wait is over when no call
403   *  to {@link #broadcast()} occurs in the meantime
404   */
405  @NoInline
406  @NoOptCompile
407  @BaselineSaveLSRegisters
408  @Unpreemptible("While the thread is waiting, this method may allow the thread to be asynchronously blocked")
409  public void timedWaitRelativeWithHandshake(long delayNanos) {
410    RVMThread.saveThreadState();
411    timedWaitRelativeWithHandshakeImpl(delayNanos);
412  }
413  @NoInline
414  @Unpreemptible
415  @NoOptCompile
416  private void timedWaitRelativeWithHandshakeImpl(long delayNanos) {
417    RVMThread.enterNative();
418    timedWaitRelativeNoHandshake(delayNanos);
419    int recCount = unlockCompletely();
420    RVMThread.leaveNative();
421    relockWithHandshakeImpl(recCount);
422  }
423
424  /**
425   * Send a broadcast, which should awaken anyone who is currently blocked
426   * in any of the wait methods.  This method should (in principle) be
427   * non-blocking, and, as such, it does not notify the threading subsystem
428   * that it is blocking.
429   */
430  @NoInline
431  @NoOptCompile
432  public void broadcast() {
433    sysCall.sysMonitorBroadcast(monitor);
434  }
435  /**
436   * Send a broadcast after first acquiring the lock.  Release the lock
437   * after sending the broadcast.  In most cases where you want to send
438   * a broadcast but you don't need to acquire the lock to set the
439   * condition that the other thread(s) are waiting on, you want to call
440   * this method instead of {@link #broadcast()}.
441   */
442  @NoInline
443  @NoOptCompile
444  public void lockedBroadcastNoHandshake() {
445    lockNoHandshake();
446    broadcast();
447    unlock();
448  }
449
450  @NoInline
451  public static boolean lockNoHandshake(Monitor l) {
452    if (l == null) {
453      return false;
454    } else {
455      l.lockNoHandshake();
456      return true;
457    }
458  }
459  @NoInline
460  public static void unlock(boolean b, Monitor l) {
461    if (b) l.unlock();
462  }
463
464  @NoInline
465  @NoOptCompile
466  @Unpreemptible
467  public static void lockWithHandshake(Monitor m1,Word priority1,
468                                       Monitor m2,Word priority2) {
469    if (priority1.LE(priority2)) {
470      m1.lockWithHandshake();
471      m2.lockWithHandshake();
472    } else {
473      m2.lockWithHandshake();
474      m1.lockWithHandshake();
475    }
476  }
477}
478