< prev index next >

src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.c

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 51,60 **** --- 51,61 ---- jlocation location; } LocationFilter; typedef struct ThreadFilter { jthread thread; + jboolean is_fiber; /* true if the filter thread is actually a fiber. */ } ThreadFilter; typedef struct CountFilter { jint count; } CountFilter;
*** 80,89 **** --- 81,91 ---- typedef struct StepFilter { jint size; jint depth; jthread thread; + jboolean is_fiber; /* true if the step filter thread is actually a fiber. */ } StepFilter; typedef struct MatchFilter { char *classPattern; } MatchFilter;
*** 357,394 **** return object; } /* * Determine if this event is interesting to this handler. * Do so by checking each of the handler's filters. * Return false if any of the filters fail, * true if the handler wants this event. * Anyone modifying this function should check * eventFilterRestricted_passesUnloadFilter and * eventFilter_predictFiltering as well. * * If shouldDelete is returned true, a count filter has expired * and the corresponding node should be deleted. */ jboolean eventFilterRestricted_passesFilter(JNIEnv *env, char *classname, EventInfo *evinfo, HandlerNode *node, ! jboolean *shouldDelete) { jthread thread; jclass clazz; jmethodID method; Filter *filter = FILTERS_ARRAY(node); int i; *shouldDelete = JNI_FALSE; thread = evinfo->thread; clazz = evinfo->clazz; method = evinfo->method; /* * Suppress most events if they happen in debug threads */ if ((evinfo->ei != EI_CLASS_PREPARE) && --- 359,476 ---- return object; } /* + * Return true if this an event that we prefer to deliver on the fiber if it arrived on a carrier thread. + */ + static jboolean + preferDeliverEventOnFiber(EventIndex ei) + { + /* Determine if this is an event that should be delivered on the fiber.*/ + switch(ei) { + case EI_SINGLE_STEP: + case EI_BREAKPOINT: + case EI_EXCEPTION: + case EI_EXCEPTION_CATCH: + case EI_THREAD_START: + case EI_THREAD_END: + case EI_FIELD_ACCESS: + case EI_FIELD_MODIFICATION: + case EI_MONITOR_CONTENDED_ENTER: + case EI_MONITOR_CONTENDED_ENTERED: + case EI_FIBER_TERMINATED: + case EI_FIBER_SCHEDULED: + return JNI_TRUE; + /* Not delivering the following events on fibers helps keep down the number of + * fibers we need to notify the debugger about. */ + case EI_CLASS_PREPARE: + case EI_FRAME_POP: + case EI_GC_FINISH: + case EI_CLASS_LOAD: + case EI_METHOD_ENTRY: + case EI_METHOD_EXIT: + case EI_MONITOR_WAIT: + case EI_MONITOR_WAITED: + case EI_VM_DEATH: + return gdata->notifyDebuggerOfAllFibers; /* Only deliver on fiber if notifying of all fibers. */ + case EI_FIBER_MOUNT: /* Not passed to event_callback(). */ + case EI_FIBER_UNMOUNT: /* Not passed to event_callback(). */ + case EI_CONTINUATION_RUN: /* Not passed to event_callback(). */ + case EI_CONTINUATION_YIELD: /* Not passed to event_callback(). */ + EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE, "invalid event index"); + break; + default: + EXIT_ERROR(AGENT_ERROR_INVALID_EVENT_TYPE, "unknown event index"); + break; + } + return JNI_FALSE; + } + + static jboolean + matchesThreadOrFiber(JNIEnv* env, + jthread thread, jthread fiber, + jthread filterThread, jboolean filter_is_fiber, + jboolean *matchesFiber) + { + jboolean matchesThread = JNI_FALSE; + *matchesFiber = JNI_FALSE; + + /* + * First check if it matches the fiber. If not, then check if it + * matches the thread. Only one of matchesFiber and matchesThread + * will be set true, with the fiber check coming first. true is returned + * if either matches, false otherwise. + */ + if (filter_is_fiber) { + *matchesFiber = isSameObject(env, fiber, filterThread); + } else { + matchesThread = isSameObject(env, thread, filterThread); + } + return matchesThread || *matchesFiber; + } + + /* * Determine if this event is interesting to this handler. * Do so by checking each of the handler's filters. * Return false if any of the filters fail, * true if the handler wants this event. * Anyone modifying this function should check * eventFilterRestricted_passesUnloadFilter and * eventFilter_predictFiltering as well. * + * evinfo->matchesFiber will be set if the handler matched based on + * the fiber specified in the evinfo. + * * If shouldDelete is returned true, a count filter has expired * and the corresponding node should be deleted. + * + * If filterOnly is true, then we don't perform any actions that may + * change the state of the filter or the debugging state of the thread. */ jboolean eventFilterRestricted_passesFilter(JNIEnv *env, char *classname, EventInfo *evinfo, HandlerNode *node, ! jboolean *shouldDelete, ! jboolean filterOnly) { jthread thread; + jthread fiber; jclass clazz; jmethodID method; Filter *filter = FILTERS_ARRAY(node); int i; + jboolean mustDeliverEventOnFiber = JNI_FALSE; *shouldDelete = JNI_FALSE; thread = evinfo->thread; + fiber = evinfo->fiber; clazz = evinfo->clazz; method = evinfo->method; + evinfo->matchesFiber = fiber != NULL; /* Assume it matches the fiber. Will be cleared below if not. */ /* * Suppress most events if they happen in debug threads */ if ((evinfo->ei != EI_CLASS_PREPARE) &&
*** 399,411 **** } for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) { switch (filter->modifier) { case JDWP_REQUEST_MODIFIER(ThreadOnly): ! if (!isSameObject(env, thread, filter->u.ThreadOnly.thread)) { return JNI_FALSE; } break; case JDWP_REQUEST_MODIFIER(ClassOnly): /* Class filters catch events in the specified * class and any subclass/subinterface. --- 481,496 ---- } for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) { switch (filter->modifier) { case JDWP_REQUEST_MODIFIER(ThreadOnly): ! if (!matchesThreadOrFiber(env, thread, fiber, ! filter->u.ThreadOnly.thread, filter->u.ThreadOnly.is_fiber, ! &evinfo->matchesFiber)) { return JNI_FALSE; } + mustDeliverEventOnFiber = evinfo->matchesFiber; break; case JDWP_REQUEST_MODIFIER(ClassOnly): /* Class filters catch events in the specified * class and any subclass/subinterface.
*** 474,483 **** --- 559,576 ---- } break; } case JDWP_REQUEST_MODIFIER(Count): { JDI_ASSERT(filter->u.Count.count > 0); + if (filterOnly) { + /* Don't decrement the counter. */ + if (filter->u.Count.count > 1) { + return JNI_FALSE; + } else { + break; + } + } if (--filter->u.Count.count > 0) { return JNI_FALSE; } *shouldDelete = JNI_TRUE; break;
*** 506,522 **** } break; } case JDWP_REQUEST_MODIFIER(Step): ! if (!isSameObject(env, thread, filter->u.Step.thread)) { ! return JNI_FALSE; ! } ! if (!stepControl_handleStep(env, thread, clazz, method)) { return JNI_FALSE; } ! break; case JDWP_REQUEST_MODIFIER(SourceNameMatch): { char* desiredNamePattern = filter->u.SourceNameOnly.sourceNamePattern; if (searchAllSourceNames(env, clazz, desiredNamePattern) != 1) { --- 599,626 ---- } break; } case JDWP_REQUEST_MODIFIER(Step): ! if (!matchesThreadOrFiber(env, thread, fiber, ! filter->u.Step.thread, filter->u.Step.is_fiber, ! &evinfo->matchesFiber)) { ! return JNI_FALSE; ! } ! mustDeliverEventOnFiber = evinfo->matchesFiber; ! /* ! * Don't call handleStep() if filterOnly is true. It's too complicated to see if the step ! * would be completed without actually changing the state, so we just assume it will be. ! * No harm can come from this since the fiber is already a known one, and that's the ! * only reason this "filterOnly" request is being made. ! */ ! if (!filterOnly) { ! if (!stepControl_handleStep(env, thread, fiber, evinfo->matchesFiber, clazz, method)) { return JNI_FALSE; } ! } ! break; case JDWP_REQUEST_MODIFIER(SourceNameMatch): { char* desiredNamePattern = filter->u.SourceNameOnly.sourceNamePattern; if (searchAllSourceNames(env, clazz, desiredNamePattern) != 1) {
*** 544,553 **** --- 648,661 ---- default: EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"Invalid filter modifier"); return JNI_FALSE; } } + /* Update matchesFiber based on whether or not we prefer to deliver this event on the fiber. */ + if (evinfo->matchesFiber && !mustDeliverEventOnFiber) { + evinfo->matchesFiber = preferDeliverEventOnFiber(evinfo->ei); + } return JNI_TRUE; } /* Determine if this event is interesting to this handler. Do so * by checking each of the handler's filters. Return false if any
*** 739,748 **** --- 847,859 ---- } if (NODE_EI(node) == EI_GC_FINISH) { return AGENT_ERROR_ILLEGAL_ARGUMENT; } + /* The thread we are filtering on might be a fiber. */ + filter->is_fiber = isFiber(thread); + /* Create a thread ref that will live beyond */ /* the end of this call */ saveGlobalRef(env, thread, &(filter->thread)); FILTER(node, index).modifier = JDWP_REQUEST_MODIFIER(ThreadOnly); return JVMTI_ERROR_NONE;
*** 927,936 **** --- 1038,1050 ---- } if (NODE_EI(node) != EI_SINGLE_STEP) { return AGENT_ERROR_ILLEGAL_ARGUMENT; } + /* The thread we are filtering on might be a fiber. */ + filter->is_fiber = isFiber(thread); + /* Create a thread ref that will live beyond */ /* the end of this call */ saveGlobalRef(env, thread, &(filter->thread)); error = stepControl_beginStep(env, filter->thread, size, depth, node); if (error != JVMTI_ERROR_NONE) {
*** 941,950 **** --- 1055,1084 ---- filter->depth = depth; filter->size = size; return JVMTI_ERROR_NONE; } + /* + * Finds the step filter in a node, and sets the thread for that filter. + * fiber fixme: not used. delete once we know for sure we'll never need it. + */ + void + eventFilter_setStepFilterThread(HandlerNode *node, jthread thread) + { + JNIEnv *env = getEnv(); + Filter *filter = FILTERS_ARRAY(node); + int i; + for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) { + switch (filter->modifier) { + case JDWP_REQUEST_MODIFIER(Step): + tossGlobalRef(env, &(filter->u.Step.thread)); + saveGlobalRef(env, thread, &(filter->u.Step.thread)); + return; + } + } + JDI_ASSERT(JNI_FALSE); /* We should have found a step filter, but didn't. */ + } jvmtiError eventFilter_setSourceNameMatchFilter(HandlerNode *node, jint index, char *sourceNamePattern) {
*** 1240,1249 **** --- 1374,1389 ---- case EI_THREAD_END: case EI_VM_INIT: case EI_VM_DEATH: case EI_CLASS_PREPARE: case EI_GC_FINISH: + case EI_FIBER_SCHEDULED: + case EI_FIBER_TERMINATED: + case EI_FIBER_MOUNT: + case EI_FIBER_UNMOUNT: + case EI_CONTINUATION_RUN: + case EI_CONTINUATION_YIELD: return error; case EI_FIELD_ACCESS: case EI_FIELD_MODIFICATION: error = setWatchpoint(node);
*** 1299,1308 **** --- 1439,1454 ---- case EI_THREAD_END: case EI_VM_INIT: case EI_VM_DEATH: case EI_CLASS_PREPARE: case EI_GC_FINISH: + case EI_FIBER_SCHEDULED: + case EI_FIBER_TERMINATED: + case EI_FIBER_MOUNT: + case EI_FIBER_UNMOUNT: + case EI_CONTINUATION_RUN: + case EI_CONTINUATION_YIELD: return error; case EI_FIELD_ACCESS: case EI_FIELD_MODIFICATION: error = clearWatchpoint(node);
*** 1329,1338 **** --- 1475,1569 ---- NODE_EI(node), thread); } return error != JVMTI_ERROR_NONE? error : error2; } + /***** debugging *****/ + + void + eventFilter_dumpHandlerFilters(HandlerNode *node) + { + int i; + Filter *filter = FILTERS_ARRAY(node); + + for (i = 0; i < FILTER_COUNT(node); ++i, ++filter) { + switch (filter->modifier) { + case JDWP_REQUEST_MODIFIER(ThreadOnly): + tty_message("ThreadOnly: thread(%p) is_fiber(%d)", + filter->u.ThreadOnly.thread, + filter->u.ThreadOnly.is_fiber); + break; + case JDWP_REQUEST_MODIFIER(ClassOnly): { + char *class_name; + classSignature(filter->u.ClassOnly.clazz, &class_name, NULL); + tty_message("ClassOnly: clazz(%s)", + class_name); + break; + } + case JDWP_REQUEST_MODIFIER(LocationOnly): { + char *method_name; + char *class_name; + methodSignature(filter->u.LocationOnly.method, &method_name, NULL, NULL); + classSignature(filter->u.LocationOnly.clazz, &class_name, NULL); + tty_message("LocationOnly: clazz(%s), method(%s) location(%d)", + class_name, + method_name, + filter->u.LocationOnly.location); + break; + } + case JDWP_REQUEST_MODIFIER(FieldOnly): { + char *class_name; + classSignature(filter->u.FieldOnly.clazz, &class_name, NULL); + tty_message("FieldOnly: clazz(%p), field(%d)", + class_name, + filter->u.FieldOnly.field); + break; + } + case JDWP_REQUEST_MODIFIER(ExceptionOnly): + tty_message("ExceptionOnly: clazz(%p), caught(%d) uncaught(%d)", + filter->u.ExceptionOnly.exception, + filter->u.ExceptionOnly.caught, + filter->u.ExceptionOnly.uncaught); + break; + case JDWP_REQUEST_MODIFIER(InstanceOnly): + tty_message("InstanceOnly: instance(%p)", + filter->u.InstanceOnly.instance); + break; + case JDWP_REQUEST_MODIFIER(Count): + tty_message("Count: count(%d)", + filter->u.Count.count); + break; + case JDWP_REQUEST_MODIFIER(Conditional): + tty_message("Conditional: exprID(%d)", + filter->u.Conditional.exprID); + break; + case JDWP_REQUEST_MODIFIER(ClassMatch): + tty_message("ClassMatch: classPattern(%s)", + filter->u.ClassMatch.classPattern); + break; + case JDWP_REQUEST_MODIFIER(ClassExclude): + tty_message("ClassExclude: classPattern(%s)", + filter->u.ClassExclude.classPattern); + break; + case JDWP_REQUEST_MODIFIER(Step): + tty_message("Step: size(%d) depth(%d) thread(%p) is_fiber(%d)", + filter->u.Step.size, + filter->u.Step.depth, + filter->u.Step.thread, + filter->u.Step.is_fiber); + break; + case JDWP_REQUEST_MODIFIER(SourceNameMatch): + tty_message("SourceNameMatch: sourceNamePattern(%s)", + filter->u.SourceNameOnly.sourceNamePattern); + break; + default: + EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT, "Invalid filter modifier"); + return; + } + } + } + /***** filter (and event) installation and deinstallation *****/ /** * Make the set of event filters that correspond with this
< prev index next >