From eb6e69952e7ba7cb47dcb5c46745684484d89077 Mon Sep 17 00:00:00 2001 From: Pepijn Noltes Date: Sun, 25 Feb 2024 17:08:46 +0100 Subject: [PATCH] gh-87: Refactor bnd ctx to use a rwlock instead of mutex. Also: - Remove celix_bundleContext_trackService and celix_bundleContext_trackServiceAsync functions. - Update doxygen for useTrackedService* calls. - Remove celix_bundle_destroyServiceTrackerList. function by return an array list with a configured remove callback. - Remove waitTimeoutInSeconds option for celix_tracked_service_use_options_t. --- CHANGES.md | 2 + .../log_admin/gtest/src/LogAdminTestSuite.cc | 6 +- bundles/shell/shell/src/query_command.c | 2 +- .../src/CelixBundleContextBundlesTestSuite.cc | 2 +- .../CelixBundleContextServicesTestSuite.cc | 2 +- libs/framework/include/celix_bundle.h | 12 +- libs/framework/include/celix_bundle_context.h | 297 +++++++++--------- libs/framework/src/bundle.c | 31 +- libs/framework/src/bundle_context.c | 110 +++---- libs/framework/src/bundle_context_private.h | 4 +- 10 files changed, 231 insertions(+), 237 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 39d56c315..8dab49dc3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -63,6 +63,8 @@ limitations under the License. - The signature of `celix_bundleContext_trackServices` has changed. The signature is now simpler to better support the use-case of using a service tracker with the `celix_bundleContext_useTrackedService*` functions. The `celix_bundleContext_trackServicesWithOptions` is still available for more advanced use-cases. +- Function `celix_bundle_destroyServiceTrackerList` is removed. The returned array list from + `celix_bundle_listServiceTrackers` is now configured to destroy the service trackers info entries. ## New Features diff --git a/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc b/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc index 606b07ecf..918f116e4 100644 --- a/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc +++ b/bundles/logging/log_admin/gtest/src/LogAdminTestSuite.cc @@ -84,11 +84,11 @@ TEST_F(LogBundleTestSuite, NrOfLogServices) { EXPECT_EQ(1, control->nrOfLogServices(control->handle, nullptr)); //default the framework log services is available //request "default" log service - long trkId1 = celix_bundleContext_trackService(ctx.get(), CELIX_LOG_SERVICE_NAME); + long trkId1 = celix_bundleContext_trackServices(ctx.get(), CELIX_LOG_SERVICE_NAME); EXPECT_EQ(2, control->nrOfLogServices(control->handle, nullptr)); //request "default" log service -> already created - long trkId2 = celix_bundleContext_trackService(ctx.get(), CELIX_LOG_SERVICE_NAME); + long trkId2 = celix_bundleContext_trackServices(ctx.get(), CELIX_LOG_SERVICE_NAME); EXPECT_EQ(2, control->nrOfLogServices(control->handle, nullptr)); //request a 'logger1' log service @@ -225,7 +225,7 @@ TEST_F(LogBundleTestSuite, SinkLogControl) { TEST_F(LogBundleTestSuite, LogServiceControl) { //request "default" log service - long trkId1 = celix_bundleContext_trackService(ctx.get(), CELIX_LOG_SERVICE_NAME); + long trkId1 = celix_bundleContext_trackServices(ctx.get(), CELIX_LOG_SERVICE_NAME); celix_framework_waitForEmptyEventQueue(fw.get()); EXPECT_EQ(2, control->nrOfLogServices(control->handle, nullptr)); diff --git a/bundles/shell/shell/src/query_command.c b/bundles/shell/shell/src/query_command.c index 13d6fab74..49eb73444 100644 --- a/bundles/shell/shell/src/query_command.c +++ b/bundles/shell/shell/src/query_command.c @@ -118,7 +118,7 @@ static void queryCommand_callback(void *handle, const celix_bundle_t *bnd) { } } } - celix_bundle_destroyServiceTrackerList(trackers); + celix_arrayList_destroy(trackers); } if (printBundleCalled) { diff --git a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc index 88d900c7c..01616065b 100644 --- a/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc +++ b/libs/framework/gtest/src/CelixBundleContextBundlesTestSuite.cc @@ -745,7 +745,7 @@ TEST_F(CelixBundleContextBundlesTestSuite, BundleInfoTests) { auto *services = celix_bundle_listRegisteredServices(bnd); data->requestedCount = celix_arrayList_size(trackers); data->provideCount = celix_arrayList_size(services); - celix_bundle_destroyServiceTrackerList(trackers); + celix_arrayList_destroy(trackers); celix_bundle_destroyRegisteredServicesList(services); }; diff --git a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc index 3f57f7ae1..bd2894d64 100644 --- a/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc +++ b/libs/framework/gtest/src/CelixBundleContextServicesTestSuite.cc @@ -1349,7 +1349,7 @@ TEST_F(CelixBundleContextServicesTestSuite, TrackServiceTrackerTest) { EXPECT_TRUE(trackerId >= 0); EXPECT_EQ(0, count); - long tracker2 = celix_bundleContext_trackService(ctx, "example"); + long tracker2 = celix_bundleContext_trackServices(ctx, "example"); EXPECT_TRUE(tracker2 >= 0); EXPECT_EQ(1, count); diff --git a/libs/framework/include/celix_bundle.h b/libs/framework/include/celix_bundle.h index fb3487094..88218cf17 100644 --- a/libs/framework/include/celix_bundle.h +++ b/libs/framework/include/celix_bundle.h @@ -173,7 +173,6 @@ typedef struct celix_bundle_service_tracker_list_entry { size_t nrOfTrackedServices; } celix_bundle_service_tracker_list_entry_t; - /** * Returns a array list of service tracker info entries for this bundle. * @@ -181,15 +180,10 @@ typedef struct celix_bundle_service_tracker_list_entry { * * @param ctx The bundle context * @param bndId The bundle id for which the services should be listed - * @return A celix array list with celix_bundle_service_tracker_list_entry_t*. Caller is owner of the celix array. + * @return A celix array list with celix_bundle_service_tracker_list_entry_t*. Caller is owner of the celix + * array. The returned list should be freed using celix_arrayList_destroy. */ -CELIX_FRAMEWORK_EXPORT celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t *bnd); - -/** - * Utils function to free memory for the return of a celix_bundle_listServiceTrackers call. - */ -CELIX_FRAMEWORK_EXPORT void celix_bundle_destroyServiceTrackerList(celix_array_list_t* list); - +CELIX_FRAMEWORK_EXPORT celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t* bnd); #ifdef __cplusplus } diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h index e46996e9d..93250ac9f 100644 --- a/libs/framework/include/celix_bundle_context.h +++ b/libs/framework/include/celix_bundle_context.h @@ -391,6 +391,9 @@ CELIX_FRAMEWORK_EXPORT celix_array_list_t* celix_bundleContext_findServicesWithO * @brief Use the service with the provided service id using the provided callback. The Celix framework will ensure that * the targeted service cannot be removed during the callback. * + * @deprecated Use celix_bundleContext_trackService* combined with celix_bundleContext_useServiceTracker* functions + * instead. + * * The svc is should only be considered valid during the callback. * If no service is found, the callback will not be invoked and this function will return false immediately. * @@ -399,22 +402,24 @@ CELIX_FRAMEWORK_EXPORT celix_array_list_t* celix_bundleContext_findServicesWithO * * @param ctx The bundle context * @param serviceId the service id. - * @param serviceName the service name of the service. Should match with the registered service name of the provided service id (sanity check) + * @param serviceName the service name of the service. Should match with the registered service name of the provided + * service id (sanity check) * @param callbackHandle The data pointer, which will be used in the callbacks * @param use The callback, which will be called when service is retrieved. * @param bool returns true if a service was found. */ -CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useServiceWithId( - celix_bundle_context_t *ctx, - long serviceId, - const char* serviceName /*sanity check*/, - void *callbackHandle, - void (*use)(void *handle, void* svc) -); +CELIX_FRAMEWORK_DEPRECATED_EXPORT bool celix_bundleContext_useServiceWithId(celix_bundle_context_t* ctx, + long serviceId, + const char* serviceName /*sanity check*/, + void* callbackHandle, + void (*use)(void* handle, void* svc)); /** * @brief Use the highest ranking service with the provided service name using the provided callback. * + * @deprecated Use celix_bundleContext_trackService* combined with celix_bundleContext_useServiceTracker* functions + * instead. + * * The Celix framework will ensure that the targeted service cannot be removed during the callback. * * The svc is should only be considered valid during the callback. @@ -429,7 +434,7 @@ CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useServiceWithId( * @param use The callback, which will be called when service is retrieved. * @return True if a service was found. */ -CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useService( +CELIX_FRAMEWORK_DEPRECATED_EXPORT bool celix_bundleContext_useService( celix_bundle_context_t *ctx, const char* serviceName, void *callbackHandle, @@ -439,6 +444,9 @@ CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useService( /** * @brief Use the services with the provided service name using the provided callback. * + * @deprecated Use celix_bundleContext_trackService* combined with celix_bundleContext_useServiceTracker* functions + * instead. + * * The Celix framework will ensure that the targeted service cannot be removed during the callback. * * The svc is should only be considered valid during the callback. @@ -453,7 +461,7 @@ CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useService( * @param use The callback, which will be called for every service found. * @return The number of services found and called */ -CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useServices( +CELIX_FRAMEWORK_DEPRECATED_EXPORT size_t celix_bundleContext_useServices( celix_bundle_context_t *ctx, const char* serviceName, void *callbackHandle, @@ -540,6 +548,9 @@ typedef struct celix_service_use_options { /** * @brief Use the highest ranking service satisfying the provided service filter options using the provided callback. * + * @deprecated Use celix_bundleContext_trackService* combined with celix_bundleContext_useServiceTracker* functions + * instead. + * * The Celix framework will ensure that the targeted service cannot be removed during the callback. * * The svc is should only be considered valid during the callback. @@ -553,7 +564,7 @@ typedef struct celix_service_use_options { * @param opts The required options. Note that the serviceName is required. * @return True if a service was found. */ -CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useServiceWithOptions( +CELIX_FRAMEWORK_DEPRECATED_EXPORT bool celix_bundleContext_useServiceWithOptions( celix_bundle_context_t *ctx, const celix_service_use_options_t *opts); @@ -561,6 +572,9 @@ CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useServiceWithOptions( /** * @brief Use the services with the provided service filter options using the provided callback. * + * @deprecated Use celix_bundleContext_trackService* combined with celix_bundleContext_useServiceTracker* functions + * instead. + * * The Celix framework will ensure that the targeted service cannot be removed during the callback. * * The svc is should only be considered valid during the callback. @@ -574,33 +588,10 @@ CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useServiceWithOptions( * @param opts The required options. Note that the serviceName is required. * @return The number of services found and called */ -CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useServicesWithOptions( +CELIX_FRAMEWORK_DEPRECATED_EXPORT size_t celix_bundleContext_useServicesWithOptions( celix_bundle_context_t *ctx, const celix_service_use_options_t *opts); -/** - * @brief Track the highest ranking service with the provided serviceName. - * - * The service tracker will be created async on the Celix event loop thread. This means that the function can return - * before the tracker is created. - * - * @param ctx The bundle context. - * @param serviceName The required service name to track. - * If NULL is all service are tracked. - * @return the tracker id (>=0) or < 0 if unsuccessful. - */ -CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServiceAsync(celix_bundle_context_t* ctx, const char* serviceName); - -/** - * @brief Track the highest ranking service with the provided serviceName - * - * Note: If possible, use the celix_bundleContext_trackServiceAsync instead. - * - * @param ctx The bundle context. - * @return the tracker id (>=0) or < 0 if unsuccessful. - */ -CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackService(celix_bundle_context_t* ctx, const char* serviceName); - /** * @brief Track services with the provided serviceName. * @@ -628,7 +619,8 @@ CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServicesAsync(celix_bundle_ CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServices(celix_bundle_context_t* ctx, const char* serviceName); /** - * @brief Service Tracker Options used to fine tune which services to track and the callback to be used for the tracked services. + * @brief Service Tracker Options used to fine tune which services to track and the callback to be used for the tracked + * services. */ typedef struct celix_service_tracking_options { /** @@ -637,78 +629,83 @@ typedef struct celix_service_tracking_options { celix_service_filter_options_t filter CELIX_OPTS_INIT; /** - * @brief The optional callback pointer used in all the provided callback function (set, add, remove, setWithProperties, etc). + * @brief The optional callback pointer used in all the provided callback function (set, add, remove, + * setWithProperties, etc). */ void* callbackHandle CELIX_OPTS_INIT; /** - * @brief The optional set callback will be called when a new highest ranking service is available conform the provided - * service filter options. + * @brief The optional set callback will be called when a new highest ranking service is available conform the + * provided service filter options. * @param handle The callbackHandle pointer as provided in the service tracker options. * @param svc The service pointer of the highest ranking service. */ - void (*set)(void *handle, void *svc) CELIX_OPTS_INIT; + void (*set)(void* handle, void* svc) CELIX_OPTS_INIT; /** - * @brief The optional setWithProperties callback is handled as the set callback, but with the addition that the service properties - * will also be provided to the callback. + * @brief The optional setWithProperties callback is handled as the set callback, but with the addition that the + * service properties will also be provided to the callback. */ - void (*setWithProperties)(void *handle, void *svc, const celix_properties_t *props) CELIX_OPTS_INIT; //highest ranking + void (*setWithProperties)(void* handle, + void* svc, + const celix_properties_t* props) CELIX_OPTS_INIT; // highest ranking /** - * @brief The optional setWithOwner callback is handled as the set callback, but with the addition that the service properties - * and the bundle owning the service will also be provided to the callback. + * @brief The optional setWithOwner callback is handled as the set callback, but with the addition that the service + * properties and the bundle owning the service will also be provided to the callback. */ - void (*setWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) CELIX_OPTS_INIT; //highest ranking + void (*setWithOwner)(void* handle, void* svc, const celix_properties_t* props, const celix_bundle_t* svcOwner) + CELIX_OPTS_INIT; /** - * @brief The optional add callback will be called for every current and future service found conform the provided service filter - * options as long as the tracker is active. + * @brief The optional add callback will be called for every current and future service found conform the provided + * service filter options as long as the tracker is active. * @param handle The callbackHandle pointer as provided in the service tracker options. * @param svc The service pointer of a service matching the provided service filter options. */ - void (*add)(void *handle, void *svc) CELIX_OPTS_INIT; + void (*add)(void* handle, void* svc) CELIX_OPTS_INIT; /** - * @brief The optional addWithProperties callback is handled as the add callback, but with the addition that the service properties - * will also be provided to the callback. + * @brief The optional addWithProperties callback is handled as the add callback, but with the addition that the + * service properties will also be provided to the callback. */ - void (*addWithProperties)(void *handle, void *svc, const celix_properties_t *props) CELIX_OPTS_INIT; + void (*addWithProperties)(void* handle, void* svc, const celix_properties_t* props) CELIX_OPTS_INIT; /** - * @brief The optional addWithOwner callback is handled as the add callback, but with the addition that the service properties - * and the bundle owning the service will also be provided to the callback. + * @brief The optional addWithOwner callback is handled as the add callback, but with the addition that the service + * properties and the bundle owning the service will also be provided to the callback. */ - void (*addWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) CELIX_OPTS_INIT; + void (*addWithOwner)(void* handle, void* svc, const celix_properties_t* props, const celix_bundle_t* svcOwner) + CELIX_OPTS_INIT; /** - * @brief The optional remove callback will be called for every service conform the provided service filter options that is - * unregistered. When the remove call is finished the removed services should be considered invalid. This means - * that the callback provider should ensure that the removed service is not in use or going to be used after the - * remove callback is finished. + * @brief The optional remove callback will be called for every service conform the provided service filter options + * that is unregistered. When the remove call is finished the removed services should be considered invalid. This + * means that the callback provider should ensure that the removed service is not in use or going to be used after + * the remove callback is finished. * * @param handle The callbackHandle pointer as provided in the service tracker options. * @param svc The service pointer of a service matching the provided service filter options. */ - void (*remove)(void *handle, void *svc) CELIX_OPTS_INIT; + void (*remove)(void* handle, void* svc) CELIX_OPTS_INIT; /** - * @brief The optional removeWithProperties callback is handled as the remove callback, but with the addition that the service properties - * will also be provided to the callback. + * @brief The optional removeWithProperties callback is handled as the remove callback, but with the addition that + * the service properties will also be provided to the callback. */ - void (*removeWithProperties)(void *handle, void *svc, const celix_properties_t *props) CELIX_OPTS_INIT; + void (*removeWithProperties)(void* handle, void* svc, const celix_properties_t* props) CELIX_OPTS_INIT; /** - * @brief The optional removeWithOwner callback is handled as the remove callback, but with the addition that the service properties - * and the bundle owning the service will also be provided to the callback. - */ - void (*removeWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) CELIX_OPTS_INIT; - + * @brief The optional removeWithOwner callback is handled as the remove callback, but with the addition that the + * service properties and the bundle owning the service will also be provided to the callback. + */ + void (*removeWithOwner)(void* handle, void* svc, const celix_properties_t* props, const celix_bundle_t* svcOwner) + CELIX_OPTS_INIT; /** * @brief Data for the trackerCreatedCallback. */ - void *trackerCreatedCallbackData CELIX_OPTS_INIT; + void* trackerCreatedCallbackData CELIX_OPTS_INIT; /** * @brief The callback called when the tracker has ben created (and is active) when using a async call. @@ -717,7 +714,7 @@ typedef struct celix_service_tracking_options { * "stop tracker" happens before the "create tracker" event is processed. In this case the asyncCallback * will not be called. */ - void (*trackerCreatedCallback)(void *trackerCreatedCallbackData) CELIX_OPTS_INIT; + void (*trackerCreatedCallback)(void* trackerCreatedCallbackData) CELIX_OPTS_INIT; } celix_service_tracking_options_t; #ifndef __cplusplus @@ -753,7 +750,9 @@ typedef struct celix_service_tracking_options { * @param opts The pointer to the tracker options. * @return the tracker id (>=0) or < 0 if unsuccessful. */ -CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServicesWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts); +CELIX_FRAMEWORK_EXPORT long +celix_bundleContext_trackServicesWithOptionsAsync(celix_bundle_context_t* ctx, + const celix_service_tracking_options_t* opts); /** * @brief Tracks services using the provided tracker options. @@ -765,23 +764,25 @@ CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServicesWithOptionsAsync(ce * @param opts The pointer to the tracker options. * @return the tracker id (>=0) or < 0 if unsuccessful. */ -CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_tracking_options_t *opts); +CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServicesWithOptions(celix_bundle_context_t* ctx, + const celix_service_tracking_options_t* opts); /** - * @brief Use the highest ranking service, tracked by the provided tracker id, using the provided callback. + * @brief Use the highest-ranking service tracked by the specified tracker id by invoking the provided use callback. * - * If an service is found the use callback will be called on the thread that called this function and when function - * returns the callback is finished. + * The callback is executed on the thread that invokes this function, and the function waits until the use callback + * is completed before returning. * - * An tracker id < 0 will be silently ignored. - * An invalid (non existing) tracker id >= 0 will be logged and the function will return false. + * A tracker id less than 0 is ignored without action. An invalid (non-existent) tracker id of 0 or greater results + * in a logged error, and the function returns false. * * @param[in] ctx The bundle context. - * @param[in] trackerId The tracker id. - * @param[in] callbackHandle The data pointer, which will be used in the callbacks. - * @param[in] use The callback, which will be called when service is retrieved. - * @return True if a service was found and the use callback was called. Returns false if the tracker is not yet active - * (async tracker creation). + * @param[in] trackerId The service tracker id. + * @param[in] callbackHandle An optional pointer to a user-defined context or data structure, passed to the provided use + * callback function. + * @param[in] use The use callback invoked for highest-ranking service tracked. + * @return True if a service was found and the provided use callback was executed; false if the tracker is not yet + * active (asynchronous tracker creation), the are no matching services tracked or if the tracker id is invalid. */ CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useTrackedService(celix_bundle_context_t* ctx, @@ -790,20 +791,21 @@ bool celix_bundleContext_useTrackedService(celix_bundle_context_t* ctx, void (*use)(void* handle, void* svc)); /** - * @brief Use the services, tracked by the provided tracker id, using the provided callback. + * @brief Use the services tracked by the specified tracker id by invoking the provided use callback. * - * If 1 or more services is found the use callback will be called for every service found on the thread that called this - * function and when function returns the callbacks are finished. + * The callback is executed on the thread that invokes this function, and the function waits until the use callback, + * called for all tracked. services, is completed before returning. * - * An tracker id < 0 will be silently ignored. - * An invalid (non existing) tracker id >= 0 will be logged and the function will return 0. + * A tracker id less than 0 is ignored without action. An invalid (non-existent) tracker id of 0 or greater results + * in a logged error, and the function returns 0. * * @param[in] ctx The bundle context. - * @param[in] trackerId The tracker id. - * @param[in] callbackHandle The data pointer, which will be used in the callbacks. - * @param[in] use The callback, which will be called for every service found. - * @return The number of services found and therefore the number of times the use callback was called. Returns 0 if the - * tracker is not yet active (async tracker creation). + * @param[in] trackerId The service tracker id. + * @param[in] callbackHandle An optional pointer to a user-defined context or data structure, passed to the provided use + * callback function. + * @param[in] use The use callback invoked for all tracked services. + * @return The number of services found. Returns 0 if the tracker + * is not yet active (asynchronous tracker creation), 0 services are found or if the tracker id is invalid. */ CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useTrackedServices(celix_bundle_context_t* ctx, @@ -812,75 +814,75 @@ size_t celix_bundleContext_useTrackedServices(celix_bundle_context_t* ctx, void (*use)(void* handle, void* svc)); /** - * @brief Use tracked service options used to configure which use callback to use on the tracked services. - * If multiple use callbacks are set, all set callbacks will be called for every service found. + * @brief Options for using services tracked by a service tracker. These options enable specifying callbacks + * to be invoked for each tracked service that matches the selection criteria. If multiple callbacks are provided, + * each will be called for every matching service. */ typedef struct celix_tracked_service_use_options { /** - * @brief An optional timeout (in seconds), if > 0 the use tracked service(s) call will block until the timeout is - * expired or when at least one service is found. Note that it will be ignored when use service on the event loop. - * Default (0) + * @brief An optional pointer to a user-defined context or data structure, passed to all specified callback + * functions (use, useWithProperties, and useWithOwner). * - * Only applicable when using the celix_bundleContext_useTrackedService or - * celix_bundleContext_useTrackedServiceWithOptions (use single service calls). + * Default value: NULL. */ - double waitTimeoutInSeconds CELIX_OPTS_INIT; - - /** - * @brief The optional callback pointer used in all the provided callback function (use, useWithProperties and useWithOwner). - */ - void *callbackHandle CELIX_OPTS_INIT; + void* callbackHandle CELIX_OPTS_INIT; /** - * @brief The optional use callback will be called when for every service tracked. + * @brief An optional callback invoked for each tracked service that matches the selection criteria. + * This callback does not receive the service's properties or information about the service's owning bundle. * - * @param handle The callbackHandle pointer as provided in the service tracker options. - * @param svc The service pointer of the highest ranking service. + * The svc pointer is only valid during the callback. + * + * Default value: NULL. */ - void (*use)(void *handle, void *svc) CELIX_OPTS_INIT; + void (*use)(void* handle, void* svc) CELIX_OPTS_INIT; /** - * @brief The optional useWithProperties callback will be called when for every service tracked and the - * service properties will also be provided to the callback. + * @brief An optional callback invoked for each tracked service that matches the selection criteria, + * providing the service's properties. This enables the callback to utilize additional metadata associated + * with the service. + * + * The svc and props pointers are only valid during the callback. + * + * Default value: NULL. */ - void (*useWithProperties)(void *handle, void *svc, const celix_properties_t *props) CELIX_OPTS_INIT; + void (*useWithProperties)(void* handle, void* svc, const celix_properties_t* props) CELIX_OPTS_INIT; /** - * @brief The optional useWithOwner callback will be called when for every service tracked and the - * service properties and the bundle owning the service will also be provided to the callback. + * @brief An optional callback invoked for each tracked service that matches the selection criteria, + * along with the service's properties and the service's owning bundle. + * + * The svc, props, and svcOwner pointers are only valid during the callback. + * + * Default value: NULL. */ - void (*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) CELIX_OPTS_INIT; + void (*useWithOwner)(void* handle, void* svc, const celix_properties_t* props, const celix_bundle_t* svcOwner) + CELIX_OPTS_INIT; } celix_tracked_service_use_options_t; #ifndef __cplusplus -/*! - * @brief C Macro to create a empty celix_tracked_service_use_options_t type. +/** + * @brief Macro to initialize a celix_tracked_service_use_options_t structure with default values. */ #define CELIX_EMPTY_TRACKER_SERVICE_USE_OPTIONS \ - { \ - .waitTimeoutInSeconds = 0.0F, .callbackHandle = NULL, .use = NULL, .useWithProperties = NULL, \ - .useWithOwner = NULL \ - } + { .callbackHandle = NULL, .use = NULL, .useWithProperties = NULL, .useWithOwner = NULL } #endif /** - * @brief Use the highest ranking service, tracked by the provided tracker id, using the callbacks in the provided - * options. - * - * If an service is found the use callbacks will be called on the thread that called this function and when function - * returns the callbacks are finished. + * @brief Use the highest-ranking service tracked by the specified tracker id by invoking the callbacks + * specified in the provided options. * - * An tracker id < 0 will be silently ignored. - * An invalid (non existing) tracker id >= 0 will be logged and the function will return false. + * The callbacks are executed on the thread that invokes this function, and the function waits until all callbacks + * are completed before returning. * - * @note the field USE_DIRECT in the provided options has no effect with this function. + * A tracker id less than 0 is ignored without action. An invalid (non-existent) tracker id of 0 or greater results + * in a logged error, and the function returns false. * * @param[in] ctx The bundle context. - * @param[in] trackerId The tracker id. - * @param[in] callbackHandle The data pointer, which will be used in the callbacks. - * @param[in] opts The service use options. - * @return True if a service was found and the use callbacks where called. Returns false if the tracker is not yet - * active (async tracker creation). + * @param[in] trackerId The service tracker id. + * @param[in] opts The service use options containing callbacks and additional configurations. + * @return True if a service was found and the specified callbacks were executed; false if the tracker is not yet + * active (asynchronous tracker creation), the are no matching services tracked or if the tracker id is invalid. */ CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useTrackedServiceWithOptions(celix_bundle_context_t* ctx, @@ -888,23 +890,20 @@ bool celix_bundleContext_useTrackedServiceWithOptions(celix_bundle_context_t* ct const celix_tracked_service_use_options_t* opts); /** - * @brief Use the services, tracked by the provided tracker id, using the callbacks in the provided options. - * - * If 1 or more services is found the use callbacks will be called for every service found on the thread that called - * this function and when function returns the callbacks are finished. + * @brief Use the services tracked by the specified tracker id by invoking the callbacks specified in the + * provided options for each matching service. * - * An tracker id < 0 will be silently ignored. - * An invalid (non existing) tracker id >= 0 will be logged and the function will return 0. + * The callbacks are executed on the thread that invokes this function, and the function waits until all callbacks + * for all found services are completed before returning. * - * @note the field USE_DIRECT in the provided options has no effect with this function. + * A tracker id less than 0 is ignored without action. An invalid (non-existent) tracker id of 0 or greater results + * in a logged error, and the function returns 0. * * @param[in] ctx The bundle context. - * @param[in] trackerId The tracker id. - * @param[in] callbackHandle The data pointer, which will be used in the callbacks. - * @param[in] opts The service use options. - * @return The number of services found and therefore the number of times the callbacks in the provided options where - * called. Returns 0 if the tracker is not yet active - * (async tracker creation). + * @param[in] trackerId The service tracker id. + * @param[in] opts The service use options containing callbacks and additional configurations. + * @return The number of services found and for which the specified callbacks were executed. Returns 0 if the tracker + * is not yet active (asynchronous tracker creation), 0 services are found or if the tracker id is invalid. */ CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useTrackedServicesWithOptions(celix_bundle_context_t* ctx, @@ -972,7 +971,7 @@ CELIX_FRAMEWORK_EXPORT void celix_bundleContext_stopTrackerAsync( void (*doneCallback)(void* doneCallbackData)); /** - * @brief Wait, if able, for (async) creation of tracker. + * @brief Wait, if able, for (async) creation of a tracker. * * Will silently ignore trackerId < 0 and log an error if the tracker id is unknown. * If called on the Apache Celix event loop thread, the function will log a warning and return immediately. @@ -998,7 +997,7 @@ CELIX_FRAMEWORK_EXPORT void celix_bundleContext_waitForAsyncStopTracker(celix_bu * * Could be a service tracker, bundle tracker or service tracker tracker. * Only works for the trackers owned by the bundle of the bundle context. - * Note: Please use the celix_bundleContext_registerServiceFactoryAsync instead. + * Note: Please use the celix_bundleContext_stopTrackerAsync instead. * * Will log a error if the provided tracker id is unknown. Will silently ignore trackerId < 0. */ diff --git a/libs/framework/src/bundle.c b/libs/framework/src/bundle.c index 8eaf7112e..97a4f6e29 100644 --- a/libs/framework/src/bundle.c +++ b/libs/framework/src/bundle.c @@ -580,9 +580,18 @@ void celix_bundle_destroyRegisteredServicesList(celix_array_list_t* list) { } } +static void celix_bundle_destroyServiceTrackerListCallback(void *data) { + celix_bundle_service_tracker_list_entry_t *entry = data; + free(entry->filter); + free(entry->serviceName); + free(entry); +} + celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t *bnd) { - celix_array_list_t* result = celix_arrayList_create(); - celixThreadMutex_lock(&bnd->context->mutex); + celix_array_list_create_options_t opts = CELIX_EMPTY_ARRAY_LIST_CREATE_OPTIONS; + opts.simpleRemovedCallback = celix_bundle_destroyServiceTrackerListCallback; + celix_array_list_t* result = celix_arrayList_createWithOptions(&opts); + celixThreadRwlock_readLock(&bnd->context->lock); CELIX_LONG_HASH_MAP_ITERATE(bnd->context->serviceTrackers, iter) { celix_bundle_context_service_tracker_entry_t *trkEntry = iter.value.ptrValue; if (trkEntry->tracker != NULL) { @@ -597,28 +606,14 @@ celix_array_list_t* celix_bundle_listServiceTrackers(const celix_bundle_t *bnd) } else { framework_logIfError(bnd->framework->logger, CELIX_BUNDLE_EXCEPTION, NULL, "Failed to get service name from tracker. filter is %s", entry->filter); - free(entry->filter); - free(entry); + celix_bundle_destroyServiceTrackerListCallback(entry); } } } - celixThreadMutex_unlock(&bnd->context->mutex); + celixThreadRwlock_unlock(&bnd->context->lock); return result; } - -void celix_bundle_destroyServiceTrackerList(celix_array_list_t* list) { - if (list != NULL) { - for (int i = 0; i < celix_arrayList_size(list); ++i) { - celix_bundle_service_tracker_list_entry_t *entry = celix_arrayList_get(list, i); - free(entry->filter); - free(entry->serviceName); - free(entry); - } - celix_arrayList_destroy(list); - } -} - bundle_archive_t* celix_bundle_getArchive(const celix_bundle_t *bundle) { bundle_archive_t* archive = NULL; bundle_getArchive(bundle, &archive); diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c index ec81025a0..def9b586f 100644 --- a/libs/framework/src/bundle_context.c +++ b/libs/framework/src/bundle_context.c @@ -65,7 +65,7 @@ celix_status_t bundleContext_create(framework_pt framework, celix_framework_logg context->bundle = bundle; context->mng = NULL; - celixThreadMutex_create(&context->mutex, NULL); + celixThreadRwlock_create(&context->lock, NULL); context->svcRegistrations = celix_arrayList_create(); context->bundleTrackers = celix_longHashMap_create(); @@ -98,7 +98,7 @@ celix_status_t bundleContext_destroy(bundle_context_pt context) { celix_arrayList_destroy(context->svcRegistrations); celix_longHashMap_destroy(context->stoppingTrackerEventIds); - celixThreadMutex_destroy(&context->mutex); + celixThreadRwlock_destroy(&context->lock); if (context->mng != NULL) { celix_dependencyManager_removeAllComponents(context->mng); @@ -434,9 +434,9 @@ static long celix_bundleContext_registerServiceWithOptionsInternal(bundle_contex } if (svcId >= 0) { - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); celix_arrayList_addLong(ctx->svcRegistrations, svcId); - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); } return svcId; } @@ -462,7 +462,7 @@ bool celix_bundleContext_isServiceRegistered(celix_bundle_context_t* ctx, long s static void celix_bundleContext_unregisterServiceInternal(celix_bundle_context_t *ctx, long serviceId, bool async, void *data, void (*done)(void*)) { long found = -1L; if (ctx != NULL && serviceId >= 0) { - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); int size = celix_arrayList_size(ctx->svcRegistrations); for (int i = 0; i < size; ++i) { long entryId = celix_arrayList_getLong(ctx->svcRegistrations, i); @@ -472,7 +472,7 @@ static void celix_bundleContext_unregisterServiceInternal(celix_bundle_context_t break; } } - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); if (found >= 0) { if (async) { @@ -519,7 +519,7 @@ void celix_bundleContext_waitForAsyncUnregistration(celix_bundle_context_t* ctx, celix_dependency_manager_t* celix_bundleContext_getDependencyManager(bundle_context_t *ctx) { celix_dependency_manager_t* result = NULL; if (ctx != NULL) { - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_readLock(&ctx->lock); if (ctx->mng == NULL) { ctx->mng = celix_private_dependencyManager_create(ctx); } @@ -527,7 +527,7 @@ celix_dependency_manager_t* celix_bundleContext_getDependencyManager(bundle_cont framework_logIfError(ctx->framework->logger, CELIX_BUNDLE_EXCEPTION, NULL, "Cannot create dependency manager"); } result = ctx->mng; - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); } return result; } @@ -563,10 +563,10 @@ static celix_status_t bundleContext_bundleChanged(void* listenerSvc, bundle_even void celix_bundleContext_trackBundlesWithOptionsCallback(void *data) { celix_bundle_context_bundle_tracker_entry_t* entry = data; assert(celix_framework_isCurrentThreadTheEventLoop(entry->ctx->framework)); - celixThreadMutex_lock(&entry->ctx->mutex); + celixThreadRwlock_writeLock(&entry->ctx->lock); bool cancelled = entry->cancelled; entry->created = true; - celixThreadMutex_unlock(&entry->ctx->mutex); + celixThreadRwlock_unlock(&entry->ctx->lock); if (cancelled) { fw_log(entry->ctx->framework->logger, CELIX_LOG_LEVEL_DEBUG, "Creation of bundle tracker cancelled. trk id = %li", entry->trackerId); free(entry); @@ -590,11 +590,11 @@ static long celix_bundleContext_trackBundlesWithOptionsInternal( entry->listener.handle = entry; entry->listener.bundleChanged = bundleContext_bundleChanged; - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); entry->trackerId = ctx->nextTrackerId++; celix_longHashMap_put(ctx->bundleTrackers, entry->trackerId, entry); long trackerId = entry->trackerId; - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); if (!async) { //note only using the async callback if this is a async call. entry->opts.trackerCreatedCallback = NULL; @@ -677,7 +677,7 @@ static void bundleContext_cleanupBundleTrackers(bundle_context_t* ctx) { celix_array_list_t* danglingTrkIds = NULL; - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); CELIX_LONG_HASH_MAP_ITERATE(ctx->bundleTrackers, iter) { long trkId = iter.key; fw_log( @@ -691,7 +691,8 @@ static void bundleContext_cleanupBundleTrackers(bundle_context_t* ctx) { } celix_arrayList_addLong(danglingTrkIds, trkId); } - celixThreadMutex_unlock(&ctx->mutex); + celix_longHashMap_clear(ctx->bundleTrackers); + celixThreadRwlock_unlock(&ctx->lock); if (danglingTrkIds != NULL) { for (int i = 0; i < celix_arrayList_size(danglingTrkIds); ++i) { @@ -710,7 +711,7 @@ static void bundleContext_cleanupServiceTrackers(bundle_context_t* ctx) { celix_array_list_t* danglingTrkIds = NULL; - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); CELIX_LONG_HASH_MAP_ITERATE(ctx->serviceTrackers, iter) { long trkId = iter.key; celix_bundle_context_service_tracker_entry_t* entry = celix_longHashMap_get(ctx->serviceTrackers, trkId); @@ -726,7 +727,8 @@ static void bundleContext_cleanupServiceTrackers(bundle_context_t* ctx) { } celix_arrayList_addLong(danglingTrkIds, trkId); } - celixThreadMutex_unlock(&ctx->mutex); + celix_longHashMap_clear(ctx->serviceTrackers); + celixThreadRwlock_unlock(&ctx->lock); if (danglingTrkIds != NULL) { for (int i = 0; i < celix_arrayList_size(danglingTrkIds); ++i) { @@ -745,7 +747,7 @@ static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t* ctx) { celix_array_list_t* danglingTrkIds = NULL; - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); CELIX_LONG_HASH_MAP_ITERATE(ctx->metaTrackers, iter) { long trkId = iter.key; celix_bundle_context_service_tracker_tracker_entry_t* entry = celix_longHashMap_get(ctx->metaTrackers, trkId); @@ -761,7 +763,8 @@ static void bundleContext_cleanupServiceTrackerTrackers(bundle_context_t* ctx) { } celix_arrayList_addLong(danglingTrkIds, trkId); } - celixThreadMutex_unlock(&ctx->mutex); + celix_longHashMap_clear(ctx->metaTrackers); + celixThreadRwlock_unlock(&ctx->lock); if (danglingTrkIds != NULL) { for (int i = 0; i < celix_arrayList_size(danglingTrkIds); ++i) { @@ -780,7 +783,7 @@ static void bundleContext_cleanupServiceRegistration(bundle_context_t* ctx) { celix_array_list_t* danglingSvcIds = NULL; - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); for (int i = 0; i < celix_arrayList_size(ctx->svcRegistrations); ++i) { long svcId = celix_arrayList_getLong(ctx->svcRegistrations, i); fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Dangling service registration with svcId %li, for bundle %s. Add missing 'celix_bundleContext_unregisterService' calls.", svcId, symbolicName); @@ -789,7 +792,8 @@ static void bundleContext_cleanupServiceRegistration(bundle_context_t* ctx) { } celix_arrayList_addLong(danglingSvcIds, svcId); } - celixThreadMutex_unlock(&ctx->mutex); + celix_arrayList_clear(ctx->svcRegistrations); + celixThreadRwlock_unlock(&ctx->lock); if (danglingSvcIds != NULL) { for (int i = 0; i < celix_arrayList_size(danglingSvcIds); ++i) { @@ -803,18 +807,18 @@ static void bundleContext_cleanupServiceRegistration(bundle_context_t* ctx) { static void celix_bundleContext_removeBundleTracker(void *data) { celix_bundle_context_bundle_tracker_entry_t *tracker = data; fw_removeBundleListener(tracker->ctx->framework, tracker->ctx->bundle, &tracker->listener); - celixThreadMutex_lock(&tracker->ctx->mutex); + celixThreadRwlock_writeLock(&tracker->ctx->lock); celix_longHashMap_remove(tracker->ctx->stoppingTrackerEventIds, tracker->trackerId); - celixThreadMutex_unlock(&tracker->ctx->mutex); + celixThreadRwlock_unlock(&tracker->ctx->lock); free(tracker); } static void celix_bundleContext_removeServiceTracker(void *data) { celix_bundle_context_service_tracker_entry_t *tracker = data; celix_serviceTracker_destroy(tracker->tracker); - celixThreadMutex_lock(&tracker->ctx->mutex); + celixThreadRwlock_writeLock(&tracker->ctx->lock); celix_longHashMap_remove(tracker->ctx->stoppingTrackerEventIds, tracker->trackerId); - celixThreadMutex_unlock(&tracker->ctx->mutex); + celixThreadRwlock_unlock(&tracker->ctx->lock); if (tracker->isFreeFilterNeeded) { free((char*)tracker->opts.filter.serviceName); free((char*)tracker->opts.filter.versionRange); @@ -826,9 +830,9 @@ static void celix_bundleContext_removeServiceTracker(void *data) { static void celix_bundleContext_removeServiceTrackerTracker(void *data) { celix_bundle_context_service_tracker_tracker_entry_t *tracker = data; celix_framework_unregister(tracker->ctx->framework, tracker->ctx->bundle, tracker->serviceId); - celixThreadMutex_lock(&tracker->ctx->mutex); + celixThreadRwlock_writeLock(&tracker->ctx->lock); celix_longHashMap_remove(tracker->ctx->stoppingTrackerEventIds, tracker->trackerId); - celixThreadMutex_unlock(&tracker->ctx->mutex); + celixThreadRwlock_unlock(&tracker->ctx->lock); free(tracker->serviceName); free(tracker); } @@ -844,7 +848,7 @@ static void celix_bundleContext_stopTrackerInternal(bundle_context_t *ctx, long celix_bundle_context_service_tracker_entry_t *serviceTracker = NULL; celix_bundle_context_service_tracker_tracker_entry_t *svcTrackerTracker = NULL; - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); if (celix_longHashMap_hasKey(ctx->bundleTrackers, trackerId)) { found = true; @@ -873,10 +877,10 @@ static void celix_bundleContext_stopTrackerInternal(bundle_context_t *ctx, long if (found && cancelled) { //nop - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); } else if (found && !async && celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) { //already on the event loop, stop tracker "traditionally" to keep old behavior - celixThreadMutex_unlock(&ctx->mutex); //note calling remove/stops/unregister out side of locks + celixThreadRwlock_unlock(&ctx->lock); //note calling remove/stops/unregister out side of locks if (bundleTracker != NULL) { fw_removeBundleListener(ctx->framework, ctx->bundle, &bundleTracker->listener); @@ -912,7 +916,7 @@ static void celix_bundleContext_stopTrackerInternal(bundle_context_t *ctx, long } else { fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Unexpected else branch"); } - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); } else if (found) { /*sync, so waiting for events*/ long eventId = -1L; if (bundleTracker != NULL) { @@ -924,10 +928,10 @@ static void celix_bundleContext_stopTrackerInternal(bundle_context_t *ctx, long } else { fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "Unexpected else branch"); } - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); celix_framework_waitForGenericEvent(ctx->framework, eventId); } else { - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); fw_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, "No tracker with id %li found'", trackerId); } } @@ -958,7 +962,7 @@ static void celix_bundleContext_waitForTrackerInternal(celix_bundle_context_t* c long svcId = -1; if (waitForStart) { - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_readLock(&ctx->lock); if (celix_longHashMap_hasKey(ctx->bundleTrackers, trackerId)) { found = true; celix_bundle_context_bundle_tracker_entry_t* bundleTracker = celix_longHashMap_get(ctx->bundleTrackers, trackerId); @@ -972,14 +976,14 @@ static void celix_bundleContext_waitForTrackerInternal(celix_bundle_context_t* c celix_bundle_context_service_tracker_tracker_entry_t* svcTrackerTracker = celix_longHashMap_get(ctx->metaTrackers, trackerId); svcId = svcTrackerTracker->serviceId; } - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); } else { - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_readLock(&ctx->lock); if (celix_longHashMap_hasKey(ctx->stoppingTrackerEventIds, trackerId)) { found = true; eventId = celix_longHashMap_getLong(ctx->stoppingTrackerEventIds, trackerId, -1); } - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); } if (found) { @@ -1241,11 +1245,11 @@ long celix_bundleContext_trackServicesAsync(celix_bundle_context_t* ctx, const c static void celix_bundleContext_createTrackerOnEventLoop(void *data) { celix_bundle_context_service_tracker_entry_t* entry = data; assert(celix_framework_isCurrentThreadTheEventLoop(entry->ctx->framework)); - celixThreadMutex_lock(&entry->ctx->mutex); + celixThreadRwlock_writeLock(&entry->ctx->lock); bool cancelled = entry->cancelled; if (cancelled) { fw_log(entry->ctx->framework->logger, CELIX_LOG_LEVEL_DEBUG, "Creating of service tracker was cancelled. trk id = %li, svc name tracked = %s", entry->trackerId, entry->opts.filter.serviceName); - celixThreadMutex_unlock(&entry->ctx->mutex); + celixThreadRwlock_unlock(&entry->ctx->lock); return; } celix_service_tracker_t *tracker = celix_serviceTracker_createClosedWithOptions(entry->ctx, &entry->opts); @@ -1254,7 +1258,7 @@ static void celix_bundleContext_createTrackerOnEventLoop(void *data) { } else { entry->tracker = tracker; } - celixThreadMutex_unlock(&entry->ctx->mutex); + celixThreadRwlock_unlock(&entry->ctx->lock); if (tracker) { serviceTracker_open(tracker); } @@ -1262,9 +1266,9 @@ static void celix_bundleContext_createTrackerOnEventLoop(void *data) { static void celix_bundleContext_doneCreatingTrackerOnEventLoop(void *data) { celix_bundle_context_service_tracker_entry_t* entry = data; - celixThreadMutex_lock(&entry->ctx->mutex); + celixThreadRwlock_readLock(&entry->ctx->lock); bool cancelled = entry->cancelled; - celixThreadMutex_unlock(&entry->ctx->mutex); + celixThreadRwlock_unlock(&entry->ctx->lock); if (cancelled) { //tracker creation cancelled -> entry already removed from map, but memory needs to be freed. if (entry->isFreeFilterNeeded) { @@ -1303,11 +1307,11 @@ static long celix_bundleContext_trackServicesWithOptionsInternal(celix_bundle_co entry->opts = *opts; entry->isFreeFilterNeeded = false; entry->createEventId = -1; - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); entry->trackerId = ctx->nextTrackerId++; trackerId = entry->trackerId; celix_longHashMap_put(ctx->serviceTrackers, trackerId, entry); - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); } return trackerId; } else { @@ -1329,11 +1333,11 @@ static long celix_bundleContext_trackServicesWithOptionsInternal(celix_bundle_co entry->opts.filter.filter = celix_utils_strdup(opts->filter.filter); } - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); entry->trackerId = ctx->nextTrackerId++; long trackerId = entry->trackerId; celix_longHashMap_put(ctx->serviceTrackers, entry->trackerId, entry); - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); long id = celix_framework_fireGenericEvent(ctx->framework, createEventId, @@ -1416,7 +1420,7 @@ static size_t celix_bundleContext_useTrackedServiceWithOptionsInternal(celix_bun long trackerId, const celix_tracked_service_use_options_t* opts, bool singleUse) { - celix_auto(celix_mutex_lock_guard_t) lck = celixMutexLockGuard_init(&ctx->mutex); + celix_auto(celix_rwlock_rlock_guard_t) lck = celixRwlockRlockGuard_init(&ctx->lock); celix_service_tracker_t* trk = celix_bundleContext_findServiceTracker(ctx, trackerId); if (!trk) { return 0; @@ -1425,7 +1429,7 @@ static size_t celix_bundleContext_useTrackedServiceWithOptionsInternal(celix_bun if (singleUse) { bool called = celix_serviceTracker_useHighestRankingService(trk, NULL, - opts->waitTimeoutInSeconds, + 0, opts->callbackHandle, opts->use, opts->useWithProperties, @@ -1460,7 +1464,7 @@ void celix_bundleContext_getTrackerInfo(celix_bundle_context_t *ctx, long tracke *trackedServiceFilter = NULL; } - celix_auto(celix_mutex_lock_guard_t) lck = celixMutexLockGuard_init(&ctx->mutex); + celix_auto(celix_rwlock_rlock_guard_t) lck = celixRwlockRlockGuard_init(&ctx->lock); celix_service_tracker_t* trk = celix_bundleContext_findServiceTracker(ctx, trackerId); if (!trk) { return; @@ -1496,7 +1500,7 @@ const char* celix_bundleContext_getTrackedServiceFilter(celix_bundle_context_t* } bool celix_bundleContext_isValidTrackerId(celix_bundle_context_t* ctx, long trackerId) { - celix_auto(celix_mutex_lock_guard_t) lck = celixMutexLockGuard_init(&ctx->mutex); + celix_auto(celix_rwlock_rlock_guard_t) lck = celixRwlockRlockGuard_init(&ctx->lock); return celix_longHashMap_hasKey(ctx->serviceTrackers, trackerId); } @@ -1590,9 +1594,9 @@ long celix_bundleContext_trackServiceTrackersInternal( } celix_bundle_context_service_tracker_tracker_entry_t *entry = calloc(1, sizeof(*entry)); - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); entry->trackerId = ctx->nextTrackerId++; - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); entry->ctx = ctx; entry->callbackHandle = callbackHandle; entry->add = trackerAdd; @@ -1615,10 +1619,10 @@ long celix_bundleContext_trackServiceTrackersInternal( } if (entry->serviceId >= 0) { - celixThreadMutex_lock(&ctx->mutex); + celixThreadRwlock_writeLock(&ctx->lock); celix_longHashMap_put(ctx->metaTrackers, entry->trackerId, entry); long trkId = entry->trackerId; - celixThreadMutex_unlock(&ctx->mutex); + celixThreadRwlock_unlock(&ctx->lock); return trkId; } else { celix_framework_log(ctx->framework->logger, CELIX_LOG_LEVEL_ERROR, __FUNCTION__, __BASE_FILE__, __LINE__, "Error registering service listener hook for service tracker tracker\n"); diff --git a/libs/framework/src/bundle_context_private.h b/libs/framework/src/bundle_context_private.h index 1eacc48ba..5fe106016 100644 --- a/libs/framework/src/bundle_context_private.h +++ b/libs/framework/src/bundle_context_private.h @@ -81,8 +81,8 @@ struct celix_bundle_context { celix_framework_t* framework; celix_bundle_t* bundle; - celix_thread_mutex_t - mutex; // protects fields below (NOTE/FIXME also used by bundle.c for listing service tracker usage) + celix_thread_rwlock_t + lock; // protects fields below celix_array_list_t* svcRegistrations; // serviceIds celix_dependency_manager_t* mng; long nextTrackerId;