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
commit a576a90565b0ac8701d9d61346e8bf778186c3d4 Author: Pepijn Noltes <[email protected]> AuthorDate: Mon Sep 7 16:26:45 2020 +0200 Added async svc regitration usage to log_admin --- bundles/logging/log_admin/src/celix_log_admin.c | 45 ++++++++++------------ .../gtest/src/bundle_context_services_test.cpp | 2 +- libs/framework/include/celix_bundle_context.h | 8 +++- libs/framework/include/celix_framework.h | 6 +++ libs/framework/src/bundle_context.c | 10 +++-- libs/framework/src/framework.c | 30 +++++++++++++++ 6 files changed, 72 insertions(+), 29 deletions(-) diff --git a/bundles/logging/log_admin/src/celix_log_admin.c b/bundles/logging/log_admin/src/celix_log_admin.c index e594abc..805233b 100644 --- a/bundles/logging/log_admin/src/celix_log_admin.c +++ b/bundles/logging/log_admin/src/celix_log_admin.c @@ -210,7 +210,7 @@ static void celix_logAdmin_addLogSvcForName(celix_log_admin_t* admin, const char opts.serviceVersion = CELIX_LOG_SERVICE_VERSION; opts.properties = props; opts.svc = &newEntry->logSvc; - newEntry->logSvcId = celix_bundleContext_registerServiceAsyncWithOptions(admin->ctx, &opts); + newEntry->logSvcId = celix_bundleContext_registerServiceWithOptionsAsync(admin->ctx, &opts); } if (celix_utils_stringEquals(newEntry->name, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME)) { @@ -232,31 +232,28 @@ static void celix_logAdmin_trackerAdd(void *handle, const celix_service_tracker_ celix_logAdmin_addLogSvcForName(admin, name); } -static void celix_logAdmin_remLogSvcForName(celix_log_admin_t* admin, const char* name) { - celix_log_service_entry_t* remEntry = NULL; +static void celix_logAdmin_freeLogEntry(void *data) { + celix_log_service_entry_t* entry = data; + if (celix_utils_stringEquals(entry->name, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME)) { + celix_framework_t* fw = celix_bundleContext_getFramework(entry->admin->ctx); + celix_framework_setLogCallback(fw, NULL, NULL); + } + free(entry->name); + free(entry); +} +static void celix_logAdmin_remLogSvcForName(celix_log_admin_t* admin, const char* name) { celixThreadRwlock_writeLock(&admin->lock); celix_log_service_entry_t* found = hashMap_get(admin->loggers, name); if (found != NULL) { found->count -= 1; if (found->count == 0) { //remove - remEntry = found; hashMap_remove(admin->loggers, name); + celix_bundleContext_unregisterServiceAsync(admin->ctx, found->logSvcId, found, celix_logAdmin_freeLogEntry); } } celixThreadRwlock_unlock(&admin->lock); - - if (remEntry != NULL) { - if (celix_utils_stringEquals(remEntry->name, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME)) { - celix_framework_t* fw = celix_bundleContext_getFramework(admin->ctx); - celix_framework_setLogCallback(fw, NULL, NULL); - } - - celix_bundleContext_unregisterService(admin->ctx, remEntry->logSvcId); - free(remEntry->name); - free(remEntry); - } } @@ -591,10 +588,10 @@ celix_log_admin_t* celix_logAdmin_create(celix_bundle_context_t *ctx) { opts.callbackHandle = admin; opts.addWithProperties = celix_logAdmin_addSink; opts.removeWithProperties = celix_logAdmin_remSink; - admin->logWriterTrackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts); + admin->logWriterTrackerId = celix_bundleContext_trackServicesWithOptionsAsync(ctx, &opts); } - admin->logServiceMetaTrackerId = celix_bundleContext_trackServiceTrackers(ctx, CELIX_LOG_SERVICE_NAME, admin, celix_logAdmin_trackerAdd, celix_logAdmin_trackerRem); + admin->logServiceMetaTrackerId = celix_bundleContext_trackServiceTrackersAsync(ctx, CELIX_LOG_SERVICE_NAME, admin, celix_logAdmin_trackerAdd, celix_logAdmin_trackerRem, NULL, NULL); { admin->controlSvc.handle = admin; @@ -612,7 +609,7 @@ celix_log_admin_t* celix_logAdmin_create(celix_bundle_context_t *ctx) { opts.serviceName = CELIX_LOG_CONTROL_NAME; opts.serviceVersion = CELIX_LOG_CONTROL_VERSION; opts.svc = &admin->controlSvc; - admin->controlSvcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts); + admin->controlSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); } { @@ -629,12 +626,11 @@ celix_log_admin_t* celix_logAdmin_create(celix_bundle_context_t *ctx) { opts.serviceVersion = CELIX_SHELL_COMMAND_SERVICE_VERSION; opts.properties = props; opts.svc = &admin->cmdSvc; - admin->cmdSvcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts); + admin->cmdSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); } //add log service for the framework celix_logAdmin_addLogSvcForName(admin, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME); - return admin; } @@ -642,10 +638,11 @@ void celix_logAdmin_destroy(celix_log_admin_t *admin) { if (admin != NULL) { celix_logAdmin_remLogSvcForName(admin, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME); - celix_bundleContext_unregisterService(admin->ctx, admin->cmdSvcId); - celix_bundleContext_unregisterService(admin->ctx, admin->controlSvcId); - celix_bundleContext_stopTracker(admin->ctx, admin->logServiceMetaTrackerId); - celix_bundleContext_stopTracker(admin->ctx, admin->logWriterTrackerId); + celix_bundleContext_unregisterServiceAsync(admin->ctx, admin->cmdSvcId, NULL, NULL); + celix_bundleContext_unregisterServiceAsync(admin->ctx, admin->controlSvcId, NULL, NULL); + celix_bundleContext_stopTrackerAsync(admin->ctx, admin->logServiceMetaTrackerId, NULL, NULL); + celix_bundleContext_stopTrackerAsync(admin->ctx, admin->logWriterTrackerId, NULL, NULL); + celix_bundleContext_waitForEvents(admin->ctx); assert(hashMap_size(admin->loggers) == 0); //note stopping service tracker tracker should triggered all needed remove events hashMap_destroy(admin->loggers, false, false); diff --git a/libs/framework/gtest/src/bundle_context_services_test.cpp b/libs/framework/gtest/src/bundle_context_services_test.cpp index 96ba33c..9e5335f 100644 --- a/libs/framework/gtest/src/bundle_context_services_test.cpp +++ b/libs/framework/gtest/src/bundle_context_services_test.cpp @@ -1052,7 +1052,7 @@ TEST_F(CelixBundleContextServicesTests, floodEventLoopTest) { localData->cond.wait_for(lck, std::chrono::seconds{30}, [&]{ return localData->ready; }); //wait til ready. EXPECT_TRUE(localData->ready); }; - long svcId = celix_bundleContext_registerServiceAsyncWithOptions(ctx, &opts); + long svcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); EXPECT_GE(svcId, 0); int nrOfAdditionalRegistrations = 300; diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h index 90f733c..060a749 100644 --- a/libs/framework/include/celix_bundle_context.h +++ b/libs/framework/include/celix_bundle_context.h @@ -204,7 +204,7 @@ typedef struct celix_service_registration_options { * @param opts The pointer to the registration options. The options are only in the during registration call. * @return The serviceId (>= 0) or -1 if the registration was unsuccessful and -2 if the registration was cancelled (@see celix_bundleContext_reserveSvcId). */ -long celix_bundleContext_registerServiceAsyncWithOptions(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts); +long celix_bundleContext_registerServiceWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts); /** * Register a service to the Celix framework using the provided service registration options. @@ -1109,6 +1109,12 @@ celix_dependency_manager_t* celix_bundleContext_getDependencyManager(celix_bundl /** + * Wait till there are event for the bundle of this bundle context. + */ +void celix_bundleContext_waitForEvents(celix_bundle_context_t* ctx); + + +/** * Returns the bundle for this bundle context. */ celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx); diff --git a/libs/framework/include/celix_framework.h b/libs/framework/include/celix_framework.h index 7af1e2c..8b5482f 100644 --- a/libs/framework/include/celix_framework.h +++ b/libs/framework/include/celix_framework.h @@ -156,6 +156,12 @@ void celix_framework_waitForEmptyEventQueue(celix_framework_t *fw); void celix_framework_setLogCallback(celix_framework_t* fw, void* logHandle, void (*logFunction)(void* handle, celix_log_level_e level, const char* file, const char *function, int line, const char *format, va_list formatArgs)); +/** + * wait till all events for the bundle identified by the bndId are processed. + */ +void celix_framework_waitForEvents(celix_framework_t* fw, long bndId); + + #ifdef __cplusplus } #endif diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c index 43a11cd..70aa37c 100644 --- a/libs/framework/src/bundle_context.c +++ b/libs/framework/src/bundle_context.c @@ -457,7 +457,7 @@ long celix_bundleContext_registerServiceAsync(celix_bundle_context_t *ctx, void opts.svc = svc; opts.serviceName = serviceName; opts.properties = properties; - return celix_bundleContext_registerServiceAsyncWithOptions(ctx, &opts); + return celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); } long celix_bundleContext_registerService(bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties) { @@ -474,7 +474,7 @@ long celix_bundleContext_registerServiceFactoryAsync(celix_bundle_context_t *ctx opts.factory = factory; opts.serviceName = serviceName; opts.properties = props; - return celix_bundleContext_registerServiceAsyncWithOptions(ctx, &opts); + return celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts); } long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props) { @@ -547,7 +547,7 @@ long celix_bundleContext_registerServiceWithOptions(bundle_context_t *ctx, const return celix_bundleContext_registerServiceWithOptionsInternal(ctx, opts, false); } -long celix_bundleContext_registerServiceAsyncWithOptions(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts) { +long celix_bundleContext_registerServiceWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts) { return celix_bundleContext_registerServiceWithOptionsInternal(ctx, opts, true); } @@ -1484,6 +1484,10 @@ long celix_bundleContext_trackServiceTrackersAsync( return celix_bundleContext_trackServiceTrackersInternal(ctx, serviceName, callbackHandle, trackerAdd, trackerRemove, true, doneCallbackData, doneCallback); } +void celix_bundleContext_waitForEvents(celix_bundle_context_t* ctx) { + celix_framework_waitForEvents(ctx->framework, celix_bundle_getId(ctx->bundle)); +} + celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx) { celix_bundle_t *bnd = NULL; if (ctx != NULL) { diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c index 84eaf67..de19f63 100644 --- a/libs/framework/src/framework.c +++ b/libs/framework/src/framework.c @@ -2640,6 +2640,36 @@ void celix_framework_waitForEmptyEventQueue(celix_framework_t *fw) { celixThreadMutex_unlock(&fw->dispatcher.mutex); } +void celix_framework_waitForEvents(celix_framework_t* fw, long bndId) { + assert(!celix_framework_isCurrentThreadTheEventLoop(fw)); + + celixThreadMutex_lock(&fw->dispatcher.mutex); + bool eventInProgress = true; + while (eventInProgress) { + eventInProgress = false; + for (int i = 0; i < fw->dispatcher.eventQueueSize; ++i) { + int index = (fw->dispatcher.eventQueueFirstEntry + i) % CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE; + celix_framework_event_t* e = &fw->dispatcher.eventQueue[index]; + if (e->bndEntry != NULL && e->bndEntry->bndId == bndId) { + eventInProgress = true; + break; + } + } + for (int i = 0; !eventInProgress && i < celix_arrayList_size(fw->dispatcher.dynamicEventQueue); ++i) { + celix_framework_event_t* e = celix_arrayList_get(fw->dispatcher.dynamicEventQueue, i); + if (e->bndEntry != NULL && e->bndEntry->bndId == bndId) { + eventInProgress = true; + break; + } + } + if (eventInProgress) { + celixThreadCondition_timedwaitRelative(&fw->dispatcher.cond, &fw->dispatcher.mutex, 5, 0); + } + } + celixThreadMutex_unlock(&fw->dispatcher.mutex); +} + + void celix_framework_setLogCallback(celix_framework_t* fw, void* logHandle, void (*logFunction)(void* handle, celix_log_level_e level, const char* file, const char *function, int line, const char *format, va_list formatArgs)) { celix_frameworkLogger_setLogCallback(fw->logger, logHandle, logFunction); }
