1/* 2 * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26#include "util.h" 27#include "eventHandler.h" 28#include "threadControl.h" 29#include "commonRef.h" 30#include "eventHelper.h" 31#include "stepControl.h" 32#include "invoker.h" 33#include "bag.h" 34 35#define HANDLING_EVENT(node) ((node)->current_ei != 0) 36 37/* 38 * Collection of info for properly handling co-located events. 39 * If the ei field is non-zero, then one of the possible 40 * co-located events has been posted and the other fields describe 41 * the event's location. 42 */ 43typedef struct CoLocatedEventInfo_ { 44 EventIndex ei; 45 jclass clazz; 46 jmethodID method; 47 jlocation location; 48} CoLocatedEventInfo; 49 50/** 51 * The main data structure in threadControl is the ThreadNode. 52 * This is a per-thread structure that is allocated on the 53 * first event that occurs in a thread. It is freed after the 54 * thread's thread end event has completed processing. The 55 * structure contains state information on its thread including 56 * suspend counts. It also acts as a repository for other 57 * per-thread state such as the current method invocation or 58 * current step. 59 * 60 * suspendCount is the number of outstanding suspends 61 * from the debugger. suspends from the app itself are 62 * not included in this count. 63 */ 64typedef struct ThreadNode { 65 jthread thread; 66 unsigned int toBeResumed : 1; 67 unsigned int pendingInterrupt : 1; 68 unsigned int isDebugThread : 1; 69 unsigned int suspendOnStart : 1; 70 unsigned int isStarted : 1; 71 unsigned int popFrameEvent : 1; 72 unsigned int popFrameProceed : 1; 73 unsigned int popFrameThread : 1; 74 EventIndex current_ei; 75 jobject pendingStop; 76 jint suspendCount; 77 jint resumeFrameDepth; /* !=0 => This thread is in a call to Thread.resume() */ 78 jvmtiEventMode instructionStepMode; 79 StepRequest currentStep; 80 InvokeRequest currentInvoke; 81 struct bag *eventBag; 82 CoLocatedEventInfo cleInfo; 83 struct ThreadNode *next; 84 struct ThreadNode *prev; 85 jlong frameGeneration; 86 struct ThreadList *list; /* Tells us what list this thread is in */ 87} ThreadNode; 88 89static jint suspendAllCount; 90 91typedef struct ThreadList { 92 ThreadNode *first; 93} ThreadList; 94 95/* 96 * popFrameEventLock is used to notify that the event has been received 97 */ 98static jrawMonitorID popFrameEventLock = NULL; 99 100/* 101 * popFrameProceedLock is used to assure that the event thread is 102 * re-suspended immediately after the event is acknowledged. 103 */ 104static jrawMonitorID popFrameProceedLock = NULL; 105 106static jrawMonitorID threadLock; 107static jlocation resumeLocation; 108static HandlerNode *breakpointHandlerNode; 109static HandlerNode *framePopHandlerNode; 110static HandlerNode *catchHandlerNode; 111 112static jvmtiError threadControl_removeDebugThread(jthread thread); 113 114/* 115 * Threads which have issued thread start events and not yet issued thread 116 * end events are maintained in the "runningThreads" list. All other threads known 117 * to this module are kept in the "otherThreads" list. 118 */ 119static ThreadList runningThreads; 120static ThreadList otherThreads; 121 122#define MAX_DEBUG_THREADS 10 123static int debugThreadCount; 124static jthread debugThreads[MAX_DEBUG_THREADS]; 125 126typedef struct DeferredEventMode { 127 EventIndex ei; 128 jvmtiEventMode mode; 129 jthread thread; 130 struct DeferredEventMode *next; 131} DeferredEventMode; 132 133typedef struct { 134 DeferredEventMode *first; 135 DeferredEventMode *last; 136} DeferredEventModeList; 137 138static DeferredEventModeList deferredEventModes; 139 140static jint 141getStackDepth(jthread thread) 142{ 143 jint count = 0; 144 jvmtiError error; 145 146 error = JVMTI_FUNC_PTR(gdata->jvmti,GetFrameCount) 147 (gdata->jvmti, thread, &count); 148 if (error != JVMTI_ERROR_NONE) { 149 EXIT_ERROR(error, "getting frame count"); 150 } 151 return count; 152} 153 154/* Get the state of the thread direct from JVMTI */ 155static jvmtiError 156threadState(jthread thread, jint *pstate) 157{ 158 *pstate = 0; 159 return JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState) 160 (gdata->jvmti, thread, pstate); 161} 162 163/* Set TLS on a specific jthread to the ThreadNode* */ 164static void 165setThreadLocalStorage(jthread thread, ThreadNode *node) 166{ 167 jvmtiError error; 168 169 error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage) 170 (gdata->jvmti, thread, (void*)node); 171 if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE ) { 172 /* Just return, thread hasn't started yet */ 173 return; 174 } else if ( error != JVMTI_ERROR_NONE ) { 175 /* The jthread object must be valid, so this must be a fatal error */ 176 EXIT_ERROR(error, "cannot set thread local storage"); 177 } 178} 179 180/* Get TLS on a specific jthread, which is the ThreadNode* */ 181static ThreadNode * 182getThreadLocalStorage(jthread thread) 183{ 184 jvmtiError error; 185 ThreadNode *node; 186 187 node = NULL; 188 error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadLocalStorage) 189 (gdata->jvmti, thread, (void**)&node); 190 if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE ) { 191 /* Just return NULL, thread hasn't started yet */ 192 return NULL; 193 } else if ( error != JVMTI_ERROR_NONE ) { 194 /* The jthread object must be valid, so this must be a fatal error */ 195 EXIT_ERROR(error, "cannot get thread local storage"); 196 } 197 return node; 198} 199 200/* Search list for nodes that don't have TLS set and match this thread. 201 * It assumed that this logic is never dealing with terminated threads, 202 * since the ThreadEnd events always delete the ThreadNode while the 203 * jthread is still alive. So we can only look at the ThreadNode's that 204 * have never had their TLS set, making the search much faster. 205 * But keep in mind, this kind of search should rarely be needed. 206 */ 207static ThreadNode * 208nonTlsSearch(JNIEnv *env, ThreadList *list, jthread thread) 209{ 210 ThreadNode *node; 211 212 for (node = list->first; node != NULL; node = node->next) { 213 if (isSameObject(env, node->thread, thread)) { 214 break; 215 } 216 } 217 return node; 218} 219 220/* 221 * These functions maintain the linked list of currently running threads. 222 * All assume that the threadLock is held before calling. 223 * If list==NULL, search both lists. 224 */ 225static ThreadNode * 226findThread(ThreadList *list, jthread thread) 227{ 228 ThreadNode *node; 229 230 /* Get thread local storage for quick thread -> node access */ 231 node = getThreadLocalStorage(thread); 232 233 /* In some rare cases we might get NULL, so we check the list manually for 234 * any threads that we could match. 235 */ 236 if ( node == NULL ) { 237 JNIEnv *env; 238 239 env = getEnv(); 240 if ( list != NULL ) { 241 node = nonTlsSearch(env, list, thread); 242 } else { 243 node = nonTlsSearch(env, &runningThreads, thread); 244 if ( node == NULL ) { 245 node = nonTlsSearch(env, &otherThreads, thread); 246 } 247 } 248 if ( node != NULL ) { 249 /* Here we make another attempt to set TLS, it's ok if this fails */ 250 setThreadLocalStorage(thread, (void*)node); 251 } 252 } 253 254 /* If a list is supplied, only return ones in this list */ 255 if ( node != NULL && list != NULL && node->list != list ) { 256 return NULL; 257 } 258 return node; 259} 260 261/* Remove a ThreadNode from a ThreadList */ 262static void 263removeNode(ThreadList *list, ThreadNode *node) 264{ 265 ThreadNode *prev; 266 ThreadNode *next; 267 268 prev = node->prev; 269 next = node->next; 270 if ( prev != NULL ) { 271 prev->next = next; 272 } 273 if ( next != NULL ) { 274 next->prev = prev; 275 } 276 if ( prev == NULL ) { 277 list->first = next; 278 } 279 node->next = NULL; 280 node->prev = NULL; 281 node->list = NULL; 282} 283 284/* Add a ThreadNode to a ThreadList */ 285static void 286addNode(ThreadList *list, ThreadNode *node) 287{ 288 node->next = NULL; 289 node->prev = NULL; 290 node->list = NULL; 291 if ( list->first == NULL ) { 292 list->first = node; 293 } else { 294 list->first->prev = node; 295 node->next = list->first; 296 list->first = node; 297 } 298 node->list = list; 299} 300 301static ThreadNode * 302insertThread(JNIEnv *env, ThreadList *list, jthread thread) 303{ 304 ThreadNode *node; 305 struct bag *eventBag; 306 307 node = findThread(list, thread); 308 if (node == NULL) { 309 node = jvmtiAllocate(sizeof(*node)); 310 if (node == NULL) { 311 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry"); 312 return NULL; 313 } 314 (void)memset(node, 0, sizeof(*node)); 315 eventBag = eventHelper_createEventBag(); 316 if (eventBag == NULL) { 317 jvmtiDeallocate(node); 318 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry"); 319 return NULL; 320 } 321 322 /* 323 * Init all flags false, all refs NULL, all counts 0 324 */ 325 326 saveGlobalRef(env, thread, &(node->thread)); 327 if (node->thread == NULL) { 328 jvmtiDeallocate(node); 329 bagDestroyBag(eventBag); 330 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table entry"); 331 return NULL; 332 } 333 /* 334 * Remember if it is a debug thread 335 */ 336 if (threadControl_isDebugThread(node->thread)) { 337 node->isDebugThread = JNI_TRUE; 338 } else if (suspendAllCount > 0){ 339 /* 340 * If there is a pending suspendAll, all new threads should 341 * be initialized as if they were suspended by the suspendAll, 342 * and the thread will need to be suspended when it starts. 343 */ 344 node->suspendCount = suspendAllCount; 345 node->suspendOnStart = JNI_TRUE; 346 } 347 node->current_ei = 0; 348 node->instructionStepMode = JVMTI_DISABLE; 349 node->eventBag = eventBag; 350 addNode(list, node); 351 352 /* Set thread local storage for quick thread -> node access. 353 * Some threads may not be in a state that allows setting of TLS, 354 * which is ok, see findThread, it deals with threads without TLS set. 355 */ 356 setThreadLocalStorage(node->thread, (void*)node); 357 } 358 359 return node; 360} 361 362static void 363clearThread(JNIEnv *env, ThreadNode *node) 364{ 365 if (node->pendingStop != NULL) { 366 tossGlobalRef(env, &(node->pendingStop)); 367 } 368 stepControl_clearRequest(node->thread, &node->currentStep); 369 if (node->isDebugThread) { 370 (void)threadControl_removeDebugThread(node->thread); 371 } 372 /* Clear out TLS on this thread (just a cleanup action) */ 373 setThreadLocalStorage(node->thread, NULL); 374 tossGlobalRef(env, &(node->thread)); 375 bagDestroyBag(node->eventBag); 376 jvmtiDeallocate(node); 377} 378 379static void 380removeThread(JNIEnv *env, ThreadList *list, jthread thread) 381{ 382 ThreadNode *node; 383 384 node = findThread(list, thread); 385 if (node != NULL) { 386 removeNode(list, node); 387 clearThread(env, node); 388 } 389} 390 391static void 392removeResumed(JNIEnv *env, ThreadList *list) 393{ 394 ThreadNode *node; 395 396 node = list->first; 397 while (node != NULL) { 398 ThreadNode *temp = node->next; 399 if (node->suspendCount == 0) { 400 removeThread(env, list, node->thread); 401 } 402 node = temp; 403 } 404} 405 406static void 407moveNode(ThreadList *source, ThreadList *dest, ThreadNode *node) 408{ 409 removeNode(source, node); 410 JDI_ASSERT(findThread(dest, node->thread) == NULL); 411 addNode(dest, node); 412} 413 414typedef jvmtiError (*ThreadEnumerateFunction)(JNIEnv *, ThreadNode *, void *); 415 416static jvmtiError 417enumerateOverThreadList(JNIEnv *env, ThreadList *list, 418 ThreadEnumerateFunction function, void *arg) 419{ 420 ThreadNode *node; 421 jvmtiError error = JVMTI_ERROR_NONE; 422 423 for (node = list->first; node != NULL; node = node->next) { 424 error = (*function)(env, node, arg); 425 if ( error != JVMTI_ERROR_NONE ) { 426 break; 427 } 428 } 429 return error; 430} 431 432static void 433insertEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode) 434{ 435 if (list->last != NULL) { 436 list->last->next = eventMode; 437 } else { 438 list->first = eventMode; 439 } 440 list->last = eventMode; 441} 442 443static void 444removeEventMode(DeferredEventModeList *list, DeferredEventMode *eventMode, DeferredEventMode *prev) 445{ 446 if (prev == NULL) { 447 list->first = eventMode->next; 448 } else { 449 prev->next = eventMode->next; 450 } 451 if (eventMode->next == NULL) { 452 list->last = prev; 453 } 454} 455 456static jvmtiError 457addDeferredEventMode(JNIEnv *env, jvmtiEventMode mode, EventIndex ei, jthread thread) 458{ 459 DeferredEventMode *eventMode; 460 461 /*LINTED*/ 462 eventMode = jvmtiAllocate((jint)sizeof(DeferredEventMode)); 463 if (eventMode == NULL) { 464 return AGENT_ERROR_OUT_OF_MEMORY; 465 } 466 eventMode->thread = NULL; 467 saveGlobalRef(env, thread, &(eventMode->thread)); 468 eventMode->mode = mode; 469 eventMode->ei = ei; 470 eventMode->next = NULL; 471 insertEventMode(&deferredEventModes, eventMode); 472 return JVMTI_ERROR_NONE; 473} 474 475static void 476freeDeferredEventModes(JNIEnv *env) 477{ 478 DeferredEventMode *eventMode; 479 eventMode = deferredEventModes.first; 480 while (eventMode != NULL) { 481 DeferredEventMode *next; 482 next = eventMode->next; 483 tossGlobalRef(env, &(eventMode->thread)); 484 jvmtiDeallocate(eventMode); 485 eventMode = next; 486 } 487 deferredEventModes.first = NULL; 488 deferredEventModes.last = NULL; 489} 490 491static jvmtiError 492threadSetEventNotificationMode(ThreadNode *node, 493 jvmtiEventMode mode, EventIndex ei, jthread thread) 494{ 495 jvmtiError error; 496 497 /* record single step mode */ 498 if (ei == EI_SINGLE_STEP) { 499 node->instructionStepMode = mode; 500 } 501 error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode) 502 (gdata->jvmti, mode, eventIndex2jvmti(ei), thread); 503 return error; 504} 505 506static void 507processDeferredEventModes(JNIEnv *env, jthread thread, ThreadNode *node) 508{ 509 jvmtiError error; 510 DeferredEventMode *eventMode; 511 DeferredEventMode *prev; 512 513 prev = NULL; 514 eventMode = deferredEventModes.first; 515 while (eventMode != NULL) { 516 DeferredEventMode *next = eventMode->next; 517 if (isSameObject(env, thread, eventMode->thread)) { 518 error = threadSetEventNotificationMode(node, 519 eventMode->mode, eventMode->ei, eventMode->thread); 520 if (error != JVMTI_ERROR_NONE) { 521 EXIT_ERROR(error, "cannot process deferred thread event notifications at thread start"); 522 } 523 removeEventMode(&deferredEventModes, eventMode, prev); 524 tossGlobalRef(env, &(eventMode->thread)); 525 jvmtiDeallocate(eventMode); 526 } else { 527 prev = eventMode; 528 } 529 eventMode = next; 530 } 531} 532 533static void 534getLocks(void) 535{ 536 /* 537 * Anything which might be locked as part of the handling of 538 * a JVMTI event (which means: might be locked by an application 539 * thread) needs to be grabbed here. This allows thread control 540 * code to safely suspend and resume the application threads 541 * while ensuring they don't hold a critical lock. 542 */ 543 544 eventHandler_lock(); 545 invoker_lock(); 546 eventHelper_lock(); 547 stepControl_lock(); 548 commonRef_lock(); 549 debugMonitorEnter(threadLock); 550 551} 552 553static void 554releaseLocks(void) 555{ 556 debugMonitorExit(threadLock); 557 commonRef_unlock(); 558 stepControl_unlock(); 559 eventHelper_unlock(); 560 invoker_unlock(); 561 eventHandler_unlock(); 562} 563 564void 565threadControl_initialize(void) 566{ 567 jlocation unused; 568 jvmtiError error; 569 570 suspendAllCount = 0; 571 runningThreads.first = NULL; 572 otherThreads.first = NULL; 573 debugThreadCount = 0; 574 threadLock = debugMonitorCreate("JDWP Thread Lock"); 575 if (gdata->threadClass==NULL) { 576 EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "no java.lang.thread class"); 577 } 578 if (gdata->threadResume==0) { 579 EXIT_ERROR(AGENT_ERROR_NULL_POINTER, "cannot resume thread"); 580 } 581 /* Get the java.lang.Thread.resume() method beginning location */ 582 error = methodLocation(gdata->threadResume, &resumeLocation, &unused); 583 if (error != JVMTI_ERROR_NONE) { 584 EXIT_ERROR(error, "getting method location"); 585 } 586} 587 588static jthread 589getResumee(jthread resumingThread) 590{ 591 jthread resumee = NULL; 592 jvmtiError error; 593 jobject object; 594 FrameNumber fnum = 0; 595 596 error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject) 597 (gdata->jvmti, resumingThread, fnum, 0, &object); 598 if (error == JVMTI_ERROR_NONE) { 599 resumee = object; 600 } 601 return resumee; 602} 603 604 605static jboolean 606pendingAppResume(jboolean includeSuspended) 607{ 608 ThreadList *list; 609 ThreadNode *node; 610 611 list = &runningThreads; 612 node = list->first; 613 while (node != NULL) { 614 if (node->resumeFrameDepth > 0) { 615 if (includeSuspended) { 616 return JNI_TRUE; 617 } else { 618 jvmtiError error; 619 jint state; 620 621 error = threadState(node->thread, &state); 622 if (error != JVMTI_ERROR_NONE) { 623 EXIT_ERROR(error, "getting thread state"); 624 } 625 if (!(state & JVMTI_THREAD_STATE_SUSPENDED)) { 626 return JNI_TRUE; 627 } 628 } 629 } 630 node = node->next; 631 } 632 return JNI_FALSE; 633} 634 635static void 636notifyAppResumeComplete(void) 637{ 638 debugMonitorNotifyAll(threadLock); 639 if (!pendingAppResume(JNI_TRUE)) { 640 if (framePopHandlerNode != NULL) { 641 (void)eventHandler_free(framePopHandlerNode); 642 framePopHandlerNode = NULL; 643 } 644 if (catchHandlerNode != NULL) { 645 (void)eventHandler_free(catchHandlerNode); 646 catchHandlerNode = NULL; 647 } 648 } 649} 650 651static void 652handleAppResumeCompletion(JNIEnv *env, EventInfo *evinfo, 653 HandlerNode *handlerNode, 654 struct bag *eventBag) 655{ 656 ThreadNode *node; 657 jthread thread; 658 659 thread = evinfo->thread; 660 661 debugMonitorEnter(threadLock); 662 663 node = findThread(&runningThreads, thread); 664 if (node != NULL) { 665 if (node->resumeFrameDepth > 0) { 666 jint compareDepth = getStackDepth(thread); 667 if (evinfo->ei == EI_FRAME_POP) { 668 compareDepth--; 669 } 670 if (compareDepth < node->resumeFrameDepth) { 671 node->resumeFrameDepth = 0; 672 notifyAppResumeComplete(); 673 } 674 } 675 } 676 677 debugMonitorExit(threadLock); 678} 679 680static void 681blockOnDebuggerSuspend(jthread thread) 682{ 683 ThreadNode *node; 684 685 node = findThread(NULL, thread); 686 if (node != NULL) { 687 while (node && node->suspendCount > 0) { 688 debugMonitorWait(threadLock); 689 node = findThread(NULL, thread); 690 } 691 } 692} 693 694static void 695trackAppResume(jthread thread) 696{ 697 jvmtiError error; 698 FrameNumber fnum; 699 ThreadNode *node; 700 701 fnum = 0; 702 node = findThread(&runningThreads, thread); 703 if (node != NULL) { 704 JDI_ASSERT(node->resumeFrameDepth == 0); 705 error = JVMTI_FUNC_PTR(gdata->jvmti,NotifyFramePop) 706 (gdata->jvmti, thread, fnum); 707 if (error == JVMTI_ERROR_NONE) { 708 jint frameDepth = getStackDepth(thread); 709 if ((frameDepth > 0) && (framePopHandlerNode == NULL)) { 710 framePopHandlerNode = eventHandler_createInternalThreadOnly( 711 EI_FRAME_POP, 712 handleAppResumeCompletion, 713 thread); 714 catchHandlerNode = eventHandler_createInternalThreadOnly( 715 EI_EXCEPTION_CATCH, 716 handleAppResumeCompletion, 717 thread); 718 if ((framePopHandlerNode == NULL) || 719 (catchHandlerNode == NULL)) { 720 (void)eventHandler_free(framePopHandlerNode); 721 framePopHandlerNode = NULL; 722 (void)eventHandler_free(catchHandlerNode); 723 catchHandlerNode = NULL; 724 } 725 } 726 if ((framePopHandlerNode != NULL) && 727 (catchHandlerNode != NULL) && 728 (frameDepth > 0)) { 729 node->resumeFrameDepth = frameDepth; 730 } 731 } 732 } 733} 734 735static void 736handleAppResumeBreakpoint(JNIEnv *env, EventInfo *evinfo, 737 HandlerNode *handlerNode, 738 struct bag *eventBag) 739{ 740 jthread resumer = evinfo->thread; 741 jthread resumee = getResumee(resumer); 742 743 debugMonitorEnter(threadLock); 744 if (resumee != NULL) { 745 /* 746 * Hold up any attempt to resume as long as the debugger 747 * has suspended the resumee. 748 */ 749 blockOnDebuggerSuspend(resumee); 750 } 751 752 if (resumer != NULL) { 753 /* 754 * Track the resuming thread by marking it as being within 755 * a resume and by setting up for notification on 756 * a frame pop or exception. We won't allow the debugger 757 * to suspend threads while any thread is within a 758 * call to resume. This (along with the block above) 759 * ensures that when the debugger 760 * suspends a thread it will remain suspended. 761 */ 762 trackAppResume(resumer); 763 } 764 765 debugMonitorExit(threadLock); 766} 767 768void 769threadControl_onConnect(void) 770{ 771 breakpointHandlerNode = eventHandler_createInternalBreakpoint( 772 handleAppResumeBreakpoint, NULL, 773 gdata->threadClass, gdata->threadResume, resumeLocation); 774} 775 776void 777threadControl_onDisconnect(void) 778{ 779 if (breakpointHandlerNode != NULL) { 780 (void)eventHandler_free(breakpointHandlerNode); 781 breakpointHandlerNode = NULL; 782 } 783 if (framePopHandlerNode != NULL) { 784 (void)eventHandler_free(framePopHandlerNode); 785 framePopHandlerNode = NULL; 786 } 787 if (catchHandlerNode != NULL) { 788 (void)eventHandler_free(catchHandlerNode); 789 catchHandlerNode = NULL; 790 } 791} 792 793void 794threadControl_onHook(void) 795{ 796 /* 797 * As soon as the event hook is in place, we need to initialize 798 * the thread list with already-existing threads. The threadLock 799 * has been held since initialize, so we don't need to worry about 800 * insertions or deletions from the event handlers while we do this 801 */ 802 JNIEnv *env; 803 804 env = getEnv(); 805 806 /* 807 * Prevent any event processing until OnHook has been called 808 */ 809 debugMonitorEnter(threadLock); 810 811 WITH_LOCAL_REFS(env, 1) { 812 813 jint threadCount; 814 jthread *threads; 815 816 threads = allThreads(&threadCount); 817 if (threads == NULL) { 818 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"thread table"); 819 } else { 820 821 int i; 822 823 for (i = 0; i < threadCount; i++) { 824 ThreadNode *node; 825 jthread thread = threads[i]; 826 node = insertThread(env, &runningThreads, thread); 827 828 /* 829 * This is a tiny bit risky. We have to assume that the 830 * pre-existing threads have been started because we 831 * can't rely on a thread start event for them. The chances 832 * of a problem related to this are pretty slim though, and 833 * there's really no choice because without setting this flag 834 * there is no way to enable stepping and other events on 835 * the threads that already exist (e.g. the finalizer thread). 836 */ 837 node->isStarted = JNI_TRUE; 838 } 839 } 840 841 } END_WITH_LOCAL_REFS(env) 842 843 debugMonitorExit(threadLock); 844} 845 846static jvmtiError 847commonSuspendByNode(ThreadNode *node) 848{ 849 jvmtiError error; 850 851 LOG_MISC(("thread=%p suspended", node->thread)); 852 error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread) 853 (gdata->jvmti, node->thread); 854 855 /* 856 * Mark for resume only if suspend succeeded 857 */ 858 if (error == JVMTI_ERROR_NONE) { 859 node->toBeResumed = JNI_TRUE; 860 } 861 862 /* 863 * If the thread was suspended by another app thread, 864 * do nothing and report no error (we won't resume it later). 865 */ 866 if (error == JVMTI_ERROR_THREAD_SUSPENDED) { 867 error = JVMTI_ERROR_NONE; 868 } 869 870 return error; 871} 872 873/* 874 * Deferred suspends happen when the suspend is attempted on a thread 875 * that is not started. Bookkeeping (suspendCount,etc.) 876 * is handled by the original request, and once the thread actually 877 * starts, an actual suspend is attempted. This function does the 878 * deferred suspend without changing the bookkeeping that is already 879 * in place. 880 */ 881static jint 882deferredSuspendThreadByNode(ThreadNode *node) 883{ 884 jvmtiError error; 885 886 error = JVMTI_ERROR_NONE; 887 if (node->isDebugThread) { 888 /* Ignore requests for suspending debugger threads */ 889 return JVMTI_ERROR_NONE; 890 } 891 892 /* 893 * Do the actual suspend only if a subsequent resume hasn't 894 * made it irrelevant. 895 */ 896 if (node->suspendCount > 0) { 897 error = commonSuspendByNode(node); 898 899 /* 900 * Attempt to clean up from any error by decrementing the 901 * suspend count. This compensates for the increment that 902 * happens when suspendOnStart is set to true. 903 */ 904 if (error != JVMTI_ERROR_NONE) { 905 node->suspendCount--; 906 } 907 } 908 909 node->suspendOnStart = JNI_FALSE; 910 911 debugMonitorNotifyAll(threadLock); 912 913 return error; 914} 915 916static jvmtiError 917suspendThreadByNode(ThreadNode *node) 918{ 919 jvmtiError error = JVMTI_ERROR_NONE; 920 if (node->isDebugThread) { 921 /* Ignore requests for suspending debugger threads */ 922 return JVMTI_ERROR_NONE; 923 } 924 925 /* 926 * Just increment the suspend count if we are waiting 927 * for a deferred suspend. 928 */ 929 if (node->suspendOnStart) { 930 node->suspendCount++; 931 return JVMTI_ERROR_NONE; 932 } 933 934 if (node->suspendCount == 0) { 935 error = commonSuspendByNode(node); 936 937 if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) { 938 /* 939 * This error means that the thread is either a zombie or not yet 940 * started. In either case, we ignore the error. If the thread 941 * is a zombie, suspend/resume are no-ops. If the thread is not 942 * started, it will be suspended for real during the processing 943 * of its thread start event. 944 */ 945 node->suspendOnStart = JNI_TRUE; 946 error = JVMTI_ERROR_NONE; 947 } 948 } 949 950 if (error == JVMTI_ERROR_NONE) { 951 node->suspendCount++; 952 } 953 954 debugMonitorNotifyAll(threadLock); 955 956 return error; 957} 958 959static jvmtiError 960resumeThreadByNode(ThreadNode *node) 961{ 962 jvmtiError error = JVMTI_ERROR_NONE; 963 964 if (node->isDebugThread) { 965 /* never suspended by debugger => don't ever try to resume */ 966 return JVMTI_ERROR_NONE; 967 } 968 if (node->suspendCount > 0) { 969 node->suspendCount--; 970 debugMonitorNotifyAll(threadLock); 971 if ((node->suspendCount == 0) && node->toBeResumed && 972 !node->suspendOnStart) { 973 LOG_MISC(("thread=%p resumed", node->thread)); 974 error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread) 975 (gdata->jvmti, node->thread); 976 node->frameGeneration++; /* Increment on each resume */ 977 node->toBeResumed = JNI_FALSE; 978 if (error == JVMTI_ERROR_THREAD_NOT_ALIVE && !node->isStarted) { 979 /* 980 * We successfully "suspended" this thread, but 981 * we never received a THREAD_START event for it. 982 * Since the thread never ran, we can ignore our 983 * failure to resume the thread. 984 */ 985 error = JVMTI_ERROR_NONE; 986 } 987 } 988 } 989 990 return error; 991} 992 993/* 994 * Functions which respond to user requests to suspend/resume 995 * threads. 996 * Suspends and resumes add and subtract from a count respectively. 997 * The thread is only suspended when the count goes from 0 to 1 and 998 * resumed only when the count goes from 1 to 0. 999 * 1000 * These functions suspend and resume application threads 1001 * without changing the 1002 * state of threads that were already suspended beforehand. 1003 * They must not be called from an application thread because 1004 * that thread may be suspended somewhere in the middle of things. 1005 */ 1006static void 1007preSuspend(void) 1008{ 1009 getLocks(); /* Avoid debugger deadlocks */ 1010 1011 /* 1012 * Delay any suspend while a call to java.lang.Thread.resume is in 1013 * progress (not including those in suspended threads). The wait is 1014 * timed because the threads suspended through 1015 * java.lang.Thread.suspend won't result in a notify even though 1016 * it may change the result of pendingAppResume() 1017 */ 1018 while (pendingAppResume(JNI_FALSE)) { 1019 /* 1020 * This is ugly but we need to release the locks from getLocks 1021 * or else the notify will never happen. The locks must be 1022 * released and reacquired in the right order. else deadlocks 1023 * can happen. It is possible that, during this dance, the 1024 * notify will be missed, but since the wait needs to be timed 1025 * anyway, it won't be a disaster. Note that this code will 1026 * execute only on very rare occasions anyway. 1027 */ 1028 releaseLocks(); 1029 1030 debugMonitorEnter(threadLock); 1031 debugMonitorTimedWait(threadLock, 1000); 1032 debugMonitorExit(threadLock); 1033 1034 getLocks(); 1035 } 1036} 1037 1038static void 1039postSuspend(void) 1040{ 1041 releaseLocks(); 1042} 1043 1044/* 1045 * This function must be called after preSuspend and before postSuspend. 1046 */ 1047static jvmtiError 1048commonSuspend(JNIEnv *env, jthread thread, jboolean deferred) 1049{ 1050 ThreadNode *node; 1051 1052 /* 1053 * If the thread is not between its start and end events, we should 1054 * still suspend it. To keep track of things, add the thread 1055 * to a separate list of threads so that we'll resume it later. 1056 */ 1057 node = findThread(&runningThreads, thread); 1058 if (node == NULL) { 1059 node = insertThread(env, &otherThreads, thread); 1060 } 1061 1062 if ( deferred ) { 1063 return deferredSuspendThreadByNode(node); 1064 } else { 1065 return suspendThreadByNode(node); 1066 } 1067} 1068 1069 1070static jvmtiError 1071resumeCopyHelper(JNIEnv *env, ThreadNode *node, void *arg) 1072{ 1073 if (node->isDebugThread) { 1074 /* never suspended by debugger => don't ever try to resume */ 1075 return JVMTI_ERROR_NONE; 1076 } 1077 1078 if (node->suspendCount > 1) { 1079 node->suspendCount--; 1080 /* nested suspend so just undo one level */ 1081 return JVMTI_ERROR_NONE; 1082 } 1083 1084 /* 1085 * This thread was marked for suspension since its THREAD_START 1086 * event came in during a suspendAll, but the helper hasn't 1087 * completed the job yet. We decrement the count so the helper 1088 * won't suspend this thread after we are done with the resumeAll. 1089 * Another case to be handled here is when the debugger suspends 1090 * the thread while the app has it suspended. In this case, 1091 * the toBeResumed flag has been cleared indicating that 1092 * the thread should not be resumed when the debugger does a resume. 1093 * In this case, we also have to decrement the suspend count. 1094 * If we don't then when the app resumes the thread and our Thread.resume 1095 * bkpt handler is called, blockOnDebuggerSuspend will not resume 1096 * the thread because suspendCount will be 1 meaning that the 1097 * debugger has the thread suspended. See bug 6224859. 1098 */ 1099 if (node->suspendCount == 1 && (!node->toBeResumed || node->suspendOnStart)) { 1100 node->suspendCount--; 1101 return JVMTI_ERROR_NONE; 1102 } 1103 1104 if (arg == NULL) { 1105 /* nothing to hard resume so we're done */ 1106 return JVMTI_ERROR_NONE; 1107 } 1108 1109 /* 1110 * This is tricky. A suspendCount of 1 and toBeResumed means that 1111 * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called 1112 * on this thread. The check for !suspendOnStart is paranoia that 1113 * we inherited from resumeThreadByNode(). 1114 */ 1115 if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) { 1116 jthread **listPtr = (jthread **)arg; 1117 1118 **listPtr = node->thread; 1119 (*listPtr)++; 1120 } 1121 return JVMTI_ERROR_NONE; 1122} 1123 1124 1125static jvmtiError 1126resumeCountHelper(JNIEnv *env, ThreadNode *node, void *arg) 1127{ 1128 if (node->isDebugThread) { 1129 /* never suspended by debugger => don't ever try to resume */ 1130 return JVMTI_ERROR_NONE; 1131 } 1132 1133 /* 1134 * This is tricky. A suspendCount of 1 and toBeResumed means that 1135 * JVM/DI SuspendThread() or JVM/DI SuspendThreadList() was called 1136 * on this thread. The check for !suspendOnStart is paranoia that 1137 * we inherited from resumeThreadByNode(). 1138 */ 1139 if (node->suspendCount == 1 && node->toBeResumed && !node->suspendOnStart) { 1140 jint *counter = (jint *)arg; 1141 1142 (*counter)++; 1143 } 1144 return JVMTI_ERROR_NONE; 1145} 1146 1147static void * 1148newArray(jint length, size_t nbytes) 1149{ 1150 void *ptr; 1151 ptr = jvmtiAllocate(length*(jint)nbytes); 1152 if ( ptr != NULL ) { 1153 (void)memset(ptr, 0, length*nbytes); 1154 } 1155 return ptr; 1156} 1157 1158static void 1159deleteArray(void *ptr) 1160{ 1161 jvmtiDeallocate(ptr); 1162} 1163 1164/* 1165 * This function must be called with the threadLock held. 1166 * 1167 * Two facts conspire to make this routine complicated: 1168 * 1169 * 1) the VM doesn't support nested external suspend 1170 * 2) the original resumeAll code structure doesn't retrieve the 1171 * entire thread list from JVMTI so we use the runningThreads 1172 * list and two helpers to get the job done. 1173 * 1174 * Because we hold the threadLock, state seen by resumeCountHelper() 1175 * is the same state seen in resumeCopyHelper(). resumeCountHelper() 1176 * just counts up the number of threads to be hard resumed. 1177 * resumeCopyHelper() does the accounting for nested suspends and 1178 * special cases and, finally, populates the list of hard resume 1179 * threads to be passed to ResumeThreadList(). 1180 * 1181 * At first glance, you might think that the accounting could be done 1182 * in resumeCountHelper(), but then resumeCopyHelper() would see 1183 * "post-resume" state in the accounting values (suspendCount and 1184 * toBeResumed) and would not be able to distinguish between a thread 1185 * that needs a hard resume versus a thread that is already running. 1186 */ 1187static jvmtiError 1188commonResumeList(JNIEnv *env) 1189{ 1190 jvmtiError error; 1191 jint i; 1192 jint reqCnt; 1193 jthread *reqList; 1194 jthread *reqPtr; 1195 jvmtiError *results; 1196 1197 reqCnt = 0; 1198 1199 /* count number of threads to hard resume */ 1200 (void) enumerateOverThreadList(env, &runningThreads, resumeCountHelper, 1201 &reqCnt); 1202 if (reqCnt == 0) { 1203 /* nothing to hard resume so do just the accounting part */ 1204 (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper, 1205 NULL); 1206 return JVMTI_ERROR_NONE; 1207 } 1208 1209 /*LINTED*/ 1210 reqList = newArray(reqCnt, sizeof(jthread)); 1211 if (reqList == NULL) { 1212 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume request list"); 1213 } 1214 /*LINTED*/ 1215 results = newArray(reqCnt, sizeof(jvmtiError)); 1216 if (results == NULL) { 1217 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"resume list"); 1218 } 1219 1220 /* copy the jthread values for threads to hard resume */ 1221 reqPtr = reqList; 1222 (void) enumerateOverThreadList(env, &runningThreads, resumeCopyHelper, 1223 &reqPtr); 1224 1225 error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThreadList) 1226 (gdata->jvmti, reqCnt, reqList, results); 1227 for (i = 0; i < reqCnt; i++) { 1228 ThreadNode *node; 1229 1230 node = findThread(&runningThreads, reqList[i]); 1231 if (node == NULL) { 1232 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in running thread table"); 1233 } 1234 LOG_MISC(("thread=%p resumed as part of list", node->thread)); 1235 1236 /* 1237 * resumeThreadByNode() assumes that JVM/DI ResumeThread() 1238 * always works and does all the accounting updates. We do 1239 * the same here. We also don't clear the error. 1240 */ 1241 node->suspendCount--; 1242 node->toBeResumed = JNI_FALSE; 1243 node->frameGeneration++; /* Increment on each resume */ 1244 } 1245 deleteArray(results); 1246 deleteArray(reqList); 1247 1248 debugMonitorNotifyAll(threadLock); 1249 1250 return error; 1251} 1252 1253 1254/* 1255 * This function must be called after preSuspend and before postSuspend. 1256 */ 1257static jvmtiError 1258commonSuspendList(JNIEnv *env, jint initCount, jthread *initList) 1259{ 1260 jvmtiError error; 1261 jint i; 1262 jint reqCnt; 1263 jthread *reqList; 1264 1265 error = JVMTI_ERROR_NONE; 1266 reqCnt = 0; 1267 reqList = newArray(initCount, sizeof(jthread)); 1268 if (reqList == NULL) { 1269 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"request list"); 1270 } 1271 1272 /* 1273 * Go through the initial list and see if we have anything to suspend. 1274 */ 1275 for (i = 0; i < initCount; i++) { 1276 ThreadNode *node; 1277 1278 /* 1279 * If the thread is not between its start and end events, we should 1280 * still suspend it. To keep track of things, add the thread 1281 * to a separate list of threads so that we'll resume it later. 1282 */ 1283 node = findThread(&runningThreads, initList[i]); 1284 if (node == NULL) { 1285 node = insertThread(env, &otherThreads, initList[i]); 1286 } 1287 1288 if (node->isDebugThread) { 1289 /* Ignore requests for suspending debugger threads */ 1290 continue; 1291 } 1292 1293 /* 1294 * Just increment the suspend count if we are waiting 1295 * for a deferred suspend or if this is a nested suspend. 1296 */ 1297 if (node->suspendOnStart || node->suspendCount > 0) { 1298 node->suspendCount++; 1299 continue; 1300 } 1301 1302 if (node->suspendCount == 0) { 1303 /* thread is not suspended yet so put it on the request list */ 1304 reqList[reqCnt++] = initList[i]; 1305 } 1306 } 1307 1308 if (reqCnt > 0) { 1309 jvmtiError *results = newArray(reqCnt, sizeof(jvmtiError)); 1310 1311 if (results == NULL) { 1312 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"suspend list results"); 1313 } 1314 1315 /* 1316 * We have something to suspend so try to do it. 1317 */ 1318 error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThreadList) 1319 (gdata->jvmti, reqCnt, reqList, results); 1320 for (i = 0; i < reqCnt; i++) { 1321 ThreadNode *node; 1322 1323 node = findThread(NULL, reqList[i]); 1324 if (node == NULL) { 1325 EXIT_ERROR(AGENT_ERROR_INVALID_THREAD,"missing entry in thread tables"); 1326 } 1327 LOG_MISC(("thread=%p suspended as part of list", node->thread)); 1328 1329 if (results[i] == JVMTI_ERROR_NONE) { 1330 /* thread was suspended as requested */ 1331 node->toBeResumed = JNI_TRUE; 1332 } else if (results[i] == JVMTI_ERROR_THREAD_SUSPENDED) { 1333 /* 1334 * If the thread was suspended by another app thread, 1335 * do nothing and report no error (we won't resume it later). 1336 */ 1337 results[i] = JVMTI_ERROR_NONE; 1338 } else if (results[i] == JVMTI_ERROR_THREAD_NOT_ALIVE) { 1339 /* 1340 * This error means that the suspend request failed 1341 * because the thread is either a zombie or not yet 1342 * started. In either case, we ignore the error. If the 1343 * thread is a zombie, suspend/resume are no-ops. If the 1344 * thread is not started, it will be suspended for real 1345 * during the processing of its thread start event. 1346 */ 1347 node->suspendOnStart = JNI_TRUE; 1348 results[i] = JVMTI_ERROR_NONE; 1349 } 1350 1351 /* count real, app and deferred (suspendOnStart) suspensions */ 1352 if (results[i] == JVMTI_ERROR_NONE) { 1353 node->suspendCount++; 1354 } 1355 } 1356 deleteArray(results); 1357 } 1358 deleteArray(reqList); 1359 1360 debugMonitorNotifyAll(threadLock); 1361 1362 return error; 1363} 1364 1365 1366static jvmtiError 1367commonResume(jthread thread) 1368{ 1369 jvmtiError error; 1370 ThreadNode *node; 1371 1372 /* 1373 * The thread is normally between its start and end events, but if 1374 * not, check the auxiliary list used by threadControl_suspendThread. 1375 */ 1376 node = findThread(NULL, thread); 1377 1378 /* 1379 * If the node is in neither list, the debugger never suspended 1380 * this thread, so do nothing. 1381 */ 1382 error = JVMTI_ERROR_NONE; 1383 if (node != NULL) { 1384 error = resumeThreadByNode(node); 1385 } 1386 return error; 1387} 1388 1389 1390jvmtiError 1391threadControl_suspendThread(jthread thread, jboolean deferred) 1392{ 1393 jvmtiError error; 1394 JNIEnv *env; 1395 1396 env = getEnv(); 1397 1398 log_debugee_location("threadControl_suspendThread()", thread, NULL, 0); 1399 1400 preSuspend(); 1401 error = commonSuspend(env, thread, deferred); 1402 postSuspend(); 1403 1404 return error; 1405} 1406 1407jvmtiError 1408threadControl_resumeThread(jthread thread, jboolean do_unblock) 1409{ 1410 jvmtiError error; 1411 JNIEnv *env; 1412 1413 env = getEnv(); 1414 1415 log_debugee_location("threadControl_resumeThread()", thread, NULL, 0); 1416 1417 eventHandler_lock(); /* for proper lock order */ 1418 debugMonitorEnter(threadLock); 1419 error = commonResume(thread); 1420 removeResumed(env, &otherThreads); 1421 debugMonitorExit(threadLock); 1422 eventHandler_unlock(); 1423 1424 if (do_unblock) { 1425 /* let eventHelper.c: commandLoop() know we resumed one thread */ 1426 unblockCommandLoop(); 1427 } 1428 1429 return error; 1430} 1431 1432jvmtiError 1433threadControl_suspendCount(jthread thread, jint *count) 1434{ 1435 jvmtiError error; 1436 ThreadNode *node; 1437 1438 debugMonitorEnter(threadLock); 1439 1440 node = findThread(&runningThreads, thread); 1441 if (node == NULL) { 1442 node = findThread(&otherThreads, thread); 1443 } 1444 1445 error = JVMTI_ERROR_NONE; 1446 if (node != NULL) { 1447 *count = node->suspendCount; 1448 } else { 1449 /* 1450 * If the node is in neither list, the debugger never suspended 1451 * this thread, so the suspend count is 0. 1452 */ 1453 *count = 0; 1454 } 1455 1456 debugMonitorExit(threadLock); 1457 1458 return error; 1459} 1460 1461static jboolean 1462contains(JNIEnv *env, jthread *list, jint count, jthread item) 1463{ 1464 int i; 1465 1466 for (i = 0; i < count; i++) { 1467 if (isSameObject(env, list[i], item)) { 1468 return JNI_TRUE; 1469 } 1470 } 1471 return JNI_FALSE; 1472} 1473 1474 1475typedef struct { 1476 jthread *list; 1477 jint count; 1478} SuspendAllArg; 1479 1480static jvmtiError 1481suspendAllHelper(JNIEnv *env, ThreadNode *node, void *arg) 1482{ 1483 SuspendAllArg *saArg = (SuspendAllArg *)arg; 1484 jvmtiError error = JVMTI_ERROR_NONE; 1485 jthread *list = saArg->list; 1486 jint count = saArg->count; 1487 if (!contains(env, list, count, node->thread)) { 1488 error = commonSuspend(env, node->thread, JNI_FALSE); 1489 } 1490 return error; 1491} 1492 1493jvmtiError 1494threadControl_suspendAll(void) 1495{ 1496 jvmtiError error; 1497 JNIEnv *env; 1498 1499 env = getEnv(); 1500 1501 log_debugee_location("threadControl_suspendAll()", NULL, NULL, 0); 1502 1503 preSuspend(); 1504 1505 /* 1506 * Get a list of all threads and suspend them. 1507 */ 1508 WITH_LOCAL_REFS(env, 1) { 1509 1510 jthread *threads; 1511 jint count; 1512 1513 threads = allThreads(&count); 1514 if (threads == NULL) { 1515 error = AGENT_ERROR_OUT_OF_MEMORY; 1516 goto err; 1517 } 1518 if (canSuspendResumeThreadLists()) { 1519 error = commonSuspendList(env, count, threads); 1520 if (error != JVMTI_ERROR_NONE) { 1521 goto err; 1522 } 1523 } else { 1524 1525 int i; 1526 1527 for (i = 0; i < count; i++) { 1528 error = commonSuspend(env, threads[i], JNI_FALSE); 1529 1530 if (error != JVMTI_ERROR_NONE) { 1531 goto err; 1532 } 1533 } 1534 } 1535 1536 /* 1537 * Update the suspend count of any threads not yet (or no longer) 1538 * in the thread list above. 1539 */ 1540 { 1541 SuspendAllArg arg; 1542 arg.list = threads; 1543 arg.count = count; 1544 error = enumerateOverThreadList(env, &otherThreads, 1545 suspendAllHelper, &arg); 1546 } 1547 1548 if (error == JVMTI_ERROR_NONE) { 1549 suspendAllCount++; 1550 } 1551 1552 err: ; 1553 1554 } END_WITH_LOCAL_REFS(env) 1555 1556 postSuspend(); 1557 1558 return error; 1559} 1560 1561static jvmtiError 1562resumeHelper(JNIEnv *env, ThreadNode *node, void *ignored) 1563{ 1564 /* 1565 * Since this helper is called with the threadLock held, we 1566 * don't need to recheck to see if the node is still on one 1567 * of the two thread lists. 1568 */ 1569 return resumeThreadByNode(node); 1570} 1571 1572jvmtiError 1573threadControl_resumeAll(void) 1574{ 1575 jvmtiError error; 1576 JNIEnv *env; 1577 1578 env = getEnv(); 1579 1580 log_debugee_location("threadControl_resumeAll()", NULL, NULL, 0); 1581 1582 eventHandler_lock(); /* for proper lock order */ 1583 debugMonitorEnter(threadLock); 1584 1585 /* 1586 * Resume only those threads that the debugger has suspended. All 1587 * such threads must have a node in one of the thread lists, so there's 1588 * no need to get the whole thread list from JVMTI (unlike 1589 * suspendAll). 1590 */ 1591 if (canSuspendResumeThreadLists()) { 1592 error = commonResumeList(env); 1593 } else { 1594 error = enumerateOverThreadList(env, &runningThreads, 1595 resumeHelper, NULL); 1596 } 1597 if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) { 1598 error = enumerateOverThreadList(env, &otherThreads, 1599 resumeHelper, NULL); 1600 removeResumed(env, &otherThreads); 1601 } 1602 1603 if (suspendAllCount > 0) { 1604 suspendAllCount--; 1605 } 1606 1607 debugMonitorExit(threadLock); 1608 eventHandler_unlock(); 1609 /* let eventHelper.c: commandLoop() know we are resuming */ 1610 unblockCommandLoop(); 1611 1612 return error; 1613} 1614 1615 1616StepRequest * 1617threadControl_getStepRequest(jthread thread) 1618{ 1619 ThreadNode *node; 1620 StepRequest *step; 1621 1622 step = NULL; 1623 1624 debugMonitorEnter(threadLock); 1625 1626 node = findThread(&runningThreads, thread); 1627 if (node != NULL) { 1628 step = &node->currentStep; 1629 } 1630 1631 debugMonitorExit(threadLock); 1632 1633 return step; 1634} 1635 1636InvokeRequest * 1637threadControl_getInvokeRequest(jthread thread) 1638{ 1639 ThreadNode *node; 1640 InvokeRequest *request; 1641 1642 request = NULL; 1643 1644 debugMonitorEnter(threadLock); 1645 1646 node = findThread(&runningThreads, thread); 1647 if (node != NULL) { 1648 request = &node->currentInvoke; 1649 } 1650 1651 debugMonitorExit(threadLock); 1652 1653 return request; 1654} 1655 1656jvmtiError 1657threadControl_addDebugThread(jthread thread) 1658{ 1659 jvmtiError error; 1660 1661 debugMonitorEnter(threadLock); 1662 if (debugThreadCount >= MAX_DEBUG_THREADS) { 1663 error = AGENT_ERROR_OUT_OF_MEMORY; 1664 } else { 1665 JNIEnv *env; 1666 1667 env = getEnv(); 1668 debugThreads[debugThreadCount] = NULL; 1669 saveGlobalRef(env, thread, &(debugThreads[debugThreadCount])); 1670 if (debugThreads[debugThreadCount] == NULL) { 1671 error = AGENT_ERROR_OUT_OF_MEMORY; 1672 } else { 1673 debugThreadCount++; 1674 error = JVMTI_ERROR_NONE; 1675 } 1676 } 1677 debugMonitorExit(threadLock); 1678 return error; 1679} 1680 1681static jvmtiError 1682threadControl_removeDebugThread(jthread thread) 1683{ 1684 jvmtiError error; 1685 JNIEnv *env; 1686 int i; 1687 1688 error = AGENT_ERROR_INVALID_THREAD; 1689 env = getEnv(); 1690 1691 debugMonitorEnter(threadLock); 1692 for (i = 0; i< debugThreadCount; i++) { 1693 if (isSameObject(env, thread, debugThreads[i])) { 1694 int j; 1695 1696 tossGlobalRef(env, &(debugThreads[i])); 1697 for (j = i+1; j < debugThreadCount; j++) { 1698 debugThreads[j-1] = debugThreads[j]; 1699 } 1700 debugThreadCount--; 1701 error = JVMTI_ERROR_NONE; 1702 break; 1703 } 1704 } 1705 debugMonitorExit(threadLock); 1706 return error; 1707} 1708 1709jboolean 1710threadControl_isDebugThread(jthread thread) 1711{ 1712 int i; 1713 jboolean rc; 1714 JNIEnv *env; 1715 1716 rc = JNI_FALSE; 1717 env = getEnv(); 1718 1719 debugMonitorEnter(threadLock); 1720 for (i = 0; i < debugThreadCount; i++) { 1721 if (isSameObject(env, thread, debugThreads[i])) { 1722 rc = JNI_TRUE; 1723 break; 1724 } 1725 } 1726 debugMonitorExit(threadLock); 1727 return rc; 1728} 1729 1730static void 1731initLocks(void) 1732{ 1733 if (popFrameEventLock == NULL) { 1734 popFrameEventLock = debugMonitorCreate("JDWP PopFrame Event Lock"); 1735 popFrameProceedLock = debugMonitorCreate("JDWP PopFrame Proceed Lock"); 1736 } 1737} 1738 1739static jboolean 1740getPopFrameThread(jthread thread) 1741{ 1742 jboolean popFrameThread; 1743 1744 debugMonitorEnter(threadLock); 1745 { 1746 ThreadNode *node; 1747 1748 node = findThread(NULL, thread); 1749 if (node == NULL) { 1750 popFrameThread = JNI_FALSE; 1751 } else { 1752 popFrameThread = node->popFrameThread; 1753 } 1754 } 1755 debugMonitorExit(threadLock); 1756 1757 return popFrameThread; 1758} 1759 1760static void 1761setPopFrameThread(jthread thread, jboolean value) 1762{ 1763 debugMonitorEnter(threadLock); 1764 { 1765 ThreadNode *node; 1766 1767 node = findThread(NULL, thread); 1768 if (node == NULL) { 1769 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table"); 1770 } else { 1771 node->popFrameThread = value; 1772 } 1773 } 1774 debugMonitorExit(threadLock); 1775} 1776 1777static jboolean 1778getPopFrameEvent(jthread thread) 1779{ 1780 jboolean popFrameEvent; 1781 1782 debugMonitorEnter(threadLock); 1783 { 1784 ThreadNode *node; 1785 1786 node = findThread(NULL, thread); 1787 if (node == NULL) { 1788 popFrameEvent = JNI_FALSE; 1789 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table"); 1790 } else { 1791 popFrameEvent = node->popFrameEvent; 1792 } 1793 } 1794 debugMonitorExit(threadLock); 1795 1796 return popFrameEvent; 1797} 1798 1799static void 1800setPopFrameEvent(jthread thread, jboolean value) 1801{ 1802 debugMonitorEnter(threadLock); 1803 { 1804 ThreadNode *node; 1805 1806 node = findThread(NULL, thread); 1807 if (node == NULL) { 1808 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table"); 1809 } else { 1810 node->popFrameEvent = value; 1811 node->frameGeneration++; /* Increment on each resume */ 1812 } 1813 } 1814 debugMonitorExit(threadLock); 1815} 1816 1817static jboolean 1818getPopFrameProceed(jthread thread) 1819{ 1820 jboolean popFrameProceed; 1821 1822 debugMonitorEnter(threadLock); 1823 { 1824 ThreadNode *node; 1825 1826 node = findThread(NULL, thread); 1827 if (node == NULL) { 1828 popFrameProceed = JNI_FALSE; 1829 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table"); 1830 } else { 1831 popFrameProceed = node->popFrameProceed; 1832 } 1833 } 1834 debugMonitorExit(threadLock); 1835 1836 return popFrameProceed; 1837} 1838 1839static void 1840setPopFrameProceed(jthread thread, jboolean value) 1841{ 1842 debugMonitorEnter(threadLock); 1843 { 1844 ThreadNode *node; 1845 1846 node = findThread(NULL, thread); 1847 if (node == NULL) { 1848 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"entry in thread table"); 1849 } else { 1850 node->popFrameProceed = value; 1851 } 1852 } 1853 debugMonitorExit(threadLock); 1854} 1855 1856/** 1857 * Special event handler for events on the popped thread 1858 * that occur during the pop operation. 1859 */ 1860static void 1861popFrameCompleteEvent(jthread thread) 1862{ 1863 debugMonitorEnter(popFrameProceedLock); 1864 { 1865 /* notify that we got the event */ 1866 debugMonitorEnter(popFrameEventLock); 1867 { 1868 setPopFrameEvent(thread, JNI_TRUE); 1869 debugMonitorNotify(popFrameEventLock); 1870 } 1871 debugMonitorExit(popFrameEventLock); 1872 1873 /* make sure we get suspended again */ 1874 setPopFrameProceed(thread, JNI_FALSE); 1875 while (getPopFrameProceed(thread) == JNI_FALSE) { 1876 debugMonitorWait(popFrameProceedLock); 1877 } 1878 } 1879 debugMonitorExit(popFrameProceedLock); 1880} 1881 1882/** 1883 * Pop one frame off the stack of thread. 1884 * popFrameEventLock is already held 1885 */ 1886static jvmtiError 1887popOneFrame(jthread thread) 1888{ 1889 jvmtiError error; 1890 1891 error = JVMTI_FUNC_PTR(gdata->jvmti,PopFrame)(gdata->jvmti, thread); 1892 if (error != JVMTI_ERROR_NONE) { 1893 return error; 1894 } 1895 1896 /* resume the popped thread so that the pop occurs and so we */ 1897 /* will get the event (step or method entry) after the pop */ 1898 LOG_MISC(("thread=%p resumed in popOneFrame", thread)); 1899 error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, thread); 1900 if (error != JVMTI_ERROR_NONE) { 1901 return error; 1902 } 1903 1904 /* wait for the event to occur */ 1905 setPopFrameEvent(thread, JNI_FALSE); 1906 while (getPopFrameEvent(thread) == JNI_FALSE) { 1907 debugMonitorWait(popFrameEventLock); 1908 } 1909 1910 /* make sure not to suspend until the popped thread is on the wait */ 1911 debugMonitorEnter(popFrameProceedLock); 1912 { 1913 /* return popped thread to suspended state */ 1914 LOG_MISC(("thread=%p suspended in popOneFrame", thread)); 1915 error = JVMTI_FUNC_PTR(gdata->jvmti,SuspendThread)(gdata->jvmti, thread); 1916 1917 /* notify popped thread so it can proceed when resumed */ 1918 setPopFrameProceed(thread, JNI_TRUE); 1919 debugMonitorNotify(popFrameProceedLock); 1920 } 1921 debugMonitorExit(popFrameProceedLock); 1922 1923 return error; 1924} 1925 1926/** 1927 * pop frames of the stack of 'thread' until 'frame' is popped. 1928 */ 1929jvmtiError 1930threadControl_popFrames(jthread thread, FrameNumber fnum) 1931{ 1932 jvmtiError error; 1933 jvmtiEventMode prevStepMode; 1934 jint framesPopped = 0; 1935 jint popCount; 1936 jboolean prevInvokeRequestMode; 1937 1938 log_debugee_location("threadControl_popFrames()", thread, NULL, 0); 1939 1940 initLocks(); 1941 1942 /* compute the number of frames to pop */ 1943 popCount = fnum+1; 1944 if (popCount < 1) { 1945 return AGENT_ERROR_NO_MORE_FRAMES; 1946 } 1947 1948 /* enable instruction level single step, but first note prev value */ 1949 prevStepMode = threadControl_getInstructionStepMode(thread); 1950 1951 /* 1952 * Fix bug 6517249. The pop processing will disable invokes, 1953 * so remember if invokes are enabled now and restore 1954 * that state after we finish popping. 1955 */ 1956 prevInvokeRequestMode = invoker_isEnabled(thread); 1957 1958 error = threadControl_setEventMode(JVMTI_ENABLE, 1959 EI_SINGLE_STEP, thread); 1960 if (error != JVMTI_ERROR_NONE) { 1961 return error; 1962 } 1963 1964 /* Inform eventHandler logic we are in a popFrame for this thread */ 1965 debugMonitorEnter(popFrameEventLock); 1966 { 1967 setPopFrameThread(thread, JNI_TRUE); 1968 /* pop frames using single step */ 1969 while (framesPopped++ < popCount) { 1970 error = popOneFrame(thread); 1971 if (error != JVMTI_ERROR_NONE) { 1972 break; 1973 } 1974 } 1975 setPopFrameThread(thread, JNI_FALSE); 1976 } 1977 debugMonitorExit(popFrameEventLock); 1978 1979 /* Reset StepRequest info (fromLine and stackDepth) after popframes 1980 * only if stepping is enabled. 1981 */ 1982 if (prevStepMode == JVMTI_ENABLE) { 1983 stepControl_resetRequest(thread); 1984 } 1985 1986 if (prevInvokeRequestMode) { 1987 invoker_enableInvokeRequests(thread); 1988 } 1989 1990 /* restore state */ 1991 (void)threadControl_setEventMode(prevStepMode, 1992 EI_SINGLE_STEP, thread); 1993 1994 return error; 1995} 1996 1997/* Check to see if any events are being consumed by a popFrame(). */ 1998static jboolean 1999checkForPopFrameEvents(JNIEnv *env, EventIndex ei, jthread thread) 2000{ 2001 if ( getPopFrameThread(thread) ) { 2002 switch (ei) { 2003 case EI_THREAD_START: 2004 /* Excuse me? */ 2005 EXIT_ERROR(AGENT_ERROR_INTERNAL, "thread start during pop frame"); 2006 break; 2007 case EI_THREAD_END: 2008 /* Thread wants to end? let it. */ 2009 setPopFrameThread(thread, JNI_FALSE); 2010 popFrameCompleteEvent(thread); 2011 break; 2012 case EI_SINGLE_STEP: 2013 /* This is an event we requested to mark the */ 2014 /* completion of the pop frame */ 2015 popFrameCompleteEvent(thread); 2016 return JNI_TRUE; 2017 case EI_BREAKPOINT: 2018 case EI_EXCEPTION: 2019 case EI_FIELD_ACCESS: 2020 case EI_FIELD_MODIFICATION: 2021 case EI_METHOD_ENTRY: 2022 case EI_METHOD_EXIT: 2023 /* Tell event handler to assume event has been consumed. */ 2024 return JNI_TRUE; 2025 default: 2026 break; 2027 } 2028 } 2029 /* Pretend we were never called */ 2030 return JNI_FALSE; 2031} 2032 2033struct bag * 2034threadControl_onEventHandlerEntry(jbyte sessionID, EventIndex ei, jthread thread, jobject currentException) 2035{ 2036 ThreadNode *node; 2037 JNIEnv *env; 2038 struct bag *eventBag; 2039 jthread threadToSuspend; 2040 jboolean consumed; 2041 2042 env = getEnv(); 2043 threadToSuspend = NULL; 2044 2045 log_debugee_location("threadControl_onEventHandlerEntry()", thread, NULL, 0); 2046 2047 /* Events during pop commands may need to be ignored here. */ 2048 consumed = checkForPopFrameEvents(env, ei, thread); 2049 if ( consumed ) { 2050 /* Always restore any exception (see below). */ 2051 if (currentException != NULL) { 2052 JNI_FUNC_PTR(env,Throw)(env, currentException); 2053 } else { 2054 JNI_FUNC_PTR(env,ExceptionClear)(env); 2055 } 2056 return NULL; 2057 } 2058 2059 debugMonitorEnter(threadLock); 2060 2061 /* 2062 * Check the list of unknown threads maintained by suspend 2063 * and resume. If this thread is currently present in the 2064 * list, it should be 2065 * moved to the runningThreads list, since it is a 2066 * well-known thread now. 2067 */ 2068 node = findThread(&otherThreads, thread); 2069 if (node != NULL) { 2070 moveNode(&otherThreads, &runningThreads, node); 2071 } else { 2072 /* 2073 * Get a thread node for the reporting thread. For thread start 2074 * events, or if this event precedes a thread start event, 2075 * the thread node may need to be created. 2076 * 2077 * It is possible for certain events (notably method entry/exit) 2078 * to precede thread start for some VM implementations. 2079 */ 2080 node = insertThread(env, &runningThreads, thread); 2081 } 2082 2083 if (ei == EI_THREAD_START) { 2084 node->isStarted = JNI_TRUE; 2085 processDeferredEventModes(env, thread, node); 2086 } 2087 2088 node->current_ei = ei; 2089 eventBag = node->eventBag; 2090 if (node->suspendOnStart) { 2091 threadToSuspend = node->thread; 2092 } 2093 debugMonitorExit(threadLock); 2094 2095 if (threadToSuspend != NULL) { 2096 /* 2097 * An attempt was made to suspend this thread before it started. 2098 * We must suspend it now, before it starts to run. This must 2099 * be done with no locks held. 2100 */ 2101 eventHelper_suspendThread(sessionID, threadToSuspend); 2102 } 2103 2104 return eventBag; 2105} 2106 2107static void 2108doPendingTasks(JNIEnv *env, ThreadNode *node) 2109{ 2110 /* 2111 * Take care of any pending interrupts/stops, and clear out 2112 * info on pending interrupts/stops. 2113 */ 2114 if (node->pendingInterrupt) { 2115 JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread) 2116 (gdata->jvmti, node->thread); 2117 /* 2118 * TO DO: Log error 2119 */ 2120 node->pendingInterrupt = JNI_FALSE; 2121 } 2122 2123 if (node->pendingStop != NULL) { 2124 JVMTI_FUNC_PTR(gdata->jvmti,StopThread) 2125 (gdata->jvmti, node->thread, node->pendingStop); 2126 /* 2127 * TO DO: Log error 2128 */ 2129 tossGlobalRef(env, &(node->pendingStop)); 2130 } 2131} 2132 2133void 2134threadControl_onEventHandlerExit(EventIndex ei, jthread thread, 2135 struct bag *eventBag) 2136{ 2137 ThreadNode *node; 2138 2139 log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL, 0); 2140 2141 if (ei == EI_THREAD_END) { 2142 eventHandler_lock(); /* for proper lock order */ 2143 } 2144 debugMonitorEnter(threadLock); 2145 2146 node = findThread(&runningThreads, thread); 2147 if (node == NULL) { 2148 EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted"); 2149 } else { 2150 JNIEnv *env; 2151 2152 env = getEnv(); 2153 if (ei == EI_THREAD_END) { 2154 jboolean inResume = (node->resumeFrameDepth > 0); 2155 removeThread(env, &runningThreads, thread); 2156 node = NULL; /* has been freed */ 2157 2158 /* 2159 * Clean up mechanism used to detect end of 2160 * resume. 2161 */ 2162 if (inResume) { 2163 notifyAppResumeComplete(); 2164 } 2165 } else { 2166 /* No point in doing this if the thread is about to die.*/ 2167 doPendingTasks(env, node); 2168 node->eventBag = eventBag; 2169 node->current_ei = 0; 2170 } 2171 } 2172 2173 debugMonitorExit(threadLock); 2174 if (ei == EI_THREAD_END) { 2175 eventHandler_unlock(); 2176 } 2177} 2178 2179/* Returns JDWP flavored status and status flags. */ 2180jvmtiError 2181threadControl_applicationThreadStatus(jthread thread, 2182 jdwpThreadStatus *pstatus, jint *statusFlags) 2183{ 2184 ThreadNode *node; 2185 jvmtiError error; 2186 jint state; 2187 2188 log_debugee_location("threadControl_applicationThreadStatus()", thread, NULL, 0); 2189 2190 debugMonitorEnter(threadLock); 2191 2192 error = threadState(thread, &state); 2193 *pstatus = map2jdwpThreadStatus(state); 2194 *statusFlags = map2jdwpSuspendStatus(state); 2195 2196 if (error == JVMTI_ERROR_NONE) { 2197 node = findThread(&runningThreads, thread); 2198 if ((node != NULL) && HANDLING_EVENT(node)) { 2199 /* 2200 * While processing an event, an application thread is always 2201 * considered to be running even if its handler happens to be 2202 * cond waiting on an internal debugger monitor, etc. 2203 * 2204 * Leave suspend status untouched since it is not possible 2205 * to distinguish debugger suspends from app suspends. 2206 */ 2207 *pstatus = JDWP_THREAD_STATUS(RUNNING); 2208 } 2209 } 2210 2211 debugMonitorExit(threadLock); 2212 2213 return error; 2214} 2215 2216jvmtiError 2217threadControl_interrupt(jthread thread) 2218{ 2219 ThreadNode *node; 2220 jvmtiError error; 2221 2222 error = JVMTI_ERROR_NONE; 2223 2224 log_debugee_location("threadControl_interrupt()", thread, NULL, 0); 2225 2226 debugMonitorEnter(threadLock); 2227 2228 node = findThread(&runningThreads, thread); 2229 if ((node == NULL) || !HANDLING_EVENT(node)) { 2230 error = JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread) 2231 (gdata->jvmti, thread); 2232 } else { 2233 /* 2234 * Hold any interrupts until after the event is processed. 2235 */ 2236 node->pendingInterrupt = JNI_TRUE; 2237 } 2238 2239 debugMonitorExit(threadLock); 2240 2241 return error; 2242} 2243 2244void 2245threadControl_clearCLEInfo(JNIEnv *env, jthread thread) 2246{ 2247 ThreadNode *node; 2248 2249 debugMonitorEnter(threadLock); 2250 2251 node = findThread(&runningThreads, thread); 2252 if (node != NULL) { 2253 node->cleInfo.ei = 0; 2254 if (node->cleInfo.clazz != NULL) { 2255 tossGlobalRef(env, &(node->cleInfo.clazz)); 2256 } 2257 } 2258 2259 debugMonitorExit(threadLock); 2260} 2261 2262jboolean 2263threadControl_cmpCLEInfo(JNIEnv *env, jthread thread, jclass clazz, 2264 jmethodID method, jlocation location) 2265{ 2266 ThreadNode *node; 2267 jboolean result; 2268 2269 result = JNI_FALSE; 2270 2271 debugMonitorEnter(threadLock); 2272 2273 node = findThread(&runningThreads, thread); 2274 if (node != NULL && node->cleInfo.ei != 0 && 2275 node->cleInfo.method == method && 2276 node->cleInfo.location == location && 2277 (isSameObject(env, node->cleInfo.clazz, clazz))) { 2278 result = JNI_TRUE; /* we have a match */ 2279 } 2280 2281 debugMonitorExit(threadLock); 2282 2283 return result; 2284} 2285 2286void 2287threadControl_saveCLEInfo(JNIEnv *env, jthread thread, EventIndex ei, 2288 jclass clazz, jmethodID method, jlocation location) 2289{ 2290 ThreadNode *node; 2291 2292 debugMonitorEnter(threadLock); 2293 2294 node = findThread(&runningThreads, thread); 2295 if (node != NULL) { 2296 node->cleInfo.ei = ei; 2297 /* Create a class ref that will live beyond */ 2298 /* the end of this call */ 2299 saveGlobalRef(env, clazz, &(node->cleInfo.clazz)); 2300 /* if returned clazz is NULL, we just won't match */ 2301 node->cleInfo.method = method; 2302 node->cleInfo.location = location; 2303 } 2304 2305 debugMonitorExit(threadLock); 2306} 2307 2308void 2309threadControl_setPendingInterrupt(jthread thread) 2310{ 2311 ThreadNode *node; 2312 2313 debugMonitorEnter(threadLock); 2314 2315 node = findThread(&runningThreads, thread); 2316 if (node != NULL) { 2317 node->pendingInterrupt = JNI_TRUE; 2318 } 2319 2320 debugMonitorExit(threadLock); 2321} 2322 2323jvmtiError 2324threadControl_stop(jthread thread, jobject throwable) 2325{ 2326 ThreadNode *node; 2327 jvmtiError error; 2328 2329 error = JVMTI_ERROR_NONE; 2330 2331 log_debugee_location("threadControl_stop()", thread, NULL, 0); 2332 2333 debugMonitorEnter(threadLock); 2334 2335 node = findThread(&runningThreads, thread); 2336 if ((node == NULL) || !HANDLING_EVENT(node)) { 2337 error = JVMTI_FUNC_PTR(gdata->jvmti,StopThread) 2338 (gdata->jvmti, thread, throwable); 2339 } else { 2340 JNIEnv *env; 2341 2342 /* 2343 * Hold any stops until after the event is processed. 2344 */ 2345 env = getEnv(); 2346 saveGlobalRef(env, throwable, &(node->pendingStop)); 2347 } 2348 2349 debugMonitorExit(threadLock); 2350 2351 return error; 2352} 2353 2354static jvmtiError 2355detachHelper(JNIEnv *env, ThreadNode *node, void *arg) 2356{ 2357 invoker_detach(&node->currentInvoke); 2358 return JVMTI_ERROR_NONE; 2359} 2360 2361void 2362threadControl_detachInvokes(void) 2363{ 2364 JNIEnv *env; 2365 2366 env = getEnv(); 2367 invoker_lock(); /* for proper lock order */ 2368 debugMonitorEnter(threadLock); 2369 (void)enumerateOverThreadList(env, &runningThreads, detachHelper, NULL); 2370 debugMonitorExit(threadLock); 2371 invoker_unlock(); 2372} 2373 2374static jvmtiError 2375resetHelper(JNIEnv *env, ThreadNode *node, void *arg) 2376{ 2377 if (node->toBeResumed) { 2378 LOG_MISC(("thread=%p resumed", node->thread)); 2379 (void)JVMTI_FUNC_PTR(gdata->jvmti,ResumeThread)(gdata->jvmti, node->thread); 2380 node->frameGeneration++; /* Increment on each resume */ 2381 } 2382 stepControl_clearRequest(node->thread, &node->currentStep); 2383 node->toBeResumed = JNI_FALSE; 2384 node->suspendCount = 0; 2385 node->suspendOnStart = JNI_FALSE; 2386 2387 return JVMTI_ERROR_NONE; 2388} 2389 2390void 2391threadControl_reset(void) 2392{ 2393 JNIEnv *env; 2394 2395 env = getEnv(); 2396 eventHandler_lock(); /* for proper lock order */ 2397 debugMonitorEnter(threadLock); 2398 (void)enumerateOverThreadList(env, &runningThreads, resetHelper, NULL); 2399 (void)enumerateOverThreadList(env, &otherThreads, resetHelper, NULL); 2400 2401 removeResumed(env, &otherThreads); 2402 2403 freeDeferredEventModes(env); 2404 2405 suspendAllCount = 0; 2406 2407 /* Everything should have been resumed */ 2408 JDI_ASSERT(otherThreads.first == NULL); 2409 2410 debugMonitorExit(threadLock); 2411 eventHandler_unlock(); 2412} 2413 2414jvmtiEventMode 2415threadControl_getInstructionStepMode(jthread thread) 2416{ 2417 ThreadNode *node; 2418 jvmtiEventMode mode; 2419 2420 mode = JVMTI_DISABLE; 2421 2422 debugMonitorEnter(threadLock); 2423 node = findThread(&runningThreads, thread); 2424 if (node != NULL) { 2425 mode = node->instructionStepMode; 2426 } 2427 debugMonitorExit(threadLock); 2428 return mode; 2429} 2430 2431jvmtiError 2432threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread) 2433{ 2434 jvmtiError error; 2435 2436 /* Global event */ 2437 if ( thread == NULL ) { 2438 error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode) 2439 (gdata->jvmti, mode, eventIndex2jvmti(ei), thread); 2440 } else { 2441 /* Thread event */ 2442 ThreadNode *node; 2443 2444 debugMonitorEnter(threadLock); 2445 { 2446 node = findThread(&runningThreads, thread); 2447 if ((node == NULL) || (!node->isStarted)) { 2448 JNIEnv *env; 2449 2450 env = getEnv(); 2451 error = addDeferredEventMode(env, mode, ei, thread); 2452 } else { 2453 error = threadSetEventNotificationMode(node, 2454 mode, ei, thread); 2455 } 2456 } 2457 debugMonitorExit(threadLock); 2458 2459 } 2460 return error; 2461} 2462 2463/* 2464 * Returns the current thread, if the thread has generated at least 2465 * one event, and has not generated a thread end event. 2466 */ 2467jthread threadControl_currentThread(void) 2468{ 2469 jthread thread; 2470 2471 debugMonitorEnter(threadLock); 2472 { 2473 ThreadNode *node; 2474 2475 node = findThread(&runningThreads, NULL); 2476 thread = (node == NULL) ? NULL : node->thread; 2477 } 2478 debugMonitorExit(threadLock); 2479 2480 return thread; 2481} 2482 2483jlong 2484threadControl_getFrameGeneration(jthread thread) 2485{ 2486 jlong frameGeneration = -1; 2487 2488 debugMonitorEnter(threadLock); 2489 { 2490 ThreadNode *node; 2491 2492 node = findThread(NULL, thread); 2493 2494 if (node != NULL) { 2495 frameGeneration = node->frameGeneration; 2496 } 2497 } 2498 debugMonitorExit(threadLock); 2499 2500 return frameGeneration; 2501} 2502