MonkOS  v0.1
A simple 64-bit operating system (x86_64)
log.c
Go to the documentation of this file.
1 //============================================================================
2 /// @file log.c
3 /// @brief Kernel logging module.
4 //
5 // Copyright 2016 Brett Vickers.
6 // Use of this source code is governed by a BSD-style license
7 // that can be found in the MonkOS LICENSE file.
8 //============================================================================
9 
10 #include <libc/stdio.h>
11 #include <libc/string.h>
12 #include <kernel/debug/log.h>
13 
14 // Record buffer constants
15 #define RBUFSHIFT 10
16 #define RBUFSIZE (1 << RBUFSHIFT) // 1024
17 #define RBUFMASK (RBUFSIZE - 1)
18 
19 // Message buffer constants
20 #define MBUFSHIFT 16
21 #define MBUFSIZE (1 << MBUFSHIFT) // 64KiB
22 #define MBUFMASK (MBUFSIZE - 1)
23 
24 // Callback registrations
25 #define MAX_CALLBACKS 8
26 
27 /// A log record represents a single logged event.
28 typedef struct record
29 {
31  int moffset; ///< Offset of message in context::mbuf
32 } record_t;
33 
34 /// Used for registering logging callback functions.
35 typedef struct callback
36 {
39 } callback_t;
40 
41 /// The log context describes the state of the log buffers. There are two
42 /// buffers: the record buffer and the message buffer. The record buffer is a
43 /// circular queue that contains records describing the most recent 1024 log
44 /// messages. The message buffer contains the text messages associated with
45 /// each of the records in the log buffer.
46 struct context
47 {
48  // Record buffer
49  record_t rbuf[RBUFSIZE]; ///< Circular record buffer
50  int rhead; ///< index of oldest record in rbuf
51  int rtail; ///< rbuf index of next record to write
52  int rbufsz; ///< number of records in rbuf
53 
54  // Message buffer
55  char mbuf[MBUFSIZE]; ///< Circular message text buffer
56  int mhead; ///< index of oldest char in mbuf
57  int mtail; ///< mbuf index of next char to write
58  int mbufsz; ///< the number of characters in mbuf
59 
60  // Callback registrations
62  int callbacks_size; ///< number of registrations
63 };
64 
65 static struct context lc;
66 
67 static void
69 {
70  lc.rhead = (lc.rhead + 1) & RBUFMASK;
71  lc.rbufsz--;
72 }
73 
74 static void
75 evict_msg(int chars)
76 {
77  // Evict the requested number of characters from the mbuf. Evict
78  // associated records when the end of a message is reached.
79  for (int i = 0; i < chars && lc.mbufsz > 0; i++) {
80  if (lc.mbuf[lc.mhead] == 0)
81  evict_record();
82  lc.mhead = (lc.mhead + 1) & MBUFMASK;
83  lc.mbufsz--;
84  }
85 
86  // Keep evicting characters from the message buffer until a null
87  // terminator is reached.
88  while (lc.mbufsz > 0) {
89  char ch = lc.mbuf[lc.mhead];
90  lc.mhead = (lc.mhead + 1) & MBUFMASK;
91  lc.mbufsz--;
92  if (ch == 0) {
93  evict_record();
94  break;
95  }
96  }
97 }
98 
99 static void
101 {
102  while (lc.mbufsz > 0) {
103  char ch = lc.mbuf[lc.mhead];
104  lc.mhead = (lc.mhead + 1) & MBUFMASK;
105  lc.mbufsz--;
106  if (ch == 0)
107  break;
108  }
109 }
110 
111 static int
112 add_msg(const char *str)
113 {
114  int offset = lc.mtail;
115 
116  // Evict one or more log records if we're going to exceed the buffer size.
117  int schars = strlen(str) + 1;
118  if (lc.mbufsz + schars > MBUFSIZE)
119  evict_msg(lc.mbufsz + schars - MBUFSIZE);
120 
121  // Copy the string into the buffer, handling wrap-around.
122  if (lc.mtail + schars > MBUFSIZE) {
123  int split = MBUFSIZE - lc.mtail;
124  memcpy(lc.mbuf + lc.mtail, str, split);
125  memcpy(lc.mbuf, str + split, schars - split);
126  lc.mtail = schars - split;
127  }
128  else {
129  memcpy(lc.mbuf + lc.mtail, str, schars);
130  lc.mtail += schars;
131  }
132 
133  lc.mbufsz += schars;
134 
135  return offset;
136 }
137 
138 static void
139 add_record(int offset, loglevel_t level, const char *str)
140 {
141  // If the record buffer is full, evict the oldest record and its
142  // associated message text.
143  if (lc.rbufsz == RBUFSIZE) {
144  evict_record();
146  }
147 
148  // Add a new record on the tail of the circular record queue.
149  record_t *r = lc.rbuf + lc.rtail;
150  r->moffset = offset;
151  r->level = level;
152 
153  lc.rtail = (lc.rtail + 1) & RBUFMASK;
154  lc.rbufsz++;
155 
156  // Issue registered log callbacks.
157  for (int i = 0; i < lc.callbacks_size; i++) {
158  const callback_t *callback = &lc.callbacks[i];
159  if (level <= callback->maxlevel)
160  callback->cb(level, str);
161  }
162 }
163 
164 void
166 {
168  return;
169 
170  callback_t *record = &lc.callbacks[lc.callbacks_size++];
171  record->maxlevel = maxlevel;
172  record->cb = cb;
173 }
174 
175 void
177 {
178  for (int i = 0; i < lc.callbacks_size; i++) {
179  if (lc.callbacks[i].cb == cb) {
180  memmove(lc.callbacks + i, lc.callbacks + i + 1,
181  sizeof(callback_t) * (lc.callbacks_size - (i + 1)));
182  return;
183  }
184  }
185 }
186 
187 void
188 log(loglevel_t level, const char *str)
189 {
190  int offset = add_msg(str);
191  add_record(offset, level, str);
192 }
193 
194 void
195 logf(loglevel_t level, const char *format, ...)
196 {
197  va_list args;
198  va_start(args, format);
199  logvf(level, format, args);
200  va_end(args);
201 }
202 
203 void
204 logvf(loglevel_t level, const char *format, va_list args)
205 {
206  char str[1024];
207  vsnprintf(str, arrsize(str), format, args);
208  int offset = add_msg(str);
209  add_record(offset, level, str);
210 }
#define MBUFMASK
Definition: log.c:22
record_t rbuf[RBUFSIZE]
Circular record buffer.
Definition: log.c:49
String and memory operations.
int mtail
mbuf index of next char to write
Definition: log.c:57
#define RBUFMASK
Definition: log.c:17
#define RBUFSIZE
Definition: log.c:16
Used for registering logging callback functions.
Definition: log.c:35
callback_t callbacks[MAX_CALLBACKS]
Definition: log.c:61
int vsnprintf(char *buf, size_t n, const char *format, va_list arg)
Compose a printf-formatted string into the target buffer using a variable argument list...
loglevel_t level
Definition: log.c:30
void log_removecallback(log_callback cb)
Remove a callback handler for log messages.
Definition: log.c:176
#define MBUFSIZE
Definition: log.c:21
void logvf(loglevel_t level, const char *format, va_list args)
Log a printf-formatted string using a variable argument list.
Definition: log.c:204
static void evict_record()
Definition: log.c:68
void * memmove(void *dst, const void *src, size_t num)
Move bytes from one memory region to another, even if the regions overlap.
static void evict_oldest_msg()
Definition: log.c:100
loglevel_t maxlevel
Definition: log.c:37
size_t strlen(const char *str)
Return the length of a null-terminated string.
static int add_msg(const char *str)
Definition: log.c:112
static void evict_msg(int chars)
Definition: log.c:75
int mhead
index of oldest char in mbuf
Definition: log.c:56
int rbufsz
number of records in rbuf
Definition: log.c:52
char mbuf[MBUFSIZE]
Circular message text buffer.
Definition: log.c:55
void logf(loglevel_t level, const char *format,...)
Log a printf-formatted message to the kernel log buffer.
Definition: log.c:195
loglevel_t
A log level indicates the importance of a logged message.
Definition: log.h:19
void(* log_callback)(loglevel_t level, const char *msg)
Callback handler called when a message is logged.
Definition: log.h:36
Standard i/o library.
static struct context lc
Definition: log.c:65
int callbacks_size
number of registrations
Definition: log.c:62
int rtail
rbuf index of next record to write
Definition: log.c:51
int rhead
index of oldest record in rbuf
Definition: log.c:50
int mbufsz
the number of characters in mbuf
Definition: log.c:58
log_callback cb
Definition: log.c:38
#define arrsize(x)
Return the number of elements in the C array.
Definition: core.h:26
The log context describes the state of the log buffers.
Definition: log.c:46
static void add_record(int offset, loglevel_t level, const char *str)
Definition: log.c:139
#define MAX_CALLBACKS
Definition: log.c:25
A log record represents a single logged event.
Definition: log.c:28
void log_addcallback(loglevel_t maxlevel, log_callback cb)
Add a callback handler for log messages.
Definition: log.c:165
void log(loglevel_t level, const char *str)
Log a message to the kernel log buffer.
Definition: log.c:188
int moffset
Offset of message in context::mbuf.
Definition: log.c:31
void * memcpy(void *dst, const void *src, size_t num)
Copy bytes from one memory region to another.