Uploaded image for project: 'Openfire'
  1. Openfire
  2. OF-944

Deadlock in PrivacyList

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: Major
    • Resolution: Cannot Reproduce
    • Affects Version/s: 3.9.3
    • Fix Version/s: None
    • Component/s: Core
    • Labels:
      None

      Description

      Community forum post has the details.

      I am experiencing a deadlock in the OpenFire 3.9.3 (not sure if present in the last stable version), when using PrivacyLists.

      High level description
      I implemented a custom OpenFire plugin, which manages PrivacyLists. At some point the plugin's worker thread calls PrivacyListManager.getDefaultPrivacyList() to get default privacy list for some user. But my plugin happens to deadlock sometimes on this call.

      The problem is that two different threads use synchronized() call on two different objects in a different order.
      It is caused when one client thread processing presence update calls PresenceManager.probePresence() and a different thread tries to load a default privacy list for the same user, calling PrivacyListManager.getDefaultPrivacyList().

      Detailed explanation
      I am using a thread dump (bottom of this message) as a reference.

      Thread:TaskExecutor.0:BLOCKED
      Call flow (from top to bottom, first line causes call of the second line and so on):
      [Irrelevant calls prior this call]
      PrivacyListManager.getDefaultPrivacyList("test@demo.com"), called from my application code - plugin.
      synchronized ("test@demo.com".intern()), in PrivacyListManager:153
      [Irrelevant calls, without nested locks]
      RosterManager.getRoster("test@demo.com"); called from PrivacyList.<init> -> updateList -> updateList -> getRoster.
      synchronized (("test@demo.com" + " ro").intern()) , in RosterManager.java:112. Deadlock. This lock is held by the thread Thread:client-9:BLOCKED.
      [Deadlock]

      Thread:client-9:BLOCKED
      Call flow (from top to bottom, first line causes call of the second line and so on):
      [Irrelevant calls prior this call]
      RosterManager.getRoster("test@demo.com"); called from PresenceManagerImpl.canProbePresence(PresenceManagerImpl.java:331)
      synchronized (("test@demo.com" + " ro").intern()) , in RosterManager.java:112
      [Irrelevant calls, without nested locks]
      GroupManager.getSharedGroups()
      synchronized("test@demo.com".intern()), in GroupManager:454. Deadlock. This lock is held by the thread Thread:TaskExecutor.0
      [Deadlock]

      Workaround
      As the following locking order: synchronized ((username + " ro").intern()) , synchronized(username.intern()) is common in the OpenFire (code path by RosterManager.getRoster()) I would suggest to preserve this locking order also in the getDefaultPrivacyList() call. The workaround (which worked for me) is to call getDefaultPrivacyList() in the synchronized ((username + " ro").intern()) block:

      synchronized ((username + " ro").intern())

      {
 // Following call synchronizes on username.intern(), then on (username + "ro").
 final PrivacyList list = privListManager.getDefaultPrivacyList(username); // Do your job here // ... }

      As the synchronized() block uses reentrant locking, when execution flow reaches getRoster() call the thread already holds username + " ro" lock.

        Attachments

          Activity

            People

            Assignee:
            dwd Dave Cridland
            Reporter:
            akrherz Daryl Herzmann
            Votes:
            2 Vote for this issue
            Watchers:
            4 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved: