-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy patherror.c
More file actions
139 lines (124 loc) · 4.29 KB
/
Copy patherror.c
File metadata and controls
139 lines (124 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/* SPDX-License-Identifier: MIT */
/* Copyright (c) 2026 MoatLab, Virginia Tech. */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include "error.h"
int global_log_level = LOG_LEVEL_INFO;
static void noop_log(const char *function, const char *format, ...)
{
(void)function;
(void)format;
}
static void log_error_impl(const char *function, const char *format, ...);
static void log_warning_impl(const char *function, const char *format, ...);
static void log_info_impl(const char *function, const char *format, ...);
static void log_debug_impl(const char *function, const char *format, ...);
static void log_trace_impl(const char *function, const char *format, ...);
void (*log_error_fn)(const char *function, const char *format, ...) = log_error_impl;
void (*log_warning_fn)(const char *function, const char *format, ...) = log_warning_impl;
void (*log_info_fn)(const char *function, const char *format, ...) = log_info_impl;
void (*log_debug_fn)(const char *function, const char *format, ...) = noop_log;
void (*log_trace_fn)(const char *function, const char *format, ...) = log_trace_impl;
/* Thread-safety contract ():
*
* set_log_level() reassigns five function-pointer globals
* (log_error_fn / log_warning_fn / log_info_fn / log_debug_fn / log_trace_fn).
* These reassignments are NOT atomic and have no memory-barrier protection.
*
* INVARIANT: set_log_level() MUST be called exactly once during single-threaded
* startup (before pthread_create or coroutine spawn), and MUST NOT be called
* again once worker threads are running.
*
* All current callers (parse_command_line_args during main()'s init phase)
* satisfy this. If runtime log-level changes are ever needed, this function
* needs a pthread_mutex AND atomic stores; do not just sprinkle pthread_mutex —
* readers (every log call on the hot path) also need acquire-loads. */
void set_log_level(int level)
{
global_log_level = level;
log_error_fn = log_error_impl; // Always log errors
log_warning_fn = (level >= LOG_LEVEL_WARNING) ? log_warning_impl : noop_log;
log_info_fn = (level >= LOG_LEVEL_INFO) ? log_info_impl : noop_log;
log_debug_fn = (level >= LOG_LEVEL_DEBUG) ? log_debug_impl : noop_log;
log_trace_fn = (level >= LOG_LEVEL_TRACE) ? log_trace_impl : noop_log;
}
static void log_error_impl(const char *function, const char *format, ...)
{
fprintf(stderr, "[ERROR] %s: ", function);
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, " (errno: %s)\n", strerror(errno));
}
static void log_warning_impl(const char *function, const char *format, ...)
{
fprintf(stderr, "[WARNING] %s: ", function);
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "\n");
}
static void log_info_impl(const char *function, const char *format, ...)
{
fprintf(stdout, "[INFO] %s: ", function);
va_list args;
va_start(args, format);
vfprintf(stdout, format, args);
va_end(args);
fprintf(stdout, "\n");
fflush(stdout);
}
static void log_debug_impl(const char *function, const char *format, ...)
{
fprintf(stdout, "[DEBUG] %s: ", function);
va_list args;
va_start(args, format);
vfprintf(stdout, format, args);
va_end(args);
fprintf(stdout, "\n");
fflush(stdout);
}
static void log_trace_impl(const char *function, const char *format, ...)
{
fprintf(stdout, "[TRACE] %s: ", function);
va_list args;
va_start(args, format);
vfprintf(stdout, format, args);
va_end(args);
fprintf(stdout, "\n");
fflush(stdout);
}
void *safe_malloc(size_t size, const char *context)
{
void *ptr = malloc(size);
if (!ptr) {
log_error(context, "Memory allocation failed");
exit(EXIT_FAILURE);
}
return ptr;
}
void *safe_calloc(size_t nmemb, size_t size, const char *context)
{
void *ptr = calloc(nmemb, size);
if (!ptr) {
log_error(context, "Memory allocation failed");
exit(EXIT_FAILURE);
}
return ptr;
}
int safe_close(int fd, const char *context)
{
if (fd >= 0) {
if (close(fd) < 0) {
log_error(context, "Failed to close file descriptor");
return -1;
}
}
return 0;
}