Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions Source/Thunder/PluginServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,15 @@ namespace PluginHost {
}

_composit.ReleaseInterfaces();
_handler = nullptr;

_pluginHandling.Unlock();

if (currentIF != nullptr) {
_external.SetInterface(nullptr);
currentIF->Release();
}

if (_connection != nullptr) {
// Lets record the ID associated with this connection.
// If the other end of this connection (indicated by the
Expand All @@ -1697,15 +1706,6 @@ namespace PluginHost {
_connection = nullptr;
}

_handler = nullptr;

_pluginHandling.Unlock();

if (currentIF != nullptr) {
_external.SetInterface(nullptr);
currentIF->Release();
}

if (_library.IsLoaded() == true) {
Core::ServiceAdministrator::Instance().ReleaseLibrary(std::move(_library));
}
Expand Down
22 changes: 15 additions & 7 deletions Source/ThunderPlugin/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,11 @@ POP_WARNING()
else {
TRACE_L1("All living objects are killed. Time for HaraKiri!!.");

// Seems there is no more live here, time to signal the
// WorkerPool to quit running and close down...
_parent.Stop();
if (_parent.HostsPluginInterface() == false) {
// IPlugin interface is released by the host, which
// terminates this process after the final proxy release completes
_parent.Stop();
}
}
}
void Destructed() override {
Expand Down Expand Up @@ -111,10 +113,11 @@ POP_WARNING()
WorkerPoolImplementation& operator=(const WorkerPoolImplementation&) = delete;

PUSH_WARNING(DISABLE_WARNING_THIS_IN_MEMBER_INITIALIZER_LIST)
WorkerPoolImplementation(const uint8_t threads, const uint32_t stackSize, const uint32_t queueSize, const string& callsign, const uint8_t additionalThreads = 1)
WorkerPoolImplementation(const uint8_t threads, const uint32_t stackSize, const uint32_t queueSize, const string& callsign, const uint32_t interfaceId, const uint8_t additionalThreads = 1)
: WorkerPool((threads - additionalThreads), stackSize, queueSize, &_dispatcher, this, (threads > 2 ? (threads - 1) : threads), (threads > 2 ? (threads - 1) : threads), additionalThreads)
, _dispatcher(callsign)
, _sink(*this)
, _interfaceId(interfaceId)
{
Core::ServiceAdministrator::Instance().Callback(&_sink);

Expand Down Expand Up @@ -147,6 +150,10 @@ POP_WARNING()
{
Core::WorkerPool::Stop();
}
bool HostsPluginInterface() const
{
return (_interfaceId == PluginHost::IPlugin::ID);
}
void Idle() override
{
// If we handled all pending requests, it is safe to "unload"
Expand All @@ -165,6 +172,7 @@ POP_WARNING()
private:
Dispatcher _dispatcher;
Sink _sink;
const uint32_t _interfaceId;
};

class ConsoleOptions : public Core::Options {
Expand Down Expand Up @@ -503,10 +511,10 @@ class ProcessFlow {

_lock.Unlock();
}
void Startup(const uint8_t threadCount, const Core::NodeId& remoteNode, const string& callsign)
void Startup(const uint8_t threadCount, const Core::NodeId& remoteNode, const string& callsign, const uint32_t interfaceId)
{
// Seems like we have enough information, open up the Process communcication Channel.
_engine = Core::ProxyType<Process::WorkerPoolImplementation>::Create(threadCount, Core::Thread::DefaultStackSize(), 16, callsign);
_engine = Core::ProxyType<Process::WorkerPoolImplementation>::Create(threadCount, Core::Thread::DefaultStackSize(), 16, callsign, interfaceId);

// Whenever someone is looking for a WorkerPool, here it is, register it..
Core::IWorkerPool::Assign(&(*_engine));
Expand Down Expand Up @@ -709,7 +717,7 @@ int main(int argc, char** argv)
Core::ProcessCurrent().User(string(options.User));
}

process.Startup(options.Threads, remoteNode, callsign);
process.Startup(options.Threads, remoteNode, callsign, options.InterfaceId);

// Register an interface to handle incoming requests for interfaces.
if ((base = Process::AcquireInterfaces(options)) != nullptr) {
Expand Down
23 changes: 23 additions & 0 deletions docs/plugin/execution-modes/outofprocess.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@ When the plugin is activated, Thunder will automatically spawn a ThunderPlugin i
!!! tip
For larger, more complex out-of-process plugins, it is often useful to split a plugin into two separate libraries - see [here](../split-implementation) for more details.

## Whole plugin OOP

It is also possible to run the full plugin out of process. This allows a plugin to be hosted by `ThunderPlugin` even if it was not split or specifically designed for the traditional OOP plugin model. In this mode, `PluginHost::IPlugin` itself is hosted by `ThunderPlugin`.

This is mainly useful as a development and debugging option. For example, it can be used to isolate leaks,crashes, or shutdown behavior in plugins that were originally designed to run in process.

To enable this mode, add a top-level `root` section to the plugin configuration:

```json
{
"locator": "libThunderSamplePlugin.so",
"classname": "SamplePlugin",
"startmode": "Activated",
"root": {
"mode": "Local"
},
"configuration": {
}
}
```

Other root modes may also work, but `Local` is the mode covered by this documentation.

**Advantages**

* Reliability - if a plugin crashes, it will only bring down the ThunderPlugin instance and therefore not affect any other plugin. It can then be restarted as necessary
Expand Down
Loading