/*
* 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.VM;
import static org.jikesrvm.runtime.VM_SysCall.sysCall;
import org.jikesrvm.scheduler.VM_ProcessorLock;
import org.vmmagic.pragma.Interruptible;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.pragma.UninterruptibleNoWarn;
/**
* A list of threads which are blocked on the main processor while they
* are migrated to the subarch processor.
*/
@Uninterruptible
public final class VM_ThreadSubArchWaitQueue extends VM_ThreadEventWaitQueue
implements VM_ThreadEventConstants, VM_ThreadSubArchConstants {
/**
* Class to safely downcast from <code>VM_ThreadEventWaitData</code>
* to <code>VM_ThreadSubArchWaitData</code>.
* We use this because an actual Java cast could result in
* a thread switch, which is obviously bad in uninterruptible
* code.
*/
@Uninterruptible
private static class WaitDataDowncaster extends VM_ThreadEventWaitDataVisitor {
private VM_ThreadSubArchWaitData waitData;
@Override
void visitThreadSubArchWaitData(VM_ThreadSubArchWaitData waitData) {
this.waitData = waitData;
}
@Override
void visitThreadProcessWaitData(VM_ThreadProcessWaitData waitData) {
if (VM.VerifyAssertions) VM._assert(false);
}
@Override
void visitThreadIOWaitData(VM_ThreadIOWaitData waitData) {
if (VM.VerifyAssertions) VM._assert(false);
}
}
/**
* Private downcaster object for this queue.
* Avoids having to create them repeatedly.
*/
private final WaitDataDowncaster myDowncaster = new WaitDataDowncaster();
private static final int SUBARCH_SETSIZE = 32;
/**
* Array containing read, write, and exception file descriptor sets.
* Used by subArchSelect().
*/
private int[] allSubArchThrds = new int[SUBARCH_SETSIZE];
private int currOffset;
/** Guard for updating "selectInProgress" flag. */
public static final VM_ProcessorLock statusCheckInProgressMutex = new VM_ProcessorLock();
//-----------//
// Interface //
//-----------//
/**
* Poll subarch status to see which ones have become ready.
* Called from superclass's {@link VM_ThreadEventWaitQueue#isReady()} method.
* @return true if poll was successful, false if not
*/
@Override
public boolean pollForEvents() {
currOffset = 0;
// Interrogate all threads in the queue to determine
// which subArch threads they are waiting for
VM_GreenThread thread = head;
while (thread != null) {
// Safe downcast from VM_ThreadEventWaitData to VM_ThreadSubArchWaitData.
thread.waitData.accept(myDowncaster);
VM_ThreadSubArchWaitData waitData = myDowncaster.waitData;
if (VM.VerifyAssertions) VM._assert(waitData == thread.waitData);
// copy across subarch wait status to set
waitData.subArchThrdsOffset = currOffset;
allSubArchThrds[currOffset++] = waitData.subArchThreadStatus;
if (VM.VerifyAssertions) VM._assert(currOffset < SUBARCH_SETSIZE);
thread = (VM_GreenThread)thread.getNext();
}
// Do the select()
statusCheckInProgressMutex.lock("select in progress mutex");
int ret = sysCall.subArchCheckStatus(allSubArchThrds, currOffset + 1);
statusCheckInProgressMutex.unlock();
// Did the subArchCheckStatus() succeed?
return ret != -1;
}
/**
* Determine whether or not given thread has become ready
* to run, i.e., because the subarch migrated part has completed
* If the thread is ready, update its wait flags appropriately.
*/
@Override
public boolean isReady(VM_GreenThread thread) {
// Safe downcast from VM_ThreadEventWaitData to VM_ThreadSubArchWaitData.
thread.waitData.accept(myDowncaster);
VM_ThreadSubArchWaitData waitData = myDowncaster.waitData;
if (VM.VerifyAssertions) VM._assert(waitData == thread.waitData);
boolean ready = (allSubArchThrds[waitData.subArchThrdsOffset] & SUBARCH_READY_BIT) != 0;
if (ready) {
waitData.subArchThreadStatus |= SUBARCH_READY_BIT;
waitData.setFinished();
}
return ready;
}
@Interruptible
@Override
void dumpWaitDescription(VM_GreenThread thread) {
thread.waitData.accept(myDowncaster);
VM_ThreadSubArchWaitData waitData = myDowncaster.waitData;
VM.sysWrite("SubArchWaitID: ");
VM.sysWrite(Integer.toHexString(waitData.subArchThreadStatus));
}
@Interruptible
@Override
String getWaitDescription(VM_GreenThread thread) {
thread.waitData.accept(myDowncaster);
VM_ThreadSubArchWaitData waitData = myDowncaster.waitData;
StringBuffer buffer = new StringBuffer();
buffer.append("SubArchWaitID:");
buffer.append(Integer.toHexString(waitData.subArchThreadStatus));
return buffer.toString();
}
}