VT100 - Replace global buffer with per-terminal, further implementation of escape...
[tpg/acess2.git] / KernelLand / Kernel / logging.c
1 /*
2  * Acess 2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * logging.c - Kernel Logging Service
6  */
7 #include <acess.h>
8 #include <adt.h>
9
10 #define CACHE_MESSAGES  0
11 #define PRINT_ON_APPEND 1
12 #define USE_RING_BUFFER 1
13 #define RING_BUFFER_SIZE        4096
14
15 // === CONSTANTS ===
16 enum eLogLevels
17 {
18         LOG_LEVEL_KPANIC,
19         LOG_LEVEL_PANIC,
20         LOG_LEVEL_FATAL,
21         LOG_LEVEL_ERROR,
22         LOG_LEVEL_WARNING,
23         LOG_LEVEL_NOTICE,
24         LOG_LEVEL_LOG,
25         LOG_LEVEL_DEBUG,
26         NUM_LOG_LEVELS
27 };
28 const char      *csaLevelColours[] = {
29                 "\x1B[35m", "\x1B[34m", "\x1B[36m", "\x1B[31m",
30                 "\x1B[33m", "\x1B[32m", "\x1B[0m", "\x1B[0m"
31                 };
32 const char      *csaLevelCodes[] =  {"k","p","f","e","w","n","l","d"};
33
34 // === TYPES ===
35 typedef struct sLogEntry
36 {
37         struct sLogEntry        *Next;
38         struct sLogEntry        *LevelNext;
39         Sint64  Time;
40          int    Level;
41          int    Length;
42         char    Ident[9];
43         char    Data[];
44 }       tLogEntry;
45 typedef struct sLogList
46 {
47         tLogEntry       *Head;
48         tLogEntry       *Tail;
49 }       tLogList;
50
51 // === PROTOTYPES ===
52 void    Log_AddEvent(const char *Ident, int Level, const char *Format, va_list Args);
53 static void     Log_Int_PrintMessage(tLogEntry *Entry);
54 //void  Log_KernelPanic(const char *Ident, const char *Message, ...);
55 //void  Log_Panic(const char *Ident, const char *Message, ...);
56 //void  Log_Error(const char *Ident, const char *Message, ...);
57 //void  Log_Warning(const char *Ident, const char *Message, ...);
58 //void  Log_Notice(const char *Ident, const char *Message, ...);
59 //void  Log_Log(const char *Ident, const char *Message, ...);
60 //void  Log_Debug(const char *Ident, const char *Message, ...);
61
62 // === EXPORTS ===
63 EXPORT(Log_Panic);
64 EXPORT(Log_Error);
65 EXPORT(Log_Warning);
66 EXPORT(Log_Notice);
67 EXPORT(Log_Log);
68 EXPORT(Log_Debug);
69
70 // === GLOBALS ===
71 tShortSpinlock  glLogOutput;
72 #if CACHE_MESSAGES
73 # if USE_RING_BUFFER
74 Uint8   gaLog_RingBufferData[sizeof(tRingBuffer)+RING_BUFFER_SIZE];
75 tRingBuffer     *gpLog_RingBuffer = (void*)gaLog_RingBufferData;
76 # else
77 tMutex  glLog;
78 tLogList        gLog;
79 tLogList        gLog_Levels[NUM_LOG_LEVELS];
80 # endif // USE_RING_BUFFER
81 #endif // CACHE_MESSAGES
82
83 // === CODE ===
84 /**
85  * \brief Adds an event to the log
86  */
87 void Log_AddEvent(const char *Ident, int Level, const char *Format, va_list Args)
88 {
89          int    len;
90         tLogEntry       *ent;
91         va_list args_tmp;
92         
93         if( Level >= NUM_LOG_LEVELS )   return;
94
95         va_copy(args_tmp, Args);
96         len = vsnprintf(NULL, 0, Format, args_tmp);
97         
98         #if USE_RING_BUFFER || !CACHE_MESSAGES
99         {
100         char    buf[sizeof(tLogEntry)+len+1];
101         ent = (void*)buf;
102         #else
103         ent = malloc(sizeof(tLogEntry)+len+1);
104         #endif
105         ent->Time = now();
106         strncpy(ent->Ident, Ident, 8);
107         ent->Ident[8] = '\0';
108         ent->Level = Level;
109         ent->Length = len;
110         vsnprintf( ent->Data, len+1, Format, Args );
111
112         #if CACHE_MESSAGES
113         # if USE_RING_BUFFER
114         {
115                 #define LOG_HDR_LEN     (14+1+2+8+2)
116                 char    newData[ LOG_HDR_LEN + len + 2 + 1 ];
117                 sprintf( newData, "%014lli%s [%-8.8s] ",
118                         ent->Time, csaLevelCodes[Level], Ident);
119                 strcpy( newData + LOG_HDR_LEN, ent->Data );
120                 strcpy( newData + LOG_HDR_LEN + len, "\r\n" );
121                 gpLog_RingBuffer->Space = RING_BUFFER_SIZE;     // Needed to init the buffer
122                 RingBuffer_Write( gpLog_RingBuffer, newData, LOG_HDR_LEN + len + 2 );
123         }
124         # else
125         Mutex_Acquire( &glLog );
126         
127         ent->Next = gLog.Tail;
128         tLogEntry       **pnp = (gLog.Tail ? &gLog.Tail->Next : &gLog.Head);
129         *pnp = ent;
130         gLog.Tail = ent;
131         
132         ent->LevelNext = gLog_Levels[Level].Tail;
133         pnp = (gLog_Levels[Level].Tail ? &gLog_Levels[Level].Tail->LevelNext : &gLog_Levels[Level].Head);
134         *pnp = ent;
135         gLog_Levels[Level].Tail = ent;
136         
137         Mutex_Release( &glLog );
138         # endif
139         #endif
140         
141         #if PRINT_ON_APPEND || !CACHE_MESSAGES
142         Log_Int_PrintMessage( ent );
143         #endif
144         
145         #if USE_RING_BUFFER || !CACHE_MESSAGES
146         }
147         #endif
148 }
149
150 /**
151  * \brief Prints a log message to the debug console
152  */
153 void Log_Int_PrintMessage(tLogEntry *Entry)
154 {
155         if( CPU_HAS_LOCK(&glLogOutput) )
156                 return ;        // TODO: Error?
157         SHORTLOCK( &glLogOutput );
158         LogF("%s%014lli",
159                 csaLevelColours[Entry->Level],
160                 Entry->Time
161                 );
162         LogF("%s [%-8s] %i - %.*s",
163                 csaLevelCodes[Entry->Level],
164                 Entry->Ident,
165                 Threads_GetTID(),
166                 Entry->Length,
167                 Entry->Data
168                 );
169         LogF("\x1B[0m\r\n");    // Separate in case Entry->Data is too long
170         SHORTREL( &glLogOutput );
171 }
172
173 /**
174  * \brief KERNEL PANIC!!!!
175  */
176 void Log_KernelPanic(const char *Ident, const char *Message, ...)
177 {
178         va_list args;   
179         va_start(args, Message);
180         Log_AddEvent(Ident, LOG_LEVEL_KPANIC, Message, args);
181         va_end(args);
182         Panic("Log_KernelPanic - %s", Ident);
183 }
184
185 /**
186  * \brief Panic Message - Driver Unrecoverable error
187  */
188 void Log_Panic(const char *Ident, const char *Message, ...)
189 {
190         va_list args;   
191         va_start(args, Message);
192         Log_AddEvent(Ident, LOG_LEVEL_PANIC, Message, args);
193         va_end(args);
194 }
195
196 /**
197  * \brief Error Message - Recoverable Error
198  */
199 void Log_Error(const char *Ident, const char *Message, ...)
200 {
201         va_list args;   
202         va_start(args, Message);
203         Log_AddEvent(Ident, LOG_LEVEL_ERROR, Message, args);
204         va_end(args);
205 }
206
207 /**
208  * \brief Warning Message - Something the user should know
209  */
210 void Log_Warning(const char *Ident, const char *Message, ...)
211 {
212         va_list args;
213         
214         va_start(args, Message);
215         Log_AddEvent(Ident, LOG_LEVEL_WARNING, Message, args);
216         va_end(args);
217 }
218
219 /**
220  * \brief Notice Message - Something the user might like to know
221  */
222 void Log_Notice(const char *Ident, const char *Message, ...)
223 {
224         va_list args;   
225         va_start(args, Message);
226         Log_AddEvent(Ident, LOG_LEVEL_NOTICE, Message, args);
227         va_end(args);
228 }
229
230 /**
231  * \brief Log Message - Possibly useful information
232  */
233 void Log_Log(const char *Ident, const char *Message, ...)
234 {
235         va_list args;   
236         va_start(args, Message);
237         Log_AddEvent(Ident, LOG_LEVEL_LOG, Message, args);
238         va_end(args);
239 }
240
241 /**
242  * \brief Debug Message - Only a developer would want this info
243  */
244 void Log_Debug(const char *Ident, const char *Message, ...)
245 {
246         va_list args;   
247         va_start(args, Message);
248         Log_AddEvent(Ident, LOG_LEVEL_DEBUG, Message, args);
249         va_end(args);
250 }

UCC git Repository :: git.ucc.asn.au