celix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pnol...@apache.org
Subject [20/38] celix git commit: CELIX-272: Refactor service registry from mutiple (nested) mutexes to single read/write lock
Date Tue, 17 Nov 2015 11:57:37 GMT
CELIX-272: Refactor service registry from mutiple (nested) mutexes to single read/write lock


Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/5e302091
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/5e302091
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/5e302091

Branch: refs/heads/develop
Commit: 5e3020914d634f49e9f826d231181e4e55bfdf7a
Parents: 53ff9da
Author: Pepijn Noltes <pepijnnoltes@gmail.com>
Authored: Mon Nov 16 12:21:32 2015 +0100
Committer: Pepijn Noltes <pepijnnoltes@gmail.com>
Committed: Mon Nov 16 12:21:32 2015 +0100

----------------------------------------------------------------------
 .../include/service_registration_private.h      |  16 +-
 .../private/include/service_registry_private.h  |  19 +-
 framework/private/src/service_reference.c       |  42 +--
 framework/private/src/service_registration.c    |  64 ++--
 framework/private/src/service_registry.c        | 375 +++++++++++--------
 5 files changed, 297 insertions(+), 219 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/celix/blob/5e302091/framework/private/include/service_registration_private.h
----------------------------------------------------------------------
diff --git a/framework/private/include/service_registration_private.h b/framework/private/include/service_registration_private.h
index 1b48887..2b1bf6c 100644
--- a/framework/private/include/service_registration_private.h
+++ b/framework/private/include/service_registration_private.h
@@ -30,13 +30,15 @@
 
 #include "service_registration.h"
 
-struct service {
-	char *name;
-	void *serviceStruct;
-};
+typedef struct registry_callback_struct {
+	void *handle;
+	celix_status_t (*unregister)(void *handle, bundle_pt bundle, service_registration_pt reg);
+	celix_status_t (*modified)(void *handle, service_registration_pt registration, properties_pt
oldProperties);
+} registry_callback_t;
 
 struct serviceRegistration {
-	service_registry_pt registry;
+    registry_callback_t callback;
+
 	char * className;
 	bundle_pt bundle;
 	properties_pt properties;
@@ -56,8 +58,8 @@ struct serviceRegistration {
 	celix_thread_rwlock_t lock;
 };
 
-service_registration_pt serviceRegistration_create(service_registry_pt registry, bundle_pt
bundle, char * serviceName, long serviceId, void * serviceObject, properties_pt dictionary);
-service_registration_pt serviceRegistration_createServiceFactory(service_registry_pt registry,
bundle_pt bundle, char * serviceName, long serviceId, void * serviceObject, properties_pt
dictionary);
+service_registration_pt serviceRegistration_create(registry_callback_t callback, bundle_pt
bundle, char * serviceName, long serviceId, void * serviceObject, properties_pt dictionary);
+service_registration_pt serviceRegistration_createServiceFactory(registry_callback_t callback,
bundle_pt bundle, char * serviceName, long serviceId, void * serviceObject, properties_pt
dictionary);
 
 void serviceRegistration_retain(service_registration_pt registration);
 void serviceRegistration_release(service_registration_pt registration);

http://git-wip-us.apache.org/repos/asf/celix/blob/5e302091/framework/private/include/service_registry_private.h
----------------------------------------------------------------------
diff --git a/framework/private/include/service_registry_private.h b/framework/private/include/service_registry_private.h
index c5a731c..f3edd17 100644
--- a/framework/private/include/service_registry_private.h
+++ b/framework/private/include/service_registry_private.h
@@ -32,20 +32,27 @@
 
 struct serviceRegistry {
 	framework_pt framework;
-	hash_map_pt serviceRegistrations;
+
+	hash_map_pt serviceRegistrations; //key = bundle (reg owner), value = registration
 	hash_map_pt serviceReferences; //key = bundle, value = map (key = registration, value =
reference)
+
+	bool checkDeletedReferences; //If enabled. check if provided service references are still
valid
+	hash_map_pt deletedServiceReferences; //key = ref pointer, value = bool
+
 	serviceChanged_function_pt serviceChanged;
 	long currentServiceId;
 
 	array_list_pt listenerHooks;
 
-	celix_thread_mutex_t mutex;
-	celix_thread_mutexattr_t mutexAttr;
-
-	celix_thread_mutex_t referencesMapMutex;
-
+	celix_thread_rwlock_t lock;
 };
 
