PengZheng commented on code in PR #729: URL: https://github.com/apache/celix/pull/729#discussion_r1497282812
########## libs/framework/src/service_tracker.c: ########## @@ -817,4 +816,19 @@ size_t celix_serviceTracker_useServices( tracked_release(entry); } return count; -} \ No newline at end of file +} + +size_t celix_serviceTracker_getTrackedServiceCount(celix_service_tracker_t *tracker) { + celix_auto(celix_mutex_lock_guard_t) lck = celixMutexLockGuard_init(&tracker->mutex); + return (size_t) celix_arrayList_size(tracker->trackedServices); +} + +const char* celix_serviceTracker_getTrackedServiceName(celix_service_tracker_t *tracker) { + celix_auto(celix_mutex_lock_guard_t) lck = celixMutexLockGuard_init(&tracker->mutex); + return tracker->serviceName; Review Comment: No need to lock a class invariant, i.e. unchanged during lifetime. ########## libs/framework/include/celix_bundle_context.h: ########## @@ -393,50 +388,218 @@ CELIX_FRAMEWORK_EXPORT long celix_bundleContext_findServiceWithOptions(celix_bun CELIX_FRAMEWORK_EXPORT celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts); /** - * @brief Track the highest ranking service with the provided serviceName. + * @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. + * + * 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. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @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 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( Review Comment: Considering nearly all of these useService(s)(withOptions) are impractical to use in production (causing various performance/deaklock issues), should they be marked as deprecated or removed? ########## libs/framework/include/celix_bundle_context.h: ########## @@ -393,50 +388,218 @@ CELIX_FRAMEWORK_EXPORT long celix_bundleContext_findServiceWithOptions(celix_bun CELIX_FRAMEWORK_EXPORT celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts); /** - * @brief Track the highest ranking service with the provided serviceName. + * @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. + * + * 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. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @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 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) +); + +/** + * @brief Use the highest ranking service with the provided service name using the provided callback. + * + * 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. + * If no service is found, the callback will not be invoked and this function will return false immediately. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @param ctx The bundle context + * @param serviceName the required service name. + * @param callbackHandle The data pointer, which will be used in the callbacks + * @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_bundle_context_t *ctx, + const char* serviceName, + void *callbackHandle, + void (*use)(void *handle, void *svc) +); + +/** + * @brief Use the services with the provided service name using the provided callback. + * + * 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. + * If no service is found, the callback will not be invoked and this function will return 0 immediately. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @param ctx The bundle context + * @param serviceName the required service name. + * @param callbackHandle The data pointer, which will be used in the callbacks + * @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_bundle_context_t *ctx, + const char* serviceName, + void *callbackHandle, + void (*use)(void *handle, void *svc) +); + +/** + * @brief Service Use Options used to fine tune which services to use and which callbacks to use. + * + * If multiple use callbacks are set, all set callbacks will be called for every service found. + */ +typedef struct celix_service_use_options { + /** + * @brief The service filter options, used to setup the filter for the service to track. + */ + celix_service_filter_options_t filter CELIX_OPTS_INIT; + + /** + * @brief An optional timeout (in seconds), if > 0 the use service 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) + * + * Only applicable when using the celix_bundleContext_useService or + * celix_bundleContext_useServiceWithOptions (use single service calls). + */ + 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; + + /** + * @brief The optional use callback will be called when for every services found conform the service filter options + * - in case of findServices - or only for the highest ranking service found - in case of findService -. + * + * @param handle The callbackHandle pointer as provided in the service tracker options. + * @param svc The service pointer of the highest ranking service. + */ + void (*use)(void* handle, void* svc) CELIX_OPTS_INIT; + + /** + * @brief The optional useWithProperties callback is handled as the use callback, but with the addition that the + * service properties will also be provided to the callback. + */ + void (*useWithProperties)(void* handle, void* svc, const celix_properties_t* props) CELIX_OPTS_INIT; + + /** + * @brief The optional useWithOwner callback is handled as the yse callback, but with the addition that the service + * properties and the bundle owning the service will also be provided to the callback. + */ + void (*useWithOwner)(void* handle, void* svc, const celix_properties_t* props, const celix_bundle_t* svcOwner) + CELIX_OPTS_INIT; + /** + * @brief Call the provided callbacks from the caller thread directly if set, otherwise the callbacks will be called + * from the Celix event loop (most likely indirectly). Note that using blocking service in the Celix event loop is + * generally a bad idea, which should be avoided if possible. + */ +#define CELIX_SERVICE_USE_DIRECT (1) + /** + * @brief Whether "service on demand" pattern is supported when CELIX_SERVICE_USE_DIRECT is set. + * Note that it has no effect in indirect mode, in which case "service on demand" is supported. + */ +#define CELIX_SERVICE_USE_SOD (2) + int flags CELIX_OPTS_INIT; +} celix_service_use_options_t; + +#ifndef __cplusplus +/*! + * @brief C Macro to create a empty celix_service_use_options_t type. + */ +#define CELIX_EMPTY_SERVICE_USE_OPTIONS {.filter.serviceName = NULL, \ + .filter.versionRange = NULL, \ + .filter.filter = NULL, \ + .waitTimeoutInSeconds = 0.0F, \ + .callbackHandle = NULL, \ + .use = NULL, \ + .useWithProperties = NULL, \ + .useWithOwner = NULL, \ + .flags=0} +#endif + +/** + * @brief Use the highest ranking service satisfying the provided service filter options using the provided callback. + * + * The Celix framework will ensure that the targeted service cannot be removed during the callback. * - * The highest ranking services will used for the callback. - * If a new and higher ranking services the callback with be called again with the new service. - * If a service is removed a the callback with be called with next highest ranking service or NULL as service. + * The svc is should only be considered valid during the callback. + * If no service is found the callback will not be invoked. In such cases, if a non-zero waitTimeoutInSeconds is specified in opts, + * this function will block until the timeout is expired or when at least one service is found, otherwise it will return false immediately. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @param ctx The bundle context. + * @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_bundle_context_t *ctx, + const celix_service_use_options_t *opts); + + +/** + * @brief Use the services with the provided service filter options using the provided callback. + * + * 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. + * If no service is found, the callback will not be invoked and this function will return 0 immediately. + * Note that waitTimeoutInSeconds in opts has no effect. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @param ctx The bundle context. + * @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_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. - * @param callbackHandle The data pointer, which will be used in the callbacks - * @param set is a required callback, which will be called when a new highest ranking service is set. * @return the tracker id (>=0) or < 0 if unsuccessful. */ -CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServiceAsync( - celix_bundle_context_t *ctx, - const char* serviceName, - void* callbackHandle, - void (*set)(void* handle, void* svc) -); +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. + * @brief Track the highest ranking service with the provided serviceName Review Comment: It is not true, since a tracker always tracks services rather than a single one. Thus, `celix_bundleContext_trackService` does not really make sense. ########## libs/framework/include/celix_bundle_context.h: ########## @@ -615,236 +761,290 @@ CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServicesWithOptionsAsync(ce * The tracker options are only using during this call and can safely be freed/reused after this call returns. * Note: Please use the celix_bundleContext_registerServiceFactoryAsync instead. * - * * @param ctx The bundle context. * @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); /** - * @brief Stop the tracker with the provided track id. + * @brief Use the highest ranking service, tracked by the provided tracker id, using the provided callback. * - * Could be a service tracker, bundle tracker or service tracker tracker. - * Only works for the trackers owned by the bundle of the bundle context. + * 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 service tracker will be destroyed async on the Celix event loop thread. This means that the function can return - * before the tracker is destroyed. - * - * if the doneCallback is not NULL, this will be called when the destruction of the service tracker is done. - * (will be called on the event loop thread). - * - * Will log a error if the provided tracker id is unknown. Will silently ignore trackerId < 0. - */ -CELIX_FRAMEWORK_EXPORT void celix_bundleContext_stopTrackerAsync( - celix_bundle_context_t *ctx, - long trackerId, - void *doneCallbackData, - void (*doneCallback)(void* doneCallbackData)); - -/** - * @brief Wait for (async) creation of tracker - */ -CELIX_FRAMEWORK_EXPORT void celix_bundleContext_waitForAsyncTracker(celix_bundle_context_t *ctx, long trackerId); - -/** - * @brief Wait for (async) stopping of tracking. - */ -CELIX_FRAMEWORK_EXPORT void celix_bundleContext_waitForAsyncStopTracker(celix_bundle_context_t *ctx, long trackerId); - -/** - * @brief Stop the tracker with the provided track id. + * An tracker id < 0 will be silently ignored. + * An invalid (non existing) tracker id >= 0 will be logged and the function will return false. * - * 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. - * - * Will log a error if the provided tracker id is unknown. Will silently ignore trackerId < 0. - */ -CELIX_FRAMEWORK_EXPORT void celix_bundleContext_stopTracker(celix_bundle_context_t *ctx, long trackerId); - -/** - * @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. - * - * 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. - * - * This function will block until the callback is finished. As result it is possible to provide callback data from the - * stack. - * - * @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 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) -); - -/** - * @brief Use the highest ranking service with the provided service name using the provided callback. - * - * 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. - * If no service is found, the callback will not be invoked and this function will return false immediately. - * - * This function will block until the callback is finished. As result it is possible to provide callback data from the - * stack. - * - * @param ctx The bundle context - * @param serviceName the required service name. - * @param callbackHandle The data pointer, which will be used in the callbacks - * @param use The callback, which will be called when service is retrieved. - * @return True if a service was found. + * @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). */ -CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useService( - celix_bundle_context_t *ctx, - const char* serviceName, - void *callbackHandle, - void (*use)(void *handle, void *svc) -); +CELIX_FRAMEWORK_EXPORT +bool celix_bundleContext_useTrackedService(celix_bundle_context_t* ctx, + long trackerId, + void* callbackHandle, + void (*use)(void* handle, void* svc)); /** - * @brief Use the services with the provided service name using the provided callback. + * @brief Use the services, tracked by the provided tracker id, using the provided callback. * - * The Celix framework will ensure that the targeted service cannot be removed during the 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 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 0 immediately. + * An tracker id < 0 will be silently ignored. + * An invalid (non existing) tracker id >= 0 will be logged and the function will return 0. * - * This function will block until the callback is finished. As result it is possible to provide callback data from the - * stack. - * - * @param ctx The bundle context - * @param serviceName the required service name. - * @param callbackHandle The data pointer, which will be used in the callbacks - * @param use The callback, which will be called for every service found. - * @return The number of services found and called + * @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). */ -CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useServices( - celix_bundle_context_t *ctx, - const char* serviceName, - void *callbackHandle, - void (*use)(void *handle, void *svc) -); +CELIX_FRAMEWORK_EXPORT +size_t celix_bundleContext_useTrackedServices(celix_bundle_context_t* ctx, + long trackerId, + void* callbackHandle, + void (*use)(void* handle, void* svc)); /** - * @brief Service Use Options used to fine tune which services to use and which callbacks to use. + * @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. */ -typedef struct celix_service_use_options { +typedef struct celix_tracked_service_use_options { /** - * @brief The service filter options, used to setup the filter for the service to track. - */ - celix_service_filter_options_t filter CELIX_OPTS_INIT; - - /** - * @brief An optional timeout (in seconds), if > 0 the use service 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. + * @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) + * + * Only applicable when using the celix_bundleContext_useTrackedService or + * celix_bundleContext_useTrackedServiceWithOptions (use single service calls). */ - double waitTimeoutInSeconds CELIX_OPTS_INIT; + double waitTimeoutInSeconds 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 (use, useWithProperties and useWithOwner). */ void *callbackHandle CELIX_OPTS_INIT; /** - * @brief The optional use callback will be called when for every services found conform the service filter options - * - in case of findServices - or only for the highest ranking service found - in case of findService -. + * @brief The optional use callback will be called when for every service tracked. * * @param handle The callbackHandle pointer as provided in the service tracker options. * @param svc The service pointer of the highest ranking service. */ void (*use)(void *handle, void *svc) CELIX_OPTS_INIT; /** - * @brief The optional useWithProperties callback is handled as the use callback, but with the addition that the service properties - * will also be provided to the callback. + * @brief The optional useWithProperties callback will be called when for every service tracked and the + * service properties will also be provided to the callback. */ void (*useWithProperties)(void *handle, void *svc, const celix_properties_t *props) CELIX_OPTS_INIT; /** - * @brief The optional useWithOwner callback is handled as the yse 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 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. */ void (*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) CELIX_OPTS_INIT; - /** - * @brief Call the provided callbacks from the caller thread directly if set, otherwise the callbacks will be called from the Celix event loop (most likely indirectly). - * Note that using blocking service in the Celix event loop is generally a bad idea, which should be avoided if possible. - */ -#define CELIX_SERVICE_USE_DIRECT (1) - /** - * @brief Whether "service on demand" pattern is supported when CELIX_SERVICE_USE_DIRECT is set. - * Note that it has no effect in indirect mode, in which case "service on demand" is supported. - */ -#define CELIX_SERVICE_USE_SOD (2) - int flags CELIX_OPTS_INIT; -} celix_service_use_options_t; +} celix_tracked_service_use_options_t; #ifndef __cplusplus /*! - * @brief C Macro to create a empty celix_service_use_options_t type. + * @brief C Macro to create a empty celix_tracked_service_use_options_t type. */ -#define CELIX_EMPTY_SERVICE_USE_OPTIONS {.filter.serviceName = NULL, \ - .filter.versionRange = NULL, \ - .filter.filter = NULL, \ - .waitTimeoutInSeconds = 0.0F, \ - .callbackHandle = NULL, \ - .use = NULL, \ - .useWithProperties = NULL, \ - .useWithOwner = NULL, \ - .flags=0} +#define CELIX_EMPTY_TRACKER_SERVICE_USE_OPTIONS \ + { \ + .waitTimeoutInSeconds = 0.0F, .callbackHandle = NULL, .use = NULL, .useWithProperties = NULL, \ + .useWithOwner = NULL \ + } #endif /** - * @brief Use the highest ranking service satisfying the provided service filter options using the provided callback. + * @brief Use the highest ranking service, tracked by the provided tracker id, using the callbacks in the provided + * options. * - * The Celix framework will ensure that the targeted service cannot be removed during the callback. + * 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. * - * The svc is should only be considered valid during the callback. - * If no service is found the callback will not be invoked. In such cases, if a non-zero waitTimeoutInSeconds is specified in opts, - * this function will block until the timeout is expired or when at least one service is found, otherwise it will return false immediately. + * An tracker id < 0 will be silently ignored. + * An invalid (non existing) tracker id >= 0 will be logged and the function will return false. * - * This function will block until the callback is finished. As result it is possible to provide callback data from the - * stack. + * @note the field USE_DIRECT in the provided options has no effect with this function. Review Comment: We dont't have `USE_DIRECT` in options. This also applies to `celix_bundleContext_useTrackedServicesWithOptions`. ########## libs/framework/src/bundle_context_private.h: ########## @@ -46,47 +48,50 @@ typedef struct celix_bundle_context_bundle_tracker_entry { } celix_bundle_context_bundle_tracker_entry_t; typedef struct celix_bundle_context_service_tracker_entry { - celix_bundle_context_t *ctx; - long trackerId; + celix_bundle_context_t* ctx; + long trackerId; celix_service_tracking_options_t opts; - celix_service_tracker_t* tracker; - void *trackerCreatedCallbackData; - void (*trackerCreatedCallback)(void *trackerCreatedCallbackData); + celix_service_tracker_t* tracker; + void* trackerCreatedCallbackData; + void (*trackerCreatedCallback)(void* trackerCreatedCallbackData); bool isFreeFilterNeeded; - //used for sync + // used for sync long createEventId; - bool cancelled; //if tracker is stopped before created async + bool cancelled; // if tracker is stopped before created async } celix_bundle_context_service_tracker_entry_t; typedef struct celix_bundle_context_service_tracker_tracker_entry { - celix_bundle_context_t* ctx; - long trackerId; + celix_bundle_context_t* ctx; + long trackerId; - struct listener_hook_service hook; - long serviceId; + struct listener_hook_service hook; + long serviceId; - char *serviceName; - void *callbackHandle; - void (*add)(void *handle, const celix_service_tracker_info_t *info); - void (*remove)(void *handle, const celix_service_tracker_info_t *info); + char* serviceName; + void* callbackHandle; + void (*add)(void* handle, const celix_service_tracker_info_t* info); + void (*remove)(void* handle, const celix_service_tracker_info_t* info); - //used for sync + // used for sync long createEventId; } celix_bundle_context_service_tracker_tracker_entry_t; 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_array_list_t *svcRegistrations; //serviceIds - celix_dependency_manager_t *mng; - long nextTrackerId; - hash_map_t *bundleTrackers; //key = trackerId, value = celix_bundle_context_bundle_tracker_entry_t* - hash_map_t *serviceTrackers; //key = trackerId, value = celix_bundle_context_service_tracker_entry_t* - hash_map_t *metaTrackers; //key = trackerId, value = celix_bundle_context_service_tracker_tracker_entry_t* - hash_map_t *stoppingTrackerEventIds; //key = trackerId, value = eventId for stopping the tracker. Note id are only present if the stop tracking is queued. + 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) Review Comment: I believe `mutex` should be `celix_thread_rwlock_t` for two reasons: * Avoid deadlock in use callback if a service calls another service via useTrackedService. * Avoid unnecessary lock contention. Suppose we have a large legacy application (Big Mud Ball), which communicates with the modular part (Celix) within the same application via the single system bundle context, there will be intense lock contention. ########## libs/framework/src/service_tracker.c: ########## @@ -817,4 +816,19 @@ size_t celix_serviceTracker_useServices( tracked_release(entry); } return count; -} \ No newline at end of file +} + +size_t celix_serviceTracker_getTrackedServiceCount(celix_service_tracker_t *tracker) { + celix_auto(celix_mutex_lock_guard_t) lck = celixMutexLockGuard_init(&tracker->mutex); + return (size_t) celix_arrayList_size(tracker->trackedServices); +} + +const char* celix_serviceTracker_getTrackedServiceName(celix_service_tracker_t *tracker) { + celix_auto(celix_mutex_lock_guard_t) lck = celixMutexLockGuard_init(&tracker->mutex); + return tracker->serviceName; +} + +const char* celix_serviceTracker_getTrackedServiceFilter(celix_service_tracker_t *tracker) { + celix_auto(celix_mutex_lock_guard_t) lck = celixMutexLockGuard_init(&tracker->mutex); + return tracker->filter; Review Comment: No need to lock a class invariant. ########## libs/framework/include/celix_bundle_context.h: ########## @@ -393,50 +388,218 @@ CELIX_FRAMEWORK_EXPORT long celix_bundleContext_findServiceWithOptions(celix_bun CELIX_FRAMEWORK_EXPORT celix_array_list_t* celix_bundleContext_findServicesWithOptions(celix_bundle_context_t *ctx, const celix_service_filter_options_t *opts); /** - * @brief Track the highest ranking service with the provided serviceName. + * @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. + * + * 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. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @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 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) +); + +/** + * @brief Use the highest ranking service with the provided service name using the provided callback. + * + * 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. + * If no service is found, the callback will not be invoked and this function will return false immediately. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @param ctx The bundle context + * @param serviceName the required service name. + * @param callbackHandle The data pointer, which will be used in the callbacks + * @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_bundle_context_t *ctx, + const char* serviceName, + void *callbackHandle, + void (*use)(void *handle, void *svc) +); + +/** + * @brief Use the services with the provided service name using the provided callback. + * + * 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. + * If no service is found, the callback will not be invoked and this function will return 0 immediately. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @param ctx The bundle context + * @param serviceName the required service name. + * @param callbackHandle The data pointer, which will be used in the callbacks + * @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_bundle_context_t *ctx, + const char* serviceName, + void *callbackHandle, + void (*use)(void *handle, void *svc) +); + +/** + * @brief Service Use Options used to fine tune which services to use and which callbacks to use. + * + * If multiple use callbacks are set, all set callbacks will be called for every service found. + */ +typedef struct celix_service_use_options { + /** + * @brief The service filter options, used to setup the filter for the service to track. + */ + celix_service_filter_options_t filter CELIX_OPTS_INIT; + + /** + * @brief An optional timeout (in seconds), if > 0 the use service 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) + * + * Only applicable when using the celix_bundleContext_useService or + * celix_bundleContext_useServiceWithOptions (use single service calls). + */ + 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; + + /** + * @brief The optional use callback will be called when for every services found conform the service filter options + * - in case of findServices - or only for the highest ranking service found - in case of findService -. + * + * @param handle The callbackHandle pointer as provided in the service tracker options. + * @param svc The service pointer of the highest ranking service. + */ + void (*use)(void* handle, void* svc) CELIX_OPTS_INIT; + + /** + * @brief The optional useWithProperties callback is handled as the use callback, but with the addition that the + * service properties will also be provided to the callback. + */ + void (*useWithProperties)(void* handle, void* svc, const celix_properties_t* props) CELIX_OPTS_INIT; + + /** + * @brief The optional useWithOwner callback is handled as the yse callback, but with the addition that the service + * properties and the bundle owning the service will also be provided to the callback. + */ + void (*useWithOwner)(void* handle, void* svc, const celix_properties_t* props, const celix_bundle_t* svcOwner) + CELIX_OPTS_INIT; + /** + * @brief Call the provided callbacks from the caller thread directly if set, otherwise the callbacks will be called + * from the Celix event loop (most likely indirectly). Note that using blocking service in the Celix event loop is + * generally a bad idea, which should be avoided if possible. + */ +#define CELIX_SERVICE_USE_DIRECT (1) + /** + * @brief Whether "service on demand" pattern is supported when CELIX_SERVICE_USE_DIRECT is set. + * Note that it has no effect in indirect mode, in which case "service on demand" is supported. + */ +#define CELIX_SERVICE_USE_SOD (2) + int flags CELIX_OPTS_INIT; +} celix_service_use_options_t; + +#ifndef __cplusplus +/*! + * @brief C Macro to create a empty celix_service_use_options_t type. + */ +#define CELIX_EMPTY_SERVICE_USE_OPTIONS {.filter.serviceName = NULL, \ + .filter.versionRange = NULL, \ + .filter.filter = NULL, \ + .waitTimeoutInSeconds = 0.0F, \ + .callbackHandle = NULL, \ + .use = NULL, \ + .useWithProperties = NULL, \ + .useWithOwner = NULL, \ + .flags=0} +#endif + +/** + * @brief Use the highest ranking service satisfying the provided service filter options using the provided callback. + * + * The Celix framework will ensure that the targeted service cannot be removed during the callback. * - * The highest ranking services will used for the callback. - * If a new and higher ranking services the callback with be called again with the new service. - * If a service is removed a the callback with be called with next highest ranking service or NULL as service. + * The svc is should only be considered valid during the callback. + * If no service is found the callback will not be invoked. In such cases, if a non-zero waitTimeoutInSeconds is specified in opts, + * this function will block until the timeout is expired or when at least one service is found, otherwise it will return false immediately. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @param ctx The bundle context. + * @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_bundle_context_t *ctx, + const celix_service_use_options_t *opts); + + +/** + * @brief Use the services with the provided service filter options using the provided callback. + * + * 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. + * If no service is found, the callback will not be invoked and this function will return 0 immediately. + * Note that waitTimeoutInSeconds in opts has no effect. + * + * This function will block until the callback is finished. As result it is possible to provide callback data from the + * stack. + * + * @param ctx The bundle context. + * @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_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. - * @param callbackHandle The data pointer, which will be used in the callbacks - * @param set is a required callback, which will be called when a new highest ranking service is set. * @return the tracker id (>=0) or < 0 if unsuccessful. */ -CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServiceAsync( - celix_bundle_context_t *ctx, - const char* serviceName, - void* callbackHandle, - void (*set)(void* handle, void* svc) -); +CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServiceAsync(celix_bundle_context_t* ctx, const char* serviceName); Review Comment: It seems that `celix_bundleContext_trackServiceAsync` is identical to `celix_bundleContext_trackServicesAsync` and that `celix_bundleContext_trackServices` is identical to `celix_bundleContext_trackService`. We only need to plural form APIs, which have clearer semantics. ########## libs/framework/include/celix_bundle_context.h: ########## @@ -615,236 +761,290 @@ CELIX_FRAMEWORK_EXPORT long celix_bundleContext_trackServicesWithOptionsAsync(ce * The tracker options are only using during this call and can safely be freed/reused after this call returns. * Note: Please use the celix_bundleContext_registerServiceFactoryAsync instead. * - * * @param ctx The bundle context. * @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); /** - * @brief Stop the tracker with the provided track id. + * @brief Use the highest ranking service, tracked by the provided tracker id, using the provided callback. * - * Could be a service tracker, bundle tracker or service tracker tracker. - * Only works for the trackers owned by the bundle of the bundle context. + * 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 service tracker will be destroyed async on the Celix event loop thread. This means that the function can return - * before the tracker is destroyed. - * - * if the doneCallback is not NULL, this will be called when the destruction of the service tracker is done. - * (will be called on the event loop thread). - * - * Will log a error if the provided tracker id is unknown. Will silently ignore trackerId < 0. - */ -CELIX_FRAMEWORK_EXPORT void celix_bundleContext_stopTrackerAsync( - celix_bundle_context_t *ctx, - long trackerId, - void *doneCallbackData, - void (*doneCallback)(void* doneCallbackData)); - -/** - * @brief Wait for (async) creation of tracker - */ -CELIX_FRAMEWORK_EXPORT void celix_bundleContext_waitForAsyncTracker(celix_bundle_context_t *ctx, long trackerId); - -/** - * @brief Wait for (async) stopping of tracking. - */ -CELIX_FRAMEWORK_EXPORT void celix_bundleContext_waitForAsyncStopTracker(celix_bundle_context_t *ctx, long trackerId); - -/** - * @brief Stop the tracker with the provided track id. + * An tracker id < 0 will be silently ignored. + * An invalid (non existing) tracker id >= 0 will be logged and the function will return false. * - * 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. - * - * Will log a error if the provided tracker id is unknown. Will silently ignore trackerId < 0. - */ -CELIX_FRAMEWORK_EXPORT void celix_bundleContext_stopTracker(celix_bundle_context_t *ctx, long trackerId); - -/** - * @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. - * - * 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. - * - * This function will block until the callback is finished. As result it is possible to provide callback data from the - * stack. - * - * @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 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) -); - -/** - * @brief Use the highest ranking service with the provided service name using the provided callback. - * - * 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. - * If no service is found, the callback will not be invoked and this function will return false immediately. - * - * This function will block until the callback is finished. As result it is possible to provide callback data from the - * stack. - * - * @param ctx The bundle context - * @param serviceName the required service name. - * @param callbackHandle The data pointer, which will be used in the callbacks - * @param use The callback, which will be called when service is retrieved. - * @return True if a service was found. + * @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). */ -CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useService( - celix_bundle_context_t *ctx, - const char* serviceName, - void *callbackHandle, - void (*use)(void *handle, void *svc) -); +CELIX_FRAMEWORK_EXPORT +bool celix_bundleContext_useTrackedService(celix_bundle_context_t* ctx, + long trackerId, + void* callbackHandle, + void (*use)(void* handle, void* svc)); /** - * @brief Use the services with the provided service name using the provided callback. + * @brief Use the services, tracked by the provided tracker id, using the provided callback. * - * The Celix framework will ensure that the targeted service cannot be removed during the 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 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 0 immediately. + * An tracker id < 0 will be silently ignored. + * An invalid (non existing) tracker id >= 0 will be logged and the function will return 0. * - * This function will block until the callback is finished. As result it is possible to provide callback data from the - * stack. - * - * @param ctx The bundle context - * @param serviceName the required service name. - * @param callbackHandle The data pointer, which will be used in the callbacks - * @param use The callback, which will be called for every service found. - * @return The number of services found and called + * @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). */ -CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useServices( - celix_bundle_context_t *ctx, - const char* serviceName, - void *callbackHandle, - void (*use)(void *handle, void *svc) -); +CELIX_FRAMEWORK_EXPORT +size_t celix_bundleContext_useTrackedServices(celix_bundle_context_t* ctx, + long trackerId, + void* callbackHandle, + void (*use)(void* handle, void* svc)); /** - * @brief Service Use Options used to fine tune which services to use and which callbacks to use. + * @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. */ -typedef struct celix_service_use_options { +typedef struct celix_tracked_service_use_options { /** - * @brief The service filter options, used to setup the filter for the service to track. - */ - celix_service_filter_options_t filter CELIX_OPTS_INIT; - - /** - * @brief An optional timeout (in seconds), if > 0 the use service 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. + * @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) + * + * Only applicable when using the celix_bundleContext_useTrackedService or + * celix_bundleContext_useTrackedServiceWithOptions (use single service calls). */ - double waitTimeoutInSeconds CELIX_OPTS_INIT; + double waitTimeoutInSeconds 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 (use, useWithProperties and useWithOwner). */ void *callbackHandle CELIX_OPTS_INIT; /** - * @brief The optional use callback will be called when for every services found conform the service filter options - * - in case of findServices - or only for the highest ranking service found - in case of findService -. + * @brief The optional use callback will be called when for every service tracked. * * @param handle The callbackHandle pointer as provided in the service tracker options. * @param svc The service pointer of the highest ranking service. */ void (*use)(void *handle, void *svc) CELIX_OPTS_INIT; /** - * @brief The optional useWithProperties callback is handled as the use callback, but with the addition that the service properties - * will also be provided to the callback. + * @brief The optional useWithProperties callback will be called when for every service tracked and the + * service properties will also be provided to the callback. */ void (*useWithProperties)(void *handle, void *svc, const celix_properties_t *props) CELIX_OPTS_INIT; /** - * @brief The optional useWithOwner callback is handled as the yse 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 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. */ void (*useWithOwner)(void *handle, void *svc, const celix_properties_t *props, const celix_bundle_t *svcOwner) CELIX_OPTS_INIT; - /** - * @brief Call the provided callbacks from the caller thread directly if set, otherwise the callbacks will be called from the Celix event loop (most likely indirectly). - * Note that using blocking service in the Celix event loop is generally a bad idea, which should be avoided if possible. - */ -#define CELIX_SERVICE_USE_DIRECT (1) - /** - * @brief Whether "service on demand" pattern is supported when CELIX_SERVICE_USE_DIRECT is set. - * Note that it has no effect in indirect mode, in which case "service on demand" is supported. - */ -#define CELIX_SERVICE_USE_SOD (2) - int flags CELIX_OPTS_INIT; -} celix_service_use_options_t; +} celix_tracked_service_use_options_t; #ifndef __cplusplus /*! - * @brief C Macro to create a empty celix_service_use_options_t type. + * @brief C Macro to create a empty celix_tracked_service_use_options_t type. */ -#define CELIX_EMPTY_SERVICE_USE_OPTIONS {.filter.serviceName = NULL, \ - .filter.versionRange = NULL, \ - .filter.filter = NULL, \ - .waitTimeoutInSeconds = 0.0F, \ - .callbackHandle = NULL, \ - .use = NULL, \ - .useWithProperties = NULL, \ - .useWithOwner = NULL, \ - .flags=0} +#define CELIX_EMPTY_TRACKER_SERVICE_USE_OPTIONS \ + { \ + .waitTimeoutInSeconds = 0.0F, .callbackHandle = NULL, .use = NULL, .useWithProperties = NULL, \ + .useWithOwner = NULL \ + } #endif /** - * @brief Use the highest ranking service satisfying the provided service filter options using the provided callback. + * @brief Use the highest ranking service, tracked by the provided tracker id, using the callbacks in the provided + * options. * - * The Celix framework will ensure that the targeted service cannot be removed during the callback. + * 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. * - * The svc is should only be considered valid during the callback. - * If no service is found the callback will not be invoked. In such cases, if a non-zero waitTimeoutInSeconds is specified in opts, - * this function will block until the timeout is expired or when at least one service is found, otherwise it will return false immediately. + * An tracker id < 0 will be silently ignored. + * An invalid (non existing) tracker id >= 0 will be logged and the function will return false. * - * This function will block until the callback is finished. As result it is possible to provide callback data from the - * stack. + * @note the field USE_DIRECT in the provided options has no effect with this function. * - * @param ctx The bundle context. - * @param opts The required options. Note that the serviceName is required. - * @return True if a service was found. + * @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). */ -CELIX_FRAMEWORK_EXPORT bool celix_bundleContext_useServiceWithOptions( - celix_bundle_context_t *ctx, - const celix_service_use_options_t *opts); +CELIX_FRAMEWORK_EXPORT +bool celix_bundleContext_useTrackedServiceWithOptions(celix_bundle_context_t* ctx, + long trackerId, + 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. + * + * An tracker id < 0 will be silently ignored. + * An invalid (non existing) tracker id >= 0 will be logged and the function will return 0. + * + * @note the field USE_DIRECT in the provided options has no effect with this function. + * + * @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). + */ +CELIX_FRAMEWORK_EXPORT +size_t celix_bundleContext_useTrackedServicesWithOptions(celix_bundle_context_t* ctx, + long trackerId, + const celix_tracked_service_use_options_t* opts); /** - * @brief Use the services with the provided service filter options using the provided callback. + * @brief Get the number of tracked services for the provided tracker id. * - * The Celix framework will ensure that the targeted service cannot be removed during the callback. + * Silently ignore tracker ids < 0 and invalid tracker ids. * - * 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 0 immediately. - * Note that waitTimeoutInSeconds in opts has no effect. + * @param[in] ctx The bundle context. + * @param[in] trackerId The tracker id. + * @return The number of tracked services or 0 if the tracker id is unknown or < 0. + */ +CELIX_FRAMEWORK_EXPORT +size_t celix_bundleContext_getTrackedServiceCount(celix_bundle_context_t *ctx, long trackerId); + +/** + * @brief Get the service name of the tracked services for the provided tracker id. * - * This function will block until the callback is finished. As result it is possible to provide callback data from the - * stack. + * Silently ignore tracker ids < 0 and invalid tracker ids. * - * @param ctx The bundle context. - * @param opts The required options. Note that the serviceName is required. - * @return The number of services found and called + * @param ctx The bundle context. + * @param trackerId The tracker id. + * @return The service name of the tracked services or NULL if the tracker id is unknown or < 0. */ -CELIX_FRAMEWORK_EXPORT size_t celix_bundleContext_useServicesWithOptions( +CELIX_FRAMEWORK_EXPORT +const char* celix_bundleContext_getTrackedServiceName(celix_bundle_context_t *ctx, long trackerId); + +/** + * @brief Get the service filter of the tracked services for the provided tracker id. + * + * The returned filter is the combination of the service name and the filter from the provided service filter options. + * For example serviceName="foo" and filter="(location=middle)" will result in a filter of + * "(&(objectClass=foo)(location=middle))" + * + * Silently ignore tracker ids < 0 and invalid tracker ids. + * + * @param ctx The bundle context. + * @param trackerId The tracker id. + * @return The service filter of the tracked services or NULL if the tracker id is unknown or < 0. + */ +CELIX_FRAMEWORK_EXPORT +const char* celix_bundleContext_getTrackedServiceFilter(celix_bundle_context_t* ctx, long trackerId); + +/** + * @brief Stop the tracker with the provided track id. + * + * Could be a service tracker, bundle tracker or service tracker tracker. + * Only works for the trackers owned by the bundle of the bundle context. + * + * The service tracker will be destroyed async on the Celix event loop thread. This means that the function can return + * before the tracker is destroyed. + * + * if the doneCallback is not NULL, this will be called when the destruction of the service tracker is done. + * (will be called on the event loop thread). + * + * Will log a error if the provided tracker id is unknown. Will silently ignore trackerId < 0. + */ +CELIX_FRAMEWORK_EXPORT void celix_bundleContext_stopTrackerAsync( celix_bundle_context_t *ctx, - const celix_service_use_options_t *opts); + long trackerId, + void *doneCallbackData, + void (*doneCallback)(void* doneCallbackData)); + +/** + * @brief Wait, if able, for (async) creation of 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. + * + * @param[in] ctx The bundle context. + * @param[in] trackerId The tracker id. + */ +CELIX_FRAMEWORK_EXPORT void celix_bundleContext_waitForAsyncTracker(celix_bundle_context_t *ctx, long trackerId); + +/** + * @brief Wait, if able, for (async) stopping of tracking. + * + * 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. + * + * @param[in] ctx The bundle context. + * @param[in] trackerId The tracker id. + */ +CELIX_FRAMEWORK_EXPORT void celix_bundleContext_waitForAsyncStopTracker(celix_bundle_context_t *ctx, long trackerId); + +/** + * @brief Stop the tracker with the provided track id. + * + * 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. Review Comment: `celix_bundleContext_registerServiceFactoryAsync` or `celix_bundleContext_stopTrackerAsync`? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: dev-unsubscr...@celix.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org