This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/refactor_bundle_cache
in repository https://gitbox.apache.org/repos/asf/celix.git


The following commit(s) were added to refs/heads/feature/refactor_bundle_cache 
by this push:
     new 38176b64 Fire and forget bundle lifecycle handler.
     new cb2501b6 Merge remote-tracking branch 
'apache/feature/refactor_bundle_cache' into feature/refactor_bundle_cache
38176b64 is described below

commit 38176b645e46f87adf20e7e15ed0ebb48b373c4a
Author: PengZheng <[email protected]>
AuthorDate: Thu Feb 23 11:59:48 2023 +0800

    Fire and forget bundle lifecycle handler.
---
 libs/framework/src/framework.c                     |  6 ++--
 .../src/framework_bundle_lifecycle_handler.c       | 41 ++++++++++------------
 libs/framework/src/framework_private.h             | 11 +++---
 3 files changed, 26 insertions(+), 32 deletions(-)

diff --git a/libs/framework/src/framework.c b/libs/framework/src/framework.c
index ec2d4aa3..bdde2737 100644
--- a/libs/framework/src/framework.c
+++ b/libs/framework/src/framework.c
@@ -295,6 +295,7 @@ celix_status_t framework_create(framework_pt *out, 
celix_properties_t* config) {
     }
 
     //setup framework bundle lifecycle handling
+    celixThreadCondition_init(&framework->bundleLifecycleHandling.cond, NULL);
     celixThreadMutex_create(&framework->bundleLifecycleHandling.mutex, NULL);
     framework->bundleLifecycleHandling.bundleLifecycleHandlers = 
celix_arrayList_create();
 
@@ -369,9 +370,10 @@ celix_status_t framework_destroy(framework_pt framework) {
     celixThreadMutex_destroy(&framework->installedBundles.mutex);
 
     //teardown framework bundle lifecycle handling
-    celixThreadMutex_destroy(&framework->bundleLifecycleHandling.mutex);
     
assert(celix_arrayList_size(framework->bundleLifecycleHandling.bundleLifecycleHandlers)
 == 0);
     
celix_arrayList_destroy(framework->bundleLifecycleHandling.bundleLifecycleHandlers);
+    celixThreadMutex_destroy(&framework->bundleLifecycleHandling.mutex);
+    celixThreadCondition_destroy(&framework->bundleLifecycleHandling.cond);
 
     hashMap_destroy(framework->installRequestMap, false, false);
 
@@ -1194,7 +1196,7 @@ static void* framework_shutdown(void *framework) {
 
     fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "Celix framework shutting down");
 
-    celix_framework_cleanupBundleLifecycleHandlers(fw, true);
+    celix_framework_waitForBundleLifecycleHandlers(fw);
 
     celix_array_list_t *stopEntries = celix_arrayList_create();
     celix_framework_bundle_entry_t *fwEntry = NULL;
diff --git a/libs/framework/src/framework_bundle_lifecycle_handler.c 
b/libs/framework/src/framework_bundle_lifecycle_handler.c
index 882281ad..c0851943 100644
--- a/libs/framework/src/framework_bundle_lifecycle_handler.c
+++ b/libs/framework/src/framework_bundle_lifecycle_handler.c
@@ -23,6 +23,15 @@
 #include "celix_log.h"
 #include "bundle.h"
 
+static void celix_framework_cleanupBundleLifecycleHandler(celix_framework_t* 
fw, celix_framework_bundle_lifecycle_handler_t *handler) {
+    celixThreadMutex_lock(&fw->bundleLifecycleHandling.mutex);
+    
celix_arrayList_remove(fw->bundleLifecycleHandling.bundleLifecycleHandlers, 
handler);
+    free(handler->updatedBundleUrl);
+    free(handler);
+    celixThreadCondition_broadcast(&fw->bundleLifecycleHandling.cond);
+    celixThreadMutex_unlock(&fw->bundleLifecycleHandling.mutex);
+}
+
 /**
  * Functions focusing on handling stop, start, uninstall or update bundle 
commands so that they will not be executed on the celix Event thread.
  */
@@ -44,11 +53,10 @@ static void* 
celix_framework_BundleLifecycleHandlingThread(void *data) {
             celix_framework_updateBundleEntry(handler->framework, 
handler->bndEntry, handler->updatedBundleUrl);
             break;
     }
-    int doneVal = 1;
-    __atomic_store(&handler->done, &doneVal, __ATOMIC_SEQ_CST);
     if (handler->command != CELIX_BUNDLE_LIFECYCLE_UNINSTALL) {
         celix_framework_bundleEntry_decreaseUseCount(handler->bndEntry);
     }
+    celix_framework_cleanupBundleLifecycleHandler(handler->framework, handler);
     return NULL;
 }
 
@@ -65,27 +73,12 @@ static const char* 
celix_bundleLifecycleCommand_getDesc(enum celix_bundle_lifecy
     }
 }
 
-void celix_framework_cleanupBundleLifecycleHandlers(celix_framework_t* fw, 
bool waitTillEmpty) {
+void celix_framework_waitForBundleLifecycleHandlers(celix_framework_t* fw) {
     celixThreadMutex_lock(&fw->bundleLifecycleHandling.mutex);
-    bool cont = true;
-    while (cont) {
-        cont = false; //only continue if thread is joined or if waitTillEmpty 
and list is not empty.
-        for (int i = 0; i < 
celix_arrayList_size(fw->bundleLifecycleHandling.bundleLifecycleHandlers); ++i) 
{
-            celix_framework_bundle_lifecycle_handler_t* handler = 
celix_arrayList_get(fw->bundleLifecycleHandling.bundleLifecycleHandlers, i);
-            if (__atomic_load_n(&handler->done, __ATOMIC_RELAXED) > 0) {
-                celixThread_join(handler->thread, NULL);
-                fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "Joined thread for 
%s bundle %li",
-                       celix_bundleLifecycleCommand_getDesc(handler->command) 
, handler->bndId);
-                
celix_arrayList_removeAt(fw->bundleLifecycleHandling.bundleLifecycleHandlers, 
i);
-                free(handler->updatedBundleUrl);
-                free(handler);
-                cont = true;
-                break;
-            }
-        }
-        if (!cont) {
-            cont = waitTillEmpty && 
celix_arrayList_size(fw->bundleLifecycleHandling.bundleLifecycleHandlers) != 0;
-        }
+    while 
(celix_arrayList_size(fw->bundleLifecycleHandling.bundleLifecycleHandlers) != 
0) {
+        fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "%d bundle lifecycle 
handlers left, waiting",
+               
celix_arrayList_size(fw->bundleLifecycleHandling.bundleLifecycleHandlers));
+        
celixThreadCondition_timedwaitRelative(&fw->bundleLifecycleHandling.cond, 
&fw->bundleLifecycleHandling.mutex, 5, 0);
     }
     celixThreadMutex_unlock(&fw->bundleLifecycleHandling.mutex);
 }
@@ -103,7 +96,9 @@ static void 
celix_framework_createAndStartBundleLifecycleHandler(celix_framework
 
     fw_log(fw->logger, CELIX_LOG_LEVEL_TRACE, "Creating thread for %s bundle 
%li",
            celix_bundleLifecycleCommand_getDesc(handler->command) , 
handler->bndId);
-    celixThread_create(&handler->thread, NULL, 
celix_framework_BundleLifecycleHandlingThread, handler);
+    celix_thread_t handlerTask;
+    celixThread_create(&handlerTask, NULL, 
celix_framework_BundleLifecycleHandlingThread, handler);
+    celixThread_detach(handlerTask);
     celixThreadMutex_unlock(&fw->bundleLifecycleHandling.mutex);
 }
 
diff --git a/libs/framework/src/framework_private.h 
b/libs/framework/src/framework_private.h
index b6fd06ce..3f7d21a5 100644
--- a/libs/framework/src/framework_private.h
+++ b/libs/framework/src/framework_private.h
@@ -115,13 +115,11 @@ enum celix_bundle_lifecycle_command {
 };
 
 typedef struct celix_framework_bundle_lifecycle_handler {
-    celix_thread_t thread;
     celix_framework_t* framework;
     celix_framework_bundle_entry_t* bndEntry;
     long bndId;
     char* updatedBundleUrl; //only relevant and present for update command
     enum celix_bundle_lifecycle_command command;
-    int done; //NOTE atomic -> 0 not done, 1 done (thread can be joined)
 } celix_framework_bundle_lifecycle_handler_t;
 
 struct celix_framework {
@@ -182,6 +180,7 @@ struct celix_framework {
     long nextGenericEventId;
 
     struct {
+        celix_thread_cond_t cond;
         celix_thread_mutex_t mutex; //protects below
         celix_array_list_t* bundleLifecycleHandlers; //entry = 
celix_framework_bundle_lifecycle_handler_t*
     } bundleLifecycleHandling;
@@ -402,7 +401,6 @@ celix_status_t 
celix_framework_uninstallBundleOnANonCelixEventThread(celix_frame
 /**
  * Update (and if needed stop and start) a bundle and ensure that this is not 
done on the Celix event thread.
  * Will spawn a thread if needed.
- * @param fw The Celix framework
  * @param bndEntry A bnd entry
  * @param forceSpawnThread If the true, the start bundle will always be done 
on a spawn thread
  * @return CELIX_SUCCESS of the call went alright.
@@ -410,11 +408,10 @@ celix_status_t 
celix_framework_uninstallBundleOnANonCelixEventThread(celix_frame
 celix_status_t 
celix_framework_updateBundleOnANonCelixEventThread(celix_framework_t* fw, 
celix_framework_bundle_entry_t* bndEntry, const char* updatedBundleUrl, bool 
forceSpawnThread);
 
 /**
- * cleanup finished bundle lifecyles threads.
- * @param fw                The framework.
- * @param waitTillEmpty     Whether to wait for all threads to be finished.
+ * Wait for all bundle lifecycle handlers finishing their jobs.
+ * @param fw The Celix framework
  */
-void celix_framework_cleanupBundleLifecycleHandlers(celix_framework_t* fw, 
bool waitTillEmpty);
+void celix_framework_waitForBundleLifecycleHandlers(celix_framework_t* fw);
 
 /**
  * Start a bundle. Cannot be called on the Celix event thread.

Reply via email to