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     */
013    package org.jikesrvm.scheduler;
014    
015    import static org.jikesrvm.runtime.SysCall.sysCall;
016    import org.jikesrvm.VM;
017    
018    import org.vmmagic.pragma.Uninterruptible;
019    import org.vmmagic.pragma.Unpreemptible;
020    import org.vmmagic.pragma.NonMoving;
021    import org.vmmagic.pragma.NoInline;
022    import org.vmmagic.pragma.NoOptCompile;
023    import org.vmmagic.pragma.BaselineSaveLSRegisters;
024    import 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     *     "Nicely" 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 unlock and broadcast) or will block without
054     *     letting anyone know (like lock and wait).  Not letting the threading
055     *     system know that you are blocked may cause things like GC to stall
056     *     until you unblock.</li>
057     * </ul>
058     */
059    @Uninterruptible
060    @NonMoving
061    public class Monitor {
062      Word monitor;
063      int holderSlot=-1; // use the slot so that we're even more GC safe
064      int recCount;
065      public int acquireCount;
066      /**
067       * Allocate a heavy condition variable and lock.  This involves
068       * allocating stuff in C that never gets deallocated.  Thus, don't
069       * instantiate too many of these.
070       */
071      public Monitor() {
072        monitor = sysCall.sysMonitorCreate();
073      }
074      /**
075       * Wait until it is possible to acquire the lock and then acquire it.
076       * There is no bound on how long you might wait, if someone else is
077       * holding the lock and there is no bound on how long they will hold it.
078       * As well, even if there is a bound on how long a thread might hold a
079       * lock but there are multiple threads contending on its acquisition,
080       * there will not necessarily be a bound on how long any particular
081       * thread will wait until it gets its turn.
082       * <p>
083       * This blocking method method does not notify the threading subsystem
084       * that it is blocking.  Thus, if someone (like, say, the GC) requests
085       * that the thread is blocked then their request will block until this
086       * method unblocks.  If this sounds like it might be undesirable, call
087       * lockNicely instead.
088       */
089      @NoInline
090      @NoOptCompile
091      public void lockNoHandshake() {
092        int mySlot = RVMThread.getCurrentThreadSlot();
093        if (mySlot != holderSlot) {
094          sysCall.sysMonitorEnter(monitor);
095          if (VM.VerifyAssertions) VM._assert(holderSlot==-1);
096          if (VM.VerifyAssertions) VM._assert(recCount==0);
097          holderSlot = mySlot;
098        }
099        recCount++;
100        acquireCount++;
101      }
102      /**
103       * Relock the mutex after using unlockCompletely.
104       */
105      @NoInline
106      @NoOptCompile
107      public void relockNoHandshake(int recCount) {
108        sysCall.sysMonitorEnter(monitor);
109        if (VM.VerifyAssertions) VM._assert(holderSlot==-1);
110        if (VM.VerifyAssertions) VM._assert(this.recCount==0);
111        holderSlot=RVMThread.getCurrentThreadSlot();
112        this.recCount=recCount;
113        acquireCount++;
114      }
115      /**
116       * Wait until it is possible to acquire the lock and then acquire it.
117       * There is no bound on how long you might wait, if someone else is
118       * holding the lock and there is no bound on how long they will hold it.
119       * As well, even if there is a bound on how long a thread might hold a
120       * lock but there are multiple threads contending on its acquisition,
121       * there will not necessarily be a bound on how long any particular
122       * thread will wait until it gets its turn.
123       * <p>
124       * This blocking method method notifies the threading subsystem that it
125       * is blocking.  Thus, it may be safer than calling lock.  But,
126       * its reliance on threading subsystem accounting methods may mean that
127       * it cannot be used in certain contexts (say, the threading subsystem
128       * itself).
129       * <p>
130       * This method will ensure that if it blocks, it does so with the
131       * mutex not held.  This is useful for cases where the subsystem that
132       * requested you to block needs to acquire the lock you were trying to
133       * acquire when the blocking request came.
134       * <p>
135       * It is usually not necessary to call this method instead of lock(),
136       * since most VM locks are held for short periods of time.
137       */
138      @Unpreemptible("If the lock cannot be acquired, this method will allow the thread to be asynchronously blocked")
139      @NoInline
140      @NoOptCompile
141      public void lockWithHandshake() {
142        int mySlot = RVMThread.getCurrentThreadSlot();
143        if (mySlot != holderSlot) {
144          lockWithHandshakeNoRec();
145          if (VM.VerifyAssertions) VM._assert(holderSlot==-1);
146          if (VM.VerifyAssertions) VM._assert(recCount==0);
147          holderSlot = mySlot;
148        }
149        recCount++;
150        acquireCount++;
151      }
152      @NoInline
153      @NoOptCompile
154      @BaselineSaveLSRegisters
155      @Unpreemptible
156      private void lockWithHandshakeNoRec() {
157        RVMThread.saveThreadState();
158        lockWithHandshakeNoRecImpl();
159      }
160      @NoInline
161      @Unpreemptible
162      @NoOptCompile
163      private void lockWithHandshakeNoRecImpl() {
164        for (;;) {
165          RVMThread.enterNative();
166          sysCall.sysMonitorEnter(monitor);
167          if (RVMThread.attemptLeaveNativeNoBlock()) {
168            return;
169          } else {
170            sysCall.sysMonitorExit(monitor);
171            RVMThread.leaveNative();
172          }
173        }
174      }
175      /**
176       * Relock the mutex after using unlockCompletely, but do so "nicely".
177       */
178      @NoInline
179      @NoOptCompile
180      @BaselineSaveLSRegisters
181      @Unpreemptible("If the lock cannot be reacquired, this method may allow the thread to be asynchronously blocked")
182      public void relockWithHandshake(int recCount) {
183        RVMThread.saveThreadState();
184        relockWithHandshakeImpl(recCount);
185      }
186      @NoInline
187      @Unpreemptible
188      @NoOptCompile
189      private void relockWithHandshakeImpl(int recCount) {
190        for (;;) {
191          RVMThread.enterNative();
192          sysCall.sysMonitorEnter(monitor);
193          if (RVMThread.attemptLeaveNativeNoBlock()) {
194            break;
195          } else {
196            sysCall.sysMonitorExit(monitor);
197            RVMThread.leaveNative();
198          }
199        }
200        if (VM.VerifyAssertions) VM._assert(holderSlot==-1);
201        if (VM.VerifyAssertions) VM._assert(this.recCount==0);
202        holderSlot=RVMThread.getCurrentThreadSlot();
203        this.recCount=recCount;
204      }
205      /**
206       * Release the lock.  This method should (in principle) be non-blocking,
207       * and, as such, it does not notify the threading subsystem that it is
208       * blocking.
209       */
210      @NoInline
211      @NoOptCompile
212      public void unlock() {
213        if (--recCount==0) {
214          holderSlot=-1;
215          sysCall.sysMonitorExit(monitor);
216        }
217      }
218      /**
219       * Completely release the lock, ignoring recursion.  Returns the
220       * recursion count.
221       */
222      @NoInline
223      @NoOptCompile
224      public int unlockCompletely() {
225        int result=recCount;
226        recCount=0;
227        holderSlot=-1;
228        sysCall.sysMonitorExit(monitor);
229        return result;
230      }
231      /**
232       * Wait until someone calls broadcast.
233       * <p>
234       * This blocking method method does not notify the threading subsystem
235       * that it is blocking.  Thus, if someone (like, say, the GC) requests
236       * that the thread is blocked then their request will block until this
237       * method unblocks.  If this sounds like it might be undesirable, call
238       * waitNicely instead.
239       */
240      @NoInline
241      @NoOptCompile
242      public void waitNoHandshake() {
243        int recCount=this.recCount;
244        this.recCount=0;
245        holderSlot=-1;
246        sysCall.sysMonitorWait(monitor);
247        if (VM.VerifyAssertions) VM._assert(holderSlot==-1);
248        if (VM.VerifyAssertions) VM._assert(this.recCount==0);
249        this.recCount=recCount;
250        holderSlot=RVMThread.getCurrentThreadSlot();
251      }
252      /**
253       * Wait until someone calls broadcast, or until the clock reaches the
254       * given time.
255       * <p>
256       * This blocking method method does not notify the threading subsystem
257       * that it is blocking.  Thus, if someone (like, say, the GC) requests
258       * that the thread is blocked then their request will block until this
259       * method unblocks.  If this sounds like it might be undesirable, call
260       * timedWaitAbsoluteNicely instead.
261       */
262      @NoInline
263      @NoOptCompile
264      public void timedWaitAbsoluteNoHandshake(long whenWakeupNanos) {
265        int recCount=this.recCount;
266        this.recCount=0;
267        holderSlot=-1;
268        sysCall.sysMonitorTimedWaitAbsolute(monitor, whenWakeupNanos);
269        if (VM.VerifyAssertions) VM._assert(holderSlot==-1);
270        if (VM.VerifyAssertions) VM._assert(this.recCount==0);
271        this.recCount=recCount;
272        holderSlot=RVMThread.getCurrentThreadSlot();
273      }
274      /**
275       * Wait until someone calls broadcast, or until at least the given
276       * number of nanoseconds pass.
277       * <p>
278       * This blocking method method does not notify the threading subsystem
279       * that it is blocking.  Thus, if someone (like, say, the GC) requests
280       * that the thread is blocked then their request will block until this
281       * method unblocks.  If this sounds like it might be undesirable, call
282       * timedWaitRelativeNicely instead.
283       */
284      @NoInline
285      @NoOptCompile
286      public void timedWaitRelativeNoHandshake(long delayNanos) {
287        long now=sysCall.sysNanoTime();
288        timedWaitAbsoluteNoHandshake(now+delayNanos);
289      }
290      /**
291       * Wait until someone calls broadcast.
292       * <p>
293       * This blocking method notifies the threading subsystem that it
294       * is blocking.  Thus, it is generally safer than calling wait.  But,
295       * its reliance on threading subsystem accounting methods may mean that
296       * it cannot be used in certain contexts (say, the threading subsystem
297       * itself).
298       * <p>
299       * This method will ensure that if it blocks, it does so with the
300       * mutex not held.  This is useful for cases where the subsystem that
301       * requested you to block needs to acquire the lock you were trying to
302       * acquire when the blocking request came.
303       */
304      @NoInline
305      @NoOptCompile
306      @BaselineSaveLSRegisters
307      @Unpreemptible("While the thread is waiting, this method may allow the thread to be asynchronously blocked")
308      public void waitWithHandshake() {
309        RVMThread.saveThreadState();
310        waitWithHandshakeImpl();
311      }
312      @NoInline
313      @Unpreemptible
314      @NoOptCompile
315      private void waitWithHandshakeImpl() {
316        RVMThread.enterNative();
317        waitNoHandshake();
318        int recCount=unlockCompletely();
319        RVMThread.leaveNative();
320        relockWithHandshakeImpl(recCount);
321      }
322      /**
323       * Wait until someone calls broadcast, or until the clock reaches the
324       * given time.
325       * <p>
326       * This blocking method method notifies the threading subsystem that it
327       * is blocking.  Thus, it is generally safer than calling
328       * timedWaitAbsolute.  But, its reliance on threading subsystem accounting
329       * methods may mean that it cannot be used in certain contexts (say, the
330       * threading subsystem itself).
331       * <p>
332       * This method will ensure that if it blocks, it does so with the
333       * mutex not held.  This is useful for cases where the subsystem that
334       * requested you to block needs to acquire the lock you were trying to
335       * acquire when the blocking request came.
336       */
337      @NoInline
338      @NoOptCompile
339      @BaselineSaveLSRegisters
340      @Unpreemptible("While the thread is waiting, this method may allow the thread to be asynchronously blocked")
341      public void timedWaitAbsoluteWithHandshake(long whenWakeupNanos) {
342        RVMThread.saveThreadState();
343        timedWaitAbsoluteWithHandshakeImpl(whenWakeupNanos);
344      }
345      @NoInline
346      @Unpreemptible
347      @NoOptCompile
348      private void timedWaitAbsoluteWithHandshakeImpl(long whenWakeupNanos) {
349        RVMThread.enterNative();
350        timedWaitAbsoluteNoHandshake(whenWakeupNanos);
351        int recCount=unlockCompletely();
352        RVMThread.leaveNative();
353        relockWithHandshakeImpl(recCount);
354      }
355      /**
356       * Wait until someone calls broadcast, or until at least the given
357       * number of nanoseconds pass.
358       * <p>
359       * This blocking method method notifies the threading subsystem that it
360       * is blocking.  Thus, it is generally safer than calling
361       * timedWaitRelative.  But, its reliance on threading subsystem accounting
362       * methods may mean that it cannot be used in certain contexts (say, the
363       * threading subsystem itself).
364       * <p>
365       * This method will ensure that if it blocks, it does so with the
366       * mutex not held.  This is useful for cases where the subsystem that
367       * requested you to block needs to acquire the lock you were trying to
368       * acquire when the blocking request came.
369       */
370      @NoInline
371      @NoOptCompile
372      @BaselineSaveLSRegisters
373      @Unpreemptible("While the thread is waiting, this method may allow the thread to be asynchronously blocked")
374      public void timedWaitRelativeWithHandshake(long delayNanos) {
375        RVMThread.saveThreadState();
376        timedWaitRelativeWithHandshakeImpl(delayNanos);
377      }
378      @NoInline
379      @Unpreemptible
380      @NoOptCompile
381      private void timedWaitRelativeWithHandshakeImpl(long delayNanos) {
382        RVMThread.enterNative();
383        timedWaitRelativeNoHandshake(delayNanos);
384        int recCount=unlockCompletely();
385        RVMThread.leaveNative();
386        relockWithHandshakeImpl(recCount);
387      }
388    
389      /**
390       * Send a broadcast, which should awaken anyone who is currently blocked
391       * in any of the wait methods.  This method should (in principle) be
392       * non-blocking, and, as such, it does not notify the threading subsystem
393       * that it is blocking.
394       */
395      @NoInline
396      @NoOptCompile
397      public void broadcast() {
398        sysCall.sysMonitorBroadcast(monitor);
399      }
400      /**
401       * Send a broadcast after first acquiring the lock.  Release the lock
402       * after sending the broadcast.  In most cases where you want to send
403       * a broadcast but you don't need to acquire the lock to set the
404       * condition that the other thread(s) are waiting on, you want to call
405       * this method instead of <code>broadcast</code>.
406       */
407      @NoInline
408      @NoOptCompile
409      public void lockedBroadcastNoHandshake() {
410        lockNoHandshake();
411        broadcast();
412        unlock();
413      }
414    
415      @NoInline
416      public static boolean lockNoHandshake(Monitor l) {
417        if (l==null) {
418          return false;
419        } else {
420          l.lockNoHandshake();
421          return true;
422        }
423      }
424      @NoInline
425      public static void unlock(boolean b, Monitor l) {
426        if (b) l.unlock();
427      }
428    
429      @NoInline
430      @NoOptCompile
431      @Unpreemptible
432      public static void lockWithHandshake(Monitor m1,Word priority1,
433                                           Monitor m2,Word priority2) {
434        if (priority1.LE(priority2)) {
435          m1.lockWithHandshake();
436          m2.lockWithHandshake();
437        } else {
438          m2.lockWithHandshake();
439          m1.lockWithHandshake();
440        }
441      }
442    }
443