private boolean processEvents()

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;
    }