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

internal VM class locks can cause deadlock with sync static methods

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Won't Fix
    • Icon: P1 P1
    • None
    • 1.1.3
    • hotspot
    • None
    • other
    • generic



      Name: rs12567 Date: 08/05/97


      Attn: Sheng Liang
      This is the same bug as bug no. 4041699
      -
      There is more to this problem than we are covering here (i.e.
      there are more class object locking issues in the VM), and
      Javasoft had previously decided that it was too dangerous to
      change it now, because it needs a total re-write. I hope that
      I convinced Sheng Liang that as the code is now, synchronized
      static methods are just not safe, and that the situation can be
      considerably improved with a very limited change. The code of
      IBM's San Francisco project uses a lot of synchronized static
      methods, and so JVM hangs have been a real problem for them.
      It seems a bit silly that they should have to change all their
      synchronized static methods to lock some other object when the
      fault lies with the JVM.
      -
      I have plenty of information about this problem, and I can
      easily generate more test cases, so if there is any doubt,
      please do not hesitate to contact me (###@###.###).
      This is a serious problem!!
        ---
      Class objects are locked in five places in the JVM (this applies
      to all 1.1.x versions).
      -
        classinitialize.c:
          Place #1. ResolveClassConstantFromClass
          Place #2. ResolveClassConstant
          These both lock the class from which opcodes are being
          interpreted when certain opcodes are resolved to _quick
          opcodes.
      -
        classresolver.c:
          Place #3. makeslottable
      -
        classresolver.c:
          Place #4. InitializeClass
          Place #5. ResolveClass
          These methods are both called during the initialization of a
          newly loaded class, and they can be called under another
          class lock from ResolveClassConstant and
          ResolveClassConstantFromClass (even if the class is not
          newly loaded).
          They lock the class they're initializing.
      -
      Test case (Deadlock1.java):
      -
      class D1A {
          static int x;
            // Locks D1A
          static synchronized void foo() {
              try {
                  Thread.sleep(500);
                  System.out.println("D1A test");
                  D1B.x = 1; /* Locks D1B through ResolveClassConstant */
              }
              catch (Exception e) {}
          }
      }
      class D1B {
          static int x;
          static synchronized void foo() {
              try {
                  Thread.sleep(500);
                  System.out.println("D1B test");
                  D1A.x = 1; /* Locks D1A through ResolveClassConstant */
              }
              catch (Exception e) {}
          }
      }
      class ThreadD1A implements Runnable {
          public void run() {
              D1A.foo();
          }
      }
      class ThreadD1B implements Runnable {
          public void run() {
              D1B.foo();
          }
      }
      public class Deadlock1 {
          public static void main(String[] args)
          {
              System.out.println("This test passes if it doesn't hang");
              new Thread(new ThreadD1A(), "Thread-A").start();
              new Thread(new ThreadD1B(), "Thread-B").start();
          }
      }
      What's happening here?
      The class is locked during the synchronized static method. Each
      method then makes a reference to the other method. The JVM locks
      the other method's class while it resolves this reference.
      Because two threads are doing this at once, there is a deadlock.
      -
      SUGGESTED FIX
      SAS has done some research on this problem, and they came up
      with a very similar fix to mine (Robert Field at Javasoft has
      details about their fix). This fix makes the class locking
      work in an analogous way to JDK1.0.2. JDK1.0.2 used a
      different lock for classes within the VM from the lock used for
      synchronized methods.
      -
      This is what we suggest. This should be pretty much exactly the
      same as SAS's suggestion (but I don't have access to their
      notes):
      -
      FILE *** src/share/java/runtime/classinitialize.c
      --- FROM (ResolveClassConstantFromClass function)
              monitorEnter(obj_monitor(class));
              ret = Locked_ResolveClassConstant(class, constant_pool,
                                                index, ee, mask);
              monitorExit(obj_monitor(class));
      --- TO
              monitorEnter(obj_monitor(class)+1);
              ret = Locked_ResolveClassConstant(class, constant_pool,
                                                index, ee, mask);
              monitorExit(obj_monitor(class)+1);
      --- END
      --- FROM (ResolveClassConstant function)
              monitorEnter(obj_monitor(class));
              ret = Locked_ResolveClassConstant(class, constant_pool,
                                                index, ee, mask);
              monitorExit(obj_monitor(class));
      --- TO
              monitorEnter(obj_monitor(class)+1);
              ret = Locked_ResolveClassConstant(class, constant_pool,
                                                index, ee, mask);
              monitorExit(obj_monitor(class)+1);
      --- END
      -
      FILE *** src/share/java/runtime/classresolver.c
      Note: here we are using the class object handle address + 2
      instead of + 1 in makeslottable. SAS has a justification for
      this, so please talk to Robert Field about it.
      --- FROM (makeslottable function)
          monitorEnter(obj_monitor(clb));
          result = Locked_makeslottable(clb);
          monitorExit(obj_monitor(clb));
      --- TO
          monitorEnter(obj_monitor(clb)+2);
          result = Locked_makeslottable(clb);
          monitorExit(obj_monitor(clb)+2);
      --- END
      --- FROM (InitializeClass function)
          monitorEnter(obj_monitor(cb));
          result = Locked_InitializeClass(cb, detail);
          monitorExit(obj_monitor(cb));
      --- TO
          monitorEnter(obj_monitor(cb)+1);
          result = Locked_InitializeClass(cb, detail);
          monitorExit(obj_monitor(cb)+1);
      --- END
      --- FROM (ResolveClass function)
          monitorEnter(obj_monitor(cb));
          result = Locked_ResolveClass(cb, detail);
          monitorExit(obj_monitor(cb));
      --- TO
          monitorEnter(obj_monitor(cb)+1);
          result = Locked_ResolveClass(cb, detail);
          monitorExit(obj_monitor(cb)+1);
      --- END
      -
      FILE *** src/share/java/runtime/gc.c
      monitorDumpHelper can be improved:
      --- FROM
      void
      monitorDumpHelper(monitor_t *mid, void *arg)
      {
          unsigned int key = mid->key;
          bool_t verbose = (bool_t) arg;
          SetLimits();
          if (verbose != FALSE || mid->use_count != 0) {
              if (ValidHandle(key)) {
                  jio_fprintf(stderr, " %s: ", Object2CString((JHandle *) key));
              } else {
                  jio_fprintf(stderr, " <unknown key> (0x%lx): ", key);
              }
              sysMonitorDumpInfo((sys_mon_t *)&mid->mid);
          }
      }
      --- TO
      void
      monitorDumpHelper(monitor_t *mid, void *arg)
      {
          unsigned int key = mid->key & ~0x03;
          unsigned int offset = mid->key & 0x03;
          
          bool_t verbose = (bool_t) arg;
          SetLimits();
          if (verbose != FALSE || mid->use_count != 0) {
              if (ValidHandle(key)) {
                  if (offset)
                      jio_fprintf(stderr, " %s+%d: ", Object2CString((JHandle *) key),
                                  offset);
                  else
                      jio_fprintf(stderr, " %s: ", Object2CString((JHandle *) key));
              } else {
                  jio_fprintf(stderr, " <unknown key> (0x%lx): ", key);
              }
              sysMonitorDumpInfo((sys_mon_t *)&mid->mid);
          }
      }
      --- END

      ======================================================================

            sliangsunw Sheng Liang (Inactive)
            rschiavisunw Richard Schiavi (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: