You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2020/07/16 18:58:53 UTC
[celix] branch feature/async_svc_registration updated: Refactors
service tracker to better handle MT issues.
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/async_svc_registration
in repository https://gitbox.apache.org/repos/asf/celix.git
The following commit(s) were added to refs/heads/feature/async_svc_registration by this push:
new 714b201 Refactors service tracker to better handle MT issues.
714b201 is described below
commit 714b201ed324b00553830766730deef908a56aa1
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Thu Jul 16 20:58:26 2020 +0200
Refactors service tracker to better handle MT issues.
---
libs/framework/CMakeLists.txt | 4 -
.../gtest/src/bundle_context_services_test.cpp | 17 +-
libs/framework/gtest/src/single_framework_test.cpp | 57 +-
libs/framework/include/service_tracker.h | 10 -
libs/framework/src/framework.c | 243 +++----
libs/framework/src/resolver.c | 3 +
libs/framework/src/service_registry.c | 235 ++-----
libs/framework/src/service_registry_private.h | 9 -
libs/framework/src/service_tracker.c | 761 ++++++++-------------
libs/framework/src/service_tracker_private.h | 59 +-
10 files changed, 521 insertions(+), 877 deletions(-)
diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt
index 950de4e..5d4ea4a 100644
--- a/libs/framework/CMakeLists.txt
+++ b/libs/framework/CMakeLists.txt
@@ -45,10 +45,6 @@ set_target_properties(framework PROPERTIES "SOVERSION" 2)
target_link_libraries(framework PUBLIC Celix::utils Celix::dfi ${CELIX_OPTIONAL_EXTRA_LIBS})
target_link_libraries(framework PUBLIC UUID::lib CURL::libcurl ZLIB::ZLIB)
-#Note option to ensure celix uses separate shutdown thread for closing service trackers.
-#This can prevent deadlocks, but those deadlock are bugs which need to be solved instead of this approach.
-#target_compile_definitions(framework PRIVATE -DCELIX_SERVICE_TRACKER_USE_SHUTDOWN_THREAD)
-
install(TARGETS framework EXPORT celix DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT framework)
install(DIRECTORY include/ DESTINATION include/celix COMPONENT framework)
diff --git a/libs/framework/gtest/src/bundle_context_services_test.cpp b/libs/framework/gtest/src/bundle_context_services_test.cpp
index 2d2b833..9d29b5b 100644
--- a/libs/framework/gtest/src/bundle_context_services_test.cpp
+++ b/libs/framework/gtest/src/bundle_context_services_test.cpp
@@ -740,7 +740,6 @@ TEST_F(CelixBundleContextServicesTests, servicesTrackerSetTest) {
void *svc4 = (void*)0x400; //5 ranking
auto set = [](void *handle, void *svc) {
- ASSERT_TRUE(svc != nullptr);
static int callCount = 0;
callCount += 1;
if (callCount == 1) {
@@ -766,28 +765,28 @@ TEST_F(CelixBundleContextServicesTests, servicesTrackerSetTest) {
opts.callbackHandle = (void*)&count;
opts.filter.serviceName = "NA";
opts.set = set;
- long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+ long trackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts); //call 1
ASSERT_TRUE(trackerId >= 0);
//register svc3 should lead to second set call
properties_t *props3 = celix_properties_create();
celix_properties_set(props3, OSGI_FRAMEWORK_SERVICE_RANKING, "10");
- long svcId3 = celix_bundleContext_registerService(ctx, svc3, "NA", props3);
+ long svcId3 = celix_bundleContext_registerService(ctx, svc3, "NA", props3); //call 2
//register svc4 should lead to no set (lower ranking)
properties_t *props4 = celix_properties_create();
celix_properties_set(props4, OSGI_FRAMEWORK_SERVICE_RANKING, "10");
- long svcId4 = celix_bundleContext_registerService(ctx, svc4, "NA", props4);
+ long svcId4 = celix_bundleContext_registerService(ctx, svc4, "NA", props4); //no update
//unregister svc3 should lead to set (new highest ranking)
- celix_bundleContext_unregisterService(ctx, svcId3);
+ celix_bundleContext_unregisterService(ctx, svcId3); //call 3
- celix_bundleContext_stopTracker(ctx, trackerId);
+ celix_bundleContext_stopTracker(ctx, trackerId); //call 4 (NULL)
celix_bundleContext_unregisterService(ctx, svcId1);
celix_bundleContext_unregisterService(ctx, svcId2);
celix_bundleContext_unregisterService(ctx, svcId4);
- ASSERT_EQ(3, count); //check if the set is called the expected times
+ ASSERT_EQ(4, count); //check if the set is called the expected times
}
TEST_F(CelixBundleContextServicesTests, trackAllServices) {
@@ -991,10 +990,8 @@ TEST_F(CelixBundleContextServicesTests, trackServiceTrackerTest) {
ASSERT_EQ(2, count);
celix_bundleContext_stopTracker(ctx, tracker2);
- celix_serviceTracker_syncForContext(ctx); //service tracker shutdown on separate track -> need sync
ASSERT_EQ(1, count);
celix_bundleContext_stopTracker(ctx, tracker3);
- celix_serviceTracker_syncForContext(ctx); //service tracker shutdown on separate track -> need sync
ASSERT_EQ(0, count);
celix_bundleContext_stopTracker(ctx, trackerId);
@@ -1029,6 +1026,7 @@ TEST_F(CelixBundleContextServicesTests, floodEventLoopTest) {
long id = celix_bundleContext_registerServiceAsync(ctx, (void*)0x42, "test", nullptr); //note cannot be completed because the first service registration in blocking in the event loop.
EXPECT_GE(id, 0);
svcIds.push_back(id);
+ celix_bundleContext_findService(ctx, "test"); //just to add some entropy
}
{
@@ -1045,5 +1043,6 @@ TEST_F(CelixBundleContextServicesTests, floodEventLoopTest) {
celix_bundleContext_unregisterServiceAsync(ctx, svcId);
for (auto id : svcIds) {
celix_bundleContext_unregisterServiceAsync(ctx, id);
+ celix_bundleContext_findService(ctx, "test"); //just to add some entropy
}
}
\ No newline at end of file
diff --git a/libs/framework/gtest/src/single_framework_test.cpp b/libs/framework/gtest/src/single_framework_test.cpp
index 2fa7f39..03d164e 100644
--- a/libs/framework/gtest/src/single_framework_test.cpp
+++ b/libs/framework/gtest/src/single_framework_test.cpp
@@ -149,33 +149,32 @@ TEST_F(FrameworkFactory, recreateFramework) {
framework_destroy(fw);
}
-//TODO fix this. Restarting seems to increase the framework bundle usage count
-//TEST_F(FrameworkFactory, restartFramework) {
-// framework_t* fw = celix_frameworkFactory_createFramework(nullptr);
-// ASSERT_TRUE(fw != nullptr);
-// framework_stop(fw);
-// framework_waitForStop(fw);
-//
-// framework_start(fw);
-// framework_stop(fw);
-// framework_waitForStop(fw);
-//
-// framework_start(fw);
-// framework_stop(fw);
-// framework_waitForStop(fw);
-//
-// framework_start(fw);
-// framework_stop(fw);
-// framework_waitForStop(fw);
-//
-// framework_start(fw);
-// framework_stop(fw);
-// framework_waitForStop(fw);
-//
-// framework_start(fw);
-// framework_stop(fw);
-// framework_waitForStop(fw);
-//
-// framework_destroy(fw);
-//}
+TEST_F(FrameworkFactory, restartFramework) {
+ framework_t* fw = celix_frameworkFactory_createFramework(nullptr);
+ ASSERT_TRUE(fw != nullptr);
+ framework_stop(fw);
+ framework_waitForStop(fw);
+
+ framework_start(fw);
+ framework_stop(fw);
+ framework_waitForStop(fw);
+
+ framework_start(fw);
+ framework_stop(fw);
+ framework_waitForStop(fw);
+
+ framework_start(fw);
+ framework_stop(fw);
+ framework_waitForStop(fw);
+
+ framework_start(fw);
+ framework_stop(fw);
+ framework_waitForStop(fw);
+
+ framework_start(fw);
+ framework_stop(fw);
+ framework_waitForStop(fw);
+
+ framework_destroy(fw);
+}
diff --git a/libs/framework/include/service_tracker.h b/libs/framework/include/service_tracker.h
index 4e69621..9fd7727 100644
--- a/libs/framework/include/service_tracker.h
+++ b/libs/framework/include/service_tracker.h
@@ -134,16 +134,6 @@ size_t celix_serviceTracker_useServices(
void (*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner)
);
-/**
- * blocks until all shutdown threads for the service tracker instances for the provided framework are done.
- */
-void celix_serviceTracker_syncForFramework(void *fw);
-
-/**
- * blocks until all shutdown threads for the service tracker instances for the provided bundle context are done.
- */
-void celix_serviceTracker_syncForContext(void *ctx);
-
#ifdef __cplusplus
}
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 95ea491..70700e9 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -69,10 +69,16 @@ static inline celix_framework_bundle_entry_t* fw_bundleEntry_create(celix_bundle
static inline void fw_bundleEntry_waitTillUseCountIs(celix_framework_bundle_entry_t *entry, size_t desiredUseCount) {
celixThreadMutex_lock(&entry->useMutex);
+ time_t start = time(NULL);
+ bool warningPrinted = false;
while (entry->useCount != desiredUseCount) {
celixThreadCondition_timedwaitRelative(&entry->useCond, &entry->useMutex, 5, 0);
if (entry->useCount != desiredUseCount) {
- fw_log(celix_frameworkLogger_globalLogger(), CELIX_LOG_LEVEL_WARNING, "Bundle %s (%li) still in use. Use count is %u, desired is ", celix_bundle_getSymbolicName(entry->bnd), entry->bndId, entry->useCount, desiredUseCount);
+ time_t now = time(NULL);
+ if (!warningPrinted && (now-start) > 5) {
+ fw_log(celix_frameworkLogger_globalLogger(), CELIX_LOG_LEVEL_WARNING, "Bundle %s (%li) still in use. Use count is %u, desired is %li", celix_bundle_getSymbolicName(entry->bnd), entry->bndId, entry->useCount, desiredUseCount);
+ warningPrinted = true;
+ }
}
}
celixThreadMutex_unlock(&entry->useMutex);
@@ -137,7 +143,6 @@ static inline celix_framework_bundle_entry_t* fw_bundleEntry_removeBundleEntryAn
return found;
}
-celix_status_t framework_setBundleStateAndNotify(framework_pt framework, bundle_pt bundle, int state);
celix_status_t framework_markBundleResolved(framework_pt framework, module_pt module);
long framework_getNextBundleId(framework_pt framework);
@@ -230,61 +235,66 @@ struct fw_frameworkListener {
typedef struct fw_frameworkListener * fw_framework_listener_pt;
-celix_status_t framework_create(framework_pt *framework, properties_pt config) {
- celix_status_t status = CELIX_SUCCESS;
+celix_status_t framework_create(framework_pt *out, properties_pt config) {
+ celix_framework_t* framework = calloc(1, sizeof(*framework));
+// celix_thread_mutexattr_t attr;
+// celixThreadMutexAttr_create(&attr);
+// celixThreadMutexAttr_settype(&attr, CELIX_THREAD_MUTEX_RECURSIVE);
- *framework = (framework_pt) malloc(sizeof(**framework));
- if (*framework != NULL) {
- celix_thread_mutexattr_t attr;
- celixThreadMutexAttr_create(&attr);
- celixThreadMutexAttr_settype(&attr, CELIX_THREAD_MUTEX_RECURSIVE);
-
- status = CELIX_DO_IF(status, celixThreadCondition_init(&(*framework)->shutdown.cond, NULL));
- status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->shutdown.mutex, NULL));
- status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->dispatcher.mutex, NULL));
- status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->frameworkListenersLock, &attr));
- status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->bundleListenerLock, NULL));
- status = CELIX_DO_IF(status, celixThreadMutex_create(&(*framework)->installedBundles.mutex, NULL));
- status = CELIX_DO_IF(status, celixThreadCondition_init(&(*framework)->dispatcher.cond, NULL));
- if (status == CELIX_SUCCESS) {
- (*framework)->bundle = NULL;
- (*framework)->registry = NULL;
- (*framework)->shutdown.done = false;
- (*framework)->shutdown.initialized = false;
- (*framework)->dispatcher.active = true;
- (*framework)->nextBundleId = 1L; //system bundle is 0
- (*framework)->cache = NULL;
- (*framework)->installRequestMap = hashMap_create(utils_stringHash, utils_stringHash, utils_stringEquals, utils_stringEquals);
- (*framework)->installedBundles.entries = celix_arrayList_create();
- (*framework)->bundleListeners = NULL;
- (*framework)->frameworkListeners = NULL;
- (*framework)->dispatcher.dynamicEventQueue = NULL;
- (*framework)->configurationMap = config;
-
- const char* logStr = getenv(CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_CONFIG_NAME);
- if (logStr == NULL) {
- logStr = celix_properties_get(config, CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_CONFIG_NAME, CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_DEFAULT_VALUE);
- }
- (*framework)->logger = celix_frameworkLogger_create(celix_logUtils_logLevelFromString(logStr, CELIX_LOG_LEVEL_INFO));
+ celixThreadCondition_init(&framework->shutdown.cond, NULL);
+ celixThreadMutex_create(&framework->shutdown.mutex, NULL);
+ celixThreadMutex_create(&framework->dispatcher.mutex, NULL);
+ celixThreadMutex_create(&framework->frameworkListenersLock, NULL);
+ celixThreadMutex_create(&framework->bundleListenerLock, NULL);
+ celixThreadMutex_create(&framework->installedBundles.mutex, NULL);
+ celixThreadCondition_init(&framework->dispatcher.cond, NULL);
+ framework->dispatcher.active = true;
+ framework->nextBundleId = 1L; //system bundle is 0
+ framework->installRequestMap = hashMap_create(utils_stringHash, utils_stringHash, utils_stringEquals, utils_stringEquals);
+ framework->installedBundles.entries = celix_arrayList_create();
+ framework->configurationMap = config;
+ framework->bundleListeners = celix_arrayList_create();
+ framework->frameworkListeners = celix_arrayList_create();
+ framework->dispatcher.dynamicEventQueue = celix_arrayList_create();
+
+ //create and store framework uuid
+ char uuid[37];
+ uuid_t uid;
+ uuid_generate(uid);
+ uuid_unparse(uid, uuid);
+ properties_set(framework->configurationMap, (char*) OSGI_FRAMEWORK_FRAMEWORK_UUID, uuid);
- status = CELIX_DO_IF(status, bundle_create(&(*framework)->bundle));
- status = CELIX_DO_IF(status, bundle_getBundleId((*framework)->bundle, &(*framework)->bundleId));
- status = CELIX_DO_IF(status, bundle_setFramework((*framework)->bundle, (*framework)));
- if (status == CELIX_SUCCESS) {
- //nop
- } else {
- status = CELIX_FRAMEWORK_EXCEPTION;
- fw_logCode((*framework)->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not create framework");
- }
- } else {
- status = CELIX_FRAMEWORK_EXCEPTION;
- fw_logCode((*framework)->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not create framework");
- }
- } else {
- status = CELIX_FRAMEWORK_EXCEPTION;
- fw_logCode((*framework)->logger, CELIX_LOG_LEVEL_ERROR, CELIX_ENOMEM, "Could not create framework");
+ //setup framework logger
+ const char* logStr = getenv(CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_CONFIG_NAME);
+ if (logStr == NULL) {
+ logStr = celix_properties_get(config, CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_CONFIG_NAME, CELIX_LOGGING_DEFAULT_ACTIVE_LOG_LEVEL_DEFAULT_VALUE);
}
+ framework->logger = celix_frameworkLogger_create(celix_logUtils_logLevelFromString(logStr, CELIX_LOG_LEVEL_INFO));
+ celix_status_t status =bundle_create(&framework->bundle);
+ status = CELIX_DO_IF(status, bundle_getBundleId(framework->bundle, &framework->bundleId));
+ status = CELIX_DO_IF(status, bundle_setFramework(framework->bundle, framework));
+ status = CELIX_DO_IF(status, bundleCache_create(uuid, framework->configurationMap, &framework->cache));
+ status = CELIX_DO_IF(status, serviceRegistry_create(framework, &framework->registry));
+ bundle_context_t *context = NULL;
+ status = CELIX_DO_IF(status, bundleContext_create(framework, framework->logger, framework->bundle, &context));
+ status = CELIX_DO_IF(status, bundle_setContext(framework->bundle, context));
+
+ //create framework bundle entry
+ long bndId = -1L;
+ bundle_getBundleId(framework->bundle, &bndId);
+ celix_framework_bundle_entry_t *entry = fw_bundleEntry_create(framework->bundle);
+ celixThreadMutex_lock(&framework->installedBundles.mutex);
+ celix_arrayList_add(framework->installedBundles.entries, entry);
+ celixThreadMutex_unlock(&framework->installedBundles.mutex);
+
+ if (status != CELIX_SUCCESS) {
+ fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Could not create framework");
+ free(framework);
+ framework = NULL;
+ }
+
+ *out = framework;
return status;
}
@@ -389,22 +399,6 @@ celix_status_t framework_destroy(framework_pt framework) {
}
celix_status_t fw_init(framework_pt framework) {
- bundle_state_e state = OSGI_FRAMEWORK_BUNDLE_UNKNOWN;
- const char *location = NULL;
- module_pt module = NULL;
- linked_list_pt wires = NULL;
- array_list_pt archives = NULL;
- bundle_archive_pt archive = NULL;
-
- /*create and store framework uuid*/
- char uuid[37];
-
- uuid_t uid;
- uuid_generate(uid);
- uuid_unparse(uid, uuid);
-
- properties_set(framework->configurationMap, (char*) OSGI_FRAMEWORK_FRAMEWORK_UUID, uuid);
-
celixThreadMutex_lock(&framework->dispatcher.mutex);
framework->dispatcher.active = true;
celixThreadMutex_unlock(&framework->dispatcher.mutex);
@@ -415,49 +409,15 @@ celix_status_t fw_init(framework_pt framework) {
celixThreadMutex_unlock(&framework->shutdown.mutex);
- celix_status_t status = CELIX_SUCCESS;
- status = CELIX_DO_IF(status, arrayList_create(&framework->bundleListeners));
- status = CELIX_DO_IF(status, arrayList_create(&framework->frameworkListeners));
- status = CELIX_DO_IF(status, arrayList_create(&framework->dispatcher.dynamicEventQueue));
- status = CELIX_DO_IF(status, celixThread_create(&framework->dispatcher.thread, NULL, fw_eventDispatcher, framework));
- status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state));
- if (status == CELIX_SUCCESS) {
- if ((state == OSGI_FRAMEWORK_BUNDLE_INSTALLED) || (state == OSGI_FRAMEWORK_BUNDLE_RESOLVED)) {
- status = CELIX_DO_IF(status, bundleCache_create(uuid, framework->configurationMap,&framework->cache));
- status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state));
- if (status == CELIX_SUCCESS) {
- if (state == OSGI_FRAMEWORK_BUNDLE_INSTALLED) {
- bool cleanCache = celix_properties_getAsBool(framework->configurationMap, OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME, OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_DEFAULT);
- if (cleanCache) {
- bundleCache_delete(framework->cache);
- }
- }
- }
- }
- }
+ celixThread_create(&framework->dispatcher.thread, NULL, fw_eventDispatcher, framework);
- status = CELIX_DO_IF(status, bundle_getArchive(framework->bundle, &archive));
- status = CELIX_DO_IF(status, bundleArchive_getLocation(archive, &location));
- if (status == CELIX_SUCCESS) {
- long bndId = -1L;
- bundle_getBundleId(framework->bundle, &bndId);
- celix_framework_bundle_entry_t *entry = fw_bundleEntry_create(framework->bundle);
- celixThreadMutex_lock(&framework->installedBundles.mutex);
- celix_arrayList_add(framework->installedBundles.entries, entry);
- celixThreadMutex_unlock(&framework->installedBundles.mutex);
- }
- status = CELIX_DO_IF(status, bundle_getCurrentModule(framework->bundle, &module));
- if (status == CELIX_SUCCESS) {
- wires = resolver_resolve(module);
- if (wires != NULL) {
- framework_markResolvedModules(framework, wires);
- } else {
- status = CELIX_BUNDLE_EXCEPTION;
- fw_logCode(framework->logger, CELIX_LOG_LEVEL_ERROR, status, "Unresolved constraints in System Bundle");
- }
+ bool cleanCache = celix_properties_getAsBool(framework->configurationMap, OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_NAME, OSGI_FRAMEWORK_FRAMEWORK_STORAGE_CLEAN_DEFAULT);
+ if (cleanCache) {
+ bundleCache_delete(framework->cache);
}
- status = CELIX_DO_IF(status, bundleCache_getArchives(framework->cache, &archives));
+ celix_array_list_t* archives = NULL;
+ celix_status_t status = bundleCache_getArchives(framework->cache, &archives);
if (status == CELIX_SUCCESS) {
unsigned int arcIdx;
for (arcIdx = 0; arcIdx < arrayList_size(archives); arcIdx++) {
@@ -480,12 +440,9 @@ celix_status_t fw_init(framework_pt framework) {
arrayList_destroy(archives);
}
- status = CELIX_DO_IF(status, serviceRegistry_create(framework, &framework->registry));
- status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, framework->bundle, OSGI_FRAMEWORK_BUNDLE_STARTING));
- bundle_context_t *context = NULL;
- status = CELIX_DO_IF(status, bundleContext_create(framework, framework->logger, framework->bundle, &context));
- status = CELIX_DO_IF(status, bundle_setContext(framework->bundle, context));
+ status = CELIX_DO_IF(status, bundle_setState(framework->bundle, OSGI_FRAMEWORK_BUNDLE_STARTING));
+
if (status == CELIX_SUCCESS) {
celix_bundle_activator_t *activator = calloc(1,(sizeof(*activator)));
if (activator != NULL) {
@@ -504,19 +461,11 @@ celix_status_t fw_init(framework_pt framework) {
status = CELIX_DO_IF(status, bundle_getContext(framework->bundle, &validateContext));
if (status == CELIX_SUCCESS) {
- /* This code part is in principle dead, but in future it may do something.
- * That's why it's outcommented and not deleted
- if (create != NULL) {
- create(context, &userData);
- }
- */
activator->userData = userData;
-
if (start != NULL) {
start(userData, validateContext);
}
- }
- else{
+ } else {
free(activator);
}
} else {
@@ -543,10 +492,8 @@ celix_status_t framework_start(framework_pt framework) {
}
status = CELIX_DO_IF(status, bundle_getState(framework->bundle, &state));
- if (status == CELIX_SUCCESS) {
- if (state == OSGI_FRAMEWORK_BUNDLE_STARTING) {
- status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, framework->bundle, OSGI_FRAMEWORK_BUNDLE_ACTIVE));
- }
+ if (status == CELIX_SUCCESS && state == OSGI_FRAMEWORK_BUNDLE_STARTING) {
+ bundle_setState(framework->bundle, OSGI_FRAMEWORK_BUNDLE_ACTIVE);
}
celix_framework_bundle_entry_t* entry = fw_bundleEntry_getBundleEntryAndIncreaseUseCount(framework, framework->bundleId);
@@ -892,7 +839,7 @@ celix_status_t fw_startBundle(framework_pt framework, long bndId, int options __
status = CELIX_DO_IF(status, bundle_setActivator(entry->bnd, activator));
- status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_STARTING));
+ status = CELIX_DO_IF(status, bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_STARTING));
CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTING, entry));
status = CELIX_DO_IF(status, bundle_getContext(entry->bnd, &context));
@@ -911,7 +858,7 @@ celix_status_t fw_startBundle(framework_pt framework, long bndId, int options __
}
}
- status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_ACTIVE));
+ status = CELIX_DO_IF(status, bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_ACTIVE));
CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STARTED, entry));
if (status != CELIX_SUCCESS) {
@@ -924,7 +871,7 @@ celix_status_t fw_startBundle(framework_pt framework, long bndId, int options __
bundle_setActivator(entry->bnd, NULL);
bundleContext_destroy(context);
free(activator);
- framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_RESOLVED);
+ status = bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_RESOLVED);
}
}
}
@@ -975,7 +922,7 @@ celix_status_t framework_updateBundle(framework_pt framework, bundle_pt bundle,
status = CELIX_DO_IF(status, bundle_revise(bundle, location, inputFile));
status = CELIX_DO_IF(status, bundleArchive_setLastModified(archive, time(NULL)));
- status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED));
+ status = CELIX_DO_IF(status, bundle_setState(bundle, OSGI_FRAMEWORK_BUNDLE_INSTALLED));
bundle_revision_pt revision = NULL;
array_list_pt handles = NULL;
@@ -1069,10 +1016,10 @@ celix_status_t fw_stopBundle(framework_pt framework, long bndId, bool record) {
}
- CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_STOPPING));
+ CELIX_DO_IF(status, bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_STOPPING));
CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPING, entry));
if (status == CELIX_SUCCESS) {
- if (wasActive || (bndId == 0)) {
+ if (wasActive) {
activator = bundle_getActivator(entry->bnd);
status = CELIX_DO_IF(status, bundle_getContext(entry->bnd, &context));
@@ -1092,9 +1039,7 @@ celix_status_t fw_stopBundle(framework_pt framework, long bndId, bool record) {
}
if (bndId > 0) {
- celix_serviceTracker_syncForContext(entry->bnd->context);
celix_bundleContext_cleanup(entry->bnd->context);
- celix_serviceTracker_syncForContext(framework->bundle->context);
if (status == CELIX_SUCCESS) {
module_pt module = NULL;
const char *symbolicName = NULL;
@@ -1109,12 +1054,14 @@ celix_status_t fw_stopBundle(framework_pt framework, long bndId, bool record) {
status = CELIX_DO_IF(status, bundle_setContext(entry->bnd, NULL));
}
- status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_RESOLVED));
+ status = CELIX_DO_IF(status, bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_RESOLVED));
+ CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPED, entry));
} else if (bndId == 0) {
//framework bundle
- celix_serviceTracker_syncForContext(framework->bundle->context);
celix_bundleContext_cleanup(entry->bnd->context);
- celix_serviceTracker_syncForContext(framework->bundle->context);
+
+ status = CELIX_DO_IF(status, bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_RESOLVED));
+ CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_STOPPED, entry));
}
}
@@ -1141,7 +1088,6 @@ celix_status_t fw_stopBundle(framework_pt framework, long bndId, bool record) {
}
fw_bundleEntry_decreaseUseCount(entry);
- celix_serviceTracker_syncForFramework(framework);
return status;
}
@@ -1176,7 +1122,7 @@ static celix_status_t fw_uninstallBundleEntry(celix_framework_t *framework, celi
CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, entry));
- status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bnd, OSGI_FRAMEWORK_BUNDLE_UNINSTALLED));
+ status = CELIX_DO_IF(status, bundle_setState(bnd, OSGI_FRAMEWORK_BUNDLE_UNINSTALLED));
status = CELIX_DO_IF(status, bundleArchive_setLastModified(archive, time(NULL)));
CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNINSTALLED, entry));
@@ -1290,7 +1236,7 @@ celix_status_t fw_refreshBundle(framework_pt framework, long bndId) {
bundle_refresh(entry->bnd);
if (fire) {
- framework_setBundleStateAndNotify(framework, entry->bnd, OSGI_FRAMEWORK_BUNDLE_INSTALLED);
+ bundle_setState(entry->bnd, OSGI_FRAMEWORK_BUNDLE_INSTALLED);
fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_UNRESOLVED, entry);
}
@@ -1750,7 +1696,7 @@ celix_status_t framework_markBundleResolved(framework_pt framework, module_pt mo
status = CELIX_DO_IF(status, framework_loadBundleLibraries(framework, bundle));
}
- status = CELIX_DO_IF(status, framework_setBundleStateAndNotify(framework, bundle, OSGI_FRAMEWORK_BUNDLE_RESOLVED));
+ status = CELIX_DO_IF(status, bundle_setState(bundle, OSGI_FRAMEWORK_BUNDLE_RESOLVED));
CELIX_DO_IF(status, fw_fireBundleEvent(framework, OSGI_FRAMEWORK_BUNDLE_EVENT_RESOLVED, entry));
}
@@ -1812,12 +1758,6 @@ bundle_pt framework_getBundle(framework_pt framework, const char* location) {
return bnd;
}
-celix_status_t framework_setBundleStateAndNotify(framework_pt framework, bundle_pt bundle, int state) {
- int ret = CELIX_SUCCESS;
- bundle_setState(bundle, state);
- return ret;
-}
-
celix_status_t framework_waitForStop(framework_pt framework) {
celixThreadMutex_lock(&framework->shutdown.mutex);
while (!framework->shutdown.done) {
@@ -1979,7 +1919,7 @@ static void celix_framework_addToEventQueue(celix_framework_t *fw, const celix_f
static void fw_handleEventRequest(celix_framework_t *framework, celix_framework_event_t* event) {
if (event->type == CELIX_BUNDLE_EVENT_TYPE) {
- fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Handling fw bundle event for bundle %s", event->bndEntry->bnd->symbolicName);
+ //fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Handling fw bundle event for bundle %s", event->bndEntry->bnd->symbolicName);
celix_array_list_t *localListeners = celix_arrayList_create();
celixThreadMutex_lock(&framework->bundleListenerLock);
for (int i = 0; i < celix_arrayList_size(framework->bundleListeners); ++i) {
@@ -2003,7 +1943,6 @@ static void fw_handleEventRequest(celix_framework_t *framework, celix_framework_
} else if (event->type == CELIX_FRAMEWORK_EVENT_TYPE) {
fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Handling fw event");
celixThreadMutex_lock(&framework->frameworkListenersLock);
- //TODO refactor use of framework listeners to use a useCount + conditition.
for (int i = 0; i < celix_arrayList_size(framework->frameworkListeners); ++i) {
fw_framework_listener_pt listener = celix_arrayList_get(framework->frameworkListeners, i);
framework_event_t fEvent;
@@ -2016,7 +1955,7 @@ static void fw_handleEventRequest(celix_framework_t *framework, celix_framework_
}
celixThreadMutex_unlock(&framework->frameworkListenersLock);
} else if (event->type == CELIX_REGISTER_SERVICE_EVENT) {
- fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Handling fw service registration event for service '%s' with svc id %li", event->serviceName, event->registerServiceId);
+ //fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Handling fw service registration event for service '%s' with svc id %li", event->serviceName, event->registerServiceId);
service_registration_t* reg = NULL;
celix_status_t status;
if (event->factory != NULL) {
@@ -2030,7 +1969,7 @@ static void fw_handleEventRequest(celix_framework_t *framework, celix_framework_
event->registerCallback(event->registerData, serviceRegistration_getServiceId(reg));
}
} else if (event->type == CELIX_UNREGISTER_SERVICE_EVENT) {
- fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Handling fw service unregister event for service id %li", event->unregisterServiceId);
+ //fw_log(framework->logger, CELIX_LOG_LEVEL_TRACE, "Handling fw service unregister event for service id %li", event->unregisterServiceId);
celix_serviceRegistry_unregisterService(framework->registry, event->bndEntry->bnd, event->unregisterServiceId);
}
}
diff --git a/libs/framework/src/resolver.c b/libs/framework/src/resolver.c
index ac34609..5b68632 100644
--- a/libs/framework/src/resolver.c
+++ b/libs/framework/src/resolver.c
@@ -288,6 +288,9 @@ void resolver_addModule(module_pt module) {
}
void resolver_removeModule(module_pt module) {
+ if (m_modules == NULL) {
+ return;
+ }
linked_list_pt caps = NULL;
linkedList_removeElement(m_modules, module);
caps = module_getCapabilities(module);
diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c
index 48cc0da..bb878e3 100644
--- a/libs/framework/src/service_registry.c
+++ b/libs/framework/src/service_registry.c
@@ -30,22 +30,10 @@
#include "service_reference_private.h"
#include "framework_private.h"
-#ifdef DEBUG
-#define CHECK_DELETED_REFERENCES true
-#else
-#define CHECK_DELETED_REFERENCES false
-#endif
-
static celix_status_t serviceRegistry_registerServiceInternal(service_registry_pt registry, bundle_pt bundle, const char* serviceName, const void * serviceObject, properties_pt dictionary, long reservedId, enum celix_service_type svcType, service_registration_pt *registration);
static celix_status_t serviceRegistry_addHooks(service_registry_pt registry, const char* serviceName, const void *serviceObject, service_registration_pt registration);
static celix_status_t serviceRegistry_removeHook(service_registry_pt registry, service_registration_pt registration);
static void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry, bundle_pt bundle, service_reference_pt ref, size_t usageCount, size_t refCount);
-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);
-static celix_status_t serviceRegistry_setReferenceStatus(service_registry_pt registry, service_reference_pt reference,
- bool deleted);
static celix_status_t serviceRegistry_getUsingBundles(service_registry_pt registry, service_registration_pt reg, array_list_pt *bundles);
static celix_status_t serviceRegistry_getServiceReference_internal(service_registry_pt registry, bundle_pt owner, service_registration_pt registration, service_reference_pt *out);
static void celix_serviceRegistry_serviceChanged(celix_service_registry_t *registry, celix_service_event_type_t eventType, service_registration_pt registration);
@@ -81,9 +69,6 @@ celix_status_t serviceRegistry_create(framework_pt framework, service_registry_p
reg->nextServiceId = 1L;
reg->serviceReferences = hashMap_create(NULL, NULL, NULL, NULL);
- reg->checkDeletedReferences = CHECK_DELETED_REFERENCES;
- reg->deletedServiceReferences = hashMap_create(NULL, NULL, NULL, NULL);
-
reg->listenerHooks = celix_arrayList_create();
reg->serviceListeners = celix_arrayList_create();
@@ -154,8 +139,6 @@ celix_status_t serviceRegistry_destroy(service_registry_pt registry) {
}
celix_arrayList_destroy(registry->listenerHooks);
- hashMap_destroy(registry->deletedServiceReferences, false, false);
-
size = hashMap_size(registry->pendingRegisterEvents.map);
assert(size == 0);
celixThreadMutex_destroy(®istry->pendingRegisterEvents.mutex);
@@ -333,7 +316,6 @@ static celix_status_t serviceRegistry_getServiceReference_internal(service_regis
}
if (status == CELIX_SUCCESS) {
hashMap_put(references, (void*)registration->serviceId, ref);
- hashMap_put(registry->deletedServiceReferences, ref, (void *)false);
}
} else {
serviceReference_retain(ref);
@@ -434,21 +416,15 @@ celix_status_t serviceRegistry_getServiceReferences(service_registry_pt registry
celix_status_t serviceRegistry_retainServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference) {
celix_status_t status = CELIX_SUCCESS;
- reference_status_t refStatus;
bundle_pt refBundle = NULL;
celixThreadRwlock_writeLock(®istry->lock);
- serviceRegistry_checkReference(registry, reference, &refStatus);
- if (refStatus == REF_ACTIVE) {
- serviceReference_getOwner(reference, &refBundle);
- if (refBundle == bundle) {
- serviceReference_retain(reference);
- } else {
- status = CELIX_ILLEGAL_ARGUMENT;
- fw_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, "cannot retain a service reference from an other bundle (in ref %p) (provided %p).", refBundle, bundle);
- }
+ serviceReference_getOwner(reference, &refBundle);
+ if (refBundle == bundle) {
+ serviceReference_retain(reference);
} else {
- serviceRegistry_logIllegalReference(registry, reference, refStatus);
+ status = CELIX_ILLEGAL_ARGUMENT;
+ fw_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, "cannot retain a service reference from an other bundle (in ref %p) (provided %p).", refBundle, bundle);
}
celixThreadRwlock_unlock(®istry->lock);
@@ -460,97 +436,54 @@ celix_status_t serviceRegistry_ungetServiceReference(service_registry_pt registr
celix_status_t status = CELIX_SUCCESS;
bool destroyed = false;
size_t count = 0;
- reference_status_t refStatus;
celixThreadRwlock_writeLock(®istry->lock);
- serviceRegistry_checkReference(registry, reference, &refStatus);
- if (refStatus == REF_ACTIVE) {
- serviceReference_getUsageCount(reference, &count);
- serviceReference_release(reference, &destroyed);
- if (destroyed) {
-
- if (count > 0) {
- serviceRegistry_logWarningServiceReferenceUsageCount(registry, bundle, reference, count, 0);
- }
+ serviceReference_getUsageCount(reference, &count);
+ serviceReference_release(reference, &destroyed);
+ if (destroyed) {
- hash_map_pt refsMap = hashMap_get(registry->serviceReferences, bundle);
+ if (count > 0) {
+ serviceRegistry_logWarningServiceReferenceUsageCount(registry, bundle, reference, count, 0);
+ }
- unsigned long refId = 0UL;
- service_reference_pt ref = NULL;
+ hash_map_pt refsMap = hashMap_get(registry->serviceReferences, bundle);
- if (refsMap != NULL) {
- hash_map_iterator_t iter = hashMapIterator_construct(refsMap);
- while (hashMapIterator_hasNext(&iter)) {
- hash_map_entry_pt entry = hashMapIterator_nextEntry(&iter);
- refId = (unsigned long) hashMapEntry_getKey(entry); //note could be invalid e.g. freed
- ref = hashMapEntry_getValue(entry);
+ unsigned long refId = 0UL;
+ service_reference_pt ref = NULL;
- if (ref == reference) {
- break;
- } else {
- ref = NULL;
- refId = 0UL;
- }
+ if (refsMap != NULL) {
+ hash_map_iterator_t iter = hashMapIterator_construct(refsMap);
+ while (hashMapIterator_hasNext(&iter)) {
+ hash_map_entry_pt entry = hashMapIterator_nextEntry(&iter);
+ refId = (unsigned long) hashMapEntry_getKey(entry); //note could be invalid e.g. freed
+ ref = hashMapEntry_getValue(entry);
+
+ if (ref == reference) {
+ break;
+ } else {
+ ref = NULL;
+ refId = 0UL;
}
}
+ }
- if (ref != NULL) {
- hashMap_remove(refsMap, (void*)refId);
- int size = hashMap_size(refsMap);
- if (size == 0) {
- hashMap_destroy(refsMap, false, false);
- hashMap_remove(registry->serviceReferences, bundle);
- }
- serviceRegistry_setReferenceStatus(registry, reference, true);
- } else {
- fw_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR, "Cannot find reference %p in serviceReferences map",
- reference);
+ if (ref != NULL) {
+ hashMap_remove(refsMap, (void*)refId);
+ int size = hashMap_size(refsMap);
+ if (size == 0) {
+ hashMap_destroy(refsMap, false, false);
+ hashMap_remove(registry->serviceReferences, bundle);
}
+ } else {
+ fw_log(registry->framework->logger, CELIX_LOG_LEVEL_FATAL, "Cannot find reference %p in serviceReferences map",
+ reference);
}
- } else {
- serviceRegistry_logIllegalReference(registry, reference, refStatus);
}
celixThreadRwlock_unlock(®istry->lock);
return status;
}
-static celix_status_t serviceRegistry_setReferenceStatus(service_registry_pt registry, service_reference_pt reference,
- bool deleted) {
- //precondition write locked on registry->lock
- if (registry->checkDeletedReferences) {
- hashMap_put(registry->deletedServiceReferences, reference, (void *) deleted);
- }
- return CELIX_SUCCESS;
-}
-
-static void serviceRegistry_logIllegalReference(service_registry_pt registry __attribute__((unused)), service_reference_pt reference,
- reference_status_t refStatus) {
- fw_log(registry->framework->logger, CELIX_LOG_LEVEL_ERROR,
- "Error handling service reference %p, status is %i",reference, refStatus);
-}
-
-static celix_status_t serviceRegistry_checkReference(service_registry_pt registry, service_reference_pt ref,
- reference_status_t *out) {
- //precondition read or write locked on registry->lock
- celix_status_t status = CELIX_SUCCESS;
-
- if (registry->checkDeletedReferences) {
- reference_status_t refStatus = REF_UNKNOWN;
-
- if (hashMap_containsKey(registry->deletedServiceReferences, ref)) {
- bool deleted = (bool) hashMap_get(registry->deletedServiceReferences, ref);
- refStatus = deleted ? REF_DELETED : REF_ACTIVE;
- }
-
- *out = refStatus;
- } else {
- *out = REF_ACTIVE;
- }
-
- return status;
-}
-
static void serviceRegistry_logWarningServiceReferenceUsageCount(service_registry_pt registry __attribute__((unused)), bundle_pt bundle, service_reference_pt ref, size_t usageCount, size_t refCount) {
if (usageCount > 0) {
fw_log(registry->framework->logger, CELIX_LOG_LEVEL_WARNING, "Service Reference destroyed with usage count is %zu, expected 0. Look for missing bundleContext_ungetService calls.", usageCount);
@@ -602,8 +535,6 @@ celix_status_t serviceRegistry_clearReferencesFor(service_registry_pt registry,
while (!destroyed) {
serviceReference_release(ref, &destroyed);
}
- serviceRegistry_setReferenceStatus(registry, ref, true);
-
}
hashMapIterator_destroy(iter);
hashMap_destroy(refsMap, false, false);
@@ -648,78 +579,53 @@ celix_status_t serviceRegistry_getService(service_registry_pt registry, bundle_p
size_t count = 0;
const void *service = NULL;
bool valid = false;
- reference_status_t refStatus;
celixThreadRwlock_readLock(®istry->lock);
- serviceRegistry_checkReference(registry, reference, &refStatus);
- if (refStatus == REF_ACTIVE) {
- serviceReference_getServiceRegistration(reference, ®istration);
- valid = serviceRegistration_isValid(registration);
- if (valid) {
- serviceRegistration_retain(registration);
- serviceReference_increaseUsage(reference, &count);
- } else {
- *out = NULL; //invalid service registration
- }
+ serviceReference_getServiceRegistration(reference, ®istration);
+ valid = serviceRegistration_isValid(registration);
+ if (valid) {
+ serviceRegistration_retain(registration);
+ serviceReference_increaseUsage(reference, &count);
+ } else {
+ *out = NULL; //invalid service registration
}
celixThreadRwlock_unlock(®istry->lock);
- if (valid && refStatus == REF_ACTIVE) {
- if (count == 1) {
- serviceRegistration_getService(registration, bundle, &service);
- serviceReference_setService(reference, service);
- }
- serviceRegistration_release(registration);
-
- /* NOTE the out argument of sr_getService should be 'const void**'
- To ensure backwards compatibility a cast is made instead.
- */
- serviceReference_getService(reference, (void **)out);
- } else {
- if (refStatus != REF_ACTIVE) {
- serviceRegistry_logIllegalReference(registry, reference, refStatus);
- }
- status = CELIX_BUNDLE_EXCEPTION;
+ if (count == 1) {
+ serviceRegistration_getService(registration, bundle, &service);
+ serviceReference_setService(reference, service);
}
+ serviceRegistration_release(registration);
+
+ /* NOTE the out argument of sr_getService should be 'const void**'
+ To ensure backwards compatibility a cast is made instead.
+ */
+ serviceReference_getService(reference, (void **)out);
return status;
}
celix_status_t serviceRegistry_ungetService(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference, bool *result) {
- celix_status_t status = CELIX_SUCCESS;
service_registration_pt reg = NULL;
const void *service = NULL;
size_t count = 0;
- celix_status_t subStatus = CELIX_SUCCESS;
- reference_status_t refStatus;
celixThreadRwlock_readLock(®istry->lock);
- serviceRegistry_checkReference(registry, reference, &refStatus);
celixThreadRwlock_unlock(®istry->lock);
- if (refStatus == REF_ACTIVE) {
- subStatus = serviceReference_decreaseUsage(reference, &count);
- if (count == 0) {
- /*NOTE the argument service of sr_getService should be 'const void**'
- To ensure backwards compatibility a cast is made instead.
- */
- serviceReference_getService(reference, (void**)&service);
- serviceReference_getServiceRegistration(reference, ®);
- if (reg != NULL) {
- serviceRegistration_ungetService(reg, bundle, &service);
- }
+ celix_status_t status = serviceReference_decreaseUsage(reference, &count);
+ if (count == 0) {
+ /*NOTE the argument service of sr_getService should be 'const void**'
+ To ensure backwards compatibility a cast is made instead.
+ */
+ serviceReference_getService(reference, (void**)&service);
+ serviceReference_getServiceRegistration(reference, ®);
+ if (reg != NULL) {
+ serviceRegistration_ungetService(reg, bundle, &service);
}
- } else {
- serviceRegistry_logIllegalReference(registry, reference, refStatus);
- status = CELIX_BUNDLE_EXCEPTION;
}
- if (result) {
- *result = (subStatus == CELIX_SUCCESS);
- }
-
-
return status;
}
@@ -1085,7 +991,7 @@ celix_status_t celix_serviceRegistry_addServiceListener(celix_service_registry_t
celixThreadMutex_create(&entry->mutex, NULL);
celixThreadCondition_init(&entry->cond, NULL);
- celix_array_list_t *registrations = celix_arrayList_create();
+ celix_array_list_t *references = celix_arrayList_create();
celixThreadRwlock_writeLock(®istry->lock);
celix_arrayList_add(registry->serviceListeners, entry); //use count 1
@@ -1101,7 +1007,9 @@ celix_status_t celix_serviceRegistry_addServiceListener(celix_service_registry_t
if (celix_filter_match(filter, props)) {
serviceRegistration_retain(registration);
long svcId = serviceRegistration_getServiceId(registration);
- celix_arrayList_add(registrations, registration);
+ service_reference_pt ref = NULL;
+ serviceRegistry_getServiceReference_internal(registry, bundle, registration, &ref);
+ celix_arrayList_add(references, ref);
//update pending register event count
celix_increasePendingRegisteredEvent(registry, svcId);
}
@@ -1114,22 +1022,23 @@ celix_status_t celix_serviceRegistry_addServiceListener(celix_service_registry_t
//The handling of pending registered events is to ensure that the UNREGISTERING event is always
//after the 1 or 2 REGISTERED events.
- for (int i = 0; i < celix_arrayList_size(registrations); ++i) {
- service_registration_pt reg = celix_arrayList_get(registrations, i);
- long svcId = serviceRegistration_getServiceId(reg);
- service_reference_pt ref = NULL;
- serviceRegistry_getServiceReference_internal(registry, bundle, reg, &ref);
+ for (int i = 0; i < celix_arrayList_size(references); ++i) {
+ service_reference_pt ref = celix_arrayList_get(references, i);
+ long svcId = serviceReference_getServiceId(ref);
celix_service_event_t event;
event.reference = ref;
event.type = OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED;
listener->serviceChanged(listener->handle, &event);
serviceReference_release(ref, NULL);
+
+ service_registration_t* reg = NULL;
+ serviceReference_getServiceRegistration(ref, ®);
serviceRegistration_release(reg);
//update pending register event count
celix_decreasePendingRegisteredEvent(registry, svcId);
}
- celix_arrayList_destroy(registrations);
+ celix_arrayList_destroy(references);
serviceRegistry_callHooksForListenerFilter(registry, bundle, entry->filter, false);
diff --git a/libs/framework/src/service_registry_private.h b/libs/framework/src/service_registry_private.h
index a51bb90..f181731 100644
--- a/libs/framework/src/service_registry_private.h
+++ b/libs/framework/src/service_registry_private.h
@@ -62,9 +62,6 @@ struct celix_serviceRegistry {
hash_map_t *serviceRegistrations; //key = bundle (reg owner), value = list ( registration )
hash_map_t *serviceReferences; //key = bundle, value = map (key = serviceId, value = reference)
- bool checkDeletedReferences; //If enabled. check if provided service references are still valid
- hash_map_t *deletedServiceReferences; //key = ref pointer, value = bool
-
long nextServiceId;
celix_array_list_t *listenerHooks; //celix_service_registry_listener_hook_entry_t*
@@ -103,12 +100,6 @@ typedef struct celix_service_registry_service_listener_entry {
unsigned int useCount;
} celix_service_registry_service_listener_entry_t;
-typedef enum reference_status_enum {
- REF_ACTIVE,
- REF_DELETED,
- REF_UNKNOWN
-} reference_status_t;
-
struct usageCount {
unsigned int count;
service_reference_pt reference;
diff --git a/libs/framework/src/service_tracker.c b/libs/framework/src/service_tracker.c
index 8775c23..112c077 100644
--- a/libs/framework/src/service_tracker.c
+++ b/libs/framework/src/service_tracker.c
@@ -34,14 +34,14 @@
#include "bundle_context_private.h"
#include "celix_array_list.h"
-static celix_status_t serviceTracker_track(celix_service_tracker_instance_t *tracker, service_reference_pt reference, celix_service_event_t *event);
-static celix_status_t serviceTracker_untrack(celix_service_tracker_instance_t *tracker, service_reference_pt reference, celix_service_event_t *event);
-static void serviceTracker_untrackTracked(celix_service_tracker_instance_t *tracker, celix_tracked_entry_t *tracked);
-static celix_status_t serviceTracker_invokeAddingService(celix_service_tracker_instance_t *tracker, service_reference_pt ref, void **svcOut);
-static celix_status_t serviceTracker_invokeAddService(celix_service_tracker_instance_t *tracker, celix_tracked_entry_t *tracked);
-static celix_status_t serviceTracker_invokeRemovingService(celix_service_tracker_instance_t *tracker, celix_tracked_entry_t *tracked);
+static celix_status_t serviceTracker_track(service_tracker_t *tracker, service_reference_pt reference, celix_service_event_t *event);
+static celix_status_t serviceTracker_untrack(service_tracker_t *tracker, service_reference_pt reference);
+static void serviceTracker_untrackTracked(service_tracker_t *tracker, celix_tracked_entry_t *tracked);
+static celix_status_t serviceTracker_invokeAddingService(service_tracker_t *tracker, service_reference_pt ref, void **svcOut);
+static celix_status_t serviceTracker_invokeAddService(service_tracker_t *tracker, celix_tracked_entry_t *tracked);
+static celix_status_t serviceTracker_invokeRemovingService(service_tracker_t *tracker, celix_tracked_entry_t *tracked);
static void serviceTracker_checkAndInvokeSetService(void *handle, void *highestSvc, const properties_t *props, const bundle_t *bnd);
-static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracker_instance_t *instance,
+static bool serviceTracker_useHighestRankingServiceInternal(service_tracker_t *tracker,
const char *serviceName /*sanity*/,
void *callbackHandle,
void (*use)(void *handle, void *svc),
@@ -56,18 +56,6 @@ static void* shutdownServiceTrackerInstanceHandler(void *data);
static void serviceTracker_serviceChanged(void *handle, celix_service_event_t *event);
-static celix_thread_once_t g_once = CELIX_THREAD_ONCE_INIT; //once for g_shutdownMutex, g_shutdownCond
-
-
-static celix_thread_mutex_t g_shutdownMutex;
-static celix_thread_cond_t g_shutdownCond;
-static celix_array_list_t *g_shutdownInstances = NULL; //value = celix_service_tracker_instance -> used for syncing with shutdown threads
-
-
-static void serviceTracker_once(void) {
- celixThreadMutex_create(&g_shutdownMutex, NULL);
- celixThreadCondition_init(&g_shutdownCond, NULL);
-}
static inline celix_tracked_entry_t* tracked_create(service_reference_pt ref, void *svc, celix_properties_t *props, celix_bundle_t *bnd) {
celix_tracked_entry_t *tracked = calloc(1, sizeof(*tracked));
@@ -128,332 +116,272 @@ celix_status_t serviceTracker_create(bundle_context_pt context, const char * ser
return status;
}
-celix_status_t serviceTracker_createWithFilter(bundle_context_pt context, const char * filter, service_tracker_customizer_pt customizer, service_tracker_pt *tracker) {
- celix_status_t status = CELIX_SUCCESS;
- *tracker = (service_tracker_pt) calloc(1, sizeof(**tracker));
- if (!*tracker) {
- status = CELIX_ENOMEM;
- } else {
- (*tracker)->context = context;
- (*tracker)->filter = strdup(filter);
- (*tracker)->customizer = customizer;
- }
+celix_status_t serviceTracker_createWithFilter(bundle_context_pt context, const char * filter, service_tracker_customizer_pt customizer, service_tracker_pt *out) {
+ service_tracker_t* tracker = calloc(1, sizeof(*tracker));
+ *out = tracker;
+ tracker->context = context;
+ tracker->filter = celix_utils_strdup(filter);
+ tracker->customizer = *customizer;
+ free(customizer);
- framework_logIfError(celix_frameworkLogger_globalLogger(), status, NULL, "Cannot create service tracker [filter=%s]", filter);
+ celixThreadMutex_create(&tracker->closeSync.mutex, NULL);
+ celixThreadCondition_init(&tracker->closeSync.cond, NULL);
- return status;
+ celixThreadMutex_create(&tracker->mutex, NULL);
+ celixThreadCondition_init(&tracker->cond, NULL);
+ tracker->trackedServices = celix_arrayList_create();
+ tracker->untrackingServices = celix_arrayList_create();
+
+ celixThreadMutex_create(&tracker->mutex, NULL);
+ tracker->currentHighestServiceId = -1;
+
+ tracker->listener.handle = tracker;
+ tracker->listener.serviceChanged = (void *) serviceTracker_serviceChanged;
+
+ tracker->callbackHandle = tracker->callbackHandle;
+
+ tracker->add = tracker->add;
+ tracker->addWithProperties = tracker->addWithProperties;
+ tracker->addWithOwner = tracker->addWithOwner;
+ tracker->set = tracker->set;
+ tracker->setWithProperties = tracker->setWithProperties;
+ tracker->setWithOwner = tracker->setWithOwner;
+ tracker->remove = tracker->remove;
+ tracker->removeWithProperties = tracker->removeWithProperties;
+ tracker->removeWithOwner = tracker->removeWithOwner;
+
+ return CELIX_SUCCESS;
}
celix_status_t serviceTracker_destroy(service_tracker_pt tracker) {
- if (tracker->customizer != NULL) {
- serviceTrackerCustomizer_destroy(tracker->customizer);
- }
-
free(tracker->serviceName);
free(tracker->filter);
- free(tracker);
-
+ celixThreadMutex_destroy(&tracker->closeSync.mutex);
+ celixThreadCondition_destroy(&tracker->closeSync.cond);
+ celixThreadMutex_destroy(&tracker->mutex);
+ celixThreadCondition_destroy(&tracker->cond);
+ celix_arrayList_destroy(tracker->trackedServices);
+ celix_arrayList_destroy(tracker->untrackingServices);
+ free(tracker);
return CELIX_SUCCESS;
}
celix_status_t serviceTracker_open(service_tracker_pt tracker) {
- celix_service_listener_t *listener = NULL;
- celix_service_tracker_instance_t *instance = NULL;
- celix_status_t status = CELIX_SUCCESS;
-
- bool addListener = false;
-
- celixThreadRwlock_writeLock(&tracker->instanceLock);
- if (tracker->instance == NULL) {
- instance = calloc(1, sizeof(*instance));
- instance->context = tracker->context;
-
- instance->closing = false;
- instance->activeServiceChangeCalls = 0;
- celixThreadMutex_create(&instance->closingLock, NULL);
- celixThreadCondition_init(&instance->activeServiceChangeCallsCond, NULL);
-
-
- celixThreadRwlock_create(&instance->lock, NULL);
- instance->trackedServices = celix_arrayList_create();
-
- celixThreadMutex_create(&instance->mutex, NULL);
- instance->currentHighestServiceId = -1;
-
- instance->listener.handle = instance;
- instance->listener.serviceChanged = (void *) serviceTracker_serviceChanged;
- listener = &instance->listener;
-
- instance->callbackHandle = tracker->callbackHandle;
- instance->filter = strdup(tracker->filter);
- if (tracker->customizer != NULL) {
- memcpy(&instance->customizer, tracker->customizer, sizeof(instance->customizer));
- }
- instance->add = tracker->add;
- instance->addWithProperties = tracker->addWithProperties;
- instance->addWithOwner = tracker->addWithOwner;
- instance->set = tracker->set;
- instance->setWithProperties = tracker->setWithProperties;
- instance->setWithOwner = tracker->setWithOwner;
- instance->remove = tracker->remove;
- instance->removeWithProperties = tracker->removeWithProperties;
- instance->removeWithOwner = tracker->removeWithOwner;
-
- tracker->instance = instance;
-
- addListener = true;
- } else {
- //already open
- framework_logIfError(tracker->context->framework->logger, status, NULL, "Tracker already open");
+ celixThreadMutex_lock(&tracker->mutex);
+ bool alreadyOpen = tracker->open;
+ tracker->open = true;
+ celixThreadMutex_unlock(&tracker->mutex);
+ if (!alreadyOpen) {
+ bundleContext_addServiceListener(tracker->context, &tracker->listener, tracker->filter);
}
- celixThreadRwlock_unlock(&tracker->instanceLock);
-
- if (addListener) {
- bundleContext_addServiceListener(tracker->context, listener, tracker->filter);
- }
return CELIX_SUCCESS;
}
-celix_status_t serviceTracker_close(service_tracker_pt tracker) {
+celix_status_t serviceTracker_close(service_tracker_t* tracker) {
//put all tracked entries in tmp array list, so that the untrack (etc) calls are not blocked.
//set state to close to prevent service listener events
- celixThreadRwlock_writeLock(&tracker->instanceLock);
- celix_service_tracker_instance_t *instance = tracker->instance;
- tracker->instance = NULL;
- if (instance != NULL) {
- celixThreadMutex_lock(&instance->closingLock);
- //prevent service listener events
- instance->closing = true;
- celixThreadMutex_unlock(&instance->closingLock);
- }
- celixThreadRwlock_unlock(&tracker->instanceLock);
-
- if (instance != NULL) {
- celixThreadRwlock_writeLock(&instance->lock);
- unsigned int size = celix_arrayList_size(instance->trackedServices);
- if(size > 0) {
- celix_tracked_entry_t *trackedEntries[size];
- for (unsigned int i = 0u; i < size; i++) {
- trackedEntries[i] = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
- }
- arrayList_clear(instance->trackedServices);
- celixThreadRwlock_unlock(&instance->lock);
+ celixThreadMutex_lock(&tracker->mutex);
+ bool open = tracker->open;
+ tracker->open = false;
+ celixThreadMutex_unlock(&tracker->mutex);
- //loop trough tracked entries an untrack
- for (unsigned int i = 0u; i < size; i++) {
- serviceTracker_untrackTracked(instance, trackedEntries[i]);
+ if (!open) {
+ return CELIX_SUCCESS;
+ }
+
+
+ //indicate that the service tracking is closing and wait for the still pending service registration events.
+ celixThreadMutex_lock(&tracker->closeSync.mutex);
+ tracker->closeSync.closing = true;
+ while (tracker->closeSync.activeCalls > 0) {
+ celixThreadCondition_wait(&tracker->closeSync.cond, &tracker->closeSync.mutex);
+ }
+ celixThreadMutex_unlock(&tracker->closeSync.mutex);
+
+ int nrOfTrackedEntries;
+ do {
+ celixThreadMutex_lock(&tracker->mutex);
+ celix_tracked_entry_t* tracked = NULL;
+ nrOfTrackedEntries = celix_arrayList_size(tracker->trackedServices);
+ if (nrOfTrackedEntries > 0) {
+ tracked = celix_arrayList_get(tracker->trackedServices, 0);
+ celix_arrayList_removeAt(tracker->trackedServices, 0);
+ celix_arrayList_add(tracker->untrackingServices, tracked);
+ }
+ celixThreadMutex_unlock(&tracker->mutex);
+
+ if (tracked != NULL) {
+ int currentSize = nrOfTrackedEntries - 1;
+ if (currentSize == 0) {
+ serviceTracker_checkAndInvokeSetService(tracker, NULL, NULL, NULL);
+ } else {
+ serviceTracker_useHighestRankingServiceInternal(tracker, tracked->serviceName, tracker, NULL, NULL, serviceTracker_checkAndInvokeSetService);
}
- } else {
- celixThreadRwlock_unlock(&instance->lock);
- }
- celixThreadMutex_lock(&instance->closingLock);
- while (instance->activeServiceChangeCalls > 0) {
- celixThreadCondition_wait(&instance->activeServiceChangeCallsCond, &instance->closingLock);
+ serviceTracker_untrackTracked(tracker, tracked);
+ celixThreadMutex_lock(&tracker->mutex);
+ celix_arrayList_remove(tracker->untrackingServices, tracked);
+ celixThreadCondition_broadcast(&tracker->cond);
+ celixThreadMutex_unlock(&tracker->mutex);
}
- celixThreadMutex_unlock(&instance->closingLock);
-#ifdef CELIX_SERVICE_TRACKER_USE_SHUTDOWN_THREAD
- //NOTE Separate thread is needed to prevent deadlock where closing is triggered from a serviceChange event and the
- // untrack -> removeServiceListener will try to remove a service listener which is being invoked and is the
- // actual thread calling the removeServiceListener.
- //
- // This can be detached -> because service listener events are ignored (closing=true) and so no callbacks
- // are made back to the celix framework / tracker owner.
- serviceTracker_addInstanceFromShutdownList(instance);
- celix_thread_t localThread;
- celixThread_create(&localThread, NULL, shutdownServiceTrackerInstanceHandler, instance);
- celixThread_detach(localThread);
-#else
- fw_removeServiceListener(instance->context->framework, instance->context->bundle, &instance->listener);
-
- celixThreadMutex_destroy(&instance->closingLock);
- celixThreadCondition_destroy(&instance->activeServiceChangeCallsCond);
- celixThreadMutex_destroy(&instance->mutex);
- celixThreadRwlock_destroy(&instance->lock);
- celix_arrayList_destroy(instance->trackedServices);
- free(instance->filter);
- free(instance);
-#endif
- }
+ celixThreadMutex_lock(&tracker->mutex);
+ nrOfTrackedEntries = celix_arrayList_size(tracker->trackedServices);
+ celixThreadMutex_unlock(&tracker->mutex);
+ } while (nrOfTrackedEntries > 0);
+
+
+ fw_removeServiceListener(tracker->context->framework, tracker->context->bundle, &tracker->listener);
return CELIX_SUCCESS;
}
-service_reference_pt serviceTracker_getServiceReference(service_tracker_pt tracker) {
+service_reference_pt serviceTracker_getServiceReference(service_tracker_t* tracker) {
//TODO deprecated warning -> not locked
- celix_tracked_entry_t *tracked;
+
service_reference_pt result = NULL;
- unsigned int i;
-
- celixThreadRwlock_readLock(&tracker->instanceLock);
- celix_service_tracker_instance_t *instance = tracker->instance;
- if (instance != NULL) {
- celixThreadRwlock_readLock(&instance->lock);
- for (i = 0; i < arrayList_size(instance->trackedServices); ++i) {
- tracked = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
- result = tracked->reference;
- break;
- }
- celixThreadRwlock_unlock(&instance->lock);
+
+ celixThreadMutex_lock(&tracker->mutex);
+ for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); ++i) {
+ celix_tracked_entry_t *tracked = celix_arrayList_get(tracker->trackedServices, i);
+ result = tracked->reference;
+ break;
}
- celixThreadRwlock_unlock(&tracker->instanceLock);
+ celixThreadMutex_unlock(&tracker->mutex);
return result;
}
-array_list_pt serviceTracker_getServiceReferences(service_tracker_pt tracker) {
+array_list_pt serviceTracker_getServiceReferences(service_tracker_t* tracker) {
//TODO deprecated warning -> not locked
- celix_tracked_entry_t *tracked;
- unsigned int i;
array_list_pt references = NULL;
arrayList_create(&references);
- celixThreadRwlock_readLock(&tracker->instanceLock);
- celix_service_tracker_instance_t *instance = tracker->instance;
- if (instance != NULL) {
- celixThreadRwlock_readLock(&instance->lock);
- for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
- tracked = (celix_tracked_entry_t*) arrayList_get(instance->trackedServices, i);
- arrayList_add(references, tracked->reference);
- }
- celixThreadRwlock_unlock(&instance->lock);
+ celixThreadMutex_lock(&tracker->mutex);
+ for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
+ celix_tracked_entry_t *tracked = celix_arrayList_get(tracker->trackedServices, i);
+ arrayList_add(references, tracked->reference);
}
- celixThreadRwlock_unlock(&tracker->instanceLock);
+ celixThreadMutex_unlock(&tracker->mutex);
return references;
}
-void *serviceTracker_getService(service_tracker_pt tracker) {
+void *serviceTracker_getService(service_tracker_t* tracker) {
//TODO deprecated warning -> not locked
- celix_tracked_entry_t* tracked;
void *service = NULL;
- unsigned int i;
-
- celixThreadRwlock_readLock(&tracker->instanceLock);
- celix_service_tracker_instance_t *instance = tracker->instance;
- if (instance != NULL) {
- celixThreadRwlock_readLock(&instance->lock);
- for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
- tracked = (celix_tracked_entry_t*) arrayList_get(instance->trackedServices, i);
- service = tracked->service;
- break;
- }
- celixThreadRwlock_unlock(&instance->lock);
+
+ celixThreadMutex_lock(&tracker->mutex);
+ for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
+ celix_tracked_entry_t* tracked = celix_arrayList_get(tracker->trackedServices, i);
+ service = tracked->service;
+ break;
}
- celixThreadRwlock_unlock(&tracker->instanceLock);
+ celixThreadMutex_unlock(&tracker->mutex);
return service;
}
-array_list_pt serviceTracker_getServices(service_tracker_pt tracker) {
+array_list_pt serviceTracker_getServices(service_tracker_t* tracker) {
//TODO deprecated warning -> not locked, also make locked variant
- celix_tracked_entry_t *tracked;
- unsigned int i;
array_list_pt references = NULL;
arrayList_create(&references);
- celixThreadRwlock_readLock(&tracker->instanceLock);
- celix_service_tracker_instance_t *instance = tracker->instance;
- if (instance != NULL) {
- celixThreadRwlock_readLock(&instance->lock);
- for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
- tracked = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
- arrayList_add(references, tracked->service);
- }
- celixThreadRwlock_unlock(&instance->lock);
+ celixThreadMutex_lock(&tracker->mutex);
+ for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
+ celix_tracked_entry_t *tracked = celix_arrayList_get(tracker->trackedServices, i);
+ arrayList_add(references, tracked->service);
}
- celixThreadRwlock_unlock(&tracker->instanceLock);
+ celixThreadMutex_unlock(&tracker->mutex);
return references;
}
void *serviceTracker_getServiceByReference(service_tracker_pt tracker, service_reference_pt reference) {
//TODO deprecated warning -> not locked
- celix_tracked_entry_t *tracked;
void *service = NULL;
- unsigned int i;
-
- celixThreadRwlock_readLock(&tracker->instanceLock);
- celix_service_tracker_instance_t *instance = tracker->instance;
- if (instance != NULL) {
- celixThreadRwlock_readLock(&instance->lock);
- for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
- bool equals = false;
- tracked = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
- serviceReference_equals(reference, tracked->reference, &equals);
- if (equals) {
- service = tracked->service;
- break;
- }
+
+ celixThreadMutex_lock(&tracker->mutex);
+ for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
+ bool equals = false;
+ celix_tracked_entry_t *tracked = celix_arrayList_get(tracker->trackedServices, i);
+ serviceReference_equals(reference, tracked->reference, &equals);
+ if (equals) {
+ service = tracked->service;
+ break;
}
- celixThreadRwlock_unlock(&instance->lock);
}
- celixThreadRwlock_unlock(&tracker->instanceLock);
+ celixThreadMutex_unlock(&tracker->mutex);
return service;
}
static void serviceTracker_serviceChanged(void *handle, celix_service_event_t *event) {
- celix_service_tracker_instance_t *instance = handle;
+ service_tracker_t *tracker = handle;
- celixThreadMutex_lock(&instance->closingLock);
- bool closing = instance->closing;
+ celixThreadMutex_lock(&tracker->closeSync.mutex);
+ bool closing = tracker->closeSync.closing;
if (!closing) {
- instance->activeServiceChangeCalls += 1;
+ tracker->closeSync.activeCalls += 1;
}
- celixThreadMutex_unlock(&instance->closingLock);
+ celixThreadMutex_unlock(&tracker->closeSync.mutex);
if (!closing) {
switch (event->type) {
case OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED:
- serviceTracker_track(instance, event->reference, event);
+ serviceTracker_track(tracker, event->reference, event);
break;
case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED:
- serviceTracker_track(instance, event->reference, event);
+ serviceTracker_track(tracker, event->reference, event);
break;
case OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING:
- serviceTracker_untrack(instance, event->reference, event);
+ serviceTracker_untrack(tracker, event->reference);
break;
- case OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH:
- //TODO
+ default:
+ //nop
break;
}
- celixThreadMutex_lock(&instance->closingLock);
- assert(instance->activeServiceChangeCalls > 0);
- instance->activeServiceChangeCalls -= 1;
- if (instance->activeServiceChangeCalls == 0) {
- celixThreadCondition_broadcast(&instance->activeServiceChangeCallsCond);
+ } else {
+ switch (event->type) {
+ case OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING:
+ //untrack the service reference, because after this call the registration can be gone
+ serviceTracker_untrack(tracker, event->reference);
+ break;
+ default:
+ //nop
+ break;
}
- celixThreadMutex_unlock(&instance->closingLock);
+ }
+
+ if (!closing) {
+ celixThreadMutex_lock(&tracker->closeSync.mutex);
+ tracker->closeSync.activeCalls -= 1;
+ celixThreadCondition_broadcast(&tracker->closeSync.cond);
+ celixThreadMutex_unlock(&tracker->closeSync.mutex);
}
}
size_t serviceTracker_nrOfTrackedServices(service_tracker_t *tracker) {
- size_t result = 0;
- celixThreadRwlock_readLock(&tracker->instanceLock);
- celixThreadRwlock_readLock(&tracker->instance->lock);
- result = (size_t) arrayList_size(tracker->instance->trackedServices);
- celixThreadRwlock_unlock(&tracker->instance->lock);
- celixThreadRwlock_unlock(&tracker->instanceLock);
+ celixThreadMutex_lock(&tracker->mutex);
+ size_t result = (size_t) arrayList_size(tracker->trackedServices);
+ celixThreadMutex_unlock(&tracker->mutex);
return result;
}
-static celix_status_t serviceTracker_track(celix_service_tracker_instance_t *instance, service_reference_pt reference, celix_service_event_t *event) {
+static celix_status_t serviceTracker_track(service_tracker_t* tracker, service_reference_pt reference, celix_service_event_t *event) {
celix_status_t status = CELIX_SUCCESS;
celix_tracked_entry_t *found = NULL;
- unsigned int i;
-
- bundleContext_retainServiceReference(instance->context, reference);
- celixThreadRwlock_readLock(&instance->lock);
- for (i = 0; i < arrayList_size(instance->trackedServices); i++) {
+ bundleContext_retainServiceReference(tracker->context, reference);
+
+ celixThreadMutex_lock(&tracker->mutex);
+ for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
bool equals = false;
- celix_tracked_entry_t *visit = (celix_tracked_entry_t*) arrayList_get(instance->trackedServices, i);
+ celix_tracked_entry_t *visit = (celix_tracked_entry_t*) arrayList_get(tracker->trackedServices, i);
serviceReference_equals(reference, visit->reference, &equals);
if (equals) {
//NOTE it is possible to get two REGISTERED events, second one can be ignored.
@@ -461,12 +389,12 @@ static celix_status_t serviceTracker_track(celix_service_tracker_instance_t *ins
break;
}
}
- celixThreadRwlock_unlock(&instance->lock);
+ celixThreadMutex_unlock(&tracker->mutex);
if (found == NULL) {
//NEW entry
void *service = NULL;
- status = serviceTracker_invokeAddingService(instance, reference, &service);
+ status = serviceTracker_invokeAddingService(tracker, reference, &service);
if (status == CELIX_SUCCESS && service != NULL) {
assert(reference != NULL);
@@ -482,22 +410,24 @@ static celix_status_t serviceTracker_track(celix_service_tracker_instance_t *ins
celix_tracked_entry_t *tracked = tracked_create(reference, service, props, bnd); //use count 1
- celixThreadRwlock_writeLock(&instance->lock);
- arrayList_add(instance->trackedServices, tracked);
- celixThreadRwlock_unlock(&instance->lock);
+ celixThreadMutex_lock(&tracker->mutex);
+ arrayList_add(tracker->trackedServices, tracked);
+ celixThreadMutex_unlock(&tracker->mutex);
- serviceTracker_invokeAddService(instance, tracked);
- serviceTracker_useHighestRankingServiceInternal(instance, tracked->serviceName, instance, NULL, NULL, serviceTracker_checkAndInvokeSetService);
+ serviceTracker_invokeAddService(tracker, tracked);
+ serviceTracker_useHighestRankingServiceInternal(tracker, tracked->serviceName, tracker, NULL, NULL, serviceTracker_checkAndInvokeSetService);
}
+ } else {
+ bundleContext_ungetServiceReference(tracker->context, reference);
}
- framework_logIfError(instance->context->framework->logger, status, NULL, "Cannot track reference");
+ framework_logIfError(tracker->context->framework->logger, status, NULL, "Cannot track reference");
return status;
}
static void serviceTracker_checkAndInvokeSetService(void *handle, void *highestSvc, const celix_properties_t *props, const celix_bundle_t *bnd) {
- celix_service_tracker_instance_t *instance = handle;
+ service_tracker_t *tracker = handle;
bool update = false;
long svcId = -1;
if (highestSvc == NULL) {
@@ -507,117 +437,131 @@ static void serviceTracker_checkAndInvokeSetService(void *handle, void *highestS
svcId = celix_properties_getAsLong(props, OSGI_FRAMEWORK_SERVICE_ID, -1);
}
if (svcId >= 0) {
- celixThreadMutex_lock(&instance->mutex);
- if (instance->currentHighestServiceId != svcId) {
- instance->currentHighestServiceId = svcId;
+ celixThreadMutex_lock(&tracker->mutex);
+ if (tracker->currentHighestServiceId != svcId) {
+ tracker->currentHighestServiceId = svcId;
update = true;
//update
}
- celixThreadMutex_unlock(&instance->mutex);
+ celixThreadMutex_unlock(&tracker->mutex);
}
if (update) {
- void *h = instance->callbackHandle;
- if (instance->set != NULL) {
- instance->set(h, highestSvc);
+ void *h = tracker->callbackHandle;
+ if (tracker->set != NULL) {
+ tracker->set(h, highestSvc);
}
- if (instance->setWithProperties != NULL) {
- instance->setWithProperties(h, highestSvc, props);
+ if (tracker->setWithProperties != NULL) {
+ tracker->setWithProperties(h, highestSvc, props);
}
- if (instance->setWithOwner != NULL) {
- instance->setWithOwner(h, highestSvc, props, bnd);
+ if (tracker->setWithOwner != NULL) {
+ tracker->setWithOwner(h, highestSvc, props, bnd);
}
}
}
-static celix_status_t serviceTracker_invokeAddService(celix_service_tracker_instance_t *instance, celix_tracked_entry_t *tracked) {
+static celix_status_t serviceTracker_invokeAddService(service_tracker_t *tracker, celix_tracked_entry_t *tracked) {
celix_status_t status = CELIX_SUCCESS;
void *customizerHandle = NULL;
added_callback_pt function = NULL;
- serviceTrackerCustomizer_getHandle(&instance->customizer, &customizerHandle);
- serviceTrackerCustomizer_getAddedFunction(&instance->customizer, &function);
+ serviceTrackerCustomizer_getHandle(&tracker->customizer, &customizerHandle);
+ serviceTrackerCustomizer_getAddedFunction(&tracker->customizer, &function);
if (function != NULL) {
function(customizerHandle, tracked->reference, tracked->service);
}
- void *handle = instance->callbackHandle;
- if (instance->add != NULL) {
- instance->add(handle, tracked->service);
+ void *handle = tracker->callbackHandle;
+ if (tracker->add != NULL) {
+ tracker->add(handle, tracked->service);
}
- if (instance->addWithProperties != NULL) {
- instance->addWithProperties(handle, tracked->service, tracked->properties);
+ if (tracker->addWithProperties != NULL) {
+ tracker->addWithProperties(handle, tracked->service, tracked->properties);
}
- if (instance->addWithOwner != NULL) {
- instance->addWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
+ if (tracker->addWithOwner != NULL) {
+ tracker->addWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
}
return status;
}
-static celix_status_t serviceTracker_invokeAddingService(celix_service_tracker_instance_t *instance, service_reference_pt ref, void **svcOut) {
+static celix_status_t serviceTracker_invokeAddingService(service_tracker_t *tracker, service_reference_pt ref, void **svcOut) {
celix_status_t status = CELIX_SUCCESS;
void *handle = NULL;
adding_callback_pt function = NULL;
- status = serviceTrackerCustomizer_getHandle(&instance->customizer, &handle);
+ status = serviceTrackerCustomizer_getHandle(&tracker->customizer, &handle);
if (status == CELIX_SUCCESS) {
- status = serviceTrackerCustomizer_getAddingFunction(&instance->customizer, &function);
+ status = serviceTrackerCustomizer_getAddingFunction(&tracker->customizer, &function);
}
if (status == CELIX_SUCCESS && function != NULL) {
status = function(handle, ref, svcOut);
} else if (status == CELIX_SUCCESS) {
- status = bundleContext_getService(instance->context, ref, svcOut);
+ status = bundleContext_getService(tracker->context, ref, svcOut);
}
- framework_logIfError(instance->context->framework->logger, status, NULL, "Cannot handle addingService");
+ framework_logIfError(tracker->context->framework->logger, status, NULL, "Cannot handle addingService");
return status;
}
-static celix_status_t serviceTracker_untrack(celix_service_tracker_instance_t* instance, service_reference_pt reference, celix_service_event_t *event) {
+static celix_status_t serviceTracker_untrack(service_tracker_t* tracker, service_reference_pt reference) {
celix_status_t status = CELIX_SUCCESS;
celix_tracked_entry_t *remove = NULL;
- unsigned int i;
- unsigned int size;
const char *serviceName = NULL;
- celixThreadRwlock_writeLock(&instance->lock);
- size = arrayList_size(instance->trackedServices);
- for (i = 0; i < size; i++) {
+ celixThreadMutex_lock(&tracker->mutex);
+ for (int i = 0; i < celix_arrayList_size(tracker->trackedServices); i++) {
bool equals;
- celix_tracked_entry_t *tracked = (celix_tracked_entry_t*) arrayList_get(instance->trackedServices, i);
+ celix_tracked_entry_t *tracked = (celix_tracked_entry_t*) arrayList_get(tracker->trackedServices, i);
serviceName = tracked->serviceName;
serviceReference_equals(reference, tracked->reference, &equals);
if (equals) {
remove = tracked;
//remove from trackedServices to prevent getting this service, but don't destroy yet, can be in use
- arrayList_remove(instance->trackedServices, i);
+ celix_arrayList_removeAt(tracker->trackedServices, i);
+ celix_arrayList_add(tracker->untrackingServices, remove);
break;
}
}
- size = arrayList_size(instance->trackedServices); //updated size
- celixThreadRwlock_unlock(&instance->lock);
+ int size = celix_arrayList_size(tracker->trackedServices); //updated size
+ celixThreadMutex_unlock(&tracker->mutex);
- if (size == 0) {
- serviceTracker_checkAndInvokeSetService(instance, NULL, NULL, NULL);
- } else {
- serviceTracker_useHighestRankingServiceInternal(instance, serviceName, instance, NULL, NULL, serviceTracker_checkAndInvokeSetService);
+ if (remove != NULL) {
+ if (size == 0) {
+ serviceTracker_checkAndInvokeSetService(tracker, NULL, NULL, NULL);
+ } else {
+ serviceTracker_useHighestRankingServiceInternal(tracker, serviceName, tracker, NULL, NULL, serviceTracker_checkAndInvokeSetService);
+ }
}
- serviceTracker_untrackTracked(instance, remove);
+ //note also syncing on untracking entries, to ensure no untrack is parallel in progress
+ if (remove != NULL) {
+ serviceTracker_untrackTracked(tracker, remove);
+ celixThreadMutex_lock(&tracker->mutex);
+ celix_arrayList_remove(tracker->untrackingServices, remove);
+ celixThreadMutex_unlock(&tracker->mutex);
+ } else {
+ //ensure no untrack is still happening (to ensure it safe to unregister service)
+ celixThreadMutex_lock(&tracker->mutex);
+ while (celix_arrayList_size(tracker->untrackingServices) > 0) {
+ celixThreadCondition_wait(&tracker->cond, &tracker->mutex);
+ }
+ celixThreadMutex_unlock(&tracker->mutex);
+ }
- framework_logIfError(instance->context->framework->logger, status, NULL, "Cannot untrack reference");
+ framework_logIfError(tracker->context->framework->logger, status, NULL, "Cannot untrack reference");
return status;
}
-static void serviceTracker_untrackTracked(celix_service_tracker_instance_t *instance, celix_tracked_entry_t *tracked) {
+static void serviceTracker_untrackTracked(service_tracker_t *tracker, celix_tracked_entry_t *tracked) {
if (tracked != NULL) {
- serviceTracker_invokeRemovingService(instance, tracked);
- bundleContext_ungetServiceReference(instance->context, tracked->reference);
+ serviceTracker_invokeRemovingService(tracker, tracked);
+
+ bundleContext_ungetServiceReference(tracker->context, tracked->reference);
tracked_release(tracked);
//Wait till the useCount is 0, because the untrack should only return if the service is not used anymore.
@@ -625,37 +569,37 @@ static void serviceTracker_untrackTracked(celix_service_tracker_instance_t *inst
}
}
-static celix_status_t serviceTracker_invokeRemovingService(celix_service_tracker_instance_t *instance, celix_tracked_entry_t *tracked) {
+static celix_status_t serviceTracker_invokeRemovingService(service_tracker_t *tracker, celix_tracked_entry_t *tracked) {
celix_status_t status = CELIX_SUCCESS;
bool ungetSuccess = true;
void *customizerHandle = NULL;
removed_callback_pt function = NULL;
- serviceTrackerCustomizer_getHandle(&instance->customizer, &customizerHandle);
- serviceTrackerCustomizer_getRemovedFunction(&instance->customizer, &function);
+ serviceTrackerCustomizer_getHandle(&tracker->customizer, &customizerHandle);
+ serviceTrackerCustomizer_getRemovedFunction(&tracker->customizer, &function);
if (function != NULL) {
status = function(customizerHandle, tracked->reference, tracked->service);
}
- void *handle = instance->callbackHandle;
- if (instance->remove != NULL) {
- instance->remove(handle, tracked->service);
+ void *handle = tracker->callbackHandle;
+ if (tracker->remove != NULL) {
+ tracker->remove(handle, tracked->service);
}
- if (instance->addWithProperties != NULL) {
- instance->removeWithProperties(handle, tracked->service, tracked->properties);
+ if (tracker->addWithProperties != NULL) {
+ tracker->removeWithProperties(handle, tracked->service, tracked->properties);
}
- if (instance->removeWithOwner != NULL) {
- instance->removeWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
+ if (tracker->removeWithOwner != NULL) {
+ tracker->removeWithOwner(handle, tracked->service, tracked->properties, tracked->serviceOwner);
}
if (status == CELIX_SUCCESS) {
- status = bundleContext_ungetService(instance->context, tracked->reference, &ungetSuccess);
+ status = bundleContext_ungetService(tracker->context, tracked->reference, &ungetSuccess);
}
if (!ungetSuccess) {
- framework_log(instance->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error ungetting service");
+ framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error ungetting service");
status = CELIX_BUNDLE_EXCEPTION;
}
@@ -706,7 +650,19 @@ celix_service_tracker_t* celix_serviceTracker_createWithOptions(
tracker->addWithOwner = opts->addWithOwner;
tracker->removeWithOwner = opts->removeWithOwner;
- celixThreadRwlock_create(&tracker->instanceLock, NULL);
+ celixThreadMutex_create(&tracker->closeSync.mutex, NULL);
+ celixThreadCondition_init(&tracker->closeSync.cond, NULL);
+
+ celixThreadMutex_create(&tracker->mutex, NULL);
+ celixThreadCondition_init(&tracker->cond, NULL);
+ tracker->trackedServices = celix_arrayList_create();
+ tracker->untrackingServices = celix_arrayList_create();
+
+ celixThreadMutex_create(&tracker->mutex, NULL);
+ tracker->currentHighestServiceId = -1;
+
+ tracker->listener.handle = tracker;
+ tracker->listener.serviceChanged = (void *) serviceTracker_serviceChanged;
//setting lang
const char *lang = opts->filter.serviceLanguage;
@@ -721,7 +677,7 @@ celix_service_tracker_t* celix_serviceTracker_createWithOptions(
if(status != CELIX_SUCCESS) {
framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
"Error incorrect version range.");
- celixThreadRwlock_destroy(&tracker->instanceLock);
+ free(tracker->serviceName);
free(tracker);
return NULL;
}
@@ -730,7 +686,7 @@ celix_service_tracker_t* celix_serviceTracker_createWithOptions(
if(versionRange == NULL) {
framework_log(tracker->context->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__,
"Error creating LDAP filter.");
- celixThreadRwlock_destroy(&tracker->instanceLock);
+ free(tracker->serviceName);
free(tracker);
return NULL;
}
@@ -759,7 +715,7 @@ celix_service_tracker_t* celix_serviceTracker_createWithOptions(
}
}
- if(versionRange != NULL){
+ if (versionRange != NULL){
free(versionRange);
}
@@ -778,7 +734,7 @@ void celix_serviceTracker_destroy(celix_service_tracker_t *tracker) {
}
}
-static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracker_instance_t *instance,
+static bool serviceTracker_useHighestRankingServiceInternal(service_tracker_t *tracker,
const char *serviceName /*sanity*/,
void *callbackHandle,
void (*use)(void *handle, void *svc),
@@ -791,11 +747,11 @@ static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracke
unsigned int i;
//first lock tracker and get highest tracked entry
- celixThreadRwlock_readLock(&instance->lock);
- unsigned int size = arrayList_size(instance->trackedServices);
+ celixThreadMutex_lock(&tracker->mutex);
+ unsigned int size = arrayList_size(tracker->trackedServices);
for (i = 0; i < size; i++) {
- tracked = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
+ tracked = (celix_tracked_entry_t *) arrayList_get(tracker->trackedServices, i);
if (serviceName != NULL && tracked->serviceName != NULL && strncmp(tracked->serviceName, serviceName, 10*1024) == 0) {
const char *val = properties_getWithDefault(tracked->properties, OSGI_FRAMEWORK_SERVICE_RANKING, "0");
long rank = strtol(val, NULL, 10);
@@ -809,7 +765,7 @@ static bool serviceTracker_useHighestRankingServiceInternal(celix_service_tracke
tracked_retain(highest);
}
//unlock tracker so that the tracked entry can be removed from the trackedServices list if unregistered.
- celixThreadRwlock_unlock(&instance->lock);
+ celixThreadMutex_unlock(&tracker->mutex);
if (highest != NULL) {
//got service, call, decrease use count an signal useCond after.
@@ -843,11 +799,7 @@ bool celix_serviceTracker_useHighestRankingService(
struct timespec start, now;
clock_gettime(CLOCK_MONOTONIC, &start);
do {
- celixThreadRwlock_readLock(&tracker->instanceLock);
- if (tracker->instance != NULL) {
- called = serviceTracker_useHighestRankingServiceInternal(tracker->instance, serviceName, callbackHandle, use, useWithProperties, useWithOwner);
- }
- celixThreadRwlock_unlock(&tracker->instanceLock);
+ called = serviceTracker_useHighestRankingServiceInternal(tracker, serviceName, callbackHandle, use, useWithProperties, useWithOwner);
if (waitTimeoutInSeconds <= 0) {
break;
@@ -871,141 +823,34 @@ size_t celix_serviceTracker_useServices(
void (*useWithProperties)(void *handle, void *svc, const celix_properties_t *props),
void (*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *owner)) {
size_t count = 0;
- celixThreadRwlock_readLock(&tracker->instanceLock);
- celix_service_tracker_instance_t *instance = tracker->instance;
- if (instance != NULL) {
- //first lock tracker, get tracked entries and increase use count
- celixThreadRwlock_readLock(&instance->lock);
- int size = celix_arrayList_size(instance->trackedServices);
- count = (size_t)size;
- celix_tracked_entry_t *entries[size];
- for (int i = 0; i < size; i++) {
- celix_tracked_entry_t *tracked = (celix_tracked_entry_t *) arrayList_get(instance->trackedServices, i);
- tracked_retain(tracked);
- entries[i] = tracked;
- }
- //unlock tracker so that the tracked entry can be removed from the trackedServices list if unregistered.
- celixThreadRwlock_unlock(&instance->lock);
-
- //then use entries and decrease use count
- for (int i = 0; i < size; i++) {
- celix_tracked_entry_t *entry = entries[i];
- //got service, call, decrease use count an signal useCond after.
- if (use != NULL) {
- use(callbackHandle, entry->service);
- }
- if (useWithProperties != NULL) {
- useWithProperties(callbackHandle, entry->service, entry->properties);
- }
- if (useWithOwner != NULL) {
- useWithOwner(callbackHandle, entry->service, entry->properties, entry->serviceOwner);
- }
-
- tracked_release(entry);
- }
+ //first lock tracker, get tracked entries and increase use count
+ celixThreadMutex_lock(&tracker->mutex);
+ int size = celix_arrayList_size(tracker->trackedServices);
+ count = (size_t)size;
+ celix_tracked_entry_t *entries[size];
+ for (int i = 0; i < size; i++) {
+ celix_tracked_entry_t *tracked = (celix_tracked_entry_t *) arrayList_get(tracker->trackedServices, i);
+ tracked_retain(tracked);
+ entries[i] = tracked;
}
- celixThreadRwlock_unlock(&tracker->instanceLock);
- return count;
-}
+ //unlock tracker so that the tracked entry can be removed from the trackedServices list if unregistered.
+ celixThreadMutex_unlock(&tracker->mutex);
-void celix_serviceTracker_syncForFramework(void *fw) {
- celixThread_once(&g_once, serviceTracker_once);
- celixThreadMutex_lock(&g_shutdownMutex);
- size_t count = 0;
- do {
- count = 0;
- if (g_shutdownInstances != NULL) {
- for (int i = 0; i < celix_arrayList_size(g_shutdownInstances); ++i) {
- celix_service_tracker_instance_t *instance = celix_arrayList_get(g_shutdownInstances, i);
- if (instance->context->framework == fw) {
- count += 1;
- }
- }
- }
- if (count > 0) {
- pthread_cond_wait(&g_shutdownCond, &g_shutdownMutex);
+ //then use entries and decrease use count
+ for (int i = 0; i < size; i++) {
+ celix_tracked_entry_t *entry = entries[i];
+ //got service, call, decrease use count an signal useCond after.
+ if (use != NULL) {
+ use(callbackHandle, entry->service);
}
- } while (count > 0);
-
- if (g_shutdownInstances != NULL && celix_arrayList_size(g_shutdownInstances) == 0) {
- celix_arrayList_destroy(g_shutdownInstances);
- g_shutdownInstances = NULL;
- }
- celixThreadMutex_unlock(&g_shutdownMutex);
-}
-
-void celix_serviceTracker_syncForContext(void *ctx) {
- celixThread_once(&g_once, serviceTracker_once);
- celixThreadMutex_lock(&g_shutdownMutex);
- size_t count;
- do {
- count = 0;
- if (g_shutdownInstances != NULL) {
- for (int i = 0; i < celix_arrayList_size(g_shutdownInstances); ++i) {
- celix_service_tracker_instance_t *instance = celix_arrayList_get(g_shutdownInstances, i);
- if (instance->context == ctx) {
- count += 1;
- }
- }
+ if (useWithProperties != NULL) {
+ useWithProperties(callbackHandle, entry->service, entry->properties);
}
- if (count > 0) {
- pthread_cond_wait(&g_shutdownCond, &g_shutdownMutex);
+ if (useWithOwner != NULL) {
+ useWithOwner(callbackHandle, entry->service, entry->properties, entry->serviceOwner);
}
- } while (count > 0);
- if (g_shutdownInstances != NULL && celix_arrayList_size(g_shutdownInstances) == 0) {
- celix_arrayList_destroy(g_shutdownInstances);
- g_shutdownInstances = NULL;
+ tracked_release(entry);
}
- celixThreadMutex_unlock(&g_shutdownMutex);
-}
-
-#ifdef CELIX_SERVICE_TRACKER_USE_SHUTDOWN_THREAD
-static void serviceTracker_addInstanceFromShutdownList(celix_service_tracker_instance_t *instance) {
- celixThread_once(&g_once, serviceTracker_once);
- celixThreadMutex_lock(&g_shutdownMutex);
- if (g_shutdownInstances == NULL) {
- g_shutdownInstances = celix_arrayList_create();
- }
- celix_arrayList_add(g_shutdownInstances, instance);
- celixThreadMutex_unlock(&g_shutdownMutex);
-}
-
-static void serviceTracker_remInstanceFromShutdownList(celix_service_tracker_instance_t *instance) {
- celixThread_once(&g_once, serviceTracker_once);
- celixThreadMutex_lock(&g_shutdownMutex);
- if (g_shutdownInstances != NULL) {
- size_t size = celix_arrayList_size(g_shutdownInstances);
- for (size_t i = 0; i < size; ++i) {
- celix_array_list_entry_t entry;
- memset(&entry, 0, sizeof(entry));
- entry.voidPtrVal = instance;
- celix_arrayList_removeEntry(g_shutdownInstances, entry);
- }
- if (celix_arrayList_size(g_shutdownInstances) == 0) {
- celix_arrayList_destroy(g_shutdownInstances);
- g_shutdownInstances = NULL;
- }
- celixThreadCondition_broadcast(&g_shutdownCond);
- }
- celixThreadMutex_unlock(&g_shutdownMutex);
-}
-
-static void* shutdownServiceTrackerInstanceHandler(void *data) {
- celix_service_tracker_instance_t *instance = data;
-
- fw_removeServiceListener(instance->context->framework, instance->context->bundle, &instance->listener);
-
- celixThreadMutex_destroy(&instance->closingLock);
- celixThreadCondition_destroy(&instance->activeServiceChangeCallsCond);
- celixThreadMutex_destroy(&instance->mutex);
- celixThreadRwlock_destroy(&instance->lock);
- celix_arrayList_destroy(instance->trackedServices);
- free(instance->filter);
-
- serviceTracker_remInstanceFromShutdownList(instance);
- free(instance);
-
- return NULL;
-}
-#endif
\ No newline at end of file
+ return count;
+}
\ No newline at end of file
diff --git a/libs/framework/src/service_tracker_private.h b/libs/framework/src/service_tracker_private.h
index 47b8fa7..4bc1b27 100644
--- a/libs/framework/src/service_tracker_private.h
+++ b/libs/framework/src/service_tracker_private.h
@@ -23,51 +23,14 @@
#include "service_tracker.h"
#include "celix_types.h"
-//instance for an active per open statement and removed per close statement
-typedef struct celix_service_tracker_instance {
- celix_thread_mutex_t closingLock; //projects closing and activeServiceChangeCalls
- bool closing; //when true the service tracker instance is being closed and all calls from the service listener are ignored
- size_t activeServiceChangeCalls;
- celix_thread_cond_t activeServiceChangeCallsCond;
-
- bundle_context_t *context;
- char * filter;
-
- service_tracker_customizer_t customizer;
- celix_service_listener_t listener;
-
- void *callbackHandle;
-
- void (*set)(void *handle, void *svc); //highest ranking
- void (*add)(void *handle, void *svc);
- void (*remove)(void *handle, void *svc);
- void (*modified)(void *handle, void *svc);
-
- void (*setWithProperties)(void *handle, void *svc, const properties_t *props); //highest ranking
- void (*addWithProperties)(void *handle, void *svc, const properties_t *props);
- void (*removeWithProperties)(void *handle, void *svc, const properties_t *props);
- void (*modifiedWithProperties)(void *handle, void *svc, const properties_t *props);
-
- void (*setWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner); //highest ranking
- void (*addWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
- void (*removeWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
- void (*modifiedWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
-
- celix_thread_rwlock_t lock; //projects trackedServices
- array_list_t *trackedServices;
-
- celix_thread_mutex_t mutex; //protect current highest service id
- long currentHighestServiceId;
-
- celix_thread_t shutdownThread; //will be created when this instance is shutdown
-} celix_service_tracker_instance_t;
-
struct celix_serviceTracker {
bundle_context_t *context;
char* serviceName;
char* filter;
- service_tracker_customizer_t *customizer;
+
+ service_tracker_customizer_t customizer;
+ celix_service_listener_t listener;
void *callbackHandle;
@@ -86,9 +49,19 @@ struct celix_serviceTracker {
void (*removeWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
void (*modifiedWithOwner)(void *handle, void *svc, const properties_t *props, const bundle_t *owner);
- celix_thread_rwlock_t instanceLock;
- celix_service_tracker_instance_t *instance; /*NULL -> close, !NULL->open*/
-
+ struct {
+ celix_thread_mutex_t mutex; //projects below
+ celix_thread_cond_t cond;
+ bool closing; //if closing is true, no new service registrations are added to the serice tracker
+ size_t activeCalls; // >0 if there is still a serviceChange for a service registration call active
+ } closeSync;
+
+ celix_thread_mutex_t mutex; //projects below
+ celix_thread_cond_t cond;
+ celix_array_list_t *trackedServices;
+ celix_array_list_t *untrackingServices;
+ bool open;
+ long currentHighestServiceId;
};
typedef struct celix_tracked_entry {