/*
* 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.adaptive;
import org.jikesrvm.adaptive.controller.VM_Controller;
import org.jikesrvm.runtime.VM_Entrypoints;
import org.jikesrvm.scheduler.VM_Scheduler;
import org.jikesrvm.scheduler.VM_Synchronization;
import org.jikesrvm.scheduler.greenthreads.VM_GreenThread;
import org.jikesrvm.scheduler.greenthreads.VM_GreenThreadQueue;
import org.vmmagic.pragma.Uninterruptible;
/**
* Organizer thread collects OSR requests and inserted in controller queue
* The producers are application threads, and the consumer thread is the
* organizer. The buffer is VM_Scheduler.threads array. The producer set
* it is own flag "requesting_osr" and notify the consumer. The consumer
* scans the threads array and collect requests. To work with concurrency,
* we use following scheme:
* P - producer, C - consumer
* P1, P2:
* if (C.osr_flag == false) {
* C.osr_flag = true;
* C.activate();
* }
*
* C:
* while (true) {
* while (osr_flag == true) {
* osr_flag = false;
* scan threads array
* }
* // P may set osr_flag here, C is active now
* C.passivate();
* }
*
* // compensate the case C missed osr_flag
* Other thread switching:
* if (C.osr_flag == true) {
* C.activate();
* }
*
* C.activate and passivate have to acquire a lock before dequeue and
* enqueue.
*/
public final class OSR_OrganizerThread extends VM_GreenThread {
/** Constructor */
public OSR_OrganizerThread() {
super("OSR_Organizer");
makeDaemon(true);
}
public boolean osr_flag = false;
@Override
public void run() {
while (true) {
while (this.osr_flag) {
this.osr_flag = false;
processOsrRequest();
}
// going to sleep, possible a osr request is set by producer
passivate();
}
}
// lock = 0, free , 1 owned by someone
@SuppressWarnings("unused")
// Accessed via VM_EntryPoints
private int queueLock = 0;
private final VM_GreenThreadQueue tq = new VM_GreenThreadQueue();
private void passivate() {
boolean gainedLock = VM_Synchronization.testAndSet(this, VM_Entrypoints.osrOrganizerQueueLockField.getOffset(), 1);
if (gainedLock) {
// we cannot release lock before enqueue the organizer.
// ideally, calling yield(q, l) is the solution, but
// we donot want to use a lock
//
// this.beingDispatched = true;
// tq.enqueue(this);
// this.queueLock = 0;
// morph(false);
//
// currently we go through following sequence which is incorrect
//
// this.queueLock = 0;
// this.beingDispatched = true;
// tq.enqueue(this);
// morph(false);
//
this.queueLock = 0; // release lock
yield(tq); // sleep in tq
}
// if failed, just continue the loop again
}
/**
* Activates organizer thread if it is sleeping in the queue.
* Only one thread can access queue at one time
*/
@Uninterruptible
public void activate() {
boolean gainedLock = VM_Synchronization.testAndSet(this, VM_Entrypoints.osrOrganizerQueueLockField.getOffset(), 1);
if (gainedLock) {
VM_GreenThread org = tq.dequeue();
// release lock
this.queueLock = 0;
if (org != null) {
org.schedule();
}
}
// otherwise, donot bother
}
// proces osr request
private void processOsrRequest() {
// scanning VM_Scheduler.threads
for (int i = 0, n = VM_Scheduler.threads.length; i < n; i++) {
VM_GreenThread thread = (VM_GreenThread)VM_Scheduler.threads[i];
if (thread != null) {
if (thread.requesting_osr) {
thread.requesting_osr = false;
VM_Controller.controllerInputQueue.insert(5.0, thread.onStackReplacementEvent);
}
}
}
}
}