mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-04 21:29:21 +00:00
Fix data race reading the log buffer from the display thread
Copy entries under the buffer lock before rendering; other threads mutate the deque.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/system/callbacks.h>
|
||||
#include <torrent/system/thread.h>
|
||||
@@ -41,13 +43,20 @@ WindowLog::redraw() {
|
||||
|
||||
int pos = m_canvas->height();
|
||||
|
||||
for (iterator itr = m_log->end(), last = find_older(); itr != last && pos > 0; --pos) {
|
||||
itr--;
|
||||
std::vector<torrent::log_entry> entries;
|
||||
|
||||
{
|
||||
std::lock_guard<torrent::log_buffer> guard(*m_log);
|
||||
|
||||
for (iterator itr = m_log->end(), last = find_older(); itr != last && entries.size() < static_cast<size_t>(pos); )
|
||||
entries.push_back(*--itr);
|
||||
}
|
||||
|
||||
for (const auto& entry : entries) {
|
||||
char buffer[16];
|
||||
print_hhmmss_local(buffer, buffer + 16, static_cast<time_t>(itr->timestamp));
|
||||
print_hhmmss_local(buffer, buffer + 16, static_cast<time_t>(entry.timestamp));
|
||||
|
||||
m_canvas->print(0, pos - 1, "(%s) %s", buffer, itr->message.c_str());
|
||||
m_canvas->print(0, --pos, "(%s) %s", buffer, entry.message.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,8 +69,13 @@ WindowLog::receive_update() {
|
||||
if (!is_active())
|
||||
return;
|
||||
|
||||
auto itr = find_older();
|
||||
auto height = std::min(std::distance(itr, (iterator)m_log->end()), (std::iterator_traits<iterator>::difference_type)10);
|
||||
std::iterator_traits<iterator>::difference_type height;
|
||||
|
||||
{
|
||||
std::lock_guard<torrent::log_buffer> guard(*m_log);
|
||||
|
||||
height = std::min(std::distance(find_older(), (iterator)m_log->end()), (std::iterator_traits<iterator>::difference_type)10);
|
||||
}
|
||||
|
||||
if (height != m_max_height) {
|
||||
m_min_height = height != 0 ? 1 : 0;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "canvas.h"
|
||||
#include "utils.h"
|
||||
@@ -29,24 +31,34 @@ WindowLogComplete::redraw() {
|
||||
|
||||
int pos = m_canvas->height();
|
||||
|
||||
for (iterator itr = m_log->end(), last = m_log->begin(); itr != last && pos > 0; ) {
|
||||
itr--;
|
||||
std::vector<torrent::log_entry> entries;
|
||||
|
||||
{
|
||||
std::lock_guard<torrent::log_buffer> guard(*m_log);
|
||||
|
||||
for (iterator itr = m_log->end(), last = m_log->begin(); itr != last && entries.size() < static_cast<size_t>(pos); )
|
||||
entries.push_back(*--itr);
|
||||
}
|
||||
|
||||
for (const auto& entry : entries) {
|
||||
if (pos <= 0)
|
||||
break;
|
||||
|
||||
char buffer[16];
|
||||
|
||||
// Use an arbitrary min width of 60 for allowing multiple
|
||||
// lines. This should ensure we don't mess up the display when the
|
||||
// screen is shrunk too much.
|
||||
unsigned int timeWidth = 3 + print_hhmmss_local(buffer, buffer + 16, static_cast<time_t>(itr->timestamp)) - buffer;
|
||||
unsigned int timeWidth = 3 + print_hhmmss_local(buffer, buffer + 16, static_cast<time_t>(entry.timestamp)) - buffer;
|
||||
|
||||
unsigned int logWidth = m_canvas->width() > 60 ? (m_canvas->width() - timeWidth) : (60 - timeWidth);
|
||||
unsigned int logHeight = (itr->message.size() + logWidth - 1) / logWidth;
|
||||
unsigned int logHeight = (entry.message.size() + logWidth - 1) / logWidth;
|
||||
|
||||
for (unsigned int j = logHeight; j > 0 && pos > 0; --j, --pos)
|
||||
if (j == 1)
|
||||
m_canvas->print(0, pos - 1, "(%s) %s", buffer, itr->message.substr(0, m_canvas->width() - timeWidth).c_str());
|
||||
m_canvas->print(0, pos - 1, "(%s) %s", buffer, entry.message.substr(0, m_canvas->width() - timeWidth).c_str());
|
||||
else
|
||||
m_canvas->print(timeWidth, pos - 1, "%s", itr->message.substr(logWidth * (j - 1), m_canvas->width() - timeWidth).c_str());
|
||||
m_canvas->print(timeWidth, pos - 1, "%s", entry.message.substr(logWidth * (j - 1), m_canvas->width() - timeWidth).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user