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 "config.h"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
#include <torrent/torrent.h>
|
#include <torrent/torrent.h>
|
||||||
#include <torrent/system/callbacks.h>
|
#include <torrent/system/callbacks.h>
|
||||||
#include <torrent/system/thread.h>
|
#include <torrent/system/thread.h>
|
||||||
@@ -41,13 +43,20 @@ WindowLog::redraw() {
|
|||||||
|
|
||||||
int pos = m_canvas->height();
|
int pos = m_canvas->height();
|
||||||
|
|
||||||
for (iterator itr = m_log->end(), last = find_older(); itr != last && pos > 0; --pos) {
|
std::vector<torrent::log_entry> entries;
|
||||||
itr--;
|
|
||||||
|
|
||||||
|
{
|
||||||
|
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];
|
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())
|
if (!is_active())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto itr = find_older();
|
std::iterator_traits<iterator>::difference_type height;
|
||||||
auto height = std::min(std::distance(itr, (iterator)m_log->end()), (std::iterator_traits<iterator>::difference_type)10);
|
|
||||||
|
{
|
||||||
|
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) {
|
if (height != m_max_height) {
|
||||||
m_min_height = height != 0 ? 1 : 0;
|
m_min_height = height != 0 ? 1 : 0;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "canvas.h"
|
#include "canvas.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
@@ -29,24 +31,34 @@ WindowLogComplete::redraw() {
|
|||||||
|
|
||||||
int pos = m_canvas->height();
|
int pos = m_canvas->height();
|
||||||
|
|
||||||
for (iterator itr = m_log->end(), last = m_log->begin(); itr != last && pos > 0; ) {
|
std::vector<torrent::log_entry> entries;
|
||||||
itr--;
|
|
||||||
|
{
|
||||||
|
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];
|
char buffer[16];
|
||||||
|
|
||||||
// Use an arbitrary min width of 60 for allowing multiple
|
// Use an arbitrary min width of 60 for allowing multiple
|
||||||
// lines. This should ensure we don't mess up the display when the
|
// lines. This should ensure we don't mess up the display when the
|
||||||
// screen is shrunk too much.
|
// 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 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)
|
for (unsigned int j = logHeight; j > 0 && pos > 0; --j, --pos)
|
||||||
if (j == 1)
|
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
|
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