mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-18 12:28:31 +01:00
Exit worker processes when their sockets are closed, and make sure the main app closes sockets when exiting - fixes a crash dialog on Windows.
This commit is contained in:
parent
1924107e16
commit
3e0f252b34
@ -962,3 +962,9 @@ void SpotifyClient::AlbumBrowseComplete(sp_albumbrowse* result, void* userdata)
|
|||||||
me->SendMessage(message);
|
me->SendMessage(message);
|
||||||
sp_albumbrowse_release(result);
|
sp_albumbrowse_release(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpotifyClient::SocketClosed() {
|
||||||
|
AbstractMessageHandler<pb::spotify::Message>::SocketClosed();
|
||||||
|
|
||||||
|
qApp->exit();
|
||||||
|
}
|
||||||
|
@ -50,6 +50,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void MessageArrived(const pb::spotify::Message& message);
|
void MessageArrived(const pb::spotify::Message& message);
|
||||||
|
void SocketClosed();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ProcessEvents();
|
void ProcessEvents();
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/timeconstants.h"
|
#include "core/timeconstants.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
@ -549,3 +550,9 @@ QByteArray TagReaderWorker::LoadEmbeddedArt(const QString& filename) const {
|
|||||||
|
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TagReaderWorker::SocketClosed() {
|
||||||
|
AbstractMessageHandler<pb::tagreader::Message>::SocketClosed();
|
||||||
|
|
||||||
|
qApp->exit();
|
||||||
|
}
|
||||||
|
@ -41,6 +41,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void MessageArrived(const pb::tagreader::Message& message);
|
void MessageArrived(const pb::tagreader::Message& message);
|
||||||
|
void SocketClosed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ReadFile(const QString& filename, pb::tagreader::SongMetadata* song) const;
|
void ReadFile(const QString& filename, pb::tagreader::SongMetadata* song) const;
|
||||||
|
@ -63,6 +63,7 @@ template <typename HandlerType>
|
|||||||
class WorkerPool : public _WorkerPoolBase {
|
class WorkerPool : public _WorkerPoolBase {
|
||||||
public:
|
public:
|
||||||
WorkerPool(QObject* parent = 0);
|
WorkerPool(QObject* parent = 0);
|
||||||
|
~WorkerPool();
|
||||||
|
|
||||||
// Sets the name of the worker executable. This is looked for first in the
|
// Sets the name of the worker executable. This is looked for first in the
|
||||||
// current directory, and then in $PATH. You must call this before calling
|
// current directory, and then in $PATH. You must call this before calling
|
||||||
@ -81,9 +82,8 @@ public:
|
|||||||
// Starts all workers.
|
// Starts all workers.
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
// Returns a handler in a round-robin fashion. May return NULL if no handlers
|
// Returns a handler in a round-robin fashion. Will block if no handlers are
|
||||||
// are running yet, in which case you must queue the request yourself and
|
// available yet.
|
||||||
// re-send it when the WorkerConnected() signal is emitted.
|
|
||||||
HandlerType* NextHandler();
|
HandlerType* NextHandler();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -93,9 +93,11 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
struct Worker {
|
struct Worker {
|
||||||
Worker() : local_server_(NULL), process_(NULL), handler_(NULL) {}
|
Worker() : local_server_(NULL), local_socket_(NULL), process_(NULL),
|
||||||
|
handler_(NULL) {}
|
||||||
|
|
||||||
QLocalServer* local_server_;
|
QLocalServer* local_server_;
|
||||||
|
QLocalSocket* local_socket_;
|
||||||
QProcess* process_;
|
QProcess* process_;
|
||||||
HandlerType* handler_;
|
HandlerType* handler_;
|
||||||
};
|
};
|
||||||
@ -144,6 +146,27 @@ WorkerPool<HandlerType>::WorkerPool(QObject* parent)
|
|||||||
local_server_name_ = "workerpool";
|
local_server_name_ = "workerpool";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename HandlerType>
|
||||||
|
WorkerPool<HandlerType>::~WorkerPool() {
|
||||||
|
foreach (const Worker& worker, workers_) {
|
||||||
|
if (worker.local_socket_ && worker.process_) {
|
||||||
|
// The worker is connected. Close his socket and wait for him to exit.
|
||||||
|
qLog(Debug) << "Closing worker socket";
|
||||||
|
worker.local_socket_->close();
|
||||||
|
worker.process_->waitForFinished(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (worker.process_ && worker.process_->state() == QProcess::Running) {
|
||||||
|
// The worker is still running - kill it.
|
||||||
|
qLog(Debug) << "Killing worker process";
|
||||||
|
worker.process_->terminate();
|
||||||
|
if (!worker.process_->waitForFinished(500)) {
|
||||||
|
worker.process_->kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename HandlerType>
|
template <typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::SetWorkerCount(int count) {
|
void WorkerPool<HandlerType>::SetWorkerCount(int count) {
|
||||||
Q_ASSERT(workers_.isEmpty());
|
Q_ASSERT(workers_.isEmpty());
|
||||||
@ -201,6 +224,7 @@ void WorkerPool<HandlerType>::DoStart() {
|
|||||||
template <typename HandlerType>
|
template <typename HandlerType>
|
||||||
void WorkerPool<HandlerType>::StartOneWorker(Worker* worker) {
|
void WorkerPool<HandlerType>::StartOneWorker(Worker* worker) {
|
||||||
DeleteQObjectPointerLater(&worker->local_server_);
|
DeleteQObjectPointerLater(&worker->local_server_);
|
||||||
|
DeleteQObjectPointerLater(&worker->local_socket_);
|
||||||
DeleteQObjectPointerLater(&worker->process_);
|
DeleteQObjectPointerLater(&worker->process_);
|
||||||
DeleteQObjectPointerLater(&worker->handler_);
|
DeleteQObjectPointerLater(&worker->handler_);
|
||||||
|
|
||||||
@ -242,15 +266,15 @@ void WorkerPool<HandlerType>::NewConnection() {
|
|||||||
qLog(Debug) << "Worker connected to" << server->fullServerName();
|
qLog(Debug) << "Worker connected to" << server->fullServerName();
|
||||||
|
|
||||||
// Accept the connection.
|
// Accept the connection.
|
||||||
QLocalSocket* socket = server->nextPendingConnection();
|
worker->local_socket_ = server->nextPendingConnection();
|
||||||
|
|
||||||
// We only ever accept one connection per worker, so destroy the server now.
|
// We only ever accept one connection per worker, so destroy the server now.
|
||||||
socket->setParent(this);
|
worker->local_socket_->setParent(this);
|
||||||
worker->local_server_->deleteLater();
|
worker->local_server_->deleteLater();
|
||||||
worker->local_server_ = NULL;
|
worker->local_server_ = NULL;
|
||||||
|
|
||||||
// Create the handler.
|
// Create the handler.
|
||||||
worker->handler_ = new HandlerType(socket, this);
|
worker->handler_ = new HandlerType(worker->local_socket_, this);
|
||||||
|
|
||||||
emit WorkerConnected();
|
emit WorkerConnected();
|
||||||
}
|
}
|
||||||
|
10
src/main.cpp
10
src/main.cpp
@ -370,12 +370,12 @@ int main(int argc, char *argv[]) {
|
|||||||
cover_providers.AddProvider(new AmazonCoverProvider);
|
cover_providers.AddProvider(new AmazonCoverProvider);
|
||||||
|
|
||||||
// Create the tag loader on another thread.
|
// Create the tag loader on another thread.
|
||||||
TagReaderClient tag_reader_client;
|
TagReaderClient* tag_reader_client = new TagReaderClient;
|
||||||
|
|
||||||
QThread tag_reader_thread;
|
QThread tag_reader_thread;
|
||||||
tag_reader_thread.start();
|
tag_reader_thread.start();
|
||||||
tag_reader_client.moveToThread(&tag_reader_thread);
|
tag_reader_client->moveToThread(&tag_reader_thread);
|
||||||
tag_reader_client.Start();
|
tag_reader_client->Start();
|
||||||
|
|
||||||
// Create some key objects
|
// Create some key objects
|
||||||
scoped_ptr<BackgroundThread<Database> > database(
|
scoped_ptr<BackgroundThread<Database> > database(
|
||||||
@ -436,6 +436,10 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
int ret = a.exec();
|
int ret = a.exec();
|
||||||
|
|
||||||
|
tag_reader_client->deleteLater();
|
||||||
|
tag_reader_thread.quit();
|
||||||
|
tag_reader_thread.wait();
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
// The nvidia driver would cause Clementine (or any application that used
|
// The nvidia driver would cause Clementine (or any application that used
|
||||||
// opengl) to use 100% cpu on shutdown. See:
|
// opengl) to use 100% cpu on shutdown. See:
|
||||||
|
Loading…
Reference in New Issue
Block a user