Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8209671

With dynamic compiler threads the compiler-thread count is not maintained in a thread-safe manner

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P3 P3
    • 12
    • 11, 12
    • hotspot
    • None
    • b11
    • 11

      This is the code that updates the compiler thread count:

      static bool can_remove(CompilerThread *ct, bool do_it) {
        assert(UseDynamicNumberOfCompilerThreads, "or shouldn't be here");
        if (!ReduceNumberOfCompilerThreads) return false;

        AbstractCompiler *compiler = ct->compiler();
        int compiler_count = compiler->num_compiler_threads();
        bool c1 = compiler->is_c1();

        // Keep at least 1 compiler thread of each type.
        if (compiler_count < 2) return false;

        // Keep thread alive for at least some time.
        if (ct->idle_time_millis() < (c1 ? 500 : 100)) return false;

        // We only allow the last compiler thread of each type to get removed.
        jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1)
                                   : CompileBroker::compiler2_object(compiler_count - 1);
        if (oopDesc::equals(ct->threadObj(), JNIHandles::resolve_non_null(last_compiler))) {
          if (do_it) {
            assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
            compiler->set_num_compiler_threads(compiler_count - 1);
          }
          return true;
        }
        return false;
      }

      We read the count initially with no lock held:

        int compiler_count = compiler->num_compiler_threads();

      we then later update the count with the lock held:

            assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
            compiler->set_num_compiler_threads(compiler_count - 1);

      but by this time the local variable "compiler_count" may not contain the current number of compiler threads and so we will set the wrong value. Further the count may also have changed when we use it here:

       jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1)
                                   : CompileBroker::compiler2_object(compiler_count - 1);

      In addition there is logic to try and ensure we always keep at least one compiler thread but this seems to be executed with no locking so multiple threads can execute:

        if (compiler_count < 2) return false;

      and all see a count >=2 but then all continue to exit thus leaving zero compiler threads running.

            mdoerr Martin Doerr
            dholmes David Holmes
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: