ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
session_log_buffer.c
Go to the documentation of this file.
1
6#include <ascii-chat/session/session_log_buffer.h>
7#include <ascii-chat/platform/abstraction.h>
8#include <ascii-chat/debug/memory.h>
9#include <ascii-chat/common.h>
10#include <string.h>
11#include <stdatomic.h>
12
16typedef struct session_log_buffer {
17 session_log_entry_t entries[SESSION_LOG_BUFFER_SIZE];
18 _Atomic size_t write_pos;
19 _Atomic uint64_t sequence;
20 mutex_t mutex;
22
23static session_log_buffer_t *g_log_buffer = NULL;
24
26 if (g_log_buffer) {
27 return true; // Already initialized
28 }
29
30 g_log_buffer = SAFE_CALLOC(1, sizeof(session_log_buffer_t), session_log_buffer_t *);
31 if (!g_log_buffer) {
32 return false;
33 }
34
35 atomic_init(&g_log_buffer->write_pos, 0);
36 atomic_init(&g_log_buffer->sequence, 0);
37 mutex_init(&g_log_buffer->mutex);
38
39 return true;
40}
41
43 if (!g_log_buffer) {
44 return;
45 }
46 mutex_destroy(&g_log_buffer->mutex);
47 SAFE_FREE(g_log_buffer);
48}
49
51 if (!g_log_buffer) {
52 return;
53 }
54
55 mutex_lock(&g_log_buffer->mutex);
56
57 // Reset write position and sequence
58 atomic_store(&g_log_buffer->write_pos, 0);
59 atomic_store(&g_log_buffer->sequence, 0);
60
61 // Clear all entries
62 for (size_t i = 0; i < SESSION_LOG_BUFFER_SIZE; i++) {
63 g_log_buffer->entries[i].message[0] = '\0';
64 g_log_buffer->entries[i].sequence = 0;
65 }
66
67 mutex_unlock(&g_log_buffer->mutex);
68}
69
70void session_log_buffer_append(const char *message) {
71 if (!g_log_buffer || !message) {
72 // Fail silently - this is called FROM the logging system
73 // Using SET_ERRNO here would cause infinite recursion
74 return;
75 }
76
77 mutex_lock(&g_log_buffer->mutex);
78
79 size_t pos = atomic_load(&g_log_buffer->write_pos);
80 uint64_t seq = atomic_fetch_add(&g_log_buffer->sequence, 1);
81
82 SAFE_STRNCPY(g_log_buffer->entries[pos].message, message, SESSION_LOG_LINE_MAX);
83 g_log_buffer->entries[pos].sequence = seq;
84
85 atomic_store(&g_log_buffer->write_pos, (pos + 1) % SESSION_LOG_BUFFER_SIZE);
86
87 mutex_unlock(&g_log_buffer->mutex);
88}
89
90size_t session_log_buffer_get_recent(session_log_entry_t *out_entries, size_t max_count) {
91 if (!g_log_buffer || !out_entries || max_count == 0) {
92 // Fail silently - called from display code that handles 0 gracefully
93 // Using SET_ERRNO here could cause recursion if error logging is enabled
94 return 0;
95 }
96
97 mutex_lock(&g_log_buffer->mutex);
98
99 size_t write_pos = atomic_load(&g_log_buffer->write_pos);
100 uint64_t total_entries = atomic_load(&g_log_buffer->sequence);
101
102 size_t start_pos = write_pos;
103 size_t entries_to_check = SESSION_LOG_BUFFER_SIZE;
104
105 if (total_entries < SESSION_LOG_BUFFER_SIZE) {
106 start_pos = 0;
107 entries_to_check = write_pos;
108 }
109
110 size_t count = 0;
111 for (size_t i = 0; i < entries_to_check && count < max_count; i++) {
112 size_t idx = (start_pos + i) % SESSION_LOG_BUFFER_SIZE;
113 if (g_log_buffer->entries[idx].sequence > 0) {
114 memcpy(&out_entries[count], &g_log_buffer->entries[idx], sizeof(session_log_entry_t));
115 count++;
116 }
117 }
118
119 mutex_unlock(&g_log_buffer->mutex);
120 return count;
121}
_Atomic uint64_t write_pos
Definition mmap.c:37
struct session_log_buffer session_log_buffer_t
Internal circular buffer structure.
bool session_log_buffer_init(void)
size_t session_log_buffer_get_recent(session_log_entry_t *out_entries, size_t max_count)
void session_log_buffer_append(const char *message)
void session_log_buffer_clear(void)
void session_log_buffer_destroy(void)
Internal circular buffer structure.
session_log_entry_t entries[SESSION_LOG_BUFFER_SIZE]
_Atomic size_t write_pos
_Atomic uint64_t sequence
int mutex_init(mutex_t *mutex)
Definition threading.c:16
int mutex_destroy(mutex_t *mutex)
Definition threading.c:21