/*
* JBoss, Home of Professional Open Source
* Copyright 2009-10 Red Hat and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
* @authors Andrew Dinn
*/
package org.jboss.byteman.synchronization;
import org.jboss.byteman.rule.exception.ExecuteException;
import java.util.List;
import java.util.LinkedList;
/**
* class used by default helper to implement join dependencies between threads
*/
public class Joiner
{
/**
* status values returned from child add method
*/
public enum Status {
/**
* a DUPLICATE status is returned when a child fails to add itself to the join list because it is already present
*/
DUPLICATE,
/**
* an EXCESS status is returned when a child fails to add itself to a join list because it already contains the
* expected number of children
*/
EXCESS,
/**
* an ADDED status is returned when a child successfully adds itself to the join list but without reaching
* the expected number of children
*/
ADDED,
/**
* a FILLED status is returned when a child successfully adds itself to the join list reaching the expected
* number of children but there is no parent thread waiting for the children
*/
FILLED,
/**
* a DONE status is returned when a child successfully adds itself to the join list reaching the expected
* number of children and there is a parent thread waiting for the children
*/
DONE
}
private List<Thread> children;
private int max;
private Thread parent;
public Joiner(int max)
{
this.max = max;
this.children = new LinkedList<Thread>();
this.parent = null;
}
public int getMax()
{
return max;
}
public synchronized Status addChild(Thread thread)
{
if (children.contains(thread)) {
return Status.DUPLICATE;
}
int size = children.size();
if (size == max) {
return Status.EXCESS;
}
children.add(thread);
size++;
if (size == max) {
if (parent == null) {
return Status.FILLED;
} else {
notifyAll();
return Status.DONE;
}
}
return Status.ADDED;
}
public boolean joinChildren(Thread thread, long millis)
{
long target_time=System.currentTimeMillis() + millis;
synchronized (this) {
if (parent != null) {
return false;
}
parent = thread;
while (children.size() < max) {
try {
if (millis <= 0) {
this.wait();
} else {
long wait_time=target_time - System.currentTimeMillis();
if(wait_time > 0) {
this.wait(wait_time);
} else {
throw new ExecuteException("timeout occurred in joinWait");
}
}
} catch (InterruptedException e) {
// do nothing
}
}
}
// since we are the parent and the waiting is over we don't need to stay synchronized
for (int i = 0; i < max;) {
Thread child = children.get(i);
try {
if (millis <= 0) {
child.join();
} else {
long wait_time=target_time - System.currentTimeMillis();
if(wait_time > 0) {
child.join(wait_time);
} else {
throw new ExecuteException("timeout occurred in joinWait");
}
}
} catch (InterruptedException e) {
// try again
break;
}
i++;
}
return true;
}
}