From fd2b9354a89269963311a4e1b310ea45e4bc6780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20R=C3=BCtter?= Date: Sat, 29 Aug 2026 23:19:56 +0200 Subject: [PATCH 1/3] Replace Thread.stop() with interrupt() in UpdateThread UpdateThread.terminate() falls back to killing the worker when it fails to join within 5 seconds: Log.logger.log( LogService.LOG_ERROR, "Worker thread {0} did not terminate within 5 seconds; trying to kill", ... ); workerThread.stop(); Thread.stop() has thrown UnsupportedOperationException unconditionally since Java 20, so on any recent JDK that path can only turn a slow shutdown into a failed one: the exception propagates out of terminate() instead of the thread being stopped. It now interrupts the worker, which is the supported mechanism and releases the thread if it is waiting on an interruptible operation. The javadoc and the log message are updated to match. Co-Authored-By: Claude Opus 4.8 --- .../apache/felix/cm/impl/UpdateThread.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/configadmin/src/main/java/org/apache/felix/cm/impl/UpdateThread.java b/configadmin/src/main/java/org/apache/felix/cm/impl/UpdateThread.java index f64923e4f0..7ab2b53433 100644 --- a/configadmin/src/main/java/org/apache/felix/cm/impl/UpdateThread.java +++ b/configadmin/src/main/java/org/apache/felix/cm/impl/UpdateThread.java @@ -146,13 +146,16 @@ synchronized void start() * initiated will not be processed any more. This method does nothing if * the worker thread is not currently active. *

- * If the worker thread does not terminate within 5 seconds it is killed - * by calling the (deprecated) Thread.stop() method. It may - * be that the worker thread may be blocked by a deadlock (it should not, - * though). In this case hope is that Thread.stop() will be - * able to released that deadlock at the expense of one or more tasks to - * not be executed any longer.... In any case an ERROR message is logged - * with the LogService in this situation. + * If the worker thread does not terminate within 5 seconds it is + * interrupted. It may be that the worker thread is blocked by a deadlock + * (it should not, though); interrupting it releases the thread if it is + * waiting on an interruptible operation, at the expense of one or more + * tasks not being executed any longer. In any case an ERROR message is + * logged with the LogService in this situation. + *

+ * This used to call Thread.stop(), which has thrown + * UnsupportedOperationException since Java 20 and so could + * only turn a slow shutdown into a failed one. */ synchronized void terminate() { @@ -176,9 +179,9 @@ synchronized void terminate() if ( workerThread.isAlive() ) { Log.logger.log( LogService.LOG_ERROR, - "Worker thread {0} did not terminate within 5 seconds; trying to kill", new Object[] + "Worker thread {0} did not terminate within 5 seconds; interrupting it", new Object[] { workerBaseName } ); - workerThread.stop(); + workerThread.interrupt(); } } } From 45f6d1778d5ae3180b181b62052aca14b83b71e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20R=C3=BCtter?= Date: Sat, 29 Aug 2026 23:33:48 +0200 Subject: [PATCH 2/3] Build configadmin in CI configadmin is not in the workflow's path filters, so a pull request touching only configadmin matches no trigger and gets no build at all. This change would otherwise go in unverified. Adds it to both triggers, to the paths-filter, and as a build step. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/maven-ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index ded3fe1d5b..61c66f2ad7 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -13,6 +13,7 @@ on: - 'framework/**' - 'gogo/**' - 'framework.tck/**' + - 'configadmin/**' pull_request: branches: [ "master", "feature/**", "maintenance/**" ] paths: @@ -25,6 +26,7 @@ on: - 'framework/**' - 'gogo/**' - 'framework.tck/**' + - 'configadmin/**' # Cancel superseded runs when a branch is pushed again. github.head_ref is only set # for pull_request events, so pushes to master fall back to the unique run_id and are @@ -76,6 +78,8 @@ jobs: - 'framework.tck/**' gogo: - 'gogo/**' + configadmin: + - 'configadmin/**' - name: Felix SCR if: steps.changes.outputs.scr == 'true' run: mvn -B -V -Dstyle.color=always --file scr/pom.xml clean verify @@ -103,6 +107,9 @@ jobs: - name: Felix Gogo Shell if: steps.changes.outputs.gogo == 'true' run: mvn -B -V -Dstyle.color=always --file gogo/pom.xml clean verify + - name: Felix Config Admin + if: steps.changes.outputs.configadmin == 'true' + run: mvn -B -V -Dstyle.color=always --file configadmin/pom.xml clean verify - name: Upload Test Results if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 From 3e9c967de271036b595c1db3618c03fc409af77d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20R=C3=BCtter?= Date: Sat, 29 Aug 2026 23:38:24 +0200 Subject: [PATCH 3/3] Revert "Build configadmin in CI" This reverts commit 45f6d1778d5ae3180b181b62052aca14b83b71e9. --- .github/workflows/maven-ci.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index 61c66f2ad7..ded3fe1d5b 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -13,7 +13,6 @@ on: - 'framework/**' - 'gogo/**' - 'framework.tck/**' - - 'configadmin/**' pull_request: branches: [ "master", "feature/**", "maintenance/**" ] paths: @@ -26,7 +25,6 @@ on: - 'framework/**' - 'gogo/**' - 'framework.tck/**' - - 'configadmin/**' # Cancel superseded runs when a branch is pushed again. github.head_ref is only set # for pull_request events, so pushes to master fall back to the unique run_id and are @@ -78,8 +76,6 @@ jobs: - 'framework.tck/**' gogo: - 'gogo/**' - configadmin: - - 'configadmin/**' - name: Felix SCR if: steps.changes.outputs.scr == 'true' run: mvn -B -V -Dstyle.color=always --file scr/pom.xml clean verify @@ -107,9 +103,6 @@ jobs: - name: Felix Gogo Shell if: steps.changes.outputs.gogo == 'true' run: mvn -B -V -Dstyle.color=always --file gogo/pom.xml clean verify - - name: Felix Config Admin - if: steps.changes.outputs.configadmin == 'true' - run: mvn -B -V -Dstyle.color=always --file configadmin/pom.xml clean verify - name: Upload Test Results if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1