You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2020/10/04 18:53:06 UTC
[celix] branch feature/async_svc_registration updated (292d844 ->
7511a9f)
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a change to branch feature/async_svc_registration
in repository https://gitbox.apache.org/repos/asf/celix.git.
from 292d844 Refactors creating / destroy of service, bundle and meta tracker from the bundle context so that this is done on the event loop thread. Also adds async track/untrack call variants.
new a576a90 Added async svc regitration usage to log_admin
add 7294dbf Fixed type in pubsub scheduler key, breaking tests inside userspace container builds
add ee86303 Make pstm handling thread sleep time configurable
add 23d6bce Merge pull request #267 from Oipo/feature/configurable_sleeptime_pstm
add deda9bd Don't wait infinitely for server response, might never come and prevents closing of program
add e6fe5ad Merge pull request #269 from Oipo/bugfix/psws_infinite_wait
add dab8fed Document improvements
add 62aad4f Add page titles to documentation
add c6388af Merge pull request #271 from apache/add-titles
add 9a94bd6 Add Footer
add 864ad47 Add Footer to ZMQ
add 915b306 add wire_v2 protocol with footer
add 84e0619 Fix wire_v2 unit test
add 5467050 Fix wire_v2 unit test
add 26ece37 fix test
add 873c6e3 Add ZMQ add tests (also zerocpy) Remove disable receive timeout when using tcp endpoint to fix tcp endpoint test
add 996eea7 remove build warning
add 6a9f539 Merge branch 'master' into feature/proposal_protocol_footer
add a09cda8 update wire v2 common with uint32_t
add be63ccf Refactors pubsub protocol wire, added a shared static lib and merged the byte swap functions.
add f4efaa2 Merge branch 'master' into feature/proposal_protocol_footer
add 460d129 Avoid alloc/free calls in pubsub tcp/zmq and wire protocol
add 892bef8 Merge branch 'master' of https://github.com/apache/celix into feature/avoid_mem_copies
add 3be06db Merge pull request #260 from Oipo/feature/avoid_mem_copies
add 5e1ff87 Add void promise
add eb8862e Merge pull request #270 from Oipo/feature/void_promise
add f082ee6 When a publisher has no subscribers, publishing messages is not an error. This commit sets result to succes in that case.
add afedd8c Merge pull request #273 from Troepje/bugfix/publish_without_client_not_an_error
add 6bbcdb0 Ignore interface descriptors in pubsub serialization (#275)
add eaf00f0 Reuse etcd connection to prevent storm of new sockets
add a861d21 Merge pull request #274 from Oipo/bugfix/scalable_etcd
add efee9f2 Feature/cpp17 promise (#272)
add d93e47a http -> https for doap file
add 6bb2413 celix-site is also managed by Celix
add 7b75d80 Celix uses GH issues instead of Jira
add ca200f1 #277: Updated websocket sender to use mg_websocket_write instead of client_write.
add 1d94550 Merge pull request #278 from apache/feature/277_websocket_sends_masked_frame
add 64d9111 Fix reusing connections for etcdlib
add c35735e Refactors the rsa dfi export registration to use the tracker from the bundle context (which should be thread safe)
add d2defb7 Merge pull request #281 from apache/hotfix/use_new_tracker_in_rsa_dfi
add fd57348 etcdlib_create does not return zero as long as the malloc for that struct works.
add dc08b88 Merge pull request #284 from unitink72/patch-1
add 333b874 Adds test for dynamically creating and destroying a component providing a remote service which deadlocks
add 5bf1426 Adds a stop service export thread for rsa to prevent deadlocks
add 921ed6e sets use of stop export service thread to true
add 506cb88 Adds test case for create a remote service in a remote service call and fixes the deadlock issue for that test case.
add 20f794b Merge pull request #282 from apache/hotfix/rsa_deadlock
new 815524c Merge branch 'master' into feature/async_svc_registration
new 1877032 Update bc_useService(s) so that it can be called on the event loop thread
new 7511a9f Fixes some issues
The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
CHANGES.md | 4 +
CMakeLists.txt | 8 +-
bundles/deployment_admin/README.md | 4 +
bundles/device_access/README.md | 4 +
.../device_access/example/base_driver/README.md | 4 +
.../example/consuming_driver/README.md | 4 +
.../example/refining_driver/README.md | 4 +
bundles/http_admin/README.md | 4 +
bundles/http_admin/civetweb/src/civetweb.c | 2 +-
bundles/http_admin/http_admin/src/http_admin.c | 7 +-
bundles/logging/README.md | 4 +
bundles/logging/log_admin/src/celix_log_admin.c | 45 +-
bundles/logging/log_writers/README.md | 4 +
bundles/pubsub/README.md | 4 +
bundles/pubsub/examples/keys/README.md | 4 +
.../pubsub_admin_tcp/src/pubsub_tcp_handler.c | 27 +-
bundles/pubsub/pubsub_admin_udp_mc/README.md | 4 +
.../src/pubsub_websocket_topic_sender.c | 4 +-
.../pubsub_admin_zmq/src/pubsub_zmq_topic_sender.c | 118 ++--
.../pubsub_protocol_lib/CMakeLists.txt | 8 +-
.../gtest/CMakeLists.txt | 12 +-
.../gtest/src/PS_WP_common_tests.cc | 57 ++
.../pubsub_protocol_lib}/gtest/src/main.cc | 0
.../src/pubsub_wire_protocol_common.c | 93 ++-
bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c | 3 +-
.../src/pubsub_topology_manager.c | 5 +-
.../src/pubsub_topology_manager.h | 2 +
bundles/pubsub/pubsub_utils/gtest/CMakeLists.txt | 1 +
.../gtest/msg_descriptors/int_calc.descriptor | 0
.../src/PubSubSerializationHandlerTestSuite.cc | 14 +
.../src/pubsub_serialization_provider.c | 21 +-
bundles/pubsub/test/CMakeLists.txt | 6 -
.../test/meta_data/deadlock.scope.properties | 2 +-
.../test/meta_data/deadlock.scope2.properties | 2 +-
bundles/pubsub/test/meta_data/ping.properties | 2 +-
bundles/pubsub/test/meta_data/ping2.properties | 2 +-
bundles/pubsub/test/meta_data/pong2.properties | 2 +-
bundles/remote_services/README.md | 6 +-
bundles/remote_services/discovery_etcd/README.md | 4 +
.../remote_example_api/include/remote_example.h | 2 +
.../org.apache.celix.RemoteExample.descriptor | 1 +
.../src/remote_example_activator.c | 3 +-
.../src/remote_example_impl.c | 49 +-
.../src/remote_example_impl.h | 4 +-
.../remote_service_admin_dfi/README.md | 4 +
.../gtest/src/rsa_client_server_tests.cc | 20 +
.../gtest/src/tst_activator.c | 34 ++
.../gtest/src/tst_service.h | 2 +
.../src/export_registration_dfi.c | 115 +++-
.../src/export_registration_dfi.h | 6 +-
.../src/remote_service_admin_dfi.c | 148 ++++-
.../remote_services/remote_services_api/README.md | 4 +
bundles/remote_services/rsa_spi/README.md | 4 +
bundles/remote_services/topology_manager/README.md | 4 +
bundles/shell/remote_shell/README.md | 4 +
bundles/shell/shell/README.md | 4 +
bundles/shell/shell_tui/README.md | 4 +
bundles/shell/shell_wui/README.md | 4 +
doap/doap_Celix.rdf | 20 +-
documents/building/README.md | 4 +
documents/cmake_commands/README.md | 4 +
documents/getting_started/README.md | 4 +
.../getting_started/creating_a_simple_bundle.md | 6 +-
documents/getting_started/using_services_with_c.md | 4 +
.../getting_started/using_services_with_cxx.md | 4 +
documents/intro/README.md | 6 +-
documents/subprojects/README.md | 6 +
examples/celix-examples/README.md | 4 +
examples/celix-examples/http_example/README.md | 7 +-
.../celix-examples/services_example_c/README.md | 4 +
libs/dependency_manager/README.md | 4 +
libs/dependency_manager/TODO.md | 6 +-
libs/dependency_manager_cxx/README.md | 4 +
libs/dependency_manager_cxx/TODO.md | 6 +-
libs/etcdlib/README.md | 4 +
libs/etcdlib/api/etcdlib.h | 16 +-
libs/etcdlib/src/etcd.c | 110 ++--
libs/etcdlib/test/etcdlib_test.c | 2 +-
.../gtest/src/bundle_context_services_test.cpp | 6 +-
libs/framework/include/celix_bundle_context.h | 29 +-
libs/framework/include/celix_framework.h | 6 +
libs/framework/include/service_registry.h | 2 +
libs/framework/src/bundle_context.c | 39 +-
libs/framework/src/framework.c | 30 +
libs/framework/src/service_registry.c | 30 +-
libs/launcher/README.md | 4 +
libs/utils/README.md | 4 +
misc/experimental/README.md | 4 +
misc/experimental/bundles/config_admin/README.md | 4 +
misc/experimental/promise/CMakeLists.txt | 6 +-
misc/experimental/promise/README.md | 4 +
misc/experimental/promise/api/celix/Deferred.h | 136 ++++-
misc/experimental/promise/api/celix/Promise.h | 191 +++++-
.../promise/api/celix/PromiseFactory.h | 16 +-
.../promise/api/celix/PromiseInvocationException.h | 6 +-
.../promise/api/celix/impl/SharedPromiseState.h | 654 +++++++++++++++++----
misc/experimental/promise/gtest/CMakeLists.txt | 1 +
.../promise/gtest/src/PromiseTestSuite.cc | 116 +++-
...PromiseTestSuite.cc => VoidPromiseTestSuite.cc} | 189 +++---
misc/experimental/promise/src/PromiseExamples.cc | 2 +-
100 files changed, 2025 insertions(+), 596 deletions(-)
copy bundles/pubsub/pubsub_protocol/{pubsub_protocol_wire_v1 => pubsub_protocol_lib}/gtest/CMakeLists.txt (67%)
create mode 100644 bundles/pubsub/pubsub_protocol/pubsub_protocol_lib/gtest/src/PS_WP_common_tests.cc
copy bundles/{remote_services/remote_service_admin_dfi => pubsub/pubsub_protocol/pubsub_protocol_lib}/gtest/src/main.cc (100%)
copy libs/dfi/gtest/descriptors/example1.descriptor => bundles/pubsub/pubsub_utils/gtest/msg_descriptors/int_calc.descriptor (100%)
copy misc/experimental/promise/gtest/src/{PromiseTestSuite.cc => VoidPromiseTestSuite.cc} (63%)
[celix] 01/04: Added async svc regitration usage to log_admin
Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/async_svc_registration
in repository https://gitbox.apache.org/repos/asf/celix.git
commit a576a90565b0ac8701d9d61346e8bf778186c3d4
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Mon Sep 7 16:26:45 2020 +0200
Added async svc regitration usage to log_admin
---
bundles/logging/log_admin/src/celix_log_admin.c | 45 ++++++++++------------
.../gtest/src/bundle_context_services_test.cpp | 2 +-
libs/framework/include/celix_bundle_context.h | 8 +++-
libs/framework/include/celix_framework.h | 6 +++
libs/framework/src/bundle_context.c | 10 +++--
libs/framework/src/framework.c | 30 +++++++++++++++
6 files changed, 72 insertions(+), 29 deletions(-)
diff --git a/bundles/logging/log_admin/src/celix_log_admin.c b/bundles/logging/log_admin/src/celix_log_admin.c
index e594abc..805233b 100644
--- a/bundles/logging/log_admin/src/celix_log_admin.c
+++ b/bundles/logging/log_admin/src/celix_log_admin.c
@@ -210,7 +210,7 @@ static void celix_logAdmin_addLogSvcForName(celix_log_admin_t* admin, const char
opts.serviceVersion = CELIX_LOG_SERVICE_VERSION;
opts.properties = props;
opts.svc = &newEntry->logSvc;
- newEntry->logSvcId = celix_bundleContext_registerServiceAsyncWithOptions(admin->ctx, &opts);
+ newEntry->logSvcId = celix_bundleContext_registerServiceWithOptionsAsync(admin->ctx, &opts);
}
if (celix_utils_stringEquals(newEntry->name, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME)) {
@@ -232,31 +232,28 @@ static void celix_logAdmin_trackerAdd(void *handle, const celix_service_tracker_
celix_logAdmin_addLogSvcForName(admin, name);
}
-static void celix_logAdmin_remLogSvcForName(celix_log_admin_t* admin, const char* name) {
- celix_log_service_entry_t* remEntry = NULL;
+static void celix_logAdmin_freeLogEntry(void *data) {
+ celix_log_service_entry_t* entry = data;
+ if (celix_utils_stringEquals(entry->name, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME)) {
+ celix_framework_t* fw = celix_bundleContext_getFramework(entry->admin->ctx);
+ celix_framework_setLogCallback(fw, NULL, NULL);
+ }
+ free(entry->name);
+ free(entry);
+}
+static void celix_logAdmin_remLogSvcForName(celix_log_admin_t* admin, const char* name) {
celixThreadRwlock_writeLock(&admin->lock);
celix_log_service_entry_t* found = hashMap_get(admin->loggers, name);
if (found != NULL) {
found->count -= 1;
if (found->count == 0) {
//remove
- remEntry = found;
hashMap_remove(admin->loggers, name);
+ celix_bundleContext_unregisterServiceAsync(admin->ctx, found->logSvcId, found, celix_logAdmin_freeLogEntry);
}
}
celixThreadRwlock_unlock(&admin->lock);
-
- if (remEntry != NULL) {
- if (celix_utils_stringEquals(remEntry->name, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME)) {
- celix_framework_t* fw = celix_bundleContext_getFramework(admin->ctx);
- celix_framework_setLogCallback(fw, NULL, NULL);
- }
-
- celix_bundleContext_unregisterService(admin->ctx, remEntry->logSvcId);
- free(remEntry->name);
- free(remEntry);
- }
}
@@ -591,10 +588,10 @@ celix_log_admin_t* celix_logAdmin_create(celix_bundle_context_t *ctx) {
opts.callbackHandle = admin;
opts.addWithProperties = celix_logAdmin_addSink;
opts.removeWithProperties = celix_logAdmin_remSink;
- admin->logWriterTrackerId = celix_bundleContext_trackServicesWithOptions(ctx, &opts);
+ admin->logWriterTrackerId = celix_bundleContext_trackServicesWithOptionsAsync(ctx, &opts);
}
- admin->logServiceMetaTrackerId = celix_bundleContext_trackServiceTrackers(ctx, CELIX_LOG_SERVICE_NAME, admin, celix_logAdmin_trackerAdd, celix_logAdmin_trackerRem);
+ admin->logServiceMetaTrackerId = celix_bundleContext_trackServiceTrackersAsync(ctx, CELIX_LOG_SERVICE_NAME, admin, celix_logAdmin_trackerAdd, celix_logAdmin_trackerRem, NULL, NULL);
{
admin->controlSvc.handle = admin;
@@ -612,7 +609,7 @@ celix_log_admin_t* celix_logAdmin_create(celix_bundle_context_t *ctx) {
opts.serviceName = CELIX_LOG_CONTROL_NAME;
opts.serviceVersion = CELIX_LOG_CONTROL_VERSION;
opts.svc = &admin->controlSvc;
- admin->controlSvcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts);
+ admin->controlSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
}
{
@@ -629,12 +626,11 @@ celix_log_admin_t* celix_logAdmin_create(celix_bundle_context_t *ctx) {
opts.serviceVersion = CELIX_SHELL_COMMAND_SERVICE_VERSION;
opts.properties = props;
opts.svc = &admin->cmdSvc;
- admin->cmdSvcId = celix_bundleContext_registerServiceWithOptions(ctx, &opts);
+ admin->cmdSvcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
}
//add log service for the framework
celix_logAdmin_addLogSvcForName(admin, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME);
-
return admin;
}
@@ -642,10 +638,11 @@ void celix_logAdmin_destroy(celix_log_admin_t *admin) {
if (admin != NULL) {
celix_logAdmin_remLogSvcForName(admin, CELIX_LOG_ADMIN_FRAMEWORK_LOG_NAME);
- celix_bundleContext_unregisterService(admin->ctx, admin->cmdSvcId);
- celix_bundleContext_unregisterService(admin->ctx, admin->controlSvcId);
- celix_bundleContext_stopTracker(admin->ctx, admin->logServiceMetaTrackerId);
- celix_bundleContext_stopTracker(admin->ctx, admin->logWriterTrackerId);
+ celix_bundleContext_unregisterServiceAsync(admin->ctx, admin->cmdSvcId, NULL, NULL);
+ celix_bundleContext_unregisterServiceAsync(admin->ctx, admin->controlSvcId, NULL, NULL);
+ celix_bundleContext_stopTrackerAsync(admin->ctx, admin->logServiceMetaTrackerId, NULL, NULL);
+ celix_bundleContext_stopTrackerAsync(admin->ctx, admin->logWriterTrackerId, NULL, NULL);
+ celix_bundleContext_waitForEvents(admin->ctx);
assert(hashMap_size(admin->loggers) == 0); //note stopping service tracker tracker should triggered all needed remove events
hashMap_destroy(admin->loggers, false, false);
diff --git a/libs/framework/gtest/src/bundle_context_services_test.cpp b/libs/framework/gtest/src/bundle_context_services_test.cpp
index 96ba33c..9e5335f 100644
--- a/libs/framework/gtest/src/bundle_context_services_test.cpp
+++ b/libs/framework/gtest/src/bundle_context_services_test.cpp
@@ -1052,7 +1052,7 @@ TEST_F(CelixBundleContextServicesTests, floodEventLoopTest) {
localData->cond.wait_for(lck, std::chrono::seconds{30}, [&]{ return localData->ready; }); //wait til ready.
EXPECT_TRUE(localData->ready);
};
- long svcId = celix_bundleContext_registerServiceAsyncWithOptions(ctx, &opts);
+ long svcId = celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
EXPECT_GE(svcId, 0);
int nrOfAdditionalRegistrations = 300;
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index 90f733c..060a749 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -204,7 +204,7 @@ typedef struct celix_service_registration_options {
* @param opts The pointer to the registration options. The options are only in the during registration call.
* @return The serviceId (>= 0) or -1 if the registration was unsuccessful and -2 if the registration was cancelled (@see celix_bundleContext_reserveSvcId).
*/
-long celix_bundleContext_registerServiceAsyncWithOptions(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts);
+long celix_bundleContext_registerServiceWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts);
/**
* Register a service to the Celix framework using the provided service registration options.
@@ -1109,6 +1109,12 @@ celix_dependency_manager_t* celix_bundleContext_getDependencyManager(celix_bundl
/**
+ * Wait till there are event for the bundle of this bundle context.
+ */
+void celix_bundleContext_waitForEvents(celix_bundle_context_t* ctx);
+
+
+/**
* Returns the bundle for this bundle context.
*/
celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx);
diff --git a/libs/framework/include/celix_framework.h b/libs/framework/include/celix_framework.h
index 7af1e2c..8b5482f 100644
--- a/libs/framework/include/celix_framework.h
+++ b/libs/framework/include/celix_framework.h
@@ -156,6 +156,12 @@ void celix_framework_waitForEmptyEventQueue(celix_framework_t *fw);
void celix_framework_setLogCallback(celix_framework_t* fw, void* logHandle, void (*logFunction)(void* handle, celix_log_level_e level, const char* file, const char *function, int line, const char *format, va_list formatArgs));
+/**
+ * wait till all events for the bundle identified by the bndId are processed.
+ */
+void celix_framework_waitForEvents(celix_framework_t* fw, long bndId);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index 43a11cd..70aa37c 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -457,7 +457,7 @@ long celix_bundleContext_registerServiceAsync(celix_bundle_context_t *ctx, void
opts.svc = svc;
opts.serviceName = serviceName;
opts.properties = properties;
- return celix_bundleContext_registerServiceAsyncWithOptions(ctx, &opts);
+ return celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
}
long celix_bundleContext_registerService(bundle_context_t *ctx, void *svc, const char *serviceName, celix_properties_t *properties) {
@@ -474,7 +474,7 @@ long celix_bundleContext_registerServiceFactoryAsync(celix_bundle_context_t *ctx
opts.factory = factory;
opts.serviceName = serviceName;
opts.properties = props;
- return celix_bundleContext_registerServiceAsyncWithOptions(ctx, &opts);
+ return celix_bundleContext_registerServiceWithOptionsAsync(ctx, &opts);
}
long celix_bundleContext_registerServiceFactory(celix_bundle_context_t *ctx, celix_service_factory_t *factory, const char *serviceName, celix_properties_t *props) {
@@ -547,7 +547,7 @@ long celix_bundleContext_registerServiceWithOptions(bundle_context_t *ctx, const
return celix_bundleContext_registerServiceWithOptionsInternal(ctx, opts, false);
}
-long celix_bundleContext_registerServiceAsyncWithOptions(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts) {
+long celix_bundleContext_registerServiceWithOptionsAsync(celix_bundle_context_t *ctx, const celix_service_registration_options_t *opts) {
return celix_bundleContext_registerServiceWithOptionsInternal(ctx, opts, true);
}
@@ -1484,6 +1484,10 @@ long celix_bundleContext_trackServiceTrackersAsync(
return celix_bundleContext_trackServiceTrackersInternal(ctx, serviceName, callbackHandle, trackerAdd, trackerRemove, true, doneCallbackData, doneCallback);
}
+void celix_bundleContext_waitForEvents(celix_bundle_context_t* ctx) {
+ celix_framework_waitForEvents(ctx->framework, celix_bundle_getId(ctx->bundle));
+}
+
celix_bundle_t* celix_bundleContext_getBundle(const celix_bundle_context_t *ctx) {
celix_bundle_t *bnd = NULL;
if (ctx != NULL) {
diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index 84eaf67..de19f63 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -2640,6 +2640,36 @@ void celix_framework_waitForEmptyEventQueue(celix_framework_t *fw) {
celixThreadMutex_unlock(&fw->dispatcher.mutex);
}
+void celix_framework_waitForEvents(celix_framework_t* fw, long bndId) {
+ assert(!celix_framework_isCurrentThreadTheEventLoop(fw));
+
+ celixThreadMutex_lock(&fw->dispatcher.mutex);
+ bool eventInProgress = true;
+ while (eventInProgress) {
+ eventInProgress = false;
+ for (int i = 0; i < fw->dispatcher.eventQueueSize; ++i) {
+ int index = (fw->dispatcher.eventQueueFirstEntry + i) % CELIX_FRAMEWORK_STATIC_EVENT_QUEUE_SIZE;
+ celix_framework_event_t* e = &fw->dispatcher.eventQueue[index];
+ if (e->bndEntry != NULL && e->bndEntry->bndId == bndId) {
+ eventInProgress = true;
+ break;
+ }
+ }
+ for (int i = 0; !eventInProgress && i < celix_arrayList_size(fw->dispatcher.dynamicEventQueue); ++i) {
+ celix_framework_event_t* e = celix_arrayList_get(fw->dispatcher.dynamicEventQueue, i);
+ if (e->bndEntry != NULL && e->bndEntry->bndId == bndId) {
+ eventInProgress = true;
+ break;
+ }
+ }
+ if (eventInProgress) {
+ celixThreadCondition_timedwaitRelative(&fw->dispatcher.cond, &fw->dispatcher.mutex, 5, 0);
+ }
+ }
+ celixThreadMutex_unlock(&fw->dispatcher.mutex);
+}
+
+
void celix_framework_setLogCallback(celix_framework_t* fw, void* logHandle, void (*logFunction)(void* handle, celix_log_level_e level, const char* file, const char *function, int line, const char *format, va_list formatArgs)) {
celix_frameworkLogger_setLogCallback(fw->logger, logHandle, logFunction);
}
[celix] 04/04: Fixes some issues
Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/async_svc_registration
in repository https://gitbox.apache.org/repos/asf/celix.git
commit 7511a9fbc3ea8ffcc0779e27e99153a1c23bf3ed
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Sun Oct 4 20:52:46 2020 +0200
Fixes some issues
---
bundles/http_admin/http_admin/src/http_admin.c | 7 ++++---
bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c | 3 ++-
.../remote_example_api/org.apache.celix.RemoteExample.descriptor | 2 +-
libs/framework/src/bundle_context.c | 1 +
4 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/bundles/http_admin/http_admin/src/http_admin.c b/bundles/http_admin/http_admin/src/http_admin.c
index ca7c93d..20b2287 100755
--- a/bundles/http_admin/http_admin/src/http_admin.c
+++ b/bundles/http_admin/http_admin/src/http_admin.c
@@ -122,17 +122,17 @@ void httpAdmin_destroy(http_admin_manager_t *admin) {
//Destroy alias map by removing symbolic links first.
unsigned int size = celix_arrayList_size(admin->aliasList);
- for (unsigned int i = (size - 1); i < size; i--) {
+ for (int i = 0; i < size; ++i) {
http_alias_t *alias = celix_arrayList_get(admin->aliasList, i);
//Delete alias in cache directory
- if (remove(alias->alias_path) < 0)
+ if (remove(alias->alias_path) < 0) {
fprintf(stdout, "remove of %s failed\n", alias->alias_path);
+ }
free(alias->url);
free(alias->alias_path);
free(alias);
- celix_arrayList_removeAt(admin->aliasList, i);
}
celix_arrayList_destroy(admin->aliasList);
@@ -520,6 +520,7 @@ void http_admin_stopBundle(void *data, const celix_bundle_t *bundle) {
http_alias_t *alias = arrayList_get(admin->aliasList, i);
if(alias->bundle_id == bundle_id) {
remove(alias->alias_path); //Delete alias in cache directory
+ free(alias->url);
free(alias->alias_path);
free(alias);
celix_arrayList_removeAt(admin->aliasList, i);
diff --git a/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c b/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c
index c1a715e..e7d504f 100644
--- a/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c
+++ b/bundles/pubsub/pubsub_spi/src/pubsub_endpoint.c
@@ -170,8 +170,9 @@ celix_properties_t* pubsubEndpoint_createFromPublisherTrackerInfo(bundle_context
data.topic = topic;
celix_bundleContext_useBundle(ctx, bundleId, &data, retrieveTopicProperties);
+ pubsubEndpoint_setFields(ep, fwUUID, scope, topic, PUBSUB_PUBLISHER_ENDPOINT_TYPE, NULL, NULL, NULL, data.props);
+
if (data.props != NULL) {
- pubsubEndpoint_setFields(ep, fwUUID, scope, topic, PUBSUB_PUBLISHER_ENDPOINT_TYPE, NULL, NULL, NULL, data.props);
celix_properties_destroy(data.props); //safe to delete, properties are copied in pubsubEndpoint_setFields
}
diff --git a/bundles/remote_services/examples/remote_example_api/org.apache.celix.RemoteExample.descriptor b/bundles/remote_services/examples/remote_example_api/org.apache.celix.RemoteExample.descriptor
index 6cbefb2..0558c7f 100644
--- a/bundles/remote_services/examples/remote_example_api/org.apache.celix.RemoteExample.descriptor
+++ b/bundles/remote_services/examples/remote_example_api/org.apache.celix.RemoteExample.descriptor
@@ -16,4 +16,4 @@ setName2=setName2(#am=handle;P#const=true;t#am=out;*t)N
setEnum=setEnum(#am=handle;Plenum_example;#am=pre;Lenum_example;)N
action=action(#am=handle;P)N
setComplex=setComplex(#am=handle;PLcomplex_input;#am=out;*Lcomplex_output;)N
-createAdditionalRemoteService=createAdditionalRemoteService(#am=handle;P)N
\ No newline at end of file
+createAdditionalRemoteService=createAdditionalRemoteService(#am=handle;P)N
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index 29bd2ea..34a3dcb 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -1310,6 +1310,7 @@ static long celix_bundleContext_trackServicesWithOptionsInternal(celix_bundle_co
entry->destroyEventId = celix_framework_nextEventId(ctx->framework);
celixThreadMutex_lock(&ctx->mutex);
entry->trackerId = ctx->nextTrackerId++;
+ trackerId = entry->trackerId;
hashMap_put(ctx->serviceTrackers, (void *) trackerId, entry);
celixThreadMutex_unlock(&ctx->mutex);
}
[celix] 02/04: Merge branch 'master' into
feature/async_svc_registration
Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/async_svc_registration
in repository https://gitbox.apache.org/repos/asf/celix.git
commit 815524c3f9a6409a598f7851e581d4e4c5b7b46b
Merge: a576a90 20f794b
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Sun Oct 4 15:34:15 2020 +0200
Merge branch 'master' into feature/async_svc_registration
CHANGES.md | 4 +
CMakeLists.txt | 8 +-
bundles/deployment_admin/README.md | 4 +
bundles/device_access/README.md | 4 +
.../device_access/example/base_driver/README.md | 4 +
.../example/consuming_driver/README.md | 4 +
.../example/refining_driver/README.md | 4 +
bundles/http_admin/README.md | 4 +
bundles/http_admin/civetweb/src/civetweb.c | 2 +-
bundles/logging/README.md | 4 +
bundles/logging/log_writers/README.md | 4 +
bundles/pubsub/README.md | 4 +
bundles/pubsub/examples/keys/README.md | 4 +
.../pubsub_admin_tcp/src/pubsub_tcp_handler.c | 27 +-
bundles/pubsub/pubsub_admin_udp_mc/README.md | 4 +
.../src/pubsub_websocket_topic_sender.c | 4 +-
.../pubsub_admin_zmq/src/pubsub_zmq_topic_sender.c | 118 ++--
.../pubsub_protocol_lib/CMakeLists.txt | 8 +-
.../pubsub_protocol_lib}/gtest/CMakeLists.txt | 17 +-
.../gtest/src/PS_WP_common_tests.cc | 57 ++
.../pubsub_protocol_lib/gtest/src/main.cc | 28 +-
.../src/pubsub_wire_protocol_common.c | 93 ++-
.../src/pubsub_topology_manager.c | 5 +-
.../src/pubsub_topology_manager.h | 2 +
bundles/pubsub/pubsub_utils/gtest/CMakeLists.txt | 1 +
.../gtest/msg_descriptors/int_calc.descriptor | 13 +
.../src/PubSubSerializationHandlerTestSuite.cc | 14 +
.../src/pubsub_serialization_provider.c | 21 +-
bundles/pubsub/test/CMakeLists.txt | 6 -
.../test/meta_data/deadlock.scope.properties | 2 +-
.../test/meta_data/deadlock.scope2.properties | 2 +-
bundles/pubsub/test/meta_data/ping.properties | 2 +-
bundles/pubsub/test/meta_data/ping2.properties | 2 +-
bundles/pubsub/test/meta_data/pong2.properties | 2 +-
bundles/remote_services/README.md | 6 +-
bundles/remote_services/discovery_etcd/README.md | 4 +
.../remote_example_api/include/remote_example.h | 2 +
.../org.apache.celix.RemoteExample.descriptor | 1 +
.../src/remote_example_activator.c | 3 +-
.../src/remote_example_impl.c | 49 +-
.../src/remote_example_impl.h | 4 +-
.../remote_service_admin_dfi/README.md | 4 +
.../gtest/src/rsa_client_server_tests.cc | 20 +
.../gtest/src/tst_activator.c | 33 ++
.../gtest/src/tst_service.h | 2 +
.../src/export_registration_dfi.c | 115 +++-
.../src/export_registration_dfi.h | 6 +-
.../src/remote_service_admin_dfi.c | 148 ++++-
.../remote_services/remote_services_api/README.md | 4 +
bundles/remote_services/rsa_spi/README.md | 4 +
bundles/remote_services/topology_manager/README.md | 4 +
bundles/shell/remote_shell/README.md | 4 +
bundles/shell/shell/README.md | 4 +
bundles/shell/shell_tui/README.md | 4 +
bundles/shell/shell_wui/README.md | 4 +
doap/doap_Celix.rdf | 20 +-
documents/building/README.md | 4 +
documents/cmake_commands/README.md | 4 +
documents/getting_started/README.md | 4 +
.../getting_started/creating_a_simple_bundle.md | 6 +-
documents/getting_started/using_services_with_c.md | 4 +
.../getting_started/using_services_with_cxx.md | 4 +
documents/intro/README.md | 6 +-
documents/subprojects/README.md | 6 +
examples/celix-examples/README.md | 4 +
examples/celix-examples/http_example/README.md | 7 +-
.../celix-examples/services_example_c/README.md | 4 +
libs/dependency_manager/README.md | 4 +
libs/dependency_manager/TODO.md | 6 +-
libs/dependency_manager_cxx/README.md | 4 +
libs/dependency_manager_cxx/TODO.md | 6 +-
libs/etcdlib/README.md | 4 +
libs/etcdlib/api/etcdlib.h | 16 +-
libs/etcdlib/src/etcd.c | 110 ++--
libs/etcdlib/test/etcdlib_test.c | 2 +-
libs/framework/src/service_registry.c | 10 +-
libs/launcher/README.md | 4 +
libs/utils/README.md | 4 +
misc/experimental/README.md | 4 +
misc/experimental/bundles/config_admin/README.md | 4 +
misc/experimental/promise/CMakeLists.txt | 6 +-
misc/experimental/promise/README.md | 4 +
misc/experimental/promise/api/celix/Deferred.h | 136 ++++-
misc/experimental/promise/api/celix/Promise.h | 191 +++++-
.../promise/api/celix/PromiseFactory.h | 16 +-
.../promise/api/celix/PromiseInvocationException.h | 6 +-
.../promise/api/celix/impl/SharedPromiseState.h | 654 +++++++++++++++++----
misc/experimental/promise/gtest/CMakeLists.txt | 1 +
.../promise/gtest/src/PromiseTestSuite.cc | 116 +++-
...PromiseTestSuite.cc => VoidPromiseTestSuite.cc} | 189 +++---
misc/experimental/promise/src/PromiseExamples.cc | 2 +-
91 files changed, 1903 insertions(+), 576 deletions(-)
[celix] 03/04: Update bc_useService(s) so that it can be called on
the event loop thread
Posted by pn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
pnoltes pushed a commit to branch feature/async_svc_registration
in repository https://gitbox.apache.org/repos/asf/celix.git
commit 18770324b219064a3a37a749eb3fabe7b63098e5
Author: Pepijn Noltes <pe...@gmail.com>
AuthorDate: Sun Oct 4 19:29:50 2020 +0200
Update bc_useService(s) so that it can be called on the event loop thread
---
.../org.apache.celix.RemoteExample.descriptor | 2 +-
.../gtest/src/tst_activator.c | 1 +
.../gtest/src/bundle_context_services_test.cpp | 4 ++++
libs/framework/include/celix_bundle_context.h | 21 ++++++++++++----
libs/framework/include/service_registry.h | 2 ++
libs/framework/src/bundle_context.c | 28 +++++++++++++++++-----
libs/framework/src/service_registry.c | 20 ++++++++++++++++
7 files changed, 67 insertions(+), 11 deletions(-)
diff --git a/bundles/remote_services/examples/remote_example_api/org.apache.celix.RemoteExample.descriptor b/bundles/remote_services/examples/remote_example_api/org.apache.celix.RemoteExample.descriptor
index 0558c7f..6cbefb2 100644
--- a/bundles/remote_services/examples/remote_example_api/org.apache.celix.RemoteExample.descriptor
+++ b/bundles/remote_services/examples/remote_example_api/org.apache.celix.RemoteExample.descriptor
@@ -16,4 +16,4 @@ setName2=setName2(#am=handle;P#const=true;t#am=out;*t)N
setEnum=setEnum(#am=handle;Plenum_example;#am=pre;Lenum_example;)N
action=action(#am=handle;P)N
setComplex=setComplex(#am=handle;PLcomplex_input;#am=out;*Lcomplex_output;)N
-createAdditionalRemoteService=createAdditionalRemoteService(#am=handle;P)N
+createAdditionalRemoteService=createAdditionalRemoteService(#am=handle;P)N
\ No newline at end of file
diff --git a/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c b/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c
index e3a8000..0f1cbb9 100644
--- a/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c
+++ b/bundles/remote_services/remote_service_admin_dfi/gtest/src/tst_activator.c
@@ -315,6 +315,7 @@ static celix_status_t bndStart(struct activator *act, celix_bundle_context_t* ct
act->testSvc.testCreateRemoteServiceInRemoteCall = testCreateRemoteServiceInRemoteCall;
act->testSvc.testCreateDestroyComponentWithRemoteService = bndTestCreateDestroyComponentWithRemoteService;
+ act->testSvc.testCreateRemoteServiceInRemoteCall = testCreateRemoteServiceInRemoteCall;
//create mutex
pthread_mutex_init(&act->mutex, NULL);
diff --git a/libs/framework/gtest/src/bundle_context_services_test.cpp b/libs/framework/gtest/src/bundle_context_services_test.cpp
index 9e5335f..f20a449 100644
--- a/libs/framework/gtest/src/bundle_context_services_test.cpp
+++ b/libs/framework/gtest/src/bundle_context_services_test.cpp
@@ -1063,6 +1063,9 @@ TEST_F(CelixBundleContextServicesTests, floodEventLoopTest) {
EXPECT_GE(id, 0);
svcIds.push_back(id);
trackerIds.push_back(celix_bundleContext_trackServicesAsync(ctx, "test", nullptr, nullptr, nullptr));
+
+ //CHECK if celix_bundleContext_isServiceRegistered work
+ EXPECT_FALSE(celix_bundleContext_isServiceRegistered(ctx, id));
}
{
@@ -1073,6 +1076,7 @@ TEST_F(CelixBundleContextServicesTests, floodEventLoopTest) {
}
celix_bundleContext_waitForAsyncRegistration(ctx, svcId);
+ EXPECT_TRUE(celix_bundleContext_isServiceRegistered(ctx, svcId));
long foundId = celix_bundleContext_findService(ctx, "test");
EXPECT_GE(foundId, 0);
diff --git a/libs/framework/include/celix_bundle_context.h b/libs/framework/include/celix_bundle_context.h
index 060a749..db69378 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -45,7 +45,8 @@ extern "C" {
* Register a service to the Celix framework.
*
* The service will be registered async on the Celix event loop thread. This means that service registration is (probably)
- * not yet concluded when this function returns. Use celix_bundleContext_waitForAsyncRegistration to synchronise with the
+ * not yet concluded when this function returns, but is added to the event loop.
+ * Use celix_bundleContext_waitForAsyncRegistration to synchronise with the
* actual service registration in the framework's service registry.
*
* @param ctx The bundle context
@@ -79,7 +80,8 @@ long celix_bundleContext_registerService(celix_bundle_context_t *ctx, void *svc,
* the ungetService function of the service factory will be called.
*
* The service will be registered async on the Celix event loop thread. This means that service registration is (probably)
- * not yet concluded when this function returns. Use celix_bundleContext_waitForAsyncRegistration to synchronise with the
+ * not yet concluded when this function returns, but is added to the event loop.
+ * Use celix_bundleContext_waitForAsyncRegistration to synchronise with the
* actual service registration in the framework's service registry.
*
* @param ctx The bundle context
@@ -197,7 +199,8 @@ typedef struct celix_service_registration_options {
* Register a service to the Celix framework using the provided service registration options.
*
* The service will be registered async on the Celix event loop thread. This means that service registration is (probably)
- * not yet concluded when this function returns. Use celix_bundleContext_waitForAsyncRegistration to synchronise with the
+ * not yet concluded when this function returns, but is added to the event loop..
+ * Use celix_bundleContext_waitForAsyncRegistration to synchronise with the
* actual service registration in the framework's service registry.
*
* @param ctx The bundle context
@@ -218,10 +221,20 @@ long celix_bundleContext_registerServiceWithOptions(celix_bundle_context_t *ctx,
/**
* Waits til the async service registration for the provided serviceId is done.
- * Silently ignore service < 0.
+ * Silently ignore service ids < 0.
+ * Will directly return if there is no pending service registration for the provided service id.
*/
void celix_bundleContext_waitForAsyncRegistration(celix_bundle_context_t* ctx, long serviceId);
+/**
+ * Checks whether a service for the provided service id is registered in the service registry.
+ * Note return false if the service for the provided service id is still pending in the event loop.
+ * Silently ignore service ids < 0 (returns false).
+ *
+ * Returns true if the service is registered in the service registry.
+ */
+bool celix_bundleContext_isServiceRegistered(celix_bundle_context_t* ctx, long serviceId);
+
/**
* Unregister the service or service factory with service id.
diff --git a/libs/framework/include/service_registry.h b/libs/framework/include/service_registry.h
index 44442e8..b9f1ad3 100644
--- a/libs/framework/include/service_registry.h
+++ b/libs/framework/include/service_registry.h
@@ -93,6 +93,8 @@ celix_status_t celix_serviceRegistry_addServiceListener(celix_service_registry_t
celix_status_t celix_serviceRegistry_removeServiceListener(celix_service_registry_t *reg, celix_service_listener_t *listener);
+bool celix_serviceRegistry_isServiceRegistered(celix_service_registry_t* reg, long serviceId);
+
celix_status_t
celix_serviceRegistry_registerService(
celix_service_registry_t *reg,
diff --git a/libs/framework/src/bundle_context.c b/libs/framework/src/bundle_context.c
index 70aa37c..29bd2ea 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -557,6 +557,10 @@ void celix_bundleContext_waitForAsyncRegistration(celix_bundle_context_t* ctx, l
}
}
+bool celix_bundleContext_isServiceRegistered(celix_bundle_context_t* ctx, long serviceId) {
+ return celix_serviceRegistry_isServiceRegistered(ctx->framework->registry, serviceId);
+}
+
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) {
@@ -1136,8 +1140,12 @@ bool celix_bundleContext_useServiceWithOptions(
struct timespec start;
clock_gettime(CLOCK_MONOTONIC, &start);
- long id = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "use service", &data, celix_bundleContext_useServiceWithOptionsCallback, NULL, NULL);
- celix_framework_waitForGenericEvent(ctx->framework, id);
+ if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+ celix_bundleContext_useServiceWithOptionsCallback(&data);
+ } else {
+ long id = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "use service", &data, celix_bundleContext_useServiceWithOptionsCallback, NULL, NULL);
+ celix_framework_waitForGenericEvent(ctx->framework, id);
+ }
while (!data.called && opts->waitTimeoutInSeconds > 0) {
struct timespec now;
@@ -1147,8 +1155,12 @@ bool celix_bundleContext_useServiceWithOptions(
break;
}
usleep(10);
- id = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "use service", &data, celix_bundleContext_useServiceWithOptionsCallback, NULL, NULL);
- celix_framework_waitForGenericEvent(ctx->framework, id);
+ if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+ celix_bundleContext_useServiceWithOptionsCallback(&data);
+ } else {
+ long id = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "use service", &data, celix_bundleContext_useServiceWithOptionsCallback, NULL, NULL);
+ celix_framework_waitForGenericEvent(ctx->framework, id);
+ }
}
return data.called;
}
@@ -1181,8 +1193,12 @@ size_t celix_bundleContext_useServicesWithOptions(
data.opts = *opts;
data.called = false;
- long id = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle), "use services", &data, celix_bundleContext_useServicesWithOptionsCallback, NULL, NULL);
- celix_framework_waitForGenericEvent(ctx->framework, id);
+ if (celix_framework_isCurrentThreadTheEventLoop(ctx->framework)) {
+ celix_bundleContext_useServiceWithOptionsCallback(&data);
+ } else {
+ long id = celix_framework_fireGenericEvent(ctx->framework, -1, celix_bundle_getId(ctx->bundle),"use services", &data, celix_bundleContext_useServicesWithOptionsCallback, NULL, NULL);
+ celix_framework_waitForGenericEvent(ctx->framework, id);
+ }
count = data.count;
}
return count;
diff --git a/libs/framework/src/service_registry.c b/libs/framework/src/service_registry.c
index c8570d3..1034210 100644
--- a/libs/framework/src/service_registry.c
+++ b/libs/framework/src/service_registry.c
@@ -1167,6 +1167,26 @@ long celix_serviceRegistry_nextSvcId(celix_service_registry_t* registry) {
return scvId;
}
+bool celix_serviceRegistry_isServiceRegistered(celix_service_registry_t* reg, long serviceId) {
+ bool isRegistered = false;
+ if (serviceId >= 0) {
+ celixThreadRwlock_readLock(®->lock);
+ hash_map_iterator_t iter = hashMapIterator_construct(reg->serviceRegistrations);
+ while (!isRegistered && hashMapIterator_hasNext(&iter)) {
+ celix_array_list_t *regs = hashMapIterator_nextValue(&iter);
+ for (int i = 0; i < celix_arrayList_size(regs); ++i) {
+ service_registration_t* r = celix_arrayList_get(regs, i);
+ if (serviceId == serviceRegistration_getServiceId(r)) {
+ isRegistered = true;
+ break;
+ }
+ }
+ }
+ celixThreadRwlock_unlock(®->lock);
+ }
+ return isRegistered;
+}
+
void celix_serviceRegistry_unregisterService(celix_service_registry_t* registry, celix_bundle_t* bnd, long serviceId) {
service_registration_t *reg = NULL;
celixThreadRwlock_readLock(®istry->lock);