apil.tamang
apil.tamang

Reputation: 2725

Decipher a deadlock situation in an OSGi code piece

The following piece of code is to demonstrate a deadlock that may happen in a piece of OSGi code, and taken directly from the freely downloadable book: osgi in practice (Neil Bartlett). The book is generally easy to follow and I've found it to be very useful. However, I'm not sure I follow the concurrency problem identified (and slightly discussed) in page 130. The code is as follows:

package org.osgi.book.reader.dbmailbox;

public class BadLockingMailboxRegistrationService implements MailboxRegistrationService {

    private final Map<String,ServiceRegistration> map = 
            new HashMap<String,ServiceRegistration >();

    private final BundleContext context ;

    public BadLockingMailboxRegistrationService(BundleContext context) { 
        this . context = context ;
    }

    // DO NOT DO THIS!
    public synchronized void registerMailbox ( String name, Mailbox mailbox){

        ServiceRegistration priorReg = map.get(name);

        if(priorReg != null) priorReg . unregister ();

        Properties props = new Properties (); 
        props.put(Mailbox.NAME_PROPERTY , name); 
        ServiceRegistration reg = 
                context . registerService (Mailbox.class.getName(), mailbox , props ); 
        map . put(name , reg );
    } 
}

The discussion provided to show how deadlock may happen is:

To translate this unhappy situation to OSGi programming, imagine that a thread has taken a lock on an object F. Then it tries to call our register- Mailbox, which locks object K — but it must wait, perhaps because another thread is already executing registerMailbox. One of the callbacks resulting from the service registration then attempts to lock F . The result: two starving threads and no work done.

I understand the first part of the discussion, i.e. that a thread may take a lock on an Object F, which attempts to call registerMailbox, thus taking a lock on object K (where K is the service object registered for this particular service, or so I think!). Now sure, another thread is already executing registerMailbox. That means, it also needs to hold lock on K (since OSGi distributes a singleton service object). Now where is the callback(s) discussed which may attempt to take a lock on F, thus causing deadlock?

Upvotes: 0

Views: 87

Answers (1)

Paul Bilnoski
Paul Bilnoski

Reputation: 556

The author is noting that context.registerService notifies listeners of service registrations on the same thread during its execution. If one of those listeners in turn attempts to acquire lock F it will result in a deadlock since F is held by the thread that also holds K.

Thread 2: invoke registerMailbox and acquire K

Thread 1: acquire F before invoking registerMailbox, then invoke registerMailbox which is synchronized, thus attempts to acquire K but blocks because it is held by Thread 2

Thread 2: finally executes context.registerService which in turn invokes a listener/callback that attempts to acquire F, and blocks since it is held by Thread 1

Because there are two locks acquired by two threads in opposite order and each acquires one of them but not the second, deadlock occurs. This is not really an OSGI-specific issue, but I suppose is illustrated to note that service registration involves listener notification and should be invoked when locks are held with caution.

Upvotes: 2

Related Questions