+typedef enum reference_status_enum {
+	REF_ACTIVE,
+	REF_DELETED,
+	REF_UNKNOWN
+} reference_status_t;
+
 struct usageCount {
 	unsigned int count;
 	service_reference_pt reference;

http://git-wip-us.apache.org/repos/asf/celix/blob/5e302091/framework/private/src/service_reference.c
----------------------------------------------------------------------
diff --git a/framework/private/src/service_reference.c b/framework/private/src/service_reference.c
index 333339e..2f829c2 100644
--- a/framework/private/src/service_reference.c
+++ b/framework/private/src/service_reference.c
@@ -32,13 +32,8 @@
 
 #include "service_reference.h"
 
-#include "service_registry.h"
 #include "service_reference_private.h"
 #include "service_registration_private.h"
-#include "module.h"
-#include "wire.h"
-#include "bundle.h"
-#include "celix_log.h"
 
 static void serviceReference_destroy(service_reference_pt);
 static void serviceReference_logWarningUsageCountBelowZero(service_reference_pt ref);
@@ -58,6 +53,8 @@ celix_status_t serviceReference_create(bundle_pt referenceOwner, service_registr
 		celixThreadRwlock_create(&ref->lock, NULL);
 		ref->refCount = 1;
         ref->usageCount = 0;
+
+        serviceRegistration_retain(ref->registration);
 	}
 
 	if (status == CELIX_SUCCESS) {
@@ -77,28 +74,14 @@ celix_status_t serviceReference_retain(service_reference_pt ref) {
 }
 
 celix_status_t serviceReference_release(service_reference_pt ref, bool *out) {
-    celixThreadRwlock_writeLock(&ref->lock);
-    if (ref->refCount > 0) {
-        ref->refCount -= 1;
-    } else {
-        fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "serviceReference_release error serv reference
count already at 0\n");
-    }
-
-    if (out) {
-        *out = ref->refCount == 0;
-    }
-
-    celixThreadRwlock_unlock(&ref->lock);
-    return CELIX_SUCCESS;
-}
-
-/* TODO enable, for now use a leak version to prevent to much errors
-celix_status_t serviceReference_release(service_reference_pt ref, bool *out) {
     bool destroyed = false;
     celixThreadRwlock_writeLock(&ref->lock);
     assert(ref->refCount > 0);
     ref->refCount -= 1;
     if (ref->refCount == 0) {
+        if (ref->registration != NULL) {
+            serviceRegistration_release(ref->registration);
+        }
         serviceReference_destroy(ref);
         destroyed = true;
     } else {
@@ -109,9 +92,10 @@ celix_status_t serviceReference_release(service_reference_pt ref, bool
*out) {
         *out = destroyed;
     }
     return CELIX_SUCCESS;
-}*/
+}
 
 celix_status_t serviceReference_increaseUsage(service_reference_pt ref, size_t *out) {
+    fw_log(logger, OSGI_FRAMEWORK_LOG_DEBUG, "Destroying service reference %p\n", ref);
     size_t local = 0;
     celixThreadRwlock_writeLock(&ref->lock);
     ref->usageCount += 1;
@@ -142,7 +126,7 @@ celix_status_t serviceReference_decreaseUsage(service_reference_pt ref,
size_t *
     return status;
 }
 
-static void serviceReference_logWarningUsageCountBelowZero(service_reference_pt ref) {
+static void serviceReference_logWarningUsageCountBelowZero(service_reference_pt ref __attribute__((unused)))
{
     fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING, "Cannot decrease service usage count below
0\n");
 }
 
@@ -228,7 +212,7 @@ FRAMEWORK_EXPORT celix_status_t serviceReference_getPropertyKeys(service_referen
     hash_map_iterator_pt it;
     int i = 0;
     int vsize = hashMap_size(props);
-    *size = vsize;
+    *size = (unsigned int)vsize;
     *keys = malloc(vsize * sizeof(*keys));
     it = hashMapIterator_create(props);
     while (hashMapIterator_hasNext(it)) {
@@ -262,7 +246,7 @@ celix_status_t serviceReference_isValid(service_reference_pt ref, bool
*result)
     return CELIX_SUCCESS;
 }
 
-bool serviceReference_isAssignableTo(service_reference_pt reference, bundle_pt requester,
char * serviceName) {
+bool serviceReference_isAssignableTo(service_reference_pt reference __attribute__((unused)),
bundle_pt requester __attribute__((unused)), char * serviceName __attribute__((unused))) {
 	bool allow = true;
 
 	/*NOTE for now always true. It would be nice to be able to do somechecks if the services
are really assignable.
@@ -292,7 +276,7 @@ celix_status_t serviceReference_compareTo(service_reference_pt reference,
servic
 	long id, other_id;
 	char *id_str, *other_id_str;
 	serviceReference_getProperty(reference, (char *) OSGI_FRAMEWORK_SERVICE_ID, &id_str);
-	serviceReference_getProperty(reference, (char *) OSGI_FRAMEWORK_SERVICE_ID, &other_id_str);
+	serviceReference_getProperty(compareTo, (char *) OSGI_FRAMEWORK_SERVICE_ID, &other_id_str);
 
 	id = atol(id_str);
 	other_id = atol(other_id_str);
@@ -301,12 +285,12 @@ celix_status_t serviceReference_compareTo(service_reference_pt reference,
servic
 	long rank, other_rank;
 	char *rank_str, *other_rank_str;
 	serviceReference_getProperty(reference, (char *) OSGI_FRAMEWORK_SERVICE_RANKING, &rank_str);
-	serviceReference_getProperty(reference, (char *) OSGI_FRAMEWORK_SERVICE_RANKING, &other_rank_str);
+	serviceReference_getProperty(compareTo, (char *) OSGI_FRAMEWORK_SERVICE_RANKING, &other_rank_str);
 
 	rank = rank_str == NULL ? 0 : atol(rank_str);
 	other_rank = other_rank_str == NULL ? 0 : atol(other_rank_str);
 
-	utils_compareServiceIdsAndRanking(id, rank, other_id, other_rank);
+    *compare = utils_compareServiceIdsAndRanking(id, rank, other_id, other_rank);
 
 	return status;
 }

http://git-wip-us.apache.org/repos/asf/celix/blob/5e302091/framework/private/src/service_registration.c
----------------------------------------------------------------------
diff --git a/framework/private/src/service_registration.c b/framework/private/src/service_registration.c
index f9c2ec2..dc8ae9b 100644
--- a/framework/private/src/service_registration.c
+++ b/framework/private/src/service_registration.c
@@ -30,38 +30,34 @@
 
 #include "service_registration_private.h"
 #include "constants.h"
-#include "service_factory.h"
-#include "service_reference.h"
-#include "celix_log.h"
-#include "celix_threads.h"
 
 static celix_status_t serviceRegistration_initializeProperties(service_registration_pt registration,
properties_pt properties);
-static celix_status_t serviceRegistration_createInternal(service_registry_pt registry, bundle_pt
bundle, char * serviceName, long serviceId,
+static celix_status_t serviceRegistration_createInternal(registry_callback_t callback, bundle_pt
bundle, char * serviceName, long serviceId,
         void * serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt
*registration);
 static celix_status_t serviceRegistration_destroy(service_registration_pt registration);
 
-service_registration_pt serviceRegistration_create(service_registry_pt registry, bundle_pt
bundle, char * serviceName, long serviceId, void * serviceObject, properties_pt dictionary)
{
+service_registration_pt serviceRegistration_create(registry_callback_t callback, bundle_pt
bundle, char * serviceName, long serviceId, void * serviceObject, properties_pt dictionary)
{
     service_registration_pt registration = NULL;
-	serviceRegistration_createInternal(registry, bundle, serviceName, serviceId, serviceObject,
dictionary, false, &registration);
+	serviceRegistration_createInternal(callback, bundle, serviceName, serviceId, serviceObject,
dictionary, false, &registration);
 	return registration;
 }
 
-service_registration_pt serviceRegistration_createServiceFactory(service_registry_pt registry,
bundle_pt bundle, char * serviceName, long serviceId, void * serviceObject, properties_pt
dictionary) {
+service_registration_pt serviceRegistration_createServiceFactory(registry_callback_t callback,
bundle_pt bundle, char * serviceName, long serviceId, void * serviceObject, properties_pt
dictionary) {
     service_registration_pt registration = NULL;
-    serviceRegistration_createInternal(registry, bundle, serviceName, serviceId, serviceObject,
dictionary, true, &registration);
+    serviceRegistration_createInternal(callback, bundle, serviceName, serviceId, serviceObject,
dictionary, true, &registration);
     return registration;
 }
 
-static celix_status_t serviceRegistration_createInternal(service_registry_pt registry, bundle_pt
bundle, char * serviceName, long serviceId,
+static celix_status_t serviceRegistration_createInternal(registry_callback_t callback, bundle_pt
bundle, char * serviceName, long serviceId,
         void * serviceObject, properties_pt dictionary, bool isFactory, service_registration_pt
*out) {
     celix_status_t status = CELIX_SUCCESS;
 
 	service_registration_pt  reg = calloc(1, sizeof(*reg));
     if (reg) {
+        reg->callback = callback;
         reg->services = NULL;
         reg->nrOfServices = 0;
 		reg->isServiceFactory = isFactory;
-		reg->registry = registry;
 		reg->className = strdup(serviceName);
 		reg->bundle = bundle;
 		reg->refCount = 1;
@@ -107,9 +103,11 @@ void serviceRegistration_release(service_registration_pt registration)
{
 }
 
 static celix_status_t serviceRegistration_destroy(service_registration_pt registration) {
+	fw_log(logger, OSGI_FRAMEWORK_LOG_DEBUG, "Destroying service registration %p\n", registration);
     free(registration->className);
 	registration->className = NULL;
-	registration->registry = NULL;
+
+    registration->callback.unregister = NULL;
 
 	properties_destroy(registration->properties);
     celixThreadRwlock_destroy(&registration->lock);
@@ -142,18 +140,22 @@ static celix_status_t serviceRegistration_initializeProperties(service_registrat
     return CELIX_SUCCESS;
 }
 
-bool serviceRegistration_isValid(service_registration_pt registration) {
-    bool result;
-    celixThreadRwlock_readLock(&registration->lock);
-    result = registration == NULL ? false : registration->svcObj != NULL;
+void serviceRegistration_invalidate(service_registration_pt registration) {
+    celixThreadRwlock_writeLock(&registration->lock);
+    registration->svcObj = NULL;
     celixThreadRwlock_unlock(&registration->lock);
-    return result;
 }
 
-void serviceRegistration_invalidate(service_registration_pt registration) {
-    celixThreadRwlock_writeLock(&registration->lock);
-	registration->svcObj = NULL;
+bool serviceRegistration_isValid(service_registration_pt registration) {
+    bool isValid;
+    celixThreadRwlock_readLock(&registration->lock);
+    if (registration != NULL) {
+        isValid = registration->svcObj != NULL;
+    } else {
+        isValid = false;
+    }
     celixThreadRwlock_unlock(&registration->lock);
+    return isValid;
 }
 
 celix_status_t serviceRegistration_unregister(service_registration_pt registration) {
@@ -164,6 +166,9 @@ celix_status_t serviceRegistration_unregister(service_registration_pt
registrati
     notValidOrUnregistering = !serviceRegistration_isValid(registration) || registration->isUnregistering;
     celixThreadRwlock_unlock(&registration->lock);
 
+    registry_callback_t callback;
+    callback.unregister = NULL;
+    bundle_pt bundle = NULL;
 
     if (notValidOrUnregistering) {
 		printf("Service is already unregistered\n");
@@ -171,11 +176,13 @@ celix_status_t serviceRegistration_unregister(service_registration_pt
registrati
 	} else {
         celixThreadRwlock_writeLock(&registration->lock);
         registration->isUnregistering = true;
+        bundle = registration->bundle;
+        callback = registration->callback;
         celixThreadRwlock_unlock(&registration->lock);
     }
 
-	if (status == CELIX_SUCCESS) {
-		serviceRegistry_unregisterService(registration->registry, registration->bundle, registration);
+	if (status == CELIX_SUCCESS && callback.unregister != NULL) {
+        callback.unregister(callback.handle, bundle, registration);
 	}
 
 	framework_logIfError(logger, status, NULL, "Cannot unregister service registration");
@@ -224,14 +231,21 @@ celix_status_t serviceRegistration_getProperties(service_registration_pt
registr
 }
 
 celix_status_t serviceRegistration_setProperties(service_registration_pt registration, properties_pt
properties) {
+    celix_status_t status = CELIX_SUCCESS;
 
+    properties_pt oldProperties = NULL;
+    registry_callback_t callback;
+    callback.modified = NULL;
 
     celixThreadRwlock_writeLock(&registration->lock);
-    properties_pt oldProps = registration->properties;
-    serviceRegistration_initializeProperties(registration, properties);
+    oldProperties = registration->properties;
+    status = serviceRegistration_initializeProperties(registration, properties);
+    callback = registration->callback;
     celixThreadRwlock_unlock(&registration->lock);
 
-	serviceRegistry_servicePropertiesModified(registration->registry, registration, oldProps);
+    if (status == CELIX_SUCCESS && callback.modified != NULL) {
+        callback.modified(callback.handle, registration, oldProperties);
+    }
 
 	return CELIX_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/celix/blob/5e302091/framework/private/src/service_registry.c
----------------------------------------------------------------------
diff --git a/framework/private/src/service_registry.c b/framework/private/src/service_registry.c
index 6abd0cc..13fe01a 100644
--- a/framework/private/src/service_registry.c
+++ b/framework/private/src/service_registry.c
@@ -29,55 +29,55 @@
 
 #include "service_registry_private.h"
 #include "service_registration_private.h"
-#include "module.h"
-#include "bundle.h"
 #include "listener_hook_service.h"
 #include "constants.h"
 #include "service_reference_private.h"
 #include "framework_private.h"
-#include "celix_log.h"
 
 celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt
bundle, char * serviceName, void * serviceObject, properties_pt dictionary, bool isFactory,
service_registration_pt *registration);
 celix_status_t serviceRegistry_addHooks(service_registry_pt registry, char *serviceName,
void *serviceObject, service_registration_pt registration);
 celix_status_t serviceRegistry_removeHook(service_registry_pt registry, service_registration_pt
registration);
 static void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry,
size_t usageCount, size_t refCount);
 static void serviceRegistry_logWarningServiceRegistration(service_registry_pt registry, service_registration_pt
reg);
+static celix_status_t serviceRegistry_checkReference(service_registry_pt registry, service_reference_pt
ref,
+                                                     reference_status_t *refStatus);
+static void serviceRegistry_logIllegalReference(service_registry_pt registry, service_reference_pt
reference,
+                                                   reference_status_t refStatus);
 
+celix_status_t serviceRegistry_create(framework_pt framework, serviceChanged_function_pt
serviceChanged, service_registry_pt *out) {
+	celix_status_t status;
 
-celix_status_t serviceRegistry_create(framework_pt framework, serviceChanged_function_pt
serviceChanged, service_registry_pt *registry) {
-	celix_status_t status = CELIX_SUCCESS;
-
-	*registry = malloc(sizeof(**registry));
-	if (!*registry) {
+	service_registry_pt reg = calloc(1, sizeof(*reg));
+	if (reg == NULL) {
 		status = CELIX_ENOMEM;
 	} else {
+		reg->serviceChanged = serviceChanged;
+		reg->serviceRegistrations = hashMap_create(NULL, NULL, NULL, NULL);
+		reg->framework = framework;
+		reg->currentServiceId = 1l;
+		reg->serviceReferences = hashMap_create(NULL, NULL, NULL, NULL);
+        reg->deletedServiceReferences = hashMap_create(NULL, NULL, NULL, NULL);
 
-		(*registry)->serviceChanged = serviceChanged;
-		(*registry)->serviceRegistrations = hashMap_create(NULL, NULL, NULL, NULL);
-		(*registry)->framework = framework;
-		(*registry)->currentServiceId = 1l;
-		(*registry)->serviceReferences = hashMap_create(NULL, NULL, NULL, NULL);;
-
-		arrayList_create(&(*registry)->listenerHooks);
+		arrayList_create(&reg->listenerHooks);
 
-		status = celixThreadMutexAttr_create(&(*registry)->mutexAttr);
-		status = CELIX_DO_IF(status, celixThreadMutexAttr_settype(&(*registry)->mutexAttr,
CELIX_THREAD_MUTEX_RECURSIVE));
-		status = CELIX_DO_IF(status, celixThreadMutex_create(&(*registry)->mutex, &(*registry)->mutexAttr));
-		status = CELIX_DO_IF(status, celixThreadMutex_create(&(*registry)->referencesMapMutex,
NULL));
+		status = celixThreadRwlock_create(&reg->lock, NULL);
 	}
 
-	framework_logIfError(logger, status, NULL, "Cannot create service registry");
+	if (status == CELIX_SUCCESS) {
+		*out = reg;
+	} else {
+		framework_logIfError(logger, status, NULL, "Cannot create service registry");
+	}
 
 	return status;
 }
 
 celix_status_t serviceRegistry_destroy(service_registry_pt registry) {
+	celixThreadRwlock_writeLock(&registry->lock);
     hashMap_destroy(registry->serviceRegistrations, false, false);
     hashMap_destroy(registry->serviceReferences, false, false);
     arrayList_destroy(registry->listenerHooks);
-    celixThreadMutex_destroy(&registry->mutex);
-    celixThreadMutexAttr_destroy(&registry->mutexAttr);
-    celixThreadMutex_destroy(&registry->referencesMapMutex);
+
     registry->framework = NULL;
     registry->listenerHooks = NULL;
     registry->serviceChanged = NULL;
@@ -91,7 +91,8 @@ celix_status_t serviceRegistry_destroy(service_registry_pt registry) {
 celix_status_t serviceRegistry_getRegisteredServices(service_registry_pt registry, bundle_pt
bundle, array_list_pt *services) {
 	celix_status_t status = CELIX_SUCCESS;
 
-	celixThreadMutex_lock(&registry->mutex);
+	celixThreadRwlock_readLock(&registry->lock);
+
 	array_list_pt regs = (array_list_pt) hashMap_get(registry->serviceRegistrations, bundle);
 	if (regs != NULL) {
 		unsigned int i;
@@ -108,7 +109,8 @@ celix_status_t serviceRegistry_getRegisteredServices(service_registry_pt
registr
 			}
 		}
 	}
-	celixThreadMutex_unlock(&registry->mutex);
+
+	celixThreadRwlock_unlock(&registry->lock);
 
 	framework_logIfError(logger, status, NULL, "Cannot get registered services");
 
@@ -125,16 +127,21 @@ celix_status_t serviceRegistry_registerServiceFactory(service_registry_pt
regist
 
 celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt
bundle, char * serviceName, void * serviceObject, properties_pt dictionary, bool isFactory,
service_registration_pt *registration) {
 	array_list_pt regs;
-	celixThreadMutex_lock(&registry->mutex);
+
+    registry_callback_t callback;
+    callback.handle = registry;
+    callback.unregister = (void *) serviceRegistry_unregisterService;
+    callback.modified = (void *) serviceRegistry_servicePropertiesModified;
 
 	if (isFactory) {
-	    *registration = serviceRegistration_createServiceFactory(registry, bundle, serviceName,
++registry->currentServiceId, serviceObject, dictionary);
+	    *registration = serviceRegistration_createServiceFactory(callback, bundle, serviceName,
++registry->currentServiceId, serviceObject, dictionary);
 	} else {
-	    *registration = serviceRegistration_create(registry, bundle, serviceName, ++registry->currentServiceId,
serviceObject, dictionary);
+	    *registration = serviceRegistration_create(callback, bundle, serviceName, ++registry->currentServiceId,
serviceObject, dictionary);
 	}
 
 	serviceRegistry_addHooks(registry, serviceName, serviceObject, *registration);
 
+	celixThreadRwlock_writeLock(&registry->lock);
 	regs = (array_list_pt) hashMap_get(registry->serviceRegistrations, bundle);
 	if (regs == NULL) {
 		regs = NULL;
@@ -143,15 +150,10 @@ celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt
regis
 	arrayList_add(regs, *registration);
 	hashMap_put(registry->serviceRegistrations, bundle, regs);
 
-	celixThreadMutex_unlock(&registry->mutex);
+	celixThreadRwlock_unlock(&registry->lock);
 
 	if (registry->serviceChanged != NULL) {
-//		service_event_pt event = (service_event_pt) malloc(sizeof(*event));
-//		event->type = REGISTERED;
-//		event->reference = (*registration)->reference;
 		registry->serviceChanged(registry->framework, OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED,
*registration, NULL);
-//		free(event);
-//		event = NULL;
 	}
 
 	return CELIX_SUCCESS;
@@ -161,23 +163,22 @@ celix_status_t serviceRegistry_unregisterService(service_registry_pt
registry, b
 	// array_list_t clients;
 	array_list_pt regs;
 
-	celixThreadMutex_lock(&registry->mutex);
 
 	serviceRegistry_removeHook(registry, registration);
 
+	celixThreadRwlock_writeLock(&registry->lock);
 	regs = (array_list_pt) hashMap_get(registry->serviceRegistrations, bundle);
 	if (regs != NULL) {
 		arrayList_removeElement(regs, registration);
 	}
-
-	celixThreadMutex_unlock(&registry->mutex);
+	celixThreadRwlock_unlock(&registry->lock);
 
 	if (registry->serviceChanged != NULL) {
 		registry->serviceChanged(registry->framework, OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING,
registration, NULL);
 	}
 
-	celixThreadMutex_lock(&registry->mutex);
 
+	celixThreadRwlock_readLock(&registry->lock);
     //invalidate service references
     hash_map_iterator_pt iter = hashMapIterator_create(registry->serviceReferences);
     while (hashMapIterator_hasNext(iter)) {
@@ -188,12 +189,11 @@ celix_status_t serviceRegistry_unregisterService(service_registry_pt
registry, b
         }
     }
     hashMapIterator_destroy(iter);
+	celixThreadRwlock_unlock(&registry->lock);
 
-    serviceRegistration_invalidate(registration);
+	serviceRegistration_invalidate(registration);
     serviceRegistration_release(registration);
 
-	celixThreadMutex_unlock(&registry->mutex);
-
 	return CELIX_SUCCESS;
 }
 
@@ -201,9 +201,10 @@ celix_status_t serviceRegistry_clearServiceRegistrations(service_registry_pt
reg
     celix_status_t status = CELIX_SUCCESS;
     array_list_pt registrations = NULL;
 
-    celixThreadMutex_lock(&registry->mutex);
+	celixThreadRwlock_writeLock(&registry->lock);
+	registrations = hashMap_remove(registry->serviceRegistrations, bundle);
+	celixThreadRwlock_unlock(&registry->lock);
 
-    registrations = hashMap_get(registry->serviceRegistrations, bundle);
     while (registrations != NULL && arrayList_size(registrations) > 0) {
         service_registration_pt reg = arrayList_get(registrations, 0);
 
@@ -212,17 +213,12 @@ celix_status_t serviceRegistry_clearServiceRegistrations(service_registry_pt
reg
         if (serviceRegistration_isValid(reg)) {
             serviceRegistration_unregister(reg);
         }
-        serviceRegistration_release(reg);
     }
-    hashMap_remove(registry->serviceRegistrations, bundle);
-
-    celixThreadMutex_unlock(&registry->mutex);
-
 
     return status;
 }
 
-static void serviceRegistry_logWarningServiceRegistration(service_registry_pt registry, service_registration_pt
reg) {
+static void serviceRegistry_logWarningServiceRegistration(service_registry_pt registry __attribute__((unused)),
service_registration_pt reg) {
     char *servName = NULL;
     serviceRegistration_getServiceName(reg, &servName);
     fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING, "Dangling service registration for service
%s. Look for missing serviceRegistration_unregister.", servName);
@@ -236,59 +232,60 @@ celix_status_t serviceRegistry_getServiceReference(service_registry_pt
registry,
     service_reference_pt ref = NULL;
     hash_map_pt references = NULL;
 
-    // Lock
-	celixThreadMutex_lock(&registry->referencesMapMutex);
 
-	references = hashMap_get(registry->serviceReferences, owner);
-	if (references == NULL) {
+    //LOCK
+    celixThreadRwlock_writeLock(&registry->lock);
+
+    references = hashMap_get(registry->serviceReferences, owner);
+    if (references == NULL) {
         references = hashMap_create(NULL, NULL, NULL, NULL);
-        if (references != NULL) {
-            hashMap_put(registry->serviceReferences, owner, references);
-        } else {
-            status = CELIX_BUNDLE_EXCEPTION;
-            framework_logIfError(logger, status, NULL, "Cannot create hash map");
-        }
-    }
+        hashMap_put(registry->serviceReferences, owner, references);
+	}
 
+    ref = hashMap_get(references, registration);
 
-    if (status == CELIX_SUCCESS) {
-        ref = hashMap_get(references, registration);
-        if (ref == NULL) {
-            status = serviceRegistration_getBundle(registration, &bundle);
-            if (status == CELIX_SUCCESS) {
-                status = serviceReference_create(owner, registration, &ref);
-            }
-            if (status == CELIX_SUCCESS) {
-                hashMap_put(references, registration, ref);
-            }
-        } else {
-            serviceReference_retain(ref);
+    if (ref == NULL) {
+        status = serviceRegistration_getBundle(registration, &bundle);
+        if (status == CELIX_SUCCESS) {
+            status = serviceReference_create(owner, registration, &ref);
+        }
+        if (status == CELIX_SUCCESS) {
+            hashMap_put(references, registration, ref);
+            hashMap_put(registry->deletedServiceReferences, ref, (void *)false);
         }
+    } else {
+        serviceReference_retain(ref);
     }
 
+    //UNLOCK
+    celixThreadRwlock_unlock(&registry->lock);
+
+
     if (status == CELIX_SUCCESS) {
         *out = ref;
     }
 
-    // Unlock
-	celixThreadMutex_unlock(&registry->referencesMapMutex);
-
 	framework_logIfError(logger, status, NULL, "Cannot create service reference");
 
 
 	return status;
 }
 
-celix_status_t serviceRegistry_getServiceReferences(service_registry_pt registry, bundle_pt
owner, const char *serviceName, filter_pt filter, array_list_pt *references) {
-	celix_status_t status = CELIX_SUCCESS;
-	hash_map_values_pt registrations;
+celix_status_t serviceRegistry_getServiceReferences(service_registry_pt registry, bundle_pt
owner, const char *serviceName, filter_pt filter, array_list_pt *out) {
+	celix_status_t status;
 	hash_map_iterator_pt iterator;
-	arrayList_create(references);
-
-	celixThreadMutex_lock(&registry->mutex);
-	registrations = hashMapValues_create(registry->serviceRegistrations);
-	iterator = hashMapValues_iterator(registrations);
-	while (hashMapIterator_hasNext(iterator)) {
+    array_list_pt references = NULL;
+	array_list_pt matchingRegistrations = NULL;
+    bool matchResult;
+    unsigned int i;
+    int size;
+
+    status = arrayList_create(&references);
+    status = CELIX_DO_IF(status, arrayList_create(&matchingRegistrations));
+
+    celixThreadRwlock_readLock(&registry->lock);
+	iterator = hashMapIterator_create(registry->serviceRegistrations);
+	while (status == CELIX_SUCCESS && hashMapIterator_hasNext(iterator)) {
 		array_list_pt regs = (array_list_pt) hashMapIterator_nextValue(iterator);
 		unsigned int regIdx;
 		for (regIdx = 0; (regs != NULL) && regIdx < arrayList_size(regs); regIdx++)
{
@@ -298,7 +295,7 @@ celix_status_t serviceRegistry_getServiceReferences(service_registry_pt
registry
 			status = serviceRegistration_getProperties(registration, &props);
 			if (status == CELIX_SUCCESS) {
 				bool matched = false;
-				bool matchResult = false;
+				matchResult = false;
 				if (filter != NULL) {
 					filter_match(filter, props, &matchResult);
 				}
@@ -306,7 +303,7 @@ celix_status_t serviceRegistry_getServiceReferences(service_registry_pt
registry
 					matched = true;
 				} else if (serviceName != NULL) {
 					char *className = NULL;
-					bool matchResult = false;
+					matchResult = false;
 					serviceRegistration_getServiceName(registration, &className);
 					if (filter != NULL) {
 						filter_match(filter, props, &matchResult);
@@ -317,45 +314,97 @@ celix_status_t serviceRegistry_getServiceReferences(service_registry_pt
registry
 				}
 				if (matched) {
 					if (serviceRegistration_isValid(registration)) {
-						service_reference_pt reference = NULL;
-                        serviceRegistry_getServiceReference(registry, owner, registration,
&reference);
-						arrayList_add(*references, reference);
+                        arrayList_add(matchingRegistrations, registration);
 					}
 				}
 			}
 		}
 	}
+    celixThreadRwlock_unlock(&registry->lock);
 	hashMapIterator_destroy(iterator);
-	hashMapValues_destroy(registrations);
-	celixThreadMutex_unlock(&registry->mutex);
 
-	framework_logIfError(logger, status, NULL, "Cannot get service references");
+    if (status == CELIX_SUCCESS) {
+        size = arrayList_size(matchingRegistrations);
+        for (i = 0; i < size; i += 1) {
+            service_registration_pt reg = arrayList_get(matchingRegistrations, i);
+            service_reference_pt reference = NULL;
+            status = serviceRegistry_getServiceReference(registry, owner, reg, &reference);
+            if (status == CELIX_SUCCESS) {
+                arrayList_add(references, reference);
+            } else {
+                break;
+            }
+        }
+        arrayList_destroy(matchingRegistrations);
+    }
+
+    if (status == CELIX_SUCCESS) {
+        *out = references;
+    } else {
+        //TODO ungetServiceRefs
+        arrayList_destroy(references);
+        framework_logIfError(logger, status, NULL, "Cannot get service references");
+    }
 
 	return status;
 }
 
+
 celix_status_t serviceRegistry_ungetServiceReference(service_registry_pt registry, bundle_pt
bundle, service_reference_pt reference) {
     celix_status_t status = CELIX_SUCCESS;
     bool destroyed = false;
     size_t count = 0;
     service_registration_pt reg = NULL;
+    reference_status_t refStatus;
 
-    celixThreadMutex_lock(&registry->mutex);
-    serviceReference_getUsageCount(reference, &count);
-    serviceReference_getServiceRegistration(reference, &reg);
-    serviceReference_release(reference, &destroyed);
-    if (destroyed) {
-        if (count > 0) {
-            serviceRegistry_logWarningServiceReferenceUsageCount(registry, 0, count);
+    serviceRegistry_checkReference(registry, reference, &refStatus);
+    if (refStatus == REF_ACTIVE) {
+        serviceReference_getUsageCount(reference, &count);
+        serviceReference_getServiceRegistration(reference, &reg);
+        serviceReference_release(reference, &destroyed);
+        if (destroyed) {
+            if (count > 0) {
+                serviceRegistry_logWarningServiceReferenceUsageCount(registry, 0, count);
+            }
+
+
+            celixThreadRwlock_writeLock(&registry->lock);
+            hash_map_pt refsMap = hashMap_get(registry->serviceReferences, bundle);
+            hashMap_remove(refsMap, reg);
+            hashMap_put(registry->deletedServiceReferences, reference, (void *)true);
+            celixThreadRwlock_unlock(&registry->lock);
         }
-        hash_map_pt refsMap = hashMap_get(registry->serviceReferences, bundle);
-        hashMap_remove(refsMap, reg);
+    } else {
+        serviceRegistry_logIllegalReference(registry, reference, refStatus);
     }
-    celixThreadMutex_unlock(&registry->mutex);
+
     return status;
 }
 
-void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry, size_t
usageCount, size_t refCount) {
+static void serviceRegistry_logIllegalReference(service_registry_pt registry __attribute__((unused)),
service_reference_pt reference,
+                                                   reference_status_t refStatus) {
+
+    fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "Error handling service reference %p has ref
status %i", reference, refStatus);
+}
+
+celix_status_t serviceRegistry_checkReference(service_registry_pt registry, service_reference_pt
ref,
+                                              reference_status_t *out) {
+    celix_status_t status = CELIX_SUCCESS;
+    reference_status_t refStatus = REF_UNKNOWN;
+
+    celixThreadRwlock_readLock(&registry->lock);
+    if (hashMap_containsKey(registry->deletedServiceReferences, ref)) {
+        bool deleted = (bool) hashMap_get(registry->deletedServiceReferences, ref);
+        refStatus = deleted ? REF_DELETED : REF_ACTIVE;
+    }
+    celixThreadRwlock_unlock(&registry->lock);
+
+    *out = refStatus;
+
+    return status;
+}
+
+void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry __attribute__((unused)),
size_t usageCount, size_t refCount) {
     if (usageCount > 0) {
         fw_log(logger, OSGI_FRAMEWORK_LOG_WARNING, "Service Reference destroyed will usage
count is %zu. Look for missing bundleContext_ungetService calls.", usageCount);
     }
@@ -368,10 +417,9 @@ void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt
re
 celix_status_t serviceRegistry_clearReferencesFor(service_registry_pt registry, bundle_pt
bundle) {
     celix_status_t status = CELIX_SUCCESS;
 
-    celixThreadMutex_lock(&registry->mutex);
-    hash_map_pt refsMap = hashMap_remove(registry->serviceReferences, bundle);
-    celixThreadMutex_unlock(&registry->mutex);
+    celixThreadRwlock_writeLock(&registry->lock);
 
+    hash_map_pt refsMap = hashMap_remove(registry->serviceReferences, bundle);
     if (refsMap != NULL) {
         hash_map_iterator_pt iter = hashMapIterator_create(refsMap);
         while (hashMapIterator_hasNext(iter)) {
@@ -392,11 +440,14 @@ celix_status_t serviceRegistry_clearReferencesFor(service_registry_pt
registry,
             while (!destroyed) {
                 serviceReference_release(ref, &destroyed);
             }
+            hashMap_put(registry->deletedServiceReferences, ref, (void *)true);
 
         }
         hashMapIterator_destroy(iter);
     }
 
+    celixThreadRwlock_unlock(&registry->lock);
+
     return status;
 }
 
@@ -407,7 +458,7 @@ celix_status_t serviceRegistry_getServicesInUse(service_registry_pt registry,
bu
     arrayList_create(&result);
 
     //LOCK
-    celixThreadMutex_lock(&registry->mutex);
+    celixThreadRwlock_readLock(&registry->lock);
 
     hash_map_pt refsMap = hashMap_get(registry->serviceReferences, bundle);
 
@@ -419,7 +470,7 @@ celix_status_t serviceRegistry_getServicesInUse(service_registry_pt registry,
bu
     hashMapIterator_destroy(iter);
 
     //UNLOCK
-	celixThreadMutex_unlock(&registry->mutex);
+    celixThreadRwlock_unlock(&registry->lock);
 
     *out = result;
 
@@ -431,26 +482,31 @@ celix_status_t serviceRegistry_getService(service_registry_pt registry,
bundle_p
 	service_registration_pt registration = NULL;
     size_t count = 0;
     void *service = NULL;
+    reference_status_t refStatus;
 
-	serviceReference_getServiceRegistration(reference, &registration);
-	celixThreadMutex_lock(&registry->mutex);
+    serviceRegistry_checkReference(registry, reference, &refStatus);
 
+    if (refStatus == REF_ACTIVE) {
+        celixThreadRwlock_readLock(&registry->lock);
+        serviceReference_getServiceRegistration(reference, &registration);
 
-	if (serviceRegistration_isValid(registration)) {
-        serviceReference_increaseUsage(reference, &count);
-        if (count == 1) {
-            serviceRegistration_getService(registration, bundle, &service);
-            serviceReference_setService(reference, service);
-        }
+        if (serviceRegistration_isValid(registration)) {
+            serviceReference_increaseUsage(reference, &count);
+            if (count == 1) {
+                serviceRegistration_getService(registration, bundle, &service);
+                serviceReference_setService(reference, service);
+            }
 
-        serviceReference_getService(reference, out);
-	} else {
-        *out = NULL; //invalid service registration
+            serviceReference_getService(reference, out);
+        } else {
+            *out = NULL; //invalid service registration
+        }
+        celixThreadRwlock_unlock(&registry->lock);
+    } else {
+        serviceRegistry_logIllegalReference(registry, reference, refStatus);
+        status = CELIX_BUNDLE_EXCEPTION;
     }
 
-	celixThreadMutex_unlock(&registry->mutex);
-
-
 	return status;
 }
 
@@ -459,29 +515,38 @@ celix_status_t serviceRegistry_ungetService(service_registry_pt registry,
bundle
     service_registration_pt reg = NULL;
     void *service = NULL;
     size_t count = 0;
+    celix_status_t subStatus = CELIX_SUCCESS;
+    reference_status_t refStatus;
 
-    celix_status_t subStatus = serviceReference_decreaseUsage(reference, &count);
+    serviceRegistry_checkReference(registry, reference, &refStatus);
 
-    if (count == 0) {
-        serviceReference_getService(reference, &service);
-        serviceReference_getServiceRegistration(reference, &reg);
-        serviceRegistration_ungetService(reg, bundle, &service);
+    if (refStatus == REF_ACTIVE) {
+        subStatus = serviceReference_decreaseUsage(reference, &count);
+        if (count == 0) {
+            serviceReference_getService(reference, &service);
+            serviceReference_getServiceRegistration(reference, &reg);
+            serviceRegistration_ungetService(reg, bundle, &service);
+        }
+    } else {
+        serviceRegistry_logIllegalReference(registry, reference, refStatus);
+        status = CELIX_BUNDLE_EXCEPTION;
     }
 
     if (result) {
         *result = (subStatus == CELIX_SUCCESS);
     }
 
+
 	return status;
 }
 
-celix_status_t serviceRegistry_addHooks(service_registry_pt registry, char *serviceName,
void *serviceObject, service_registration_pt registration) {
+celix_status_t serviceRegistry_addHooks(service_registry_pt registry, char *serviceName,
void *serviceObject __attribute__((unused)), service_registration_pt registration) {
 	celix_status_t status = CELIX_SUCCESS;
 
 	if (strcmp(OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, serviceName) == 0) {
-	    celixThreadMutex_lock(&registry->mutex);
+        celixThreadRwlock_writeLock(&registry->lock);
 		arrayList_add(registry->listenerHooks, registration);
-		celixThreadMutex_unlock(&registry->mutex);
+        celixThreadRwlock_unlock(&registry->lock);
 	}
 
 	return status;
@@ -495,35 +560,42 @@ celix_status_t serviceRegistry_removeHook(service_registry_pt registry,
service_
 	serviceRegistration_getProperties(registration, &props);
 	serviceName = properties_get(props, (char *) OSGI_FRAMEWORK_OBJECTCLASS);
 	if (strcmp(OSGI_FRAMEWORK_LISTENER_HOOK_SERVICE_NAME, serviceName) == 0) {
-	    celixThreadMutex_lock(&registry->mutex);
+        celixThreadRwlock_writeLock(&registry->lock);
 		arrayList_removeElement(registry->listenerHooks, registration);
-		celixThreadMutex_unlock(&registry->mutex);
+        celixThreadRwlock_unlock(&registry->lock);
 	}
 
 	return status;
 }
 
-celix_status_t serviceRegistry_getListenerHooks(service_registry_pt registry, bundle_pt owner,
array_list_pt *hooks) {
-	celix_status_t status = CELIX_SUCCESS;
+celix_status_t serviceRegistry_getListenerHooks(service_registry_pt registry, bundle_pt owner,
array_list_pt *out) {
+	celix_status_t status;
+    array_list_pt result;
+    unsigned int i;
 
-	if (registry == NULL || *hooks != NULL) {
-		status = CELIX_ILLEGAL_ARGUMENT;
-	} else {
-		status = arrayList_create(hooks);
-		if (status == CELIX_SUCCESS) {
-			unsigned int i;
-			celixThreadMutex_lock(&registry->mutex);
-			for (i = 0; i < arrayList_size(registry->listenerHooks); i++) {
-				service_registration_pt registration = arrayList_get(registry->listenerHooks, i);
-				service_reference_pt reference = NULL;
-                serviceRegistry_getServiceReference(registry, owner, registration, &reference);
-				arrayList_add(*hooks, reference);
-			}
-			celixThreadMutex_unlock(&registry->mutex);
-		}
-	}
+    status = arrayList_create(&result);
+    if (status == CELIX_SUCCESS) {
+        for (i = 0; i < arrayList_size(registry->listenerHooks); i += 1) {
+            celixThreadRwlock_readLock(&registry->lock);
+            service_registration_pt registration = arrayList_get(registry->listenerHooks,
i);
+            serviceRegistration_retain(registration);
+            celixThreadRwlock_unlock(&registry->lock);
+
+            service_reference_pt reference = NULL;
+            serviceRegistry_getServiceReference(registry, owner, registration, &reference);
+            arrayList_add(result, reference);
+            serviceRegistration_release(registration);
+        }
+    }
 
-	framework_logIfError(logger, status, NULL, "Cannot get listener hooks");
+    if (status == CELIX_SUCCESS) {
+        *out = result;
+    } else {
+        if (result != NULL) {
+            arrayList_destroy(result);
+        }
+        framework_logIfError(logger, status, NULL, "Cannot get listener hooks");
+    }
 
 	return status;
 }
@@ -532,6 +604,5 @@ celix_status_t serviceRegistry_servicePropertiesModified(service_registry_pt
reg
 	if (registry->serviceChanged != NULL) {
 		registry->serviceChanged(registry->framework, OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED,
registration, oldprops);
 	}
-
 	return CELIX_SUCCESS;
 }


Mime
View raw message