Author: j16sdiz
Date: 2009-04-21 06:05:27 +0000 (Tue, 21 Apr 2009)
New Revision: 27130
Modified:
trunk/freenet/src/freenet/support/PooledExecutor.java
Log:
Fix race condition
1) Remove from waiting threads before check for next job,
so no one may pick this thread in the time gap.
2) Update waitingThreadsCount as soon as it is changed.
3) Set thread name on the thread
Modified: trunk/freenet/src/freenet/support/PooledExecutor.java
===================================================================
--- trunk/freenet/src/freenet/support/PooledExecutor.java 2009-04-21
06:05:06 UTC (rev 27129)
+++ trunk/freenet/src/freenet/support/PooledExecutor.java 2009-04-21
06:05:27 UTC (rev 27130)
@@ -54,15 +54,17 @@
execute(job, jobName, false);
}
- public void execute(Runnable job, String jobName, boolean fromTicker) {
+ public void execute(Runnable runnable, String jobName, boolean
fromTicker) {
int prio = NativeThread.NORM_PRIORITY;
- if(job instanceof PrioRunnable)
- prio = ((PrioRunnable) job).getPriority();
+ if(runnable instanceof PrioRunnable)
+ prio = ((PrioRunnable) runnable).getPriority();
if(logMINOR)
- Logger.minor(this, "Executing " + job + " as " +
jobName + " at prio " + prio);
+ Logger.minor(this, "Executing " + runnable + " as " +
jobName + " at prio " + prio);
if(prio < NativeThread.MIN_PRIORITY || prio >
NativeThread.MAX_PRIORITY)
throw new IllegalArgumentException("Unreconized
priority level : " + prio + '!');
+
+ Job job = new Job(runnable, jobName);
while(true) {
MyThread t = null;
boolean miss = false;
@@ -70,6 +72,8 @@
jobCount++;
if(!waitingThreads[prio - 1].isEmpty()) {
t = waitingThreads[prio -
1].remove(waitingThreads[prio - 1].size() - 1);
+ if (t != null)
+ waitingThreadsCount--;
if(logMINOR)
Logger.minor(this, "Reusing
thread " + t);
} else {
@@ -77,7 +81,7 @@
if((!fromTicker) &&
NativeThread.usingNativeCode() && prio > Thread.currentThread().getPriority()) {
// Run on ticker
// j16sdiz (22-Dec-2008):
should we queue it? the ticker is "PacketSender", but it keep busying on
non-packet related works
- ticker.queueTimedJob(job,
jobName, 0, true);
+ ticker.queueTimedJob(runnable,
jobName, 0, true);
return;
}
miss = true;
@@ -90,7 +94,6 @@
// Will be coalesced by thread count listings
if we use "@" or "for"
t = new MyThread("Pooled thread awaiting work
@" + threadNo, job, threadNo, prio, !fromTicker);
t.setDaemon(true);
- t.setName(jobName + "(" + threadNo + ")");
synchronized(this) {
runningThreads[prio - 1].add(t);
@@ -111,13 +114,12 @@
if(t.nextJob != null)
continue;
t.nextJob = job;
-
+
// It is possible that we could get a
wierd race condition with
// notify()/wait() signalling on a
thread being used by higher
// level code. So we'd best use
notifyAll().
t.notifyAll();
}
- t.setName(jobName + "(" + t.threadNo + ")");
if(logMINOR)
synchronized(this) {
@@ -144,15 +146,24 @@
public int getWaitingThreadsCount() {
return waitingThreadsCount;
}
+
+ private static class Job {
+ private Runnable runnable;
+ private String name;
+ Job(Runnable runnable, String name) {
+ this.runnable = runnable;
+ this.name = name;
+ }
+ }
+
private class MyThread extends NativeThread {
-
final String defaultName;
volatile boolean alive = true;
- Runnable nextJob;
+ Job nextJob;
final long threadNo;
- public MyThread(String defaultName, Runnable firstJob, long
threadCounter, int prio, boolean dontCheckRenice) {
+ public MyThread(String defaultName, Job firstJob, long
threadCounter, int prio, boolean dontCheckRenice) {
super(defaultName, prio, dontCheckRenice);
this.defaultName = defaultName;
threadNo = threadCounter;
@@ -165,7 +176,7 @@
long ranJobs = 0;
int nativePriority = getNativePriority();
while(true) {
- Runnable job;
+ Job job;
synchronized(this) {
job = nextJob;
@@ -186,14 +197,18 @@
// Ignore
}
}
- job = nextJob;
- nextJob = null;
- if(job == null)
- alive = false;
}
synchronized(PooledExecutor.this) {
- waitingThreads[nativePriority -
1].remove(this);
- waitingThreadsCount--;
+ if
(waitingThreads[nativePriority - 1].remove(this))
+ waitingThreadsCount--;
+
+ synchronized(this) {
+ job = nextJob;
+ nextJob = null;
+ if(job == null)
+ alive = false;
+ }
+
if(!alive) {
runningThreads[nativePriority - 1].remove(this);
if(logMINOR)
@@ -205,7 +220,8 @@
// Run the job
try {
- job.run();
+ setName(job.name + "(" + threadNo +
")");
+ job.runnable.run();
} catch (OutOfMemoryError e) {
OOMHandler.handleOOM(e);
} catch(Throwable t) {
_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs