make log a bit verbose for some useful information
[lunaix-os.git] / lunaix-os / kernel / kprint / kprintf.c
1 #include <lunaix/fs/twifs.h>
2 #include <lunaix/fs/twimap.h>
3 #include <lunaix/syscall.h>
4 #include <lunaix/syscall_utils.h>
5 #include <lunaix/syslog.h>
6 #include <lunaix/device.h>
7 #include <lunaix/owloysius.h>
8 #include <lunaix/ds/flipbuf.h>
9
10 #include <hal/term.h>
11
12 #include <klibc/strfmt.h>
13
14 #include "kp_records.h"
15
16 #define MAX_BUFSZ_HLF 256
17 #define MAX_KPENT_NUM 1024
18
19 static char tmp_buf[MAX_BUFSZ_HLF * 2];
20 static DEFINE_FLIPBUF(fmtbuf, MAX_BUFSZ_HLF, tmp_buf);
21
22 static struct kp_records kprecs = {
23     .kp_ents = { .ents = { .next = &kprecs.kp_ents.ents,
24                            .prev = &kprecs.kp_ents.ents } },
25     .max_recs = MAX_KPENT_NUM,
26     .kp_ent_wp = &kprecs.kp_ents.ents
27 };
28 export_symbol(debug, kprintf, kprecs);
29
30 static char*
31 shift_level(const char* str, int* level)
32 {
33     if (str[0] == KMSG_LVLSTART) {
34         *level = KMSG_LOGLEVEL(str[1]);
35
36         return str += 2;
37     }
38
39     *level = KLOG_INFO;
40     return str;
41 }
42
43 static inline void
44 __put_console(const struct kp_entry* ent)
45 {
46     char* buf;
47     time_t s, ms;
48     size_t sz;
49
50     if (unlikely(!sysconsole)) {
51         return;
52     }
53
54     s   = ent->time / 1000;
55     ms  = ent->time % 1000;
56     buf = flipbuf_flip(&fmtbuf);
57     sz  = ksnprintf(buf, MAX_BUFSZ_HLF, 
58                     "[%04d.%03d] %s", s, ms, ent->content);
59     
60     sysconsole->ops.write(sysconsole, buf, 0, sz);
61 }
62
63 static inline void
64 kprintf_put(int level, const char* buf, size_t sz)
65 {
66     __put_console(kprec_put(&kprecs, level, buf, sz));
67 }
68
69 static inline void
70 kprintf_ml(const char* component, int level, const char* fmt, va_list args)
71 {
72     char* buf;
73     size_t sz;
74
75     buf = flipbuf_top(&fmtbuf);
76     ksnprintf(buf, MAX_BUFSZ_HLF, "%s: %s\n", component, fmt);
77
78     sz = ksnprintfv(flipbuf_flip(&fmtbuf), buf, MAX_BUFSZ_HLF, args);
79     
80     kprintf_put(level, flipbuf_top(&fmtbuf), sz);
81 }
82
83 void
84 kprintf_m(const char* component, const char* fmt, va_list args)
85 {
86     int level;
87     fmt = shift_level(fmt, &level);
88
89     kprintf_ml(component, level, fmt, args);
90 }
91
92 void
93 kprintf_v(const char* component, const char* fmt, ...)
94 {
95     va_list args;
96     va_start(args, fmt);
97     kprintf_m(component, fmt, args);
98     va_end(args);
99 }
100
101 static void
102 __twimap_kprintf_read(struct twimap* map)
103 {
104     struct kp_records* __kprecs = twimap_data(map, struct kp_records*);
105
106     /*
107         XXX we can foreach all records in a single twimap read call,
108             as records is monotonic increasing by design.
109     */
110     struct kp_entry *pos, *n;
111     llist_for_each(pos, n, __kprecs->kp_ent_wp, ents)
112     {
113         time_t s = pos->time / 1000;
114         time_t ms = pos->time % 1000;
115         twimap_printf(map, "[%05d.%03d] %s\n", s, ms, pos->content);
116     }
117 }
118
119 static void
120 kprintf_mapping_init()
121 {
122     twimap_entry_simple(NULL, "kmsg", &kprecs, __twimap_kprintf_read);
123 }
124 EXPORT_TWIFS_PLUGIN(kprintf, kprintf_mapping_init);
125
126
127 void 
128 kprintf_dump_logs() {
129     if (unlikely(!sysconsole)) {
130         return;
131     }
132
133     struct kp_entry *pos, *n;
134     llist_for_each(pos, n, kprecs.kp_ent_wp, ents)
135     {
136         __put_console(pos);
137     }
138 }
139
140 __DEFINE_LXSYSCALL3(void, syslog, int, level, 
141                     const char*, buf, unsigned int, size)
142 {
143     kprintf_put(level, buf, size);
144 }