package org.jboss.util;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.LinkedList;
import java.io.StringWriter;
import java.io.PrintWriter;
public class Semaphore
implements Sync
{
private static final long DEADLOCK_TIMEOUT = 5*60*1000;
private final static boolean m_debug = false;
private int m_users;
private int m_allowed;
private Map m_logMap;
public Semaphore(int allowed)
{
if (allowed < 1) throw new IllegalArgumentException();
m_users = 0;
m_allowed = allowed;
m_logMap = new HashMap();
}
public int getUsers()
{
synchronized (this)
{
return m_users;
}
}
public void acquire() throws InterruptedException
{
synchronized (this)
{
logAcquire();
++m_users;
boolean waitSuccessful = false;
while (m_allowed <= 0)
{
waitSuccessful = waitImpl(this);
if (!waitSuccessful)
{
--m_users;
++m_allowed;
}
}
--m_allowed;
}
}
public void release()
{
synchronized (this)
{
logRelease();
--m_users;
++m_allowed;
notify();
}
}
public String toString()
{
return super.toString() + " - " + m_users;
}
protected boolean waitImpl(Object lock) throws InterruptedException
{
long start = System.currentTimeMillis();
lock.wait(DEADLOCK_TIMEOUT);
long end = System.currentTimeMillis();
if ((end - start) > (DEADLOCK_TIMEOUT - 1000))
{
logDeadlock();
return false;
}
return true;
}
protected void logAcquire()
{
if (m_debug)
{
Thread thread = Thread.currentThread();
StringWriter sw = new StringWriter();
new Exception().printStackTrace(new PrintWriter(sw));
String trace = sw.toString();
LinkedList list = (LinkedList)m_logMap.get(thread);
if (list != null)
{
Info prevInfo = (Info)list.getLast();
Info info = new Info(thread, m_users, trace);
list.add(info);
}
else
{
list = new LinkedList();
Info info = new Info(thread, m_users, trace);
list.add(info);
m_logMap.put(thread, list);
}
}
}
protected void logDeadlock()
{
System.err.println();
System.err.println("DEADLOCK ON SEMAPHORE " + this);
if (m_debug)
{
for (Iterator i = m_logMap.values().iterator(); i.hasNext();)
{
LinkedList list = (LinkedList)i.next();
for (Iterator iter = list.iterator(); iter.hasNext();)
{
System.err.println(iter.next());
}
}
}
System.err.println();
}
protected void logRelease()
{
if (m_debug)
{
Thread thread = Thread.currentThread();
LinkedList list = (LinkedList)m_logMap.get(thread);
if (list != null)
{
Info info = new Info(thread, 0, "");
if (!list.remove(info))
{
System.err.println("LOG INFO SIZE: " + list);
new IllegalStateException("BUG: semaphore log list does not contain required info").printStackTrace();
}
int size = list.size();
if (size < 1)
{
m_logMap.remove(thread);
}
}
else
{
throw new IllegalStateException("Semaphore log failed: release called without acquire");
}
}
}
private class Info
{
private Info(Thread t, int i, String s)
{
m_thread = t;
m_counter = i;
m_trace = s;
}
private Thread m_thread;
private int m_counter;
private String m_trace;
public boolean equals(Object o)
{
Info other = (Info)o;
return m_thread == other.m_thread;
}
public String toString()
{
return m_thread + " - " + m_counter + "\n" + m_trace;
}
}
}