ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
lock.h
Go to the documentation of this file.
1#pragma once
2
40// C11 stdatomic.h conflicts with MSVC's C++ <atomic> header on Windows.
41#if defined(__cplusplus) && defined(_WIN32)
42#include <atomic>
43using std::atomic_bool;
44using std::atomic_uint_fast32_t;
45using std::atomic_uint_fast64_t;
46#else
47#include <stdatomic.h>
48#endif
49#include <stdbool.h>
50#include <stdint.h>
51#include <time.h>
52#include "platform/thread.h"
53#include "platform/mutex.h"
54#include "platform/rwlock.h"
55
56// Forward declarations for functions used in inline functions below
58
59#ifdef DEBUG_LOCKS
60// Lock debugging is enabled when DEBUG_LOCKS is defined
61#include "util/uthash.h"
62#include "util/fnv1a.h"
63
64#ifdef __cplusplus
65extern "C" {
66#endif
67
68// ============================================================================
69// Constants and Limits
70// ============================================================================
71
72#define MAX_LOCK_RECORDS 1024
73#define MAX_BACKTRACE_FRAMES 32
74#define MAX_FUNCTION_NAME_LEN 256
75#define MAX_FILE_NAME_LEN 256
76
77// ============================================================================
78// Lock Types
79// ============================================================================
80
85typedef enum {
86 LOCK_TYPE_MUTEX = 0,
87 LOCK_TYPE_RWLOCK_READ,
88 LOCK_TYPE_RWLOCK_WRITE
89} lock_type_t;
90
91// ============================================================================
92// Forward Declarations
93// ============================================================================
94
95typedef struct lock_record lock_record_t;
96
97// ============================================================================
98// Lock Record Structure
99// ============================================================================
100
112struct lock_record {
113 uint32_t key;
114 void *lock_address;
115 lock_type_t lock_type;
117 struct timespec acquisition_time;
118 const char *file_name;
119 int line_number;
120 const char *function_name;
121
122 // Backtrace information
123 void *backtrace_buffer[MAX_BACKTRACE_FRAMES];
124 int backtrace_size;
125 char **backtrace_symbols;
126
127 UT_hash_handle hash_handle;
128};
129
130// ============================================================================
131// Lock Usage Statistics Structure
132// ============================================================================
133
142typedef struct lock_usage_stats {
143 uint32_t key;
144 const char *file_name;
145 int line_number;
146 const char *function_name;
147 lock_type_t lock_type;
148 uint64_t total_acquisitions;
149 uint64_t total_hold_time_ns;
150 uint64_t max_hold_time_ns;
151 uint64_t min_hold_time_ns;
152 struct timespec first_acquisition;
153 struct timespec last_acquisition;
154 UT_hash_handle hash_handle;
155} lock_usage_stats_t;
156
157// ============================================================================
158// Lock Debug Manager
159// ============================================================================
160
172typedef struct lock_debug_manager {
173 // Uthash hash tables (head pointers, NULL-initialized)
174 lock_record_t *lock_records;
175 lock_usage_stats_t *usage_stats;
176 lock_record_t *orphaned_releases;
177
178 // External rwlocks for thread safety (uthash requires external locking)
179 rwlock_t lock_records_lock;
180 rwlock_t usage_stats_lock;
181 rwlock_t orphaned_releases_lock;
182
183 // Statistics (atomic for thread safety)
184 atomic_uint_fast64_t total_locks_acquired;
185 atomic_uint_fast64_t total_locks_released;
186 atomic_uint_fast32_t current_locks_held;
187
188 // Debug thread management
189 asciichat_thread_t debug_thread;
190 atomic_bool debug_thread_running;
191 atomic_bool debug_thread_created;
192 atomic_bool should_print_locks;
193
194 // Initialization state
195 atomic_bool initialized;
196} lock_debug_manager_t;
197
202extern lock_debug_manager_t g_lock_debug_manager;
203extern atomic_bool g_initializing;
204
205// ============================================================================
206// Helper Functions
207// ============================================================================
208
221static inline uint32_t lock_record_key(void *lock_address, lock_type_t lock_type) {
222 // Combine lock address, type, and thread ID into a unique key using FNV-1a
223 // This prevents key collisions when the same lock is used by different threads
224 // Hash all components together using FNV-1a for consistent hashing
225 struct {
226 uintptr_t addr;
227 lock_type_t lock_type;
229 } key_data = {.addr = (uintptr_t)lock_address, .lock_type = lock_type, .thread_id = asciichat_thread_current_id()};
230 return fnv1a_hash_bytes(&key_data, sizeof(key_data));
231}
232
241static inline uint32_t usage_stats_key(const char *file_name, int line_number, const char *function_name,
242 lock_type_t lock_type) {
243 // Create a hash from file name, line number, function name, and lock type
244 uint32_t hash = fnv1a_hash_string(file_name);
245 hash = fnv1a_hash_bytes(&line_number, sizeof(line_number)) ^ hash;
246 hash = fnv1a_hash_string(function_name) ^ hash;
247 hash = fnv1a_hash_bytes(&lock_type, sizeof(lock_type)) ^ hash;
248 return hash;
249}
250
251// ============================================================================
252// Public API Functions
253// ============================================================================
254
260int lock_debug_init(void);
261
267int lock_debug_start_thread(void);
268
273void lock_debug_cleanup(void);
274
279void lock_debug_cleanup_thread(void);
280
285void lock_debug_trigger_print(void);
286
287// ============================================================================
288// Tracked Lock Functions
289// ============================================================================
290
300int debug_mutex_lock(mutex_t *mutex, const char *file_name, int line_number, const char *function_name);
301
311int debug_mutex_unlock(mutex_t *mutex, const char *file_name, int line_number, const char *function_name);
312
322int debug_rwlock_rdlock(rwlock_t *rwlock, const char *file_name, int line_number, const char *function_name);
323
333int debug_rwlock_wrlock(rwlock_t *rwlock, const char *file_name, int line_number, const char *function_name);
334
344int debug_rwlock_rdunlock(rwlock_t *rwlock, const char *file_name, int line_number, const char *function_name);
345
355int debug_rwlock_wrunlock(rwlock_t *rwlock, const char *file_name, int line_number, const char *function_name);
356
366// ============================================================================
367// Convenience Macros
368// ============================================================================
369
374#ifdef DEBUG_LOCKS
375#define DEBUG_MUTEX_LOCK(mutex) debug_mutex_lock(mutex, __FILE__, __LINE__, __func__)
376#define DEBUG_MUTEX_UNLOCK(mutex) debug_mutex_unlock(mutex, __FILE__, __LINE__, __func__)
377#define DEBUG_RWLOCK_RDLOCK(rwlock) debug_rwlock_rdlock(rwlock, __FILE__, __LINE__, __func__)
378#define DEBUG_RWLOCK_WRLOCK(rwlock) debug_rwlock_wrlock(rwlock, __FILE__, __LINE__, __func__)
379#else
380#define DEBUG_MUTEX_LOCK(mutex) debug_mutex_lock(mutex, NULL, 0, NULL)
381#define DEBUG_MUTEX_UNLOCK(mutex) debug_mutex_unlock(mutex, NULL, 0, NULL)
382#define DEBUG_RWLOCK_RDLOCK(rwlock) debug_rwlock_rdlock(rwlock, NULL, 0, NULL)
383#define DEBUG_RWLOCK_WRLOCK(rwlock) debug_rwlock_wrlock(rwlock, NULL, 0, NULL)
384#endif
385
391// ============================================================================
392// Statistics and Information Functions
393// ============================================================================
394
402void lock_debug_get_stats(uint64_t *total_acquired, uint64_t *total_released, uint32_t *currently_held);
403
410
415void lock_debug_print_state(void);
416
423void print_orphaned_release_callback(lock_record_t *record, void *user_data);
424
425#ifdef __cplusplus
426}
427#endif
428
429#endif // DEBUG_LOCKS
430
int thread_id
#️⃣ FNV-1a Hash Function Implementation
unsigned int uint32_t
Definition common.h:58
unsigned long long uint64_t
Definition common.h:59
uint64_t asciichat_thread_current_id(void)
int debug_rwlock_rdlock(rwlock_t *rwlock, const char *file_name, int line_number, const char *function_name)
int debug_rwlock_wrlock(rwlock_t *rwlock, const char *file_name, int line_number, const char *function_name)
int debug_mutex_unlock(mutex_t *mutex, const char *file_name, int line_number, const char *function_name)
int debug_mutex_lock(mutex_t *mutex, const char *file_name, int line_number, const char *function_name)
pthread_mutex_t mutex_t
Mutex type (POSIX: pthread_mutex_t)
Definition mutex.h:38
int debug_rwlock_wrunlock(rwlock_t *rwlock, const char *file_name, int line_number, const char *function_name)
pthread_rwlock_t rwlock_t
Read-write lock type (POSIX: pthread_rwlock_t)
Definition rwlock.h:40
bool lock_debug_is_initialized(void)
int debug_rwlock_rdunlock(rwlock_t *rwlock, const char *file_name, int line_number, const char *function_name)
pthread_t asciichat_thread_t
Thread handle type (POSIX: pthread_t)
bool initialized
Definition mmap.c:36
Cross-platform mutex interface for ascii-chat.
🧵 Cross-platform thread interface for ascii-chat
Cross-platform read-write lock interface for ascii-chat.
rwlock_t rwlock
Read-write lock for thread-safe access (uthash requires external locking)
Definition time.c:28
⏱️ High-precision timing utilities using sokol_time.h and uthash
#️⃣ Wrapper for uthash.h that ensures common.h is included first