X-Git-Url: http://dolda2000.com/gitweb/?p=jsvc.git;a=blobdiff_plain;f=src%2Fdolda%2Fjsvc%2FThreadContext.java;h=27d90bf925c4c8a2dc2586293f5c912e332490ff;hp=486bc91bb268fa5d7e1d5af06d569fd0c48dad00;hb=5cdd61df59fc87e9f8dbbfb0f1ea1c535a3694f9;hpb=6a0cb6cbc9b46f7e220e27e08b9eaa8805e99d6d diff --git a/src/dolda/jsvc/ThreadContext.java b/src/dolda/jsvc/ThreadContext.java index 486bc91..27d90bf 100644 --- a/src/dolda/jsvc/ThreadContext.java +++ b/src/dolda/jsvc/ThreadContext.java @@ -1,7 +1,9 @@ package dolda.jsvc; +import dolda.jsvc.util.Misc; import java.util.logging.*; import java.lang.reflect.*; +import java.util.*; public class ThreadContext extends ThreadGroup { private Logger logger = Logger.getLogger("dolda.jsvc.context"); @@ -9,6 +11,8 @@ public class ThreadContext extends ThreadGroup { private long reqs = 0; private final ServerContext ctx; public final Responder root; + private int timelimit = 0; + private boolean forcelimit = false; public ThreadContext(ThreadGroup parent, String name, ServerContext ctx, Class bootclass) { super((parent == null)?(Thread.currentThread().getThreadGroup()):parent, name); @@ -18,7 +22,88 @@ public class ThreadContext extends ThreadGroup { logger.log(Level.SEVERE, "Worker thread terminated with an uncaught exception", e); } }; + + int tl; + tl = Integer.parseInt(ctx.sysconfig("jsvc.timelimit", "0")); + if((tl > 0) && ((timelimit == 0) || (tl < timelimit))) + timelimit = tl; + tl = Integer.parseInt(ctx.libconfig("jsvc.timelimit", "0")); + if((tl > 0) && ((timelimit == 0) || (tl < timelimit))) + timelimit = tl; + forcelimit |= Misc.boolval(ctx.sysconfig("jsvc.forcelimit", "0")); + forcelimit |= Misc.boolval(ctx.libconfig("jsvc.forcelimit", "0")); + root = bootstrap(bootclass); + + if(timelimit > 0) + (new WatchDog()).start(); + } + + private class WatchDog extends Thread { + private Map state = new WeakHashMap(); + + private class State { + String st = "running"; + long lastkill; + } + + private WatchDog() { + super(ThreadContext.this, "Worker watchdog"); + setDaemon(true); + } + + @SuppressWarnings("deprecation") + private long ckthread(long now, RequestThread rt) { + State st = state.get(rt); + if(st == null) { + st = new State(); + state.put(rt, st); + } + if(st.st == "running") { + if(now - rt.stime() > timelimit) { + rt.interrupt(); + st.st = "interrupted"; + st.lastkill = now; + return(5000); + } else { + return(timelimit - (now - rt.stime())); + } + } else if((st.st == "interrupted") || (st.st == "killed")) { + if(st.st == "killed") + logger.log(Level.WARNING, "Thread " + rt + " refused to die; killing again"); + if(now - st.lastkill > 5000) { + rt.stop(); + st.st = "killed"; + st.lastkill = now; + } else { + return(5000 - (now - st.lastkill)); + } + } + return(timelimit); + } + + public void run() { + try { + while(true) { + long next = timelimit; + long now = System.currentTimeMillis(); + Thread[] w = new Thread[workers.activeCount() + 5]; + int num = workers.enumerate(w); + for(int i = 0; i < num; i++) { + if(w[i] instanceof RequestThread){ + RequestThread rt = (RequestThread)w[i]; + if(rt.stime() > 0) { + long n = ckthread(now, rt); + if(n < next) + next = n; + } + } + } + Thread.sleep(next); + } + } catch(InterruptedException e) { + } + } } public void uncaughtException(Thread t, Throwable e) {