connect/src/main/java/org/apache/felix/connect/felix/framework/ServiceRegistry.java [286:488]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        return null;
    }

    @SuppressWarnings("unchecked")
    public <S> S getService(final Bundle bundle, final ServiceReference<S> ref, final boolean isServiceObjects)
    {
        // prototype scope is only possible if called from ServiceObjects
        final boolean isPrototype = isServiceObjects && ref.getProperty(Constants.SERVICE_SCOPE) == Constants.SCOPE_PROTOTYPE;
        UsageCount usage = null;
        Object svcObj = null;

        // Get the service registration.
        final ServiceRegistrationImpl reg =
            ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getRegistration();

        // We don't allow cycles when we call out to the service factory.
        if ( reg.currentThreadMarked() )
        {
            throw new ServiceException(
                    "ServiceFactory.getService() resulted in a cycle.",
                    ServiceException.FACTORY_ERROR,
                    null);
        }

        try
        {
            reg.markCurrentThread();

            // Make sure the service registration is still valid.
            if (reg.isValid())
            {
                // Get the usage count, or create a new one. If this is a
                // prototype, the we'll alway create a new one.
                usage = obtainUsageCount(bundle, ref, null, isPrototype);

                // Increment the usage count and grab the already retrieved
                // service object, if one exists.
                incrementToPositiveValue(usage.m_count);
                svcObj = usage.getService();

                if ( isServiceObjects )
                {
                    incrementToPositiveValue(usage.m_serviceObjectsCount);
                }

                // If we have a usage count, but no service object, then we haven't
                // cached the service object yet, so we need to create one.
                if (usage != null)
                {
                    ServiceHolder holder = null;

                    // There is a possibility that the holder is unset between the compareAndSet() and the get()
                    // below. If that happens get() returns null and we may have to set a new holder. This is
                    // why the below section is in a loop.
                    while (holder == null)
                    {
                        ServiceHolder h = new ServiceHolder();
                        if (usage.m_svcHolderRef.compareAndSet(null, h))
                        {
                            holder = h;
                            try {
                                svcObj = reg.getService(bundle);
                                holder.m_service = svcObj;
                            } finally {
                                holder.m_latch.countDown();
                            }
                        }
                        else
                        {
                            holder = usage.m_svcHolderRef.get();
                            if (holder != null)
                            {
                                boolean interrupted = false;
                                do
                                {
                                    try
                                    {
                                        // Need to ensure that the other thread has obtained
                                        // the service.
                                        holder.m_latch.await();
                                        if (interrupted)
                                        {
                                            Thread.currentThread().interrupt();
                                        }
                                        interrupted = false;
                                    }
                                    catch (InterruptedException e)
                                    {
                                        interrupted = true;
                                        Thread.interrupted();
                                    }
                                }
                                while (interrupted);
                                svcObj = holder.m_service;
                            }
                        }

                        // if someone concurrently changed the holder, loop again
                        if (holder != usage.m_svcHolderRef.get())
                            holder = null;
                    }
                    if (svcObj != null && isPrototype)
                    {
                        UsageCount existingUsage = obtainUsageCount(bundle, ref, svcObj, null);
                        if (existingUsage != null && existingUsage != usage)
                        {
                            flushUsageCount(bundle, ref, usage);
                            usage = existingUsage;
                            incrementToPositiveValue(usage.m_count);
                            if ( isServiceObjects )
                            {
                                incrementToPositiveValue(usage.m_serviceObjectsCount);
                            }
                        }
                    }
                }
            }
        }
        finally
        {
            reg.unmarkCurrentThread();

            if (!reg.isValid() || (svcObj == null))
            {
                flushUsageCount(bundle, ref, usage);
            }
        }

        return (S) svcObj;
    }

    // Increment the Atomic Long by 1, and ensure the result is at least 1.
    // This method uses a loop, optimistic algorithm to do this in a threadsafe
    // way without locks.
    private void incrementToPositiveValue(AtomicLong al)
    {
        boolean success = false;

        while (!success)
        {
            long oldVal = al.get();
            long newVal = Math.max(oldVal + 1L, 1L);
            checkCountOverflow(newVal);

            success = al.compareAndSet(oldVal, newVal);
        }
    }

    private void checkCountOverflow(long c)
    {
        if (c == Long.MAX_VALUE)
        {
            throw new ServiceException(
                    "The use count for the service overflowed.",
                    ServiceException.UNSPECIFIED,
                    null);
        }
    }

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

        if ( reg.currentThreadMarked() )
        {
            throw new IllegalStateException(
                    "ServiceFactory.ungetService() resulted in a cycle.");
        }

        try
        {
            // Mark the current thread to avoid cycles
            reg.markCurrentThread();

            // Get the usage count.
            UsageCount usage = obtainUsageCount(bundle, ref, svcObj, null);
            // If there are no cached services, then just return immediately.
            if (usage == null)
            {
                return false;
            }
            // if this is a call from service objects and the service was not fetched from
            // there, return false
            if ( svcObj != null )
            {
                if (usage.m_serviceObjectsCount.decrementAndGet() < 0)
                {
                    return false;
                }
            }

            // If usage count will go to zero, then unget the service
            // from the registration.
            long count = usage.m_count.decrementAndGet();
            try
            {
                if (count <= 0)
                {
                    ServiceHolder holder = usage.m_svcHolderRef.get();
                    Object svc = holder != null ? holder.m_service : null;

                    if (svc != null)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java [301:503]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        return null;
    }

    @SuppressWarnings("unchecked")
    public <S> S getService(final Bundle bundle, final ServiceReference<S> ref, final boolean isServiceObjects)
    {
        // prototype scope is only possible if called from ServiceObjects
        final boolean isPrototype = isServiceObjects && ref.getProperty(Constants.SERVICE_SCOPE) == Constants.SCOPE_PROTOTYPE;
        UsageCount usage = null;
        Object svcObj = null;

        // Get the service registration.
        final ServiceRegistrationImpl reg =
            ((ServiceRegistrationImpl.ServiceReferenceImpl) ref).getRegistration();

        // We don't allow cycles when we call out to the service factory.
        if ( reg.currentThreadMarked() )
        {
            throw new ServiceException(
                    "ServiceFactory.getService() resulted in a cycle.",
                    ServiceException.FACTORY_ERROR,
                    null);
        }

        try
        {
            reg.markCurrentThread();

            // Make sure the service registration is still valid.
            if (reg.isValid())
            {
                // Get the usage count, or create a new one. If this is a
                // prototype, the we'll alway create a new one.
                usage = obtainUsageCount(bundle, ref, null, isPrototype);

                // Increment the usage count and grab the already retrieved
                // service object, if one exists.
                incrementToPositiveValue(usage.m_count);
                svcObj = usage.getService();

                if ( isServiceObjects )
                {
                    incrementToPositiveValue(usage.m_serviceObjectsCount);
                }

                // If we have a usage count, but no service object, then we haven't
                // cached the service object yet, so we need to create one.
                if (usage != null)
                {
                    ServiceHolder holder = null;

                    // There is a possibility that the holder is unset between the compareAndSet() and the get()
                    // below. If that happens get() returns null and we may have to set a new holder. This is
                    // why the below section is in a loop.
                    while (holder == null)
                    {
                        ServiceHolder h = new ServiceHolder();
                        if (usage.m_svcHolderRef.compareAndSet(null, h))
                        {
                            holder = h;
                            try {
                                svcObj = reg.getService(bundle);
                                holder.m_service = svcObj;
                            } finally {
                                holder.m_latch.countDown();
                            }
                        }
                        else
                        {
                            holder = usage.m_svcHolderRef.get();
                            if (holder != null)
                            {
                                boolean interrupted = false;
                                do
                                {
                                    try
                                    {
                                        // Need to ensure that the other thread has obtained
                                        // the service.
                                        holder.m_latch.await();
                                        if (interrupted)
                                        {
                                            Thread.currentThread().interrupt();
                                        }
                                        interrupted = false;
                                    }
                                    catch (InterruptedException e)
                                    {
                                        interrupted = true;
                                        Thread.interrupted();
                                    }
                                }
                                while (interrupted);
                                svcObj = holder.m_service;
                            }
                        }

                        // if someone concurrently changed the holder, loop again
                        if (holder != usage.m_svcHolderRef.get())
                            holder = null;
                    }
                    if (svcObj != null && isPrototype)
                    {
                        UsageCount existingUsage = obtainUsageCount(bundle, ref, svcObj, null);
                        if (existingUsage != null && existingUsage != usage)
                        {
                            flushUsageCount(bundle, ref, usage);
                            usage = existingUsage;
                            incrementToPositiveValue(usage.m_count);
                            if ( isServiceObjects )
                            {
                                incrementToPositiveValue(usage.m_serviceObjectsCount);
                            }
                        }
                    }
                }
            }
        }
        finally
        {
            reg.unmarkCurrentThread();

            if (!reg.isValid() || (svcObj == null))
            {
                flushUsageCount(bundle, ref, usage);
            }
        }

        return (S) svcObj;
    }

    // Increment the Atomic Long by 1, and ensure the result is at least 1.
    // This method uses a loop, optimistic algorithm to do this in a threadsafe
    // way without locks.
    private void incrementToPositiveValue(AtomicLong al)
    {
        boolean success = false;

        while (!success)
        {
            long oldVal = al.get();
            long newVal = Math.max(oldVal + 1L, 1L);
            checkCountOverflow(newVal);

            success = al.compareAndSet(oldVal, newVal);
        }
    }

    private void checkCountOverflow(long c)
    {
        if (c == Long.MAX_VALUE)
        {
            throw new ServiceException(
                    "The use count for the service overflowed.",
                    ServiceException.UNSPECIFIED,
                    null);
        }
    }

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

        if ( reg.currentThreadMarked() )
        {
            throw new IllegalStateException(
                    "ServiceFactory.ungetService() resulted in a cycle.");
        }

        try
        {
            // Mark the current thread to avoid cycles
            reg.markCurrentThread();

            // Get the usage count.
            UsageCount usage = obtainUsageCount(bundle, ref, svcObj, null);
            // If there are no cached services, then just return immediately.
            if (usage == null)
            {
                return false;
            }
            // if this is a call from service objects and the service was not fetched from
            // there, return false
            if ( svcObj != null )
            {
                if (usage.m_serviceObjectsCount.decrementAndGet() < 0)
                {
                    return false;
                }
            }

            // If usage count will go to zero, then unget the service
            // from the registration.
            long count = usage.m_count.decrementAndGet();
            try
            {
                if (count <= 0)
                {
                    ServiceHolder holder = usage.m_svcHolderRef.get();
                    Object svc = holder != null ? holder.m_service : null;

                    if (svc != null)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



