in java/debugger.jpda/src/org/netbeans/modules/debugger/jpda/util/Operator.java [267:689]
private boolean processEvents(EventSet eventSet, Executor starter,
SuspendControllersSupport scs, SuspendCount suspendCount) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, ObjectCollectedExceptionWrapper, IllegalThreadStateExceptionWrapper {
List<Function<EventSet, Boolean>> interceptors;
synchronized (eventsInterceptors) {
if (eventsInterceptors.isEmpty()) {
interceptors = null;
} else {
interceptors = new ArrayList<>(eventsInterceptors);
}
}
if (interceptors != null) {
for (Function<EventSet, Boolean> interceptor : interceptors) {
if (interceptor.apply(eventSet)) {
return true;
}
}
}
boolean silent = eventSet.size() > 0;
for (Event e: eventSet) {
EventRequest r = EventWrapper.request(e);
if (r == null || !Boolean.TRUE.equals(EventRequestWrapper.getProperty (r, SILENT_EVENT_PROPERTY))) {
silent = false;
break;
}
}
// Notify threads about suspend state, but do not fire any events yet.
boolean resume = true, startEventOnly = true;
int suspendPolicy = EventSetWrapper.suspendPolicy(eventSet);
boolean suspendedAll = suspendPolicy == EventRequest.SUSPEND_ALL;
JPDAThreadImpl suspendedThread = null;
boolean threadWasInitiallySuspended = false;
Lock eventAccessLock = null;
try {
ThreadReference thref = null;
boolean isThreadEvent = false;
for (Event e: eventSet) {
if (e instanceof ThreadStartEvent || e instanceof ThreadDeathEvent) {
isThreadEvent = true;
}
thref = getEventThread(e);
if (thref != null) {
break;
}
}
Set<ThreadReference> ignoredThreads = testIgnoreEvent(eventSet);
if (ignoredThreads != null && ignoredThreads.isEmpty()) {
EventSetWrapper.resume(eventSet); // Ignore such events completely
return true;
}
if (ignoredThreads != null) {
synchronized (parallelEvents) {
parallelEvents.add(eventSet);
haveParallelEventsToProcess = true;
if (logger.isLoggable(Level.FINE)) {
try {
logger.fine(" the event(s) in the Queue are stored as parallelEvents = "+parallelEvents);
} catch (ObjectCollectedException ocex) {
logger.log(Level.FINE, " the event(s) in the Queue are stored as parallelEvents with something collected:", ocex);
}
}
}
loopControl.setHaveParallelEventsInLoopThread(true);
for (ThreadReference t : ignoredThreads) {
if (logger.isLoggable(Level.FINE)) {
logger.fine(" resuming "+t+" to finish method invocation... Status "+JPDAThreadImpl.getThreadStateLog(t));
}
ThreadReferenceWrapper.resume(t);
}
return true;
}
if (thref != null && !isThreadEvent) {
debugger.getThreadsCache().assureThreadIsCached(thref);
}
boolean suspendedCurrentThread = suspendPolicy == EventRequest.SUSPEND_EVENT_THREAD && thref != null;
// Check if it's a thread death event
boolean isThreadDeath = false;
for (Event e: eventSet) {
if (e instanceof ThreadDeathEvent) {
isThreadDeath = true;
} else {
isThreadDeath = false;
break;
}
}
if (!silent) {
if (suspendedAll) {
eventAccessLock = debugger.accessLock.writeLock();
if (logger.isLoggable(Level.FINE)) {
logger.finer("Write access lock TAKEN "+eventAccessLock+" on whole debugger.");
}
} else if (suspendedCurrentThread) {
suspendedThread = debugger.getThread(thref);
eventAccessLock = suspendedThread.accessLock.writeLock();
if (logger.isLoggable(Level.FINE)) {
logger.finer(suspendedThread.getThreadStateLog()+" Write access lock TAKEN "+eventAccessLock+" on the current thread.");
}
}
if (eventAccessLock != null) {
eventAccessLock.lock();
if (thref != null && !isThreadDeath) {
try {
if (!ThreadReferenceWrapper.isSuspended(thref)) {
// Can not do anything, someone already resumed the thread in the mean time.
// The event is missed. We will therefore ignore it.
try {
logger.warning("!!\nMissed event "+eventSet+" thread "+thref+" is not suspended!\n");
JPDAThreadImpl existingThread = debugger.getExistingThread(thref);
logger.warning(" JPDAThread: "+existingThread+" State = "+((existingThread != null) ? existingThread.getThreadStateLog() : null));
if (suspendedAll) {
List<ThreadReference> allThreads = thref.virtualMachine().allThreads();
for (ThreadReference t : allThreads) {
logger.warning(" "+t+" is suspended = "+t.isSuspended()+", status = "+t.status());
}
}
} catch (ObjectCollectedException ocex) {
try {
logger.warning("!!\nMissed event "+eventSet+" due to collected thread");
} catch (ObjectCollectedException ocex2) {
logger.warning("!!\nMissed some event, collected already!");
}
}
return true;
}
} catch (ObjectCollectedExceptionWrapper e) {
// O.K. the thread is gone...
return true;
} catch (IllegalThreadStateExceptionWrapper e) {
// O.K. the thread is gone...
return true;
} catch (InternalExceptionWrapper e) {
// ignore VM defects
}
// We check for multiple-suspension when event is received
try {
int sc = ThreadReferenceWrapper.suspendCount(thref);
if (logger.isLoggable(Level.FINER)) {
logger.finer("Suspend count of "+thref+" is "+sc+"."+((sc > 1) ? "Reducing to one." : ""));
}
suspendCount.removeSuspendCountFor(thref);
while (sc-- > 1) {
suspendCount.add(thref);
ThreadReferenceWrapper.resume(thref);
}
} catch (ObjectCollectedExceptionWrapper e) {
} catch (IllegalThreadStateExceptionWrapper e) {
// ignore mobility VM defects
} catch (InternalExceptionWrapper e) {
// ignore mobility VM defects
}
}
}
if (suspendedAll) {
//TODO: Not really all might be suspended! If some were already.
debugger.notifySuspendAllNoFire(ignoredThreads, thref);
} else if (suspendedCurrentThread && (ignoredThreads == null || !ignoredThreads.contains(thref))) {
threadWasInitiallySuspended = suspendedThread.isSuspended();
suspendedThread.notifySuspendedNoFire(true, isThreadDeath);
}
}
if (logger.isLoggable(Level.FINE)) {
switch (suspendPolicy) {
case EventRequest.SUSPEND_ALL:
logger.fine("JDI new events (suspend all)=============================================");
break;
case EventRequest.SUSPEND_EVENT_THREAD:
logger.fine("JDI new events (suspend one)=============================================");
break;
case EventRequest.SUSPEND_NONE:
logger.fine("JDI new events (suspend none)=============================================");
break;
default:
logger.fine("JDI new events (?????)=============================================");
break;
}
logger.fine(" event is silent = "+silent);
}
Map<Event, Executor> eventsToProcess = new HashMap<Event, Executor>();
for (Event e: eventSet) {
EventRequest r = EventWrapper.request(e);
Executor exec = (r != null) ? (Executor) EventRequestWrapper.getProperty (r, "executor") : null;
if (exec instanceof ConditionedExecutor) {
boolean success = ((ConditionedExecutor) exec).processCondition(e);
if (success) {
eventsToProcess.put(e, exec);
}
} else {
eventsToProcess.put(e, exec);
}
}
boolean stepFinished = false;
if (!eventsToProcess.isEmpty()) {
for (Event e: eventSet) {
if (!eventsToProcess.containsKey(e)) {
// Ignore events whose executor conditions did not evaluate successfully.
continue;
}
if ((e instanceof VMDeathEvent) ||
(e instanceof VMDisconnectEvent)
) {
if (logger.isLoggable(Level.FINE)) {
printEvent (e, null);
}
synchronized (Operator.this) {
stop = true;
}
return false;
}
if ((e instanceof VMStartEvent) && (starter != null)) {
resume = resume & starter.exec (e);
//S ystem.out.println ("Operator.start VM"); // NOI18N
if (logger.isLoggable(Level.FINE)) {
printEvent (e, null);
}
continue;
}
if (thref != null && (e instanceof StepEvent)) {
stepFinished = true;
JPDAThreadImpl jt = debugger.getThread(thref);
// The step can not be suspended by anything any more.
jt.unsetSteppingSuspendedByBpts();
}
Executor exec = null;
if (EventWrapper.request(e) == null) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("EVENT: " + e + " REQUEST: null"); // NOI18N
}
} else {
exec = eventsToProcess.get(e);
}
if (logger.isLoggable(Level.FINE)) {
printEvent (e, exec);
}
// safe invocation of user action
if (exec != null) {
try {
startEventOnly = false;
if (logger.isLoggable(Level.FINE)) {
ThreadReference tref = getEventThread(e);
if (tref != null) {
try {
logger.fine(" event thread "+tref.name()+" suspend before exec = "+tref.isSuspended());
} catch (Exception ex) {}
//System.err.println("\nOperator: event thread "+tref.name()+" suspend before exec = "+tref.isSuspended()+"\n");
}
}
resume = resume & exec.exec (e);
} catch (VMDisconnectedException exc) {
// disconnected = true;
synchronized (Operator.this) {
stop = true;
}
//S ystem.out.println ("EVENT: " + e); // NOI18N
//S ystem.out.println ("Operator end"); // NOI18N
return false;
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
}
} else {
if (e instanceof BreakpointEvent) {
resume = false;
startEventOnly = false;
}
}
} // for
} else {
startEventOnly = false;
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("JDI events dispatched (resume " + (resume && (!startEventOnly)) + ")");
logger.fine(" resume = "+resume+", startEventOnly = "+startEventOnly);
}
if (isThreadEvent && suspendPolicy == EventRequest.SUSPEND_EVENT_THREAD && !resume) {
// We must resume the thread death event, because otherwise nobody would do that in this case.
if (isThreadDeath) {
resume = true;
}
}
if (!resume) {
if (!silent && suspendedAll) {
//TODO: Not really all might be suspended!
boolean grabSolved = scs.suspend(debugger.getVirtualMachine()); // TODO: check AWT thread!
if (!grabSolved) {
resume = true; // We must not stop here, nobody will ever be able to resume
} else {
List<PropertyChangeEvent> events = debugger.notifySuspendAll(false, false, ignoredThreads);
if (eventAccessLock != null) {
logger.log(Level.FINER, "Write access lock RELEASED:{0}", eventAccessLock);
eventAccessLock.unlock();
eventAccessLock = null;
}
for (PropertyChangeEvent event : events) {
((JPDAThreadImpl) event.getSource()).fireEvent(event);
}
}
}
if (!silent && suspendedThread != null) {
boolean grabSolved = scs.suspend(thref);
if (!grabSolved) {
resume = true; // We must not stop here, nobody will ever be able to resume
} else {
PropertyChangeEvent event = suspendedThread.notifySuspended(false, false);
if (eventAccessLock != null) {
logger.log(Level.FINER, "Write access lock RELEASED:{0}", eventAccessLock);
eventAccessLock.unlock();
eventAccessLock = null;
}
if (event != null) {
suspendedThread.fireEvent(event);
}
}
}
}
if (logger.isLoggable(Level.FINE)) {
try {
logger.fine("Resuming the event set "+eventSet+" = "+resume);
} catch (ObjectCollectedException ocex) {
logger.log(Level.FINE, "Resuming the event set that has something collected = "+resume);
}
}
if (resume) {
// Notify Resumed No Fire
Set<ThreadReference> threadsResumed;
synchronized(threadsResumedForEvents) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("threadsResumedForEvents = "+threadsResumedForEvents.get(eventSet)+" for "+System.identityHashCode(eventSet));
}
threadsResumed = threadsResumedForEvents.get(eventSet);
/*if (threadsResumed != null) {
ignoredThreads.addAll(threadsResumed);
}*/
}
int sc = suspendCount.removeSuspendCountFor(thref);
if (!isThreadDeath && sc > 1) {
for (int sci = 1; sci < sc; sci++) {
ThreadReferenceWrapper.suspend(thref);
}
JPDAThreadImpl jt = debugger.getThread(thref);
jt.updateSuspendCount(sc);
}
if (!silent && suspendedAll) {
//TODO: Not really all might be suspended!
debugger.notifyToBeResumedAllNoFire(threadsResumed);
}
if (!silent && suspendedThread != null) {
resume = resume && suspendedThread.notifyToBeResumedNoFire();
}
if (threadsResumed != null) {
for (ThreadReference t : threadsResumed) {
if (ThreadReferenceWrapper.isSuspended0(t)) {
ThreadReferenceWrapper.suspend(t); // Increase the suspend count so that eventSet.resume() does not resume the thread
if (logger.isLoggable(Level.FINE)) {
logger.fine(" increased suspend count of "+t+" to "+ThreadReferenceWrapper.suspendCount0(t)+" to survive event set resume in suspended state.");
}
}
}
}
if (thref != null && logger.isLoggable(Level.FINE)) {
logger.fine(" Before event set resume, thread "+thref+" has status: "+JPDAThreadImpl.getThreadStateLog(thref));
}
dumpThreadsStatus(eventSet.virtualMachine());
if (!startEventOnly) {
try {
EventSetWrapper.resume(eventSet);
} catch (IllegalThreadStateExceptionWrapper itex) {
logger.throwing(Operator.class.getName(), "loop", itex);
} catch (ObjectCollectedExceptionWrapper ocex) {
logger.throwing(Operator.class.getName(), "loop", ocex);
}
}
} else if (!startEventOnly && !silent && (suspendedAll || suspendedThread != null)) {
Session session = debugger.getSession();
if (session != null) {
DebuggerManager.getDebuggerManager().setCurrentSession(session);
}
if (thref != null) {
debugger.setStoppedState (thref, suspendedAll, stepFinished);
}
}
} finally {
if (eventAccessLock != null) {
logger.log(Level.FINER, "Write access lock RELEASED:{0}", eventAccessLock);
eventAccessLock.unlock();
}
if (resume && threadWasInitiallySuspended) {
suspendedThread.fireAfterNotifyToBeResumedNoFire();
}
}
/* We check for multiple-suspension when event is received
* This check is already performed above
if (!silent && !resume) { // Check for multiply-suspended threads
resumeLock.writeLock().lock();
try {
List<ThreadReference> threads = VirtualMachineWrapper.allThreads(MirrorWrapper.virtualMachine(eventSet));
for (ThreadReference t : threads) {
try {
JPDAThreadImpl jt = debugger.getExistingThread(t);
while (ThreadReferenceWrapper.suspendCount(t) > 1) {
if (jt != null) {
jt.notifyToBeResumed();
jt = null;
}
ThreadReferenceWrapper.resume(t);
} // while
} catch (ObjectCollectedExceptionWrapper e) {
} catch (IllegalThreadStateExceptionWrapper e) {
// ignore mobility VM defects
} catch (InternalExceptionWrapper e) {
// ignore mobility VM defects
}
} // for
} finally {
resumeLock.writeLock().unlock();
}
}*/
return true;
}