/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.scheduler.greenthreads; import org.jikesrvm.scheduler.VM_ProcessorLock; import org.vmmagic.pragma.Uninterruptible; /** * To implement timed waits, a thread may need to be (logically) on two queues: * a waiting queue and a (the) wakeup queue. To facilitate this, a proxy * represents the thread on such queues. Unlike a thread, which can be on at * most one queue, a proxy can be on both a waiting queue and a wakeup queue. * * When the proxy is dequeued it nullifies its thread reference. Either * queue finding a proxy with a null patron knows the other queue has handled * it and should skip that entry. * * Potential race condition: a thread must not be simultaneously removed from * both queues and scheduled twice. An atomic swap prevents this. */ @Uninterruptible public final class VM_ThreadProxy { /** * The real thread that is waiting on both queues or null. Null is used to * indicate a thread has been dequed from one or other queue. If a null proxy * is found on a queue then the queue will remove it. */ private volatile VM_GreenThread patron; /** * Ensure atomicity of certain events */ final VM_ProcessorLock mutex = new VM_ProcessorLock(); /** When the thread is scheduled to wake up if it's on the wakeup queue */ private final long wakeupNano; /** The next element in the waiting queue */ private VM_ThreadProxy waitingNext; /** The next element in the wakeup queue */ private VM_ThreadProxy wakeupNext; /** Create a proxy for a thread on a waiting queue */ public VM_ThreadProxy(VM_GreenThread t) { patron = t; wakeupNano = 0; } /** * Create a proxy for a thread on a wakeup queue (may be on a waiting queue * also) */ public VM_ThreadProxy(VM_GreenThread t, long nano) { patron = t; wakeupNano = nano; } /** * Remove the thread from the queue * @return null means the thread has already been scheduled (ignore) */ public VM_GreenThread unproxy() { VM_GreenThread t = patron; if (t != null) { mutex.lock("Unproxying thread"); t = patron; patron = null; if (t != null) { t.threadProxy = null; } mutex.unlock(); } return t; } /** Get the thread owning the proxy */ VM_GreenThread getPatron() { return patron; } /** Get the wake up time */ long getWakeupNano() { return wakeupNano; } /** Get the next element in the waiting queue */ VM_ThreadProxy getWaitingNext() { return waitingNext; } /** Set the next element in the waiting queue */ void setWaitingNext(VM_ThreadProxy wn) { waitingNext = wn; } /** Get the next element in the wakeup queue */ VM_ThreadProxy getWakeupNext() { return wakeupNext; } /** Set the next element in the wakeup queue */ void setWakeupNext(VM_ThreadProxy wn) { wakeupNext = wn; } }