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 "invoker.h"
  28 #include "eventHandler.h"
  29 #include "threadControl.h"
  30 #include "outStream.h"
  31 
  32 static jrawMonitorID invokerLock;
  33 
  34 void
  35 invoker_initialize(void)
  36 {
  37     invokerLock = debugMonitorCreate("JDWP Invocation Lock");
  38 }
  39 
  40 void
  41 invoker_reset(void)
  42 {
  43 }
  44 
  45 void invoker_lock(void)
  46 {
  47     debugMonitorEnter(invokerLock);
  48 }
  49 
  50 void invoker_unlock(void)
  51 {
  52     debugMonitorExit(invokerLock);
  53 }
  54 
  55 static jbyte
  56 returnTypeTag(char *signature)
  57 {
  58     char *tagPtr = strchr(signature, SIGNATURE_END_ARGS);
  59     JDI_ASSERT(tagPtr);
  60     tagPtr++;    /* 1st character after the end of args */
  61     return (jbyte)*tagPtr;
  62 }
  63 
  64 static jbyte
  65 nextArgumentTypeTag(void **cursor)
  66 {
  67     char *tagPtr = *cursor;
  68     jbyte argumentTag = (jbyte)*tagPtr;
  69 
  70     if (*tagPtr != SIGNATURE_END_ARGS) {
  71         /* Skip any array modifiers */
  72         while (*tagPtr == JDWP_TAG(ARRAY)) {
  73             tagPtr++;
  74         }
  75         /* Skip class name */
  76         if (*tagPtr == JDWP_TAG(OBJECT)) {
  77             tagPtr = strchr(tagPtr, SIGNATURE_END_CLASS) + 1;
  78             JDI_ASSERT(tagPtr);
  79         } else {
  80             /* Skip primitive sig */
  81             tagPtr++;
  82         }
  83     }
  84 
  85     *cursor = tagPtr;
  86     return argumentTag;
  87 }
  88 
  89 static jbyte
  90 firstArgumentTypeTag(char *signature, void **cursor)
  91 {
  92     JDI_ASSERT(signature[0] == SIGNATURE_BEGIN_ARGS);
  93     *cursor = signature + 1; /* skip to the first arg */
  94     return nextArgumentTypeTag(cursor);
  95 }
  96 
  97 
  98 /*
  99  * Note: argument refs may be destroyed on out-of-memory error
 100  */
 101 static jvmtiError
 102 createGlobalRefs(JNIEnv *env, InvokeRequest *request)
 103 {
 104     jvmtiError error;
 105     jclass clazz = NULL;
 106     jobject instance = NULL;
 107     jint argIndex;
 108     jbyte argumentTag;
 109     jvalue *argument;
 110     void *cursor;
 111     jobject *argRefs = NULL;
 112 
 113     error = JVMTI_ERROR_NONE;
 114 
 115     if ( request->argumentCount > 0 ) {
 116         /*LINTED*/
 117         argRefs = jvmtiAllocate((jint)(request->argumentCount*sizeof(jobject)));
 118         if ( argRefs==NULL ) {
 119             error = AGENT_ERROR_OUT_OF_MEMORY;
 120         } else {
 121             /*LINTED*/
 122             (void)memset(argRefs, 0, request->argumentCount*sizeof(jobject));
 123         }
 124     }
 125 
 126     if ( error == JVMTI_ERROR_NONE ) {
 127         saveGlobalRef(env, request->clazz, &clazz);
 128         if (clazz == NULL) {
 129             error = AGENT_ERROR_OUT_OF_MEMORY;
 130         }
 131     }
 132 
 133     if ( error == JVMTI_ERROR_NONE && request->instance != NULL ) {
 134         saveGlobalRef(env, request->instance, &instance);
 135         if (instance == NULL) {
 136             error = AGENT_ERROR_OUT_OF_MEMORY;
 137         }
 138     }
 139 
 140     if ( error == JVMTI_ERROR_NONE && argRefs!=NULL ) {
 141         argIndex = 0;
 142         argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
 143         argument = request->arguments;
 144         while (argumentTag != SIGNATURE_END_ARGS) {
 145             if ( argIndex > request->argumentCount ) {
 146                 break;
 147             }
 148             if ((argumentTag == JDWP_TAG(OBJECT)) ||
 149                 (argumentTag == JDWP_TAG(ARRAY))) {
 150                 /* Create a global ref for any non-null argument */
 151                 if (argument->l != NULL) {
 152                     saveGlobalRef(env, argument->l, &argRefs[argIndex]);
 153                     if (argRefs[argIndex] == NULL) {
 154                         error = AGENT_ERROR_OUT_OF_MEMORY;
 155                         break;
 156                     }
 157                 }
 158             }
 159             argument++;
 160             argIndex++;
 161             argumentTag = nextArgumentTypeTag(&cursor);
 162         }
 163     }
 164 
 165 #ifdef FIXUP /* Why isn't this an error? */
 166     /* Make sure the argument count matches */
 167     if ( error == JVMTI_ERROR_NONE && argIndex != request->argumentCount ) {
 168         error = AGENT_ERROR_INVALID_COUNT;
 169     }
 170 #endif
 171 
 172     /* Finally, put the global refs into the request if no errors */
 173     if ( error == JVMTI_ERROR_NONE ) {
 174         request->clazz = clazz;
 175         request->instance = instance;
 176         if ( argRefs!=NULL ) {
 177             argIndex = 0;
 178             argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
 179             argument = request->arguments;
 180             while ( argIndex < request->argumentCount ) {
 181                 if ((argumentTag == JDWP_TAG(OBJECT)) ||
 182                     (argumentTag == JDWP_TAG(ARRAY))) {
 183                     argument->l = argRefs[argIndex];
 184                 }
 185                 argument++;
 186                 argIndex++;
 187                 argumentTag = nextArgumentTypeTag(&cursor);
 188             }
 189             jvmtiDeallocate(argRefs);
 190         }
 191         return JVMTI_ERROR_NONE;
 192 
 193     } else {
 194         /* Delete global references */
 195         if ( clazz != NULL ) {
 196             tossGlobalRef(env, &clazz);
 197         }
 198         if ( instance != NULL ) {
 199             tossGlobalRef(env, &instance);
 200         }
 201         if ( argRefs!=NULL ) {
 202             for ( argIndex=0; argIndex < request->argumentCount; argIndex++ ) {
 203                 if ( argRefs[argIndex] != NULL ) {
 204                     tossGlobalRef(env, &argRefs[argIndex]);
 205                 }
 206             }
 207             jvmtiDeallocate(argRefs);
 208         }
 209     }
 210 
 211     return error;
 212 }
 213 
 214 static jvmtiError
 215 fillInvokeRequest(JNIEnv *env, InvokeRequest *request,
 216                   jbyte invokeType, jbyte options, jint id,
 217                   jthread thread, jclass clazz, jmethodID method,
 218                   jobject instance,
 219                   jvalue *arguments, jint argumentCount)
 220 {
 221     jvmtiError error;
 222     if (!request->available) {
 223         /*
 224          * Thread is not at a point where it can invoke.
 225          */
 226         return AGENT_ERROR_INVALID_THREAD;
 227     }
 228     if (request->pending) {
 229         /*
 230          * Pending invoke
 231          */
 232         return AGENT_ERROR_ALREADY_INVOKING;
 233     }
 234 
 235     request->invokeType = invokeType;
 236     request->options = options;
 237     request->detached = JNI_FALSE;
 238     request->id = id;
 239     request->clazz = clazz;
 240     request->method = method;
 241     request->instance = instance;
 242     request->arguments = arguments;
 243     request->arguments = arguments;
 244     request->argumentCount = argumentCount;
 245 
 246     request->returnValue.j = 0;
 247     request->exception = 0;
 248 
 249     /*
 250      * Squirrel away the method signature
 251      */
 252     error = methodSignature(method, NULL, &request->methodSignature,  NULL);
 253     if (error != JVMTI_ERROR_NONE) {
 254         return error;
 255     }
 256 
 257     /*
 258      * The given references for class and instance are not guaranteed
 259      * to be around long enough for invocation, so create new ones
 260      * here.
 261      */
 262     error = createGlobalRefs(env, request);
 263     if (error != JVMTI_ERROR_NONE) {
 264         jvmtiDeallocate(request->methodSignature);
 265         return error;
 266     }
 267 
 268     request->pending = JNI_TRUE;
 269     request->available = JNI_FALSE;
 270     return JVMTI_ERROR_NONE;
 271 }
 272 
 273 void
 274 invoker_enableInvokeRequests(jthread thread)
 275 {
 276     InvokeRequest *request;
 277 
 278     JDI_ASSERT(thread);
 279 
 280     request = threadControl_getInvokeRequest(thread);
 281     if (request == NULL) {
 282         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 283     }
 284 
 285     request->available = JNI_TRUE;
 286 }
 287 
 288 jvmtiError
 289 invoker_requestInvoke(jbyte invokeType, jbyte options, jint id,
 290                       jthread thread, jclass clazz, jmethodID method,
 291                       jobject instance,
 292                       jvalue *arguments, jint argumentCount)
 293 {
 294     JNIEnv *env = getEnv();
 295     InvokeRequest *request;
 296     jvmtiError error = JVMTI_ERROR_NONE;
 297 
 298     debugMonitorEnter(invokerLock);
 299     request = threadControl_getInvokeRequest(thread);
 300     if (request != NULL) {
 301         error = fillInvokeRequest(env, request, invokeType, options, id,
 302                                   thread, clazz, method, instance,
 303                                   arguments, argumentCount);
 304     }
 305     debugMonitorExit(invokerLock);
 306 
 307     if (error == JVMTI_ERROR_NONE) {
 308         if (options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED) ) {
 309             /* true means it is okay to unblock the commandLoop thread */
 310             (void)threadControl_resumeThread(thread, JNI_TRUE);
 311         } else {
 312             (void)threadControl_resumeAll();
 313         }
 314     }
 315 
 316     return error;
 317 }
 318 
 319 static void
 320 invokeConstructor(JNIEnv *env, InvokeRequest *request)
 321 {
 322     jobject object;
 323     object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
 324                                      request->method,
 325                                      request->arguments);
 326     request->returnValue.l = NULL;
 327     if (object != NULL) {
 328         saveGlobalRef(env, object, &(request->returnValue.l));
 329     }
 330 }
 331 
 332 static void
 333 invokeStatic(JNIEnv *env, InvokeRequest *request)
 334 {
 335     switch(returnTypeTag(request->methodSignature)) {
 336         case JDWP_TAG(OBJECT):
 337         case JDWP_TAG(ARRAY): {
 338             jobject object;
 339             object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
 340                                        request->clazz,
 341                                        request->method,
 342                                        request->arguments);
 343             request->returnValue.l = NULL;
 344             if (object != NULL) {
 345                 saveGlobalRef(env, object, &(request->returnValue.l));
 346             }
 347             break;
 348         }
 349 
 350 
 351         case JDWP_TAG(BYTE):
 352             request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
 353                                                        request->clazz,
 354                                                        request->method,
 355                                                        request->arguments);
 356             break;
 357 
 358         case JDWP_TAG(CHAR):
 359             request->returnValue.c = JNI_FUNC_PTR(env,CallStaticCharMethodA)(env,
 360                                                        request->clazz,
 361                                                        request->method,
 362                                                        request->arguments);
 363             break;
 364 
 365         case JDWP_TAG(FLOAT):
 366             request->returnValue.f = JNI_FUNC_PTR(env,CallStaticFloatMethodA)(env,
 367                                                        request->clazz,
 368                                                        request->method,
 369                                                        request->arguments);
 370             break;
 371 
 372         case JDWP_TAG(DOUBLE):
 373             request->returnValue.d = JNI_FUNC_PTR(env,CallStaticDoubleMethodA)(env,
 374                                                        request->clazz,
 375                                                        request->method,
 376                                                        request->arguments);
 377             break;
 378 
 379         case JDWP_TAG(INT):
 380             request->returnValue.i = JNI_FUNC_PTR(env,CallStaticIntMethodA)(env,
 381                                                        request->clazz,
 382                                                        request->method,
 383                                                        request->arguments);
 384             break;
 385 
 386         case JDWP_TAG(LONG):
 387             request->returnValue.j = JNI_FUNC_PTR(env,CallStaticLongMethodA)(env,
 388                                                        request->clazz,
 389                                                        request->method,
 390                                                        request->arguments);
 391             break;
 392 
 393         case JDWP_TAG(SHORT):
 394             request->returnValue.s = JNI_FUNC_PTR(env,CallStaticShortMethodA)(env,
 395                                                        request->clazz,
 396                                                        request->method,
 397                                                        request->arguments);
 398             break;
 399 
 400         case JDWP_TAG(BOOLEAN):
 401             request->returnValue.z = JNI_FUNC_PTR(env,CallStaticBooleanMethodA)(env,
 402                                                        request->clazz,
 403                                                        request->method,
 404                                                        request->arguments);
 405             break;
 406 
 407         case JDWP_TAG(VOID):
 408             JNI_FUNC_PTR(env,CallStaticVoidMethodA)(env,
 409                                           request->clazz,
 410                                           request->method,
 411                                           request->arguments);
 412             break;
 413 
 414         default:
 415             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 416             break;
 417     }
 418 }
 419 
 420 static void
 421 invokeVirtual(JNIEnv *env, InvokeRequest *request)
 422 {
 423     switch(returnTypeTag(request->methodSignature)) {
 424         case JDWP_TAG(OBJECT):
 425         case JDWP_TAG(ARRAY): {
 426             jobject object;
 427             object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
 428                                  request->instance,
 429                                  request->method,
 430                                  request->arguments);
 431             request->returnValue.l = NULL;
 432             if (object != NULL) {
 433                 saveGlobalRef(env, object, &(request->returnValue.l));
 434             }
 435             break;
 436         }
 437 
 438         case JDWP_TAG(BYTE):
 439             request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
 440                                                  request->instance,
 441                                                  request->method,
 442                                                  request->arguments);
 443             break;
 444 
 445         case JDWP_TAG(CHAR):
 446             request->returnValue.c = JNI_FUNC_PTR(env,CallCharMethodA)(env,
 447                                                  request->instance,
 448                                                  request->method,
 449                                                  request->arguments);
 450             break;
 451 
 452         case JDWP_TAG(FLOAT):
 453             request->returnValue.f = JNI_FUNC_PTR(env,CallFloatMethodA)(env,
 454                                                  request->instance,
 455                                                  request->method,
 456                                                  request->arguments);
 457             break;
 458 
 459         case JDWP_TAG(DOUBLE):
 460             request->returnValue.d = JNI_FUNC_PTR(env,CallDoubleMethodA)(env,
 461                                                  request->instance,
 462                                                  request->method,
 463                                                  request->arguments);
 464             break;
 465 
 466         case JDWP_TAG(INT):
 467             request->returnValue.i = JNI_FUNC_PTR(env,CallIntMethodA)(env,
 468                                                  request->instance,
 469                                                  request->method,
 470                                                  request->arguments);
 471             break;
 472 
 473         case JDWP_TAG(LONG):
 474             request->returnValue.j = JNI_FUNC_PTR(env,CallLongMethodA)(env,
 475                                                  request->instance,
 476                                                  request->method,
 477                                                  request->arguments);
 478             break;
 479 
 480         case JDWP_TAG(SHORT):
 481             request->returnValue.s = JNI_FUNC_PTR(env,CallShortMethodA)(env,
 482                                                  request->instance,
 483                                                  request->method,
 484                                                  request->arguments);
 485             break;
 486 
 487         case JDWP_TAG(BOOLEAN):
 488             request->returnValue.z = JNI_FUNC_PTR(env,CallBooleanMethodA)(env,
 489                                                  request->instance,
 490                                                  request->method,
 491                                                  request->arguments);
 492             break;
 493 
 494         case JDWP_TAG(VOID):
 495             JNI_FUNC_PTR(env,CallVoidMethodA)(env,
 496                                     request->instance,
 497                                     request->method,
 498                                     request->arguments);
 499             break;
 500 
 501         default:
 502             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 503             break;
 504     }
 505 }
 506 
 507 static void
 508 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
 509 {
 510     switch(returnTypeTag(request->methodSignature)) {
 511         case JDWP_TAG(OBJECT):
 512         case JDWP_TAG(ARRAY): {
 513             jobject object;
 514             object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
 515                                            request->instance,
 516                                            request->clazz,
 517                                            request->method,
 518                                            request->arguments);
 519             request->returnValue.l = NULL;
 520             if (object != NULL) {
 521                 saveGlobalRef(env, object, &(request->returnValue.l));
 522             }
 523             break;
 524         }
 525 
 526         case JDWP_TAG(BYTE):
 527             request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
 528                                                  request->instance,
 529                                                  request->clazz,
 530                                                  request->method,
 531                                                  request->arguments);
 532             break;
 533 
 534         case JDWP_TAG(CHAR):
 535             request->returnValue.c = JNI_FUNC_PTR(env,CallNonvirtualCharMethodA)(env,
 536                                                  request->instance,
 537                                                  request->clazz,
 538                                                  request->method,
 539                                                  request->arguments);
 540             break;
 541 
 542         case JDWP_TAG(FLOAT):
 543             request->returnValue.f = JNI_FUNC_PTR(env,CallNonvirtualFloatMethodA)(env,
 544                                                  request->instance,
 545                                                  request->clazz,
 546                                                  request->method,
 547                                                  request->arguments);
 548             break;
 549 
 550         case JDWP_TAG(DOUBLE):
 551             request->returnValue.d = JNI_FUNC_PTR(env,CallNonvirtualDoubleMethodA)(env,
 552                                                  request->instance,
 553                                                  request->clazz,
 554                                                  request->method,
 555                                                  request->arguments);
 556             break;
 557 
 558         case JDWP_TAG(INT):
 559             request->returnValue.i = JNI_FUNC_PTR(env,CallNonvirtualIntMethodA)(env,
 560                                                  request->instance,
 561                                                  request->clazz,
 562                                                  request->method,
 563                                                  request->arguments);
 564             break;
 565 
 566         case JDWP_TAG(LONG):
 567             request->returnValue.j = JNI_FUNC_PTR(env,CallNonvirtualLongMethodA)(env,
 568                                                  request->instance,
 569                                                  request->clazz,
 570                                                  request->method,
 571                                                  request->arguments);
 572             break;
 573 
 574         case JDWP_TAG(SHORT):
 575             request->returnValue.s = JNI_FUNC_PTR(env,CallNonvirtualShortMethodA)(env,
 576                                                  request->instance,
 577                                                  request->clazz,
 578                                                  request->method,
 579                                                  request->arguments);
 580             break;
 581 
 582         case JDWP_TAG(BOOLEAN):
 583             request->returnValue.z = JNI_FUNC_PTR(env,CallNonvirtualBooleanMethodA)(env,
 584                                                  request->instance,
 585                                                  request->clazz,
 586                                                  request->method,
 587                                                  request->arguments);
 588             break;
 589 
 590         case JDWP_TAG(VOID):
 591             JNI_FUNC_PTR(env,CallNonvirtualVoidMethodA)(env,
 592                                     request->instance,
 593                                     request->clazz,
 594                                     request->method,
 595                                     request->arguments);
 596             break;
 597 
 598         default:
 599             EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"Invalid method signature");
 600             break;
 601     }
 602 }
 603 
 604 jboolean
 605 invoker_doInvoke(jthread thread)
 606 {
 607     JNIEnv *env;
 608     jboolean startNow;
 609     InvokeRequest *request;
 610 
 611     JDI_ASSERT(thread);
 612 
 613     debugMonitorEnter(invokerLock);
 614 
 615     request = threadControl_getInvokeRequest(thread);
 616     if (request == NULL) {
 617         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 618     }
 619 
 620     request->available = JNI_FALSE;
 621     startNow = request->pending && !request->started;
 622 
 623     if (startNow) {
 624         request->started = JNI_TRUE;
 625     }
 626     debugMonitorExit(invokerLock);
 627 
 628     if (!startNow) {
 629         return JNI_FALSE;
 630     }
 631 
 632     env = getEnv();
 633 
 634     WITH_LOCAL_REFS(env, 2) {  /* 1 for obj return values, 1 for exception */
 635 
 636         jobject exception;
 637 
 638         JNI_FUNC_PTR(env,ExceptionClear)(env);
 639 
 640         switch (request->invokeType) {
 641             case INVOKE_CONSTRUCTOR:
 642                 invokeConstructor(env, request);
 643                 break;
 644             case INVOKE_STATIC:
 645                 invokeStatic(env, request);
 646                 break;
 647             case INVOKE_INSTANCE:
 648                 if (request->options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
 649                     invokeNonvirtual(env, request);
 650                 } else {
 651                     invokeVirtual(env, request);
 652                 }
 653                 break;
 654             default:
 655                 JDI_ASSERT(JNI_FALSE);
 656         }
 657         request->exception = NULL;
 658         exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
 659         if (exception != NULL) {
 660             JNI_FUNC_PTR(env,ExceptionClear)(env);
 661             saveGlobalRef(env, exception, &(request->exception));
 662         }
 663 
 664     } END_WITH_LOCAL_REFS(env);
 665 
 666     return JNI_TRUE;
 667 }
 668 
 669 void
 670 invoker_completeInvokeRequest(jthread thread)
 671 {
 672     JNIEnv *env = getEnv();
 673     PacketOutputStream out;
 674     jbyte tag;
 675     jobject exc;
 676     jvalue returnValue;
 677     jint id;
 678     InvokeRequest *request;
 679     jboolean detached;
 680 
 681     JDI_ASSERT(thread);
 682 
 683     /* Prevent gcc errors on uninitialized variables. */
 684     tag = 0;
 685     exc = NULL;
 686     id  = 0;
 687 
 688     eventHandler_lock(); /* for proper lock order */
 689     debugMonitorEnter(invokerLock);
 690 
 691     request = threadControl_getInvokeRequest(thread);
 692     if (request == NULL) {
 693         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 694     }
 695 
 696     JDI_ASSERT(request->pending);
 697     JDI_ASSERT(request->started);
 698 
 699     request->pending = JNI_FALSE;
 700     request->started = JNI_FALSE;
 701     request->available = JNI_TRUE; /* For next time around */
 702 
 703     detached = request->detached;
 704     if (!detached) {
 705         if (request->options & JDWP_INVOKE_OPTIONS(SINGLE_THREADED)) {
 706             (void)threadControl_suspendThread(thread, JNI_FALSE);
 707         } else {
 708             (void)threadControl_suspendAll();
 709         }
 710 
 711         if (request->invokeType == INVOKE_CONSTRUCTOR) {
 712             /*
 713              * Although constructors technically have a return type of
 714              * void, we return the object created.
 715              */
 716             tag = specificTypeKey(env, request->returnValue.l);
 717         } else {
 718             tag = returnTypeTag(request->methodSignature);
 719         }
 720         id = request->id;
 721         exc = request->exception;
 722         returnValue = request->returnValue;
 723     }
 724 
 725     /*
 726      * Give up the lock before I/O operation
 727      */
 728     debugMonitorExit(invokerLock);
 729     eventHandler_unlock();
 730 
 731 
 732     if (!detached) {
 733         outStream_initReply(&out, id);
 734         (void)outStream_writeValue(env, &out, tag, returnValue);
 735         (void)outStream_writeObjectTag(env, &out, exc);
 736         (void)outStream_writeObjectRef(env, &out, exc);
 737         outStream_sendReply(&out);
 738     }
 739 }
 740 
 741 jboolean
 742 invoker_isPending(jthread thread)
 743 {
 744     InvokeRequest *request;
 745 
 746     JDI_ASSERT(thread);
 747     request = threadControl_getInvokeRequest(thread);
 748     if (request == NULL) {
 749         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 750     }
 751     return request->pending;
 752 }
 753 
 754 jboolean
 755 invoker_isEnabled(jthread thread)
 756 {
 757     InvokeRequest *request;
 758 
 759     JDI_ASSERT(thread);
 760     request = threadControl_getInvokeRequest(thread);
 761     if (request == NULL) {
 762         EXIT_ERROR(AGENT_ERROR_INVALID_THREAD, "getting thread invoke request");
 763     }
 764     return request->available;
 765 }
 766 
 767 void
 768 invoker_detach(InvokeRequest *request)
 769 {
 770     JDI_ASSERT(request);
 771     debugMonitorEnter(invokerLock);
 772     request->detached = JNI_TRUE;
 773     debugMonitorExit(invokerLock);
 774 }