Repository: celix Updated Branches: refs/heads/develop d7d396a54 -> d8e8fab41
CELIX-272: Add bundleContext_retainServiceReference to be able to control the ref count of service references. Project: http://git-wip-us.apache.org/repos/asf/celix/repo Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/d8e8fab4 Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/d8e8fab4 Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/d8e8fab4 Branch: refs/heads/develop Commit: d8e8fab413489ebd4ab4acae56234010f803f4f3 Parents: d7d396a Author: Pepijn Noltes <pepijnnol...@gmail.com> Authored: Thu Nov 26 20:56:07 2015 +0100 Committer: Pepijn Noltes <pepijnnol...@gmail.com> Committed: Thu Nov 26 20:56:07 2015 +0100 ---------------------------------------------------------------------- .gitignore | 1 + .../private/include/service_reference_private.h | 2 + framework/private/src/bundle_context.c | 14 +++ framework/private/src/framework.c | 89 +++++++++++--------- framework/private/src/service_reference.c | 8 ++ framework/private/src/service_registry.c | 23 +++++ framework/private/src/service_tracker.c | 86 +++++++++---------- framework/public/include/bundle_context.h | 41 ++++++++- framework/public/include/service_registry.h | 1 + 9 files changed, 180 insertions(+), 85 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/.gitignore ---------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore index f630756..6c1ab95 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ build *~ *.swp .idea +nbproject http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/include/service_reference_private.h ---------------------------------------------------------------------- diff --git a/framework/private/include/service_reference_private.h b/framework/private/include/service_reference_private.h index b0b8afb..ab3b219 100644 --- a/framework/private/include/service_reference_private.h +++ b/framework/private/include/service_reference_private.h @@ -62,6 +62,8 @@ celix_status_t serviceReference_getReferenceCount(service_reference_pt reference celix_status_t serviceReference_setService(service_reference_pt ref, void *service); celix_status_t serviceReference_getService(service_reference_pt reference, void **service); +celix_status_t serviceReference_getOwner(service_reference_pt reference, bundle_pt *owner); + #endif /* SERVICE_REFERENCE_PRIVATE_H_ */ http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/src/bundle_context.c ---------------------------------------------------------------------- diff --git a/framework/private/src/bundle_context.c b/framework/private/src/bundle_context.c index f84d767..594355c 100644 --- a/framework/private/src/bundle_context.c +++ b/framework/private/src/bundle_context.c @@ -191,6 +191,20 @@ celix_status_t bundleContext_getServiceReference(bundle_context_pt context, char return status; } +FRAMEWORK_EXPORT celix_status_t bundleContext_retainServiceReference(bundle_context_pt context, service_reference_pt ref) { + celix_status_t status = CELIX_SUCCESS; + + if (context != NULL && ref != NULL) { + serviceRegistry_retainServiceReference(context->framework->registry, context->bundle, ref); + } else { + status = CELIX_ILLEGAL_ARGUMENT; + } + + framework_logIfError(logger, status, NULL, "Failed to get service references"); + + return status; +} + celix_status_t bundleContext_ungetServiceReference(bundle_context_pt context, service_reference_pt reference) { celix_status_t status = CELIX_SUCCESS; http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/src/framework.c ---------------------------------------------------------------------- diff --git a/framework/private/src/framework.c b/framework/private/src/framework.c index 0823781..8da65d1 100644 --- a/framework/private/src/framework.c +++ b/framework/private/src/framework.c @@ -1582,67 +1582,74 @@ celix_status_t fw_removeFrameworkListener(framework_pt framework, bundle_pt bund } void fw_serviceChanged(framework_pt framework, service_event_type_e eventType, service_registration_pt registration, properties_pt oldprops) { - unsigned int i; - fw_service_listener_pt element; + unsigned int i; + fw_service_listener_pt element; - if (arrayList_size(framework->serviceListeners) > 0) { - for (i = 0; i < arrayList_size(framework->serviceListeners); i++) { - int matched = 0; - properties_pt props = NULL; - bool matchResult = false; + if (arrayList_size(framework->serviceListeners) > 0) { + for (i = 0; i < arrayList_size(framework->serviceListeners); i++) { + int matched = 0; + properties_pt props = NULL; + bool matchResult = false; - element = (fw_service_listener_pt) arrayList_get(framework->serviceListeners, i); - serviceRegistration_getProperties(registration, &props); - if (element->filter != NULL) { - filter_match(element->filter, props, &matchResult); - } - matched = (element->filter == NULL) || matchResult; - if (matched) { - service_reference_pt reference = NULL; - service_event_pt event; + element = (fw_service_listener_pt) arrayList_get(framework->serviceListeners, i); + serviceRegistration_getProperties(registration, &props); + if (element->filter != NULL) { + filter_match(element->filter, props, &matchResult); + } + matched = (element->filter == NULL) || matchResult; + if (matched) { + service_reference_pt reference = NULL; + service_event_pt event; - event = (service_event_pt) malloc(sizeof(*event)); + event = (service_event_pt) malloc(sizeof (*event)); serviceRegistry_getServiceReference(framework->registry, element->bundle, registration, &reference); + + + //FIXME, TODO need to retain the service ref. If not bundles using the service_listener will crash. + //update service_listener users so that they retain references if the keep them. + //NOTE: that you are never sure that the UNREGISTERED event will by handle by an service_listener (could be gone)) + if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED) { + serviceRegistry_retainServiceReference(framework->registry, element->bundle, reference); + } - event->type = eventType; - event->reference = reference; + event->type = eventType; + event->reference = reference; - element->listener->serviceChanged(element->listener, event); + element->listener->serviceChanged(element->listener, event); - if (eventType != OSGI_FRAMEWORK_SERVICE_EVENT_REGISTERED) { - serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference); - } + serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference); + if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) { - serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference); + serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference); // to counter retain } - + free(event); - } else if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED) { - bool matchResult = false; - int matched = 0; - if (element->filter != NULL) { - filter_match(element->filter, oldprops, &matchResult); - } - matched = (element->filter == NULL) || matchResult; - if (matched) { - service_reference_pt reference = NULL; - service_event_pt endmatch = (service_event_pt) malloc(sizeof(*endmatch)); + } else if (eventType == OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED) { + bool matchResult = false; + int matched = 0; + if (element->filter != NULL) { + filter_match(element->filter, oldprops, &matchResult); + } + matched = (element->filter == NULL) || matchResult; + if (matched) { + service_reference_pt reference = NULL; + service_event_pt endmatch = (service_event_pt) malloc(sizeof (*endmatch)); serviceRegistry_getServiceReference(framework->registry, element->bundle, registration, &reference); - endmatch->reference = reference; - endmatch->type = OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH; - element->listener->serviceChanged(element->listener, endmatch); + endmatch->reference = reference; + endmatch->type = OSGI_FRAMEWORK_SERVICE_EVENT_MODIFIED_ENDMATCH; + element->listener->serviceChanged(element->listener, endmatch); serviceRegistry_ungetServiceReference(framework->registry, element->bundle, reference); free(endmatch); } - } - } - } + } + } + } } http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/src/service_reference.c ---------------------------------------------------------------------- diff --git a/framework/private/src/service_reference.c b/framework/private/src/service_reference.c index 9fbee9e..c40d3c2 100644 --- a/framework/private/src/service_reference.c +++ b/framework/private/src/service_reference.c @@ -181,6 +181,14 @@ celix_status_t serviceReference_getBundle(service_reference_pt ref, bundle_pt *b return status; } +celix_status_t serviceReference_getOwner(service_reference_pt ref, bundle_pt *owner) { + celix_status_t status = CELIX_SUCCESS; + celixThreadRwlock_readLock(&ref->lock); + *owner = ref->referenceOwner; + celixThreadRwlock_unlock(&ref->lock); + return status; +} + celix_status_t serviceReference_getServiceRegistration(service_reference_pt ref, service_registration_pt *out) { celixThreadRwlock_readLock(&ref->lock); *out = ref->registration; http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/src/service_registry.c ---------------------------------------------------------------------- diff --git a/framework/private/src/service_registry.c b/framework/private/src/service_registry.c index 81487f2..b366f53 100644 --- a/framework/private/src/service_registry.c +++ b/framework/private/src/service_registry.c @@ -402,6 +402,29 @@ celix_status_t serviceRegistry_getServiceReferences(service_registry_pt registry return status; } +celix_status_t serviceRegistry_retainServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference) { + celix_status_t status = CELIX_SUCCESS; + reference_status_t refStatus; + bundle_pt refBundle = NULL; + + celixThreadRwlock_writeLock(®istry->lock); + serviceRegistry_checkReference(registry, reference, &refStatus); + if (status == REF_ACTIVE) { + serviceReference_getOwner(reference, &refBundle); + if (refBundle == bundle) { + serviceReference_retain(reference); + } else { + status = CELIX_ILLEGAL_ARGUMENT; + fw_log(logger, OSGI_FRAMEWORK_LOG_ERROR, "cannot retain a service reference from an other bundle (in ref %p) (provided %p).", refBundle, bundle); + } + } else { + serviceRegistry_logIllegalReference(registry, reference, refStatus); + } + celixThreadRwlock_unlock(®istry->lock); + + return status; +} + celix_status_t serviceRegistry_ungetServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference) { celix_status_t status = CELIX_SUCCESS; http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/private/src/service_tracker.c ---------------------------------------------------------------------- diff --git a/framework/private/src/service_tracker.c b/framework/private/src/service_tracker.c index 7714139..1d4e4aa 100644 --- a/framework/private/src/service_tracker.c +++ b/framework/private/src/service_tracker.c @@ -271,51 +271,50 @@ void serviceTracker_serviceChanged(service_listener_pt listener, service_event_p static celix_status_t serviceTracker_track(service_tracker_pt tracker, service_reference_pt reference, service_event_pt event) { celix_status_t status = CELIX_SUCCESS; - tracked_pt tracked = NULL; - bool found = false; - unsigned int i; + tracked_pt tracked = NULL; + bool found = false; + unsigned int i; + + bundleContext_retainServiceReference(tracker->context, reference); celixThreadRwlock_readLock(&tracker->lock); - for (i = 0; i < arrayList_size(tracker->trackedServices); i++) { - bool equals = false; - tracked = (tracked_pt) arrayList_get(tracker->trackedServices, i); - status = serviceReference_equals(reference, tracked->reference, &equals); + for (i = 0; i < arrayList_size(tracker->trackedServices); i++) { + bool equals = false; + tracked = (tracked_pt) arrayList_get(tracker->trackedServices, i); + status = serviceReference_equals(reference, tracked->reference, &equals); if (status != CELIX_SUCCESS) { break; } - if (equals) { - found = true; - break; - } - } + if (equals) { + found = true; + break; + } + } celixThreadRwlock_unlock(&tracker->lock); - if (status == CELIX_SUCCESS && !found /*new*/) { - void * service = NULL; - status = serviceTracker_invokeAddingService(tracker, reference, &service); - if (status == CELIX_SUCCESS) { - if (service != NULL) { - tracked = (tracked_pt) calloc(1, sizeof(*tracked)); - assert(reference != NULL); - tracked->reference = reference; - tracked->service = service; + if (status == CELIX_SUCCESS && !found /*new*/) { + void * service = NULL; + status = serviceTracker_invokeAddingService(tracker, reference, &service); + if (status == CELIX_SUCCESS) { + if (service != NULL) { + tracked = (tracked_pt) calloc(1, sizeof (*tracked)); + assert(reference != NULL); + tracked->reference = reference; + tracked->service = service; serviceTracker_invokeAddService(tracker, reference, service); celixThreadRwlock_writeLock(&tracker->lock); arrayList_add(tracker->trackedServices, tracked); celixThreadRwlock_unlock(&tracker->lock); - } - } + } + } - } else { + } else { status = serviceTracker_invokeModifiedService(tracker, reference, tracked->service); - } - - - + } - framework_logIfError(logger, status, NULL, "Cannot track reference"); + framework_logIfError(logger, status, NULL, "Cannot track reference"); - return status; + return status; } static celix_status_t serviceTracker_invokeModifiedService(service_tracker_pt tracker, service_reference_pt ref, void *service) { @@ -380,30 +379,31 @@ static celix_status_t serviceTracker_invokeAddingService(service_tracker_pt trac } static celix_status_t serviceTracker_untrack(service_tracker_pt tracker, service_reference_pt reference, service_event_pt event) { - celix_status_t status = CELIX_SUCCESS; - tracked_pt tracked = NULL; - unsigned int i; + celix_status_t status = CELIX_SUCCESS; + tracked_pt tracked = NULL; + unsigned int i; celixThreadRwlock_writeLock(&tracker->lock); for (i = 0; i < arrayList_size(tracker->trackedServices); i++) { - bool equals; - tracked = (tracked_pt) arrayList_get(tracker->trackedServices, i); - serviceReference_equals(reference, tracked->reference, &equals); - if (equals) { - arrayList_remove(tracker->trackedServices, i); + bool equals; + tracked = (tracked_pt) arrayList_get(tracker->trackedServices, i); + serviceReference_equals(reference, tracked->reference, &equals); + if (equals) { + arrayList_remove(tracker->trackedServices, i); break; - } - } + } + } celixThreadRwlock_unlock(&tracker->lock); if (tracked != NULL) { serviceTracker_invokeRemovingService(tracker, tracked->reference, tracked->service); free(tracked); + bundleContext_ungetServiceReference(tracker->context, reference); } + + framework_logIfError(logger, status, NULL, "Cannot untrack reference"); - framework_logIfError(logger, status, NULL, "Cannot untrack reference"); - - return status; + return status; } static celix_status_t serviceTracker_invokeRemovingService(service_tracker_pt tracker, service_reference_pt ref, void *service) { http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/public/include/bundle_context.h ---------------------------------------------------------------------- diff --git a/framework/public/include/bundle_context.h b/framework/public/include/bundle_context.h index 179e601..6c885f5 100644 --- a/framework/public/include/bundle_context.h +++ b/framework/public/include/bundle_context.h @@ -55,8 +55,47 @@ FRAMEWORK_EXPORT celix_status_t bundleContext_registerService(bundle_context_pt FRAMEWORK_EXPORT celix_status_t bundleContext_registerServiceFactory(bundle_context_pt context, char * serviceName, service_factory_pt factory, properties_pt properties, service_registration_pt *service_registration); -FRAMEWORK_EXPORT celix_status_t bundleContext_getServiceReferences(bundle_context_pt context, const char * serviceName, char * filter, array_list_pt *service_references); +/** + * Get a service reference for the bundle context. When the service reference is no longer needed use bundleContext_ungetServiceReference. + * ServiceReference are coupled to a bundle context. Do not share service reference between bundles. Exchange the service.id instead. + * + * @param context The bundle context + * @param serviceName The name of the service (objectClass) to get + * @param service_reference _output_ The found service reference, or NULL when no service is found. + * @return CELIX_SUCCESS on success + */ FRAMEWORK_EXPORT celix_status_t bundleContext_getServiceReference(bundle_context_pt context, char * serviceName, service_reference_pt *service_reference); + +/** Same as bundleContext_getServiceReference, but than for a optional serviceName combined with a optional filter. + * The resulting array_list should be destroyed by the caller. For all service references return a unget should be called. + * + * @param context the bundle context + * @param serviceName the serviceName, can be NULL + * @param filter the filter, can be NULL. If present will be combined (and) with the serviceName + * @param service_references _output_ a array list, can be size 0. + * @return CELIX_SUCCESS on success + */ +FRAMEWORK_EXPORT celix_status_t bundleContext_getServiceReferences(bundle_context_pt context, const char * serviceName, char * filter, array_list_pt *service_references); + +/** + * Retains (increases the ref count) the provided service reference. Can be used to retain a service reference. + * Note that this is a deviation from the OSGi spec, due to the fact that C has no garbage collect. + * + * @param context the bundle context + * @param reference the service reference to retain + * @return CELIX_SUCCES on success + */ +FRAMEWORK_EXPORT celix_status_t bundleContext_retainServiceReference(bundle_context_pt context, service_reference_pt reference); + +/** + * Ungets the service references. If the ref counter of the service refernce goes to 0, the reference will be destroyed. + * This is coupled with the bundleContext_getServiceReference(s) and bundleContext_retainServiceReferenc. + * Note: That this is a deviation from the OSGi standard, due to the fact that C has no garbage collect. + * + * @param context The bundle context. + * @param reference the service reference to unget + * @return CELIX_SUCCESS on success. + */ FRAMEWORK_EXPORT celix_status_t bundleContext_ungetServiceReference(bundle_context_pt context, service_reference_pt reference); FRAMEWORK_EXPORT celix_status_t bundleContext_getService(bundle_context_pt context, service_reference_pt reference, void **service_instance); http://git-wip-us.apache.org/repos/asf/celix/blob/d8e8fab4/framework/public/include/service_registry.h ---------------------------------------------------------------------- diff --git a/framework/public/include/service_registry.h b/framework/public/include/service_registry.h index 5c013cc..41560b2 100644 --- a/framework/public/include/service_registry.h +++ b/framework/public/include/service_registry.h @@ -52,6 +52,7 @@ celix_status_t serviceRegistry_clearServiceRegistrations(service_registry_pt reg celix_status_t serviceRegistry_getServiceReference(service_registry_pt registry, bundle_pt bundle, service_registration_pt registration, service_reference_pt *reference); celix_status_t serviceRegistry_getServiceReferences(service_registry_pt registry, bundle_pt bundle, const char *serviceName, filter_pt filter, array_list_pt *references); +celix_status_t serviceRegistry_retainServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference); celix_status_t serviceRegistry_ungetServiceReference(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference); celix_status_t serviceRegistry_getService(service_registry_pt registry, bundle_pt bundle, service_reference_pt reference, void **service);