1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-05-01 17:19:36 +00:00

Fix Logger under MSVC iostream libraries

We need splitted Tie classes because MSVC stream library
takes a lock on buffer both on reading and on writing and
this causes an hang because, while searching, the I/O
thread is locked on getline() and when main thread is
trying to std::cout() something it blocks on the same
lock waiting for I/O thread getting some input and
releasing the lock.

The solution is to use separated streambuf objects for
cin and cout.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
Marco Costalba 2012-03-20 20:50:24 +01:00
parent 17d1940278
commit 3b7dbc4f6d

View file

@ -106,16 +106,42 @@ void dbg_print() {
/// Our fancy logging facility. The trick here is to replace cin.rdbuf() and
/// cout.rdbuf() with this one that tees cin and cout to a file stream. We can
/// toggle the logging of std::cout and std:cin at runtime while preserving i/o
/// functionality and without changing a single line of code!
/// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We
/// can toggle the logging of std::cout and std:cin at runtime while preserving
/// usual i/o functionality and without changing a single line of code!
/// Idea from http://groups.google.com/group/comp.lang.c++/msg/1d941c0f26ea0d81
class Logger: public streambuf {
class Logger {
Logger() : cinbuf(cin.rdbuf()), coutbuf(cout.rdbuf()) {}
Logger() : in(cin.rdbuf(), file), out(cout.rdbuf(), file) {}
~Logger() { start(false); }
struct Tie: public streambuf { // MSVC requires splitted streambuf for cin and cout
Tie(streambuf* b, ofstream& f) : buf(b), file(f) {}
int sync() { return file.rdbuf()->pubsync(), buf->pubsync(); }
int overflow(int c) { return log(buf->sputc((char)c), "<< "); }
int underflow() { return buf->sgetc(); }
int uflow() { return log(buf->sbumpc(), ">> "); }
int log(int c, const char* prefix) {
static int last = '\n';
if (last == '\n')
file.rdbuf()->sputn(prefix, 3);
return last = file.rdbuf()->sputc((char)c);
}
streambuf* buf;
ofstream& file;
};
ofstream file;
Tie in, out;
public:
static void start(bool b) {
@ -124,40 +150,20 @@ public:
if (b && !l.file.is_open())
{
l.file.open("io_log.txt", ifstream::out | ifstream::app);
cin.rdbuf(&l);
cout.rdbuf(&l);
cin.rdbuf(&l.in);
cout.rdbuf(&l.out);
}
else if (!b && l.file.is_open())
{
cout.rdbuf(l.coutbuf);
cin.rdbuf(l.cinbuf);
cout.rdbuf(l.out.buf);
cin.rdbuf(l.in.buf);
l.file.close();
}
}
private:
int sync() { return file.rdbuf()->pubsync(), coutbuf->pubsync(); }
int overflow(int c) { return log(coutbuf->sputc((char)c), "<< ") ; }
int underflow() { return cinbuf->sgetc(); }
int uflow() { return log(cinbuf->sbumpc(), ">> "); }
int log(int c, const char* prefix) {
static int last = '\n';
if (last == '\n')
file.rdbuf()->sputn(prefix, 3);
return last = file.rdbuf()->sputc((char)c);
}
private:
ofstream file;
streambuf *cinbuf, *coutbuf;
};
/// Trampoline helper to avoid moving Logger to misc.h header
/// Trampoline helper to avoid moving Logger to misc.h
void start_logger(bool b) { Logger::start(b); }