public boolean ungetService(Bundle bundle, ServiceReference<?> ref)
    {
        UsageCount usage = null;
        ServiceRegistrationImpl<Object> reg =
            ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getRegistration();

        synchronized (this)
        {
            // First make sure that no existing operation is currently
            // being performed by another thread on the service registration.
            for (Object o = m_lockedRegsMap.get(reg); (o != null); o = m_lockedRegsMap.get(reg))
            {
                // We don't allow cycles when we call out to the service factory.
                if (o.equals(Thread.currentThread()))
                {
                    throw new IllegalStateException(
                        "ServiceFactory.ungetService() resulted in a cycle.");
                }

                // Otherwise, wait for it to be freed.
                try
                {
                    wait();
                }
                catch (InterruptedException ex)
                {
                }
            }

            // Get the usage count.
            usage = getUsageCount(bundle, ref);
            // If there is no cached services, then just return immediately.
            if (usage == null)
            {
                return false;
            }

            // Lock the service registration.
            m_lockedRegsMap.put(reg, Thread.currentThread());
        }

        // If usage count will go to zero, then unget the service
        // from the registration; we do this outside the lock
        // since this might call out to the service factory.
        try
        {
            if (usage.m_count == 1)
            {
                // Remove reference from usages array.
                ((ServiceRegistrationImpl.ServiceReferenceImpl) ref)
                    .getRegistration().ungetService(bundle, usage.m_svcObj);
            }
        }
        finally
        {
            // Finally, decrement usage count and flush if it goes to zero or
            // the registration became invalid while we were not holding the
            // lock. Either way, unlock the service registration so that any
            // threads waiting for it can continue.
            synchronized (this)
            {
                // Decrement usage count, which spec says should happen after
                // ungetting the service object.
                usage.m_count--;

                // If the registration is invalid or the usage count has reached
                // zero, then flush it.
                if (!reg.isValid() || (usage.m_count <= 0))
                {
                    usage.m_svcObj = null;
                    flushUsageCount(bundle, ref);
                }

                // Release the registration lock so any waiting threads can
                // continue.
                m_lockedRegsMap.remove(reg);
                notifyAll();
            }
        }

        return true;
    }