1
0
mirror of https://github.com/clementine-player/Clementine synced 2024-12-18 04:19:55 +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:
David Sansome 2012-01-08 16:34:34 +00:00
parent 1924107e16
commit 3e0f252b34
6 changed files with 53 additions and 10 deletions

View File

@ -962,3 +962,9 @@ void SpotifyClient::AlbumBrowseComplete(sp_albumbrowse* result, void* userdata)
me->SendMessage(message);
sp_albumbrowse_release(result);
}
void SpotifyClient::SocketClosed() {
AbstractMessageHandler<pb::spotify::Message>::SocketClosed();
qApp->exit();
}

View File

@ -50,6 +50,7 @@ public:
protected:
void MessageArrived(const pb::spotify::Message& message);
void SocketClosed();
private slots:
void ProcessEvents();

View File

@ -21,6 +21,7 @@
#include "core/logging.h"
#include "core/timeconstants.h"
#include <QCoreApplication>
#include <QDateTime>
#include <QFileInfo>
#include <QTextCodec>
@ -549,3 +550,9 @@ QByteArray TagReaderWorker::LoadEmbeddedArt(const QString& filename) const {
return QByteArray();
}
void TagReaderWorker::SocketClosed() {
AbstractMessageHandler<pb::tagreader::Message>::SocketClosed();
qApp->exit();
}

View File

@ -41,6 +41,7 @@ public:
protected:
void MessageArrived(const pb::tagreader::Message& message);
void SocketClosed();
private:
void ReadFile(const QString& filename, pb::tagreader::SongMetadata* song) const;

View File

@ -63,6 +63,7 @@ template <typename HandlerType>
class WorkerPool : public _WorkerPoolBase {
public:
WorkerPool(QObject* parent = 0);
~WorkerPool();
// 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
@ -81,9 +82,8 @@ public:
// Starts all workers.
void Start();
// Returns a handler in a round-robin fashion. May return NULL if no handlers
// are running yet, in which case you must queue the request yourself and
// re-send it when the WorkerConnected() signal is emitted.
// Returns a handler in a round-robin fashion. Will block if no handlers are
// available yet.
HandlerType* NextHandler();
protected:
@ -93,9 +93,11 @@ protected:
private:
struct Worker {
Worker() : local_server_(NULL), process_(NULL), handler_(NULL) {}
Worker() : local_server_(NULL), local_socket_(NULL), process_(NULL),
handler_(NULL) {}
QLocalServer* local_server_;
QLocalSocket* local_socket_;
QProcess* process_;
HandlerType* handler_;
};
@ -144,6 +146,27 @@ WorkerPool<HandlerType>::WorkerPool(QObject* parent)
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>
void WorkerPool<HandlerType>::SetWorkerCount(int count) {
Q_ASSERT(workers_.isEmpty());
@ -201,6 +224,7 @@ void WorkerPool<HandlerType>::DoStart() {
template <typename HandlerType>
void WorkerPool<HandlerType>::StartOneWorker(Worker* worker) {
DeleteQObjectPointerLater(&worker->local_server_);
DeleteQObjectPointerLater(&worker->local_socket_);
DeleteQObjectPointerLater(&worker->process_);
DeleteQObjectPointerLater(&worker->handler_);
@ -242,15 +266,15 @@ void WorkerPool<HandlerType>::NewConnection() {
qLog(Debug) << "Worker connected to" << server->fullServerName();
// 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.
socket->setParent(this);
worker->local_socket_->setParent(this);
worker->local_server_->deleteLater();
worker->local_server_ = NULL;
// Create the handler.
worker->handler_ = new HandlerType(socket, this);
worker->handler_ = new HandlerType(worker->local_socket_, this);
emit WorkerConnected();
}

View File

@ -370,12 +370,12 @@ int main(int argc, char *argv[]) {
cover_providers.AddProvider(new AmazonCoverProvider);
// Create the tag loader on another thread.
TagReaderClient tag_reader_client;
TagReaderClient* tag_reader_client = new TagReaderClient;
QThread tag_reader_thread;
tag_reader_thread.start();
tag_reader_client.moveToThread(&tag_reader_thread);
tag_reader_client.Start();
tag_reader_client->moveToThread(&tag_reader_thread);
tag_reader_client->Start();
// Create some key objects
scoped_ptr<BackgroundThread<Database> > database(
@ -436,6 +436,10 @@ int main(int argc, char *argv[]) {
int ret = a.exec();
tag_reader_client->deleteLater();
tag_reader_thread.quit();
tag_reader_thread.wait();
#ifdef Q_OS_LINUX
// The nvidia driver would cause Clementine (or any application that used
// opengl) to use 100% cpu on shutdown. See: