Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [cdt-dev] DSF executor thread consumes 100% cpu on terminate

There are other issues with the executor implementation, so a re-implementation would be nice.

Cheers,
Pawel

On 10/14/2012 05:35 AM, Dave Korn wrote:
On 13/10/2012 19:45, Dave Korn wrote:
     Hi list,

   I've got a lightly-customised DSF-GDB (based on Helios and CDT 7.0.0) and
I'm seeing very strange behaviour when I click on the terminate button: for
anywhere between 10 and 30 seconds, the DSF executor thread goes bananas,
spinning wildly and hogging 100% cpu.
   I think I've figured it out, and AFAICT it should occur to everyone
everywhere who terminates a debug session within the first 30 seconds, before ...

211,390 DSF execution #807. Executor is (org.eclipse.cdt.dsf.gdb - 3)
	Executable detail:
		type = java.lang.Object
		instance = org.eclipse.cdt.dsf.gdb.service.GDBBackend$GDBProcessStep$3@1c9c38d
		submitted by #26 at:
org.eclipse.cdt.dsf.gdb.service.GDBBackend$GDBProcessStep.initialize(GDBBackend.java:552)
org.eclipse.cdt.dsf.gdb.service.command.GDBControl$InitializationShutdownStep.execute(GDBControl.java:491)
org.eclipse.cdt.dsf.concurrent.Sequence.executeStep(Sequence.java:443)


... this step executes.  That, IIUC, is the 30-second timeout to make sure
that GDB started running correctly.

   The actual problem is caused by (what I consider to be) a design flaw in the
Java 1.6 ThreadPoolExecutor class.  If there are scheduled tasks left on the
queue when the thread enters the SHUTDOWN state, ThreadPoolExecutor.getTask
busy loops waiting for them to come ready:

     Runnable getTask() {
         for (;;) {
             try {
                 int state = runState;
                 if (state > SHUTDOWN)
                     return null;
                 Runnable r;
                 if (state == SHUTDOWN)  // Help drain queue
                     r = workQueue.poll();
                 else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
                     r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
                 else
                     r = workQueue.take();
                 if (r != null)
                     return r;
                 if (workerCanExit()) {
                     if (runState >= SHUTDOWN) // Wake up others
                         interruptIdleWorkers();
                     return null;
                 }
                 // Else retry
             } catch (InterruptedException ie) {
                 // On interruption, re-check runState
             }
         }
     }

   The comment "Help drain queue" should really read "Help consume all
available CPU time", because that's what it's going to do when there's still a
task scheduled for some time in the future.

   I can see two possible solutions to this problem: one would be to change how
we timeout GDB startup, by scheduling a task say once second in the future
that checks if GDB has started successfully and reschedules itself one further
second in the future if not, up to 30 times until startup succeeds or the
retry count expires.

   The other way would be to re-implement ScheduledThreadPoolExecutor and
ThreadPoolExecutor, from which the DefaultDsfExecutor inherits, and fix the
behaviour of getTask to not eat CPU; looking at the GNU Classpath
implementation, if the thread is shutting down and poll() returns null, it
does a take() instead.  That should avoid thrashing the CPU.

   Any suggestions for further solutions, or observations on advantages or
disadvantages of the two proposed solutions would be welcome, or indeed
corrections if I've misunderstood or missed anything out, but hopefully I'm
good to go now.  Thanks for listening while I think out loud!

     cheers,
       DaveK


_______________________________________________
cdt-dev mailing list
cdt-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/cdt-dev



Back to the top