mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-17 08:20:30 +02:00
Logging: make ring snapshot payload accesses atomic
Keep the bounded nonblocking sequence protocol, but transfer text through retro_atomic words. Readers may discard overlapping writes without invoking a plain-memory data race. Use unsigned sequence arithmetic at wraparound. This adds bounded atomic word work only to ring logging.
This commit is contained in:
1 parent
c45c1f0073
commit
ac0585439d
2 files changed
+19
-8
No files matched your search
@@ -400,7 +400,8 @@ RingbufferLog::RingbufferLog() {
|
||||
for (int i = 0; i < MAX_LOGS; i++) {
|
||||
retro_atomic_int_init(&slots_[i].seq, 0);
|
||||
retro_atomic_int_init(&slots_[i].level, 0);
|
||||
slots_[i].text[0] = '\0';
|
||||
for (int j = 0; j < TEXT_WORDS; ++j)
|
||||
retro_atomic_int_init(&slots_[i].text[j], 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,14 +410,19 @@ void RingbufferLog::Log(const LogMessage &message) {
|
||||
Slot &slot = slots_[idx];
|
||||
const int seq = retro_atomic_load_relaxed_int(&slot.seq);
|
||||
// Odd: another writer lapped the ring onto this slot. Drop ours.
|
||||
if ((seq & 1) || !retro_atomic_cas_int(&slot.seq, seq, seq + 1))
|
||||
if ((seq & 1) || !retro_atomic_cas_int(&slot.seq, seq, (int)((unsigned)seq + 1)))
|
||||
return;
|
||||
retro_atomic_thread_fence_seq_cst();
|
||||
const size_t len = std::min(message.msg.size(), (size_t)MAX_TEXT - 1);
|
||||
memcpy(slot.text, message.msg.data(), len);
|
||||
slot.text[len] = '\0';
|
||||
char text[MAX_TEXT]{};
|
||||
memcpy(text, message.msg.data(), len);
|
||||
for (int j = 0; j < TEXT_WORDS; ++j) {
|
||||
int word;
|
||||
memcpy(&word, text + j * sizeof(int), sizeof(word));
|
||||
retro_atomic_store_relaxed_int(&slot.text[j], word);
|
||||
}
|
||||
retro_atomic_store_relaxed_int(&slot.level, (int)message.level);
|
||||
retro_atomic_store_release_int(&slot.seq, seq + 2);
|
||||
retro_atomic_store_release_int(&slot.seq, (int)((unsigned)seq + 2));
|
||||
if (retro_atomic_load_relaxed_int(&count_) < MAX_LOGS)
|
||||
retro_atomic_fetch_add_int(&count_, 1);
|
||||
}
|
||||
@@ -434,7 +440,10 @@ bool RingbufferLog::Read(int i, std::string *text, LogLevel *level) const {
|
||||
if (seq & 1)
|
||||
return false;
|
||||
char buf[MAX_TEXT];
|
||||
memcpy(buf, slot.text, sizeof(buf));
|
||||
for (int j = 0; j < TEXT_WORDS; ++j) {
|
||||
int word = retro_atomic_load_relaxed_int(const_cast<retro_atomic_int_t *>(&slot.text[j]));
|
||||
memcpy(buf + j * sizeof(int), &word, sizeof(word));
|
||||
}
|
||||
buf[MAX_TEXT - 1] = '\0';
|
||||
const int lvl = retro_atomic_load_relaxed_int(const_cast<retro_atomic_int_t *>(&slot.level));
|
||||
retro_atomic_thread_fence_seq_cst();
|
||||
|
||||
@@ -66,11 +66,13 @@ public:
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
enum { MAX_LOGS = 256, MAX_TEXT = 512 };
|
||||
enum { MAX_LOGS = 256, MAX_TEXT = 512, TEXT_WORDS = MAX_TEXT / sizeof(int) };
|
||||
static_assert(MAX_TEXT % sizeof(int) == 0, "Log text must fit whole atomic words");
|
||||
struct Slot {
|
||||
retro_atomic_int_t seq;
|
||||
retro_atomic_int_t level;
|
||||
char text[MAX_TEXT];
|
||||
// Sequence validation alone cannot legalize concurrent plain-byte access.
|
||||
retro_atomic_int_t text[TEXT_WORDS];
|
||||
};
|
||||
bool Read(int i, std::string *text, LogLevel *level) const;
|
||||
Slot slots_[MAX_LOGS];
|
||||
|
||||
Reference in new issue
Block a user