diff --git a/licq/include/licq/pipe.h b/licq/include/licq/pipe.h index e5dbb2661..8521a5a93 100644 --- a/licq/include/licq/pipe.h +++ b/licq/include/licq/pipe.h @@ -1,6 +1,6 @@ /* * This file is part of Licq, an instant messaging client for UNIX. - * Copyright (C) 2010 Licq developers + * Copyright (C) 2010-2012 Licq developers * * Licq is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,6 +45,13 @@ class Pipe */ ssize_t write(const void* buf, size_t count); + /** + * (Un)block the write end of the pipe + * + * @param block False to make write fail if it would block + */ + void setWriteBlocking(bool block); + /** * Reads one byte using read(). */ @@ -58,8 +65,8 @@ class Pipe /** * Writes one byte using write(). */ - void putChar(char ch) - { write(&ch, sizeof(ch)); } + bool putChar(char ch) + { return (write(&ch, sizeof(ch)) > 0); } int getReadFd() const { return myFds[0]; } int getWriteFd() const { return myFds[1]; } diff --git a/licq/src/logging/pluginlogsink.cpp b/licq/src/logging/pluginlogsink.cpp index ed0aad994..f1ca9abdb 100644 --- a/licq/src/logging/pluginlogsink.cpp +++ b/licq/src/logging/pluginlogsink.cpp @@ -1,6 +1,6 @@ /* * This file is part of Licq, an instant messaging client for UNIX. - * Copyright (C) 2010 Licq Developers + * Copyright (C) 2010-2012 Licq developers * * Please refer to the COPYRIGHT file distributed with this source * distribution for the names of the individual contributors. @@ -37,8 +37,12 @@ class PluginLogSink::Private : public LicqDaemon::AdjustableLogSink void log(Message::Ptr message) { MutexLocker locker(myMutex); - myMessages.push_back(message); - myPipe.putChar('M'); + + // The pipe is non-blocking so we won't risk hanging here while holding + // several mutexes. If putChar fails, don't push this message, the receiver + // is either overloaded or hanged and it's just a log message anyway. + if (myPipe.putChar('M')) + myMessages.push_back(message); } LogSink::Message::Ptr popMessage(bool readPipe) @@ -62,7 +66,11 @@ class PluginLogSink::Private : public LicqDaemon::AdjustableLogSink PluginLogSink::PluginLogSink() : myPrivate(new Private()) { - // Empty + LICQ_D(); + + // Make the pipe non-blocking. If a logsink is too slow it's better to drop a + // few log messages than to block and risk deadlocking the application. + d->myPipe.setWriteBlocking(false); } PluginLogSink::~PluginLogSink() diff --git a/licq/src/utils/pipe.cpp b/licq/src/utils/pipe.cpp index b4a08e715..3b3b8f34c 100644 --- a/licq/src/utils/pipe.cpp +++ b/licq/src/utils/pipe.cpp @@ -1,6 +1,6 @@ /* * This file is part of Licq, an instant messaging client for UNIX. - * Copyright (C) 2010 Licq developers + * Copyright (C) 2010-2012 Licq developers * * Licq is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,6 +19,8 @@ #include +#include + using namespace Licq; Pipe::Pipe() @@ -41,3 +43,9 @@ ssize_t Pipe::write(const void* buf, size_t count) { return ::write(getWriteFd(), buf, count); } + +void Pipe::setWriteBlocking(bool block) +{ + int f = ::fcntl(getWriteFd(), F_GETFL); + ::fcntl(getWriteFd(), F_SETFL, (block ? (f & ~O_NONBLOCK) : (f | O_NONBLOCK))); +}