- kdevelop3 project files
[lightOS.git] / kernel / log.cpp
blob40c3dbccc1eac583f3f3047ade388809519d9ff2
1 /*
2 lightOS kernel
3 Copyright (C) 2009 Jörg Pfähler
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <libarch/scoped_lock.hpp>
20 #include <kernel/log.hpp>
21 #include <kernel/serial.hpp>
22 #include <kernel/console.hpp>
23 #include <kernel/processor.hpp>
24 using kernel::log;
25 using kernel::helper::tmp_log_entry;
28 SINGLETON_INSTANCE(kernel::log);
33 * Implementation of kernel::log
36 log::log()
37 : m_beg(0), m_cur(0), m_cur_addr(virtual_memory::kernel_log_begin<void>()),
38 m_cur_max_addr(adjust_pointer(virtual_memory::kernel_log_begin<void>(), virtual_memory::page_size))
43 log::~log()
47 void log::commit(const char* begin,
48 const char* end,
49 libkernel::log_level lvl)
51 #ifdef KERNEL_HAS_SERIAL
52 // Pump through the serial line before we do anything else
54 const char* tmp = begin;
55 serial& Serial = serial::instance();
56 while (LIKELY(tmp != end))
57 Serial.put(*tmp++);
58 Serial.put('\n');
60 #endif
62 if (LIKELY(lvl != libkernel::log_fatal))
64 // Add the entry to the log
66 const size_t needed_size = sizeof(entry) + (end - begin) + 1;
68 while (UNLIKELY(pointer_difference(m_cur_max_addr, m_cur_addr) < needed_size))
70 // TODO: Allocate space & map stuff (the fault tolerant way, perhaps tell serial if we
71 // swallowed a log entry because we ran out of memory)
74 entry* new_entry = reinterpret_cast<entry*>(m_cur_addr);
75 new_entry->next = 0;
76 new_entry->prev = m_cur;
77 new_entry->lvl = lvl;
78 if (UNLIKELY(m_cur == 0))
79 m_beg = new_entry;
80 else
81 m_cur->next = new_entry;
82 m_cur = new_entry;
83 m_cur_addr = adjust_pointer(m_cur_addr, needed_size);
85 char* entry_string = adjust_pointer_cast<char>(new_entry, sizeof(entry));
86 while (LIKELY(begin != end))
87 *entry_string++ = *begin++;
88 *entry_string = '\0';
90 else
92 size_t cur_index = 0;
93 console& Console = console::instance();
94 console_window_ptr kernel_console = Console.get(kernel_console_id);
96 // Write the log before the fatal message
97 entry *cur = m_cur;
99 if (cur != 0)
101 size_t i = console_window_height - 2;
102 while (i > 0 && cur->prev != 0)
104 cur = cur->prev;
105 --i;
109 while (cur != 0)
111 console_color_t color = KERNEL_CONSOLE_NOTICE;
112 if (cur->lvl == libkernel::log_warning)
113 color = KERNEL_CONSOLE_WARNING;
114 else if (cur->lvl == libkernel::log_error)
115 color = KERNEL_CONSOLE_ERROR;
117 const char* entry_string = adjust_pointer_cast<char>(cur, sizeof(entry));
118 while (*entry_string != '\0')
120 kernel_console->character(cur_index, *entry_string++);
121 kernel_console->color(cur_index, color);
122 ++cur_index;
124 cur_index += (console_window_width - (cur_index % console_window_width)) % console_window_width;
125 cur = cur->next;
128 // Write the fatal error message
129 const char* fatal = "FATAL: ";
130 while (*fatal != '\0')
132 kernel_console->character(cur_index, *fatal++);
133 kernel_console->color(cur_index, KERNEL_CONSOLE_FATAL);
134 ++cur_index;
137 while (begin != end)
139 kernel_console->character(cur_index, *begin++);
140 kernel_console->color(cur_index, KERNEL_CONSOLE_FATAL);
141 ++cur_index;
143 Console.switch_to(kernel_console);
145 // TODO: Fix this for multiprocessor environments
146 processor::halt();
150 size_t log::get_entry(size_t index,
151 libkernel::log_level& lvl,
152 char* begin,
153 size_t size)
155 SCOPED_LOCK(m_lock, scope);
157 entry* cur = m_beg;
158 while (cur != 0 && index > 0)
160 cur = cur->next;
161 --index;
164 if (cur == 0)
165 return 0;
167 size_t real_size = 0;
168 char* entry_string = adjust_pointer_cast<char>(cur, sizeof(entry));
169 while (*entry_string != '\0' && size >= 1)
171 *begin++ = *entry_string++;
172 --size;
173 ++real_size;
177 ++real_size;
178 } while (*entry_string++ != '\0');
179 if (size != 0)
180 *begin = '\0';
181 lvl = cur->lvl;
183 return real_size;
189 * Implementation of kernel::tmp_log_entry
192 tmp_log_entry::tmp_log_entry(libkernel::log_level lvl)
193 : m_level(lvl), m_first(virtual_memory::kernel_log_tmp_first<char>()),
194 m_next(virtual_memory::kernel_log_tmp_first<char>()), m_last(virtual_memory::kernel_log_tmp_last<char>())
196 #if defined(_LIGHTOS_MULTIPROCESSOR)
197 log::instance().m_lock.lock();
198 #endif
201 tmp_log_entry::~tmp_log_entry()
203 log::instance().commit(m_first,
204 m_next,
205 m_level);
207 #if defined(_LIGHTOS_MULTIPROCESSOR)
208 log::instance().m_lock.unlock();
209 #endif
212 tmp_log_entry& tmp_log_entry::operator << (char c)
214 if (m_next != m_last)
215 *m_next++ = c;
216 return *this;
219 tmp_log_entry& tmp_log_entry::operator << (const char* s)
221 while (*s != '\0')
222 tmp_log_entry::operator << (*s++);
223 return *this;
226 tmp_log_entry& tmp_log_entry::operator << (const void* p)
228 return *this << "0x" << hex(reinterpret_cast<uintptr_t>(p), 2 * _LIBARCH_POINTER_SIZE);