Files
scylladb/core/stdio.cc
Avi Kivity a8698fa17c core: demangle stdout
When using print() to debug on smp, it is very annoying to get interleaved
output.

Fix by wrapping stdout with a fake stream that has a line buffer for each
thread.
2015-02-19 09:26:17 +02:00

77 lines
2.0 KiB
C++

/*
* Copyright (C) 2015 Cloudius Systems, Ltd.
*/
#include "stdio.hh"
#include <memory>
#include <pthread.h>
#include <mutex>
#include <unordered_map>
#include <boost/thread/tss.hpp>
#include <vector>
#include <algorithm>
class spinlock {
pthread_spinlock_t _l;
public:
spinlock() { pthread_spin_init(&_l, PTHREAD_PROCESS_PRIVATE); }
~spinlock() { pthread_spin_destroy(&_l); }
void lock() { pthread_spin_lock(&_l); }
void unlock() { pthread_spin_unlock(&_l); }
};
class smp_file {
FILE* _out;
spinlock _lock;
boost::thread_specific_ptr<std::vector<char>> _buffer;
static constexpr size_t max = 2000;
public:
smp_file(FILE* out) : _out(out) {}
ssize_t write(const char* buffer, size_t size) {
auto& b = *_buffer;
b.insert(b.end(), buffer, buffer + size);
size_t now = 0;
if (b.size() >= max) {
now = b.size();
} else {
auto lf = std::find(b.rbegin(), b.rend(), '\n');
if (lf != b.rend()) {
auto remain = lf - b.rbegin();
now = b.size() - remain;
}
}
if (now) {
auto ret = fwrite(b.data(), 1, now, _out);
b.erase(b.begin(), b.begin() + now);
return ret;
} else {
return 0;
}
}
};
static smp_file* to_smp_file(void* cookie) {
return static_cast<smp_file*>(cookie);
}
FILE*
smp_synchronize_lines(FILE* out) {
auto p = std::make_unique<smp_file>(out);
cookie_io_functions_t vtable = {};
vtable.write = [] (void* ck, const char* b, size_t s) { return to_smp_file(ck)->write(b, s); };
vtable.close = [] (void* ck) { delete to_smp_file(ck); return 0; };
auto ret = fopencookie(p.get(), "w", vtable);
if (!ret) {
return ret;
}
// disable buffering so that writes to ret don't get mixed
// up but are sent to smp_file immediately instead.
setvbuf(ret, nullptr, _IONBF, 0);
p.release();
return ret;
}