From 87c087996224f78a228c8b2c1e0f9fbd4b79d3e3 Mon Sep 17 00:00:00 2001 From: Alexandre Bique Date: Sat, 19 Aug 2023 15:05:10 +0200 Subject: [PATCH 1/9] Add initial draft for background threads --- ChangeLog.md | 1 + include/clap/clap.h | 1 + include/clap/ext/draft/background-operation.h | 92 +++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 include/clap/ext/draft/background-operation.h diff --git a/ChangeLog.md b/ChangeLog.md index 26a20f83..98245186 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -12,6 +12,7 @@ * [undo.h](include/clap/ext/draft/undo.h): undo support * [incremental-state.h](include/clap/ext/draft/incremental-state.h): incremental state +* [background-thread.h](include/clap/ext/draft/background-operation.h): run some operations in background # Changes in 1.1.8 diff --git a/include/clap/clap.h b/include/clap/clap.h index 72fab306..4f3dec96 100644 --- a/include/clap/clap.h +++ b/include/clap/clap.h @@ -55,6 +55,7 @@ #include "ext/draft/ambisonic.h" #include "ext/draft/audio-ports-activation.h" +#include "ext/draft/background-operation.h" #include "ext/draft/context-menu.h" #include "ext/draft/cv.h" #include "ext/draft/midi-mappings.h" diff --git a/include/clap/ext/draft/background-operation.h b/include/clap/ext/draft/background-operation.h new file mode 100644 index 00000000..ab32e271 --- /dev/null +++ b/include/clap/ext/draft/background-operation.h @@ -0,0 +1,92 @@ +#pragma once + +#include "../../plugin.h" + +static const char CLAP_EXT_BACKGROUND_OPERATION[] = "clap.background_operation.draft/0"; + +/* + +This extension let the host execute some operations on a background thread. + +Some operations can be CPU intensive and require a considerable amount of time, and being force to +run them on the main thread prevent parallelisation. + +For example, loading a state or activating a plugin can require a bit of processing. +When loading a large project, with a thousand of plugin instances, it is desirable to be able +to load the plugin state and activate the plugin in a background thread. This can significantly +improve the loading time. + +Concurrency isn't a trivial thing, and this extension should only be implemented if the plugin has +expensive tasks to perform during load state or activate. + +Here is how this extension works: + +1. Check which operation can be performed in background + + plugin_bgop->is_supported(plugin, CLAP_EXT_STATE); + +2. Inform the plugin that the host is about to start a background operation + + const bool can_start = plugin_bgop->about_to_start(plugin); + + Once about_to_start() is called, no more call can be made on the main thread. + If the background thread couldn't be created then it is allowed to jump to the step 6. immediately. + +3. Inform the plugin that we've setup the background thread and are about to start (on the + background thread) + + plugin_bgop->started(plugin); + +4. Perform the background operations + + plugin_state->load(...) + ... + plugin->activate(...) + +5. Inform the plugin that we're about to quit the background thread + + plugin_bgop->about_to_finish(plugin); + +6. Inform the plugin that we're done and back onto the main thread + + plugin_bgop->finished(plugin); + +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct clap_plugin_background_operation { + // Returns true if an extension can be used in [bgop-thread]. + // [main-thread] + bool(CLAP_ABI *is_supported)(const clap_plugin_t *plugin, const char *extension_id); + + // The host is about to start a background operation. + // Return false to cancel the background operation. + // If the plugin returns true then no further call can be made on the [main-thread] by the plugin + // and host, except `finished()`. + // + // [main-thread] + bool(CLAP_ABI *about_to_start)(const clap_plugin_t *plugin); + + // The background operation has started. + // The background thread must remain the same for the whole background operation. + // + // [bgop-thread] + void(CLAP_ABI *started)(const clap_plugin_t *plugin); + + // The background operation is about to finish. + // [bgop-thread] + void(CLAP_ABI *about_to_finish)(const clap_plugin_t *plugin); + + // The background operation is now finished. + // The plugin and host can call each other on the [main-thread] again. + // + // [main-thread] + void(CLAP_ABI *finished)(const clap_plugin_t *plugin); +} clap_plugin_background_operation_t; + +#ifdef __cplusplus +} +#endif From 97096462c668f7449dc4f963d288cebc2ada3d9c Mon Sep 17 00:00:00 2001 From: Alexandre Bique Date: Sat, 19 Aug 2023 16:26:38 +0200 Subject: [PATCH 2/9] Doc. --- include/clap/ext/draft/background-operation.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/clap/ext/draft/background-operation.h b/include/clap/ext/draft/background-operation.h index ab32e271..64f6dafa 100644 --- a/include/clap/ext/draft/background-operation.h +++ b/include/clap/ext/draft/background-operation.h @@ -19,6 +19,8 @@ improve the loading time. Concurrency isn't a trivial thing, and this extension should only be implemented if the plugin has expensive tasks to perform during load state or activate. +Implementing this extension implies that plugin->activate() can be called from a [bgop-thread]. + Here is how this extension works: 1. Check which operation can be performed in background From 83b88d5230ee0e0563689badefd251b3349a9499 Mon Sep 17 00:00:00 2001 From: Alexandre Bique Date: Sat, 19 Aug 2023 16:28:29 +0200 Subject: [PATCH 3/9] doc. --- include/clap/ext/draft/background-operation.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/clap/ext/draft/background-operation.h b/include/clap/ext/draft/background-operation.h index 64f6dafa..832c4f9e 100644 --- a/include/clap/ext/draft/background-operation.h +++ b/include/clap/ext/draft/background-operation.h @@ -32,14 +32,16 @@ Here is how this extension works: const bool can_start = plugin_bgop->about_to_start(plugin); Once about_to_start() is called, no more call can be made on the main thread. - If the background thread couldn't be created then it is allowed to jump to the step 6. immediately. + If the background thread couldn't be created then it is allowed to jump to the step 6. + immediately. 3. Inform the plugin that we've setup the background thread and are about to start (on the background thread) plugin_bgop->started(plugin); -4. Perform the background operations +4. Perform the background operations, the host call any method from supported extensions which are + marked as [main-thread] on the [bgop-thread]. plugin_state->load(...) ... From 6d2f16db7534dc452371fc5dc960384e494d55d0 Mon Sep 17 00:00:00 2001 From: Alexandre Bique Date: Sat, 19 Aug 2023 18:43:31 +0200 Subject: [PATCH 4/9] Update include/clap/ext/draft/background-operation.h Co-authored-by: Russell McClellan --- include/clap/ext/draft/background-operation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/clap/ext/draft/background-operation.h b/include/clap/ext/draft/background-operation.h index 832c4f9e..7942dfd7 100644 --- a/include/clap/ext/draft/background-operation.h +++ b/include/clap/ext/draft/background-operation.h @@ -8,7 +8,7 @@ static const char CLAP_EXT_BACKGROUND_OPERATION[] = "clap.background_operation.d This extension let the host execute some operations on a background thread. -Some operations can be CPU intensive and require a considerable amount of time, and being force to +Some operations can be CPU intensive and require a considerable amount of time, and being forced to run them on the main thread prevent parallelisation. For example, loading a state or activating a plugin can require a bit of processing. From b95a3299253dd6d35f1d4611b9cd395f9b0e1317 Mon Sep 17 00:00:00 2001 From: Alexandre Bique Date: Sat, 19 Aug 2023 18:43:40 +0200 Subject: [PATCH 5/9] Update include/clap/ext/draft/background-operation.h Co-authored-by: Russell McClellan --- include/clap/ext/draft/background-operation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/clap/ext/draft/background-operation.h b/include/clap/ext/draft/background-operation.h index 7942dfd7..c38ab727 100644 --- a/include/clap/ext/draft/background-operation.h +++ b/include/clap/ext/draft/background-operation.h @@ -9,7 +9,7 @@ static const char CLAP_EXT_BACKGROUND_OPERATION[] = "clap.background_operation.d This extension let the host execute some operations on a background thread. Some operations can be CPU intensive and require a considerable amount of time, and being forced to -run them on the main thread prevent parallelisation. +run them on the main thread prevents parallelisation. For example, loading a state or activating a plugin can require a bit of processing. When loading a large project, with a thousand of plugin instances, it is desirable to be able From 089474483a4edb26c4292ccfcdbb42334a8d7cce Mon Sep 17 00:00:00 2001 From: Alexandre Bique Date: Sat, 19 Aug 2023 18:43:48 +0200 Subject: [PATCH 6/9] Update include/clap/ext/draft/background-operation.h Co-authored-by: Russell McClellan --- include/clap/ext/draft/background-operation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/clap/ext/draft/background-operation.h b/include/clap/ext/draft/background-operation.h index c38ab727..baef4614 100644 --- a/include/clap/ext/draft/background-operation.h +++ b/include/clap/ext/draft/background-operation.h @@ -12,7 +12,7 @@ Some operations can be CPU intensive and require a considerable amount of time, run them on the main thread prevents parallelisation. For example, loading a state or activating a plugin can require a bit of processing. -When loading a large project, with a thousand of plugin instances, it is desirable to be able +When loading a large project, with a thousand plugin instances, it is desirable to be able to load the plugin state and activate the plugin in a background thread. This can significantly improve the loading time. From 0fc1cff889680f45b5f0f705c99beacfe61b9bc3 Mon Sep 17 00:00:00 2001 From: Alexandre Bique Date: Wed, 23 Aug 2023 11:17:53 +0200 Subject: [PATCH 7/9] Documentation --- include/clap/ext/draft/background-operation.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/clap/ext/draft/background-operation.h b/include/clap/ext/draft/background-operation.h index baef4614..d6673ade 100644 --- a/include/clap/ext/draft/background-operation.h +++ b/include/clap/ext/draft/background-operation.h @@ -16,6 +16,13 @@ When loading a large project, with a thousand plugin instances, it is desirable to load the plugin state and activate the plugin in a background thread. This can significantly improve the loading time. +This design choose to use a clear transition from the main-thread to the background thread, +because it is then clear what to expect and how the inter-action will hapen. The other approach +would be to just let the host call a set of functions at anytime from a random thread which +would force the plugin into a highly defensive implementation regarding multi-threading where it'd +become unclear what will happen when and on which threads, and it creates a thousand of possible +scenarios. + Concurrency isn't a trivial thing, and this extension should only be implemented if the plugin has expensive tasks to perform during load state or activate. From 2b788986a4d23ad255666e11f042cb57eebd9182 Mon Sep 17 00:00:00 2001 From: Alexandre Bique Date: Wed, 23 Aug 2023 11:20:30 +0200 Subject: [PATCH 8/9] Doc. --- include/clap/ext/draft/background-operation.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/clap/ext/draft/background-operation.h b/include/clap/ext/draft/background-operation.h index d6673ade..2169ba95 100644 --- a/include/clap/ext/draft/background-operation.h +++ b/include/clap/ext/draft/background-operation.h @@ -68,6 +68,7 @@ Here is how this extension works: extern "C" { #endif +// Implementing this extension implies that plugin->activate() can be called from a [bgop-thread]. typedef struct clap_plugin_background_operation { // Returns true if an extension can be used in [bgop-thread]. // [main-thread] From bc18ee36c9a26fc022de92ea60826b6af23fd560 Mon Sep 17 00:00:00 2001 From: Alexandre Bique Date: Wed, 23 Aug 2023 11:30:23 +0200 Subject: [PATCH 9/9] Doc. --- include/clap/ext/draft/background-operation.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/clap/ext/draft/background-operation.h b/include/clap/ext/draft/background-operation.h index 2169ba95..062428ea 100644 --- a/include/clap/ext/draft/background-operation.h +++ b/include/clap/ext/draft/background-operation.h @@ -38,7 +38,7 @@ Here is how this extension works: const bool can_start = plugin_bgop->about_to_start(plugin); - Once about_to_start() is called, no more call can be made on the main thread. + After about_to_start() returned true, no more call can be made on the main thread by the plugin and host. If the background thread couldn't be created then it is allowed to jump to the step 6. immediately.