Skip to content

Commit c6e5a35

Browse files
committed
core/reloader: fix more crashes (not all of them)
1 parent 31462b9 commit c6e5a35

File tree

4 files changed

+52
-21
lines changed

4 files changed

+52
-21
lines changed

src/core/generation.cpp

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,46 @@ static QHash<QQmlEngine*, EngineGeneration*> g_generations; // NOLINT
2626

2727
EngineGeneration::EngineGeneration(QmlScanner scanner)
2828
: scanner(std::move(scanner))
29-
, interceptNetFactory(this->scanner.qmldirIntercepts) {
30-
g_generations.insert(&this->engine, this);
29+
, interceptNetFactory(this->scanner.qmldirIntercepts)
30+
, engine(new QQmlEngine()) {
31+
g_generations.insert(this->engine, this);
3132

32-
this->engine.addUrlInterceptor(&this->urlInterceptor);
33-
this->engine.setNetworkAccessManagerFactory(&this->interceptNetFactory);
34-
this->engine.setIncubationController(&this->delayedIncubationController);
33+
this->engine->addUrlInterceptor(&this->urlInterceptor);
34+
this->engine->setNetworkAccessManagerFactory(&this->interceptNetFactory);
35+
this->engine->setIncubationController(&this->delayedIncubationController);
3536

36-
this->engine.addImageProvider("icon", new IconImageProvider());
37+
this->engine->addImageProvider("icon", new IconImageProvider());
3738

3839
QuickshellPlugin::runConstructGeneration(*this);
3940
}
4041

4142
EngineGeneration::~EngineGeneration() {
42-
g_generations.remove(&this->engine);
43-
if (this->root != nullptr) this->root->deleteLater();
43+
g_generations.remove(this->engine);
44+
delete this->engine;
4445
}
4546

4647
void EngineGeneration::destroy() {
47-
if (this->root != nullptr) {
48+
// Multiple generations can detect a reload at the same time.
49+
delete this->watcher;
50+
this->watcher = nullptr;
51+
52+
// Yes all of this is actually necessary.
53+
if (this->engine != nullptr && this->root != nullptr) {
4854
QObject::connect(this->root, &QObject::destroyed, this, [this]() {
49-
delete this;
55+
// The timer seems to fix *one* of the possible qml item destructor crashes.
56+
QTimer::singleShot(0, [this]() {
57+
// Garbage is not collected during engine destruction.
58+
this->engine->collectGarbage();
59+
60+
QObject::connect(this->engine, &QObject::destroyed, this, [this]() { delete this; });
61+
62+
// Even after all of that there's still multiple failing assertions and segfaults.
63+
// Pray you don't hit one.
64+
// Note: it appeats *some* of the crashes are related to values owned by the generation.
65+
// Test by commenting the connect() above.
66+
this->engine->deleteLater();
67+
this->engine = nullptr;
68+
});
5069
});
5170

5271
this->root->deleteLater();
@@ -63,23 +82,26 @@ void EngineGeneration::onReload(EngineGeneration* old) {
6382
}
6483

6584
auto* app = QCoreApplication::instance();
66-
QObject::connect(&this->engine, &QQmlEngine::quit, app, &QCoreApplication::quit);
67-
QObject::connect(&this->engine, &QQmlEngine::exit, app, &QCoreApplication::exit);
85+
QObject::connect(this->engine, &QQmlEngine::quit, app, &QCoreApplication::quit);
86+
QObject::connect(this->engine, &QQmlEngine::exit, app, &QCoreApplication::exit);
6887

6988
this->root->reload(old == nullptr ? nullptr : old->root);
7089
this->singletonRegistry.onReload(old == nullptr ? nullptr : &old->singletonRegistry);
7190
this->reloadComplete = true;
7291
emit this->reloadFinished();
7392

7493
if (old != nullptr) {
75-
old->destroy();
7694
QObject::connect(old, &QObject::destroyed, this, [this]() { this->postReload(); });
95+
old->destroy();
7796
} else {
7897
this->postReload();
7998
}
8099
}
81100

82101
void EngineGeneration::postReload() {
102+
// This can be called on a generation during its destruction.
103+
if (this->engine == nullptr || this->root == nullptr) return;
104+
83105
QuickshellPlugin::runOnReload();
84106
PostReloadHook::postReloadTree(this->root);
85107
this->singletonRegistry.onPostReload();
@@ -132,7 +154,10 @@ void EngineGeneration::registerIncubationController(QQmlIncubationController* co
132154

133155
qCDebug(logIncubator) << "Registered incubation controller" << controller;
134156

135-
if (this->engine.incubationController() == &this->delayedIncubationController) {
157+
// This function can run during destruction.
158+
if (this->engine == nullptr) return;
159+
160+
if (this->engine->incubationController() == &this->delayedIncubationController) {
136161
this->assignIncubationController();
137162
}
138163
}
@@ -156,7 +181,10 @@ void EngineGeneration::deregisterIncubationController(QQmlIncubationController*
156181
qCDebug(logIncubator) << "Deregistered incubation controller" << controller;
157182
}
158183

159-
if (this->engine.incubationController() == controller) {
184+
// This function can run during destruction.
185+
if (this->engine == nullptr) return;
186+
187+
if (this->engine->incubationController() == controller) {
160188
qCDebug(logIncubator
161189
) << "Destroyed incubation controller was currently active, reassigning from pool";
162190
this->assignIncubationController();
@@ -183,7 +211,10 @@ void EngineGeneration::incubationControllerDestroyed() {
183211
qCDebug(logIncubator) << "Destroyed incubation controller" << controller << "deregistered";
184212
}
185213

186-
if (this->engine.incubationController() == controller) {
214+
// This function can run during destruction.
215+
if (this->engine == nullptr) return;
216+
217+
if (this->engine->incubationController() == controller) {
187218
qCDebug(logIncubator
188219
) << "Destroyed incubation controller was currently active, reassigning from pool";
189220
this->assignIncubationController();
@@ -198,7 +229,7 @@ void EngineGeneration::assignIncubationController() {
198229
qCDebug(logIncubator) << "Assigning incubation controller to engine:" << controller
199230
<< "fallback:" << (controller == &this->delayedIncubationController);
200231

201-
this->engine.setIncubationController(controller);
232+
this->engine->setIncubationController(controller);
202233
}
203234

204235
EngineGeneration* EngineGeneration::findObjectGeneration(QObject* object) {

src/core/generation.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class EngineGeneration: public QObject {
3636
QmlScanner scanner;
3737
QsUrlInterceptor urlInterceptor;
3838
QsInterceptNetworkAccessManagerFactory interceptNetFactory;
39-
QQmlEngine engine;
39+
QQmlEngine* engine = nullptr;
4040
ShellRoot* root = nullptr;
4141
SingletonRegistry singletonRegistry;
4242
QFileSystemWatcher* watcher = nullptr;

src/core/rootwrapper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ void RootWrapper::reloadGraph(bool hard) {
5858
auto url = QUrl::fromLocalFile(this->rootPath);
5959
// unless the original file comes from the qsintercept scheme
6060
url.setScheme("qsintercept");
61-
auto component = QQmlComponent(&generation->engine, url);
61+
auto component = QQmlComponent(generation->engine, url);
6262

63-
auto* obj = component.beginCreate(generation->engine.rootContext());
63+
auto* obj = component.beginCreate(generation->engine->rootContext());
6464

6565
if (obj == nullptr) {
6666
qWarning() << component.errorString().toStdString().c_str();

src/services/status_notifier/init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace {
66

77
class SniPlugin: public QuickshellPlugin {
88
void constructGeneration(EngineGeneration& generation) override {
9-
generation.engine.addImageProvider("service.sni", new qs::service::sni::TrayImageProvider());
9+
generation.engine->addImageProvider("service.sni", new qs::service::sni::TrayImageProvider());
1010
}
1111
};
1212

0 commit comments

Comments
 (0)