Refactor BeRTOS to be in his own directory.
[bertos.git] / bertos / kern / monitor.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief Monitor to check for stack overflows
34  *
35  * \version $Id$
36  *
37  * \author Giovanni Bajo <rasky@develer.com>
38  */
39
40
41 #include "monitor.h"
42
43 #if CONFIG_KERN_MONITOR
44
45 #include "proc_p.h"
46 #include <mware/list.h>
47 #include <drv/timer.h>
48 #include <kern/proc.h>
49 #include <cfg/macros.h>
50 #include <cfg/debug.h>
51
52
53 static List MonitorProcs;
54
55
56 void monitor_init(void)
57 {
58         LIST_INIT(&MonitorProcs);
59 }
60
61
62 void monitor_add(Process* proc, const char* name, cpustack_t* stack_base, size_t stack_size)
63 {
64         proc->monitor.name = name;
65         proc->monitor.stack_base = stack_base;
66         proc->monitor.stack_size = stack_size;
67
68         ADDTAIL(&MonitorProcs, &proc->monitor.link);
69 }
70
71
72 void monitor_remove(Process* proc)
73 {
74         REMOVE(&proc->monitor.link);
75 }
76
77 void monitor_rename(Process *proc, const char* name)
78 {
79         proc->monitor.name = name;
80 }
81
82 /* TODO: use containerof() */
83 #define MONITOR_NODE_TO_PROCESS(node) \
84         (struct Process *)((intptr_t)(node) - offsetof(struct Process, monitor.link))
85
86 size_t monitor_checkStack(cpustack_t* stack_base, size_t stack_size)
87 {
88         cpustack_t* beg;
89         cpustack_t* cur;
90         cpustack_t* end;
91         size_t sp_free;
92
93         beg = stack_base;
94         end = stack_base + stack_size / sizeof(cpustack_t) - 1;
95
96         if (CPU_STACK_GROWS_UPWARD)
97         {
98                 cur = beg;
99                 beg = end;
100                 end = cur;
101         }
102
103         cur = beg;
104         while (cur != end)
105         {
106                 if (*cur != CONFIG_KERN_STACKFILLCODE)
107                         break;
108
109                 if (CPU_STACK_GROWS_UPWARD)
110                         cur--;
111                 else
112                         cur++;
113         }
114
115         sp_free = ABS(cur - beg) * sizeof(cpustack_t);
116         return sp_free;
117 }
118
119
120 void monitor_report(void)
121 {
122         struct Process* p;
123         int i;
124
125         if (LIST_EMPTY(&MonitorProcs))
126         {
127                 kputs("No stacks registered in the monitor\n");
128                 return;
129         }
130
131         kprintf("%-24s%-8s%-8s%-8s%-8s\n", "Process name", "TCB", "SPbase", "SPsize", "SPfree");
132         for (i=0;i<56;i++)
133                 kputchar('-');
134         kputchar('\n');
135
136         for (p = MONITOR_NODE_TO_PROCESS(LIST_HEAD(&MonitorProcs));
137                  p->monitor.link.succ;
138                  p = MONITOR_NODE_TO_PROCESS(p->monitor.link.succ))
139         {
140                 size_t free = monitor_checkStack(p->monitor.stack_base, p->monitor.stack_size);
141                 kprintf("%-24s%-8p%-8p%-8lu%-8lu\n",
142                         p->monitor.name, p, p->monitor.stack_base, p->monitor.stack_size, free);
143         }
144 }
145
146
147 static void NORETURN monitor(void)
148 {
149         struct Process *p;
150
151         while (1)
152         {
153                 for (p = MONITOR_NODE_TO_PROCESS(LIST_HEAD(&MonitorProcs));
154                         p->monitor.link.succ;
155                         p = MONITOR_NODE_TO_PROCESS(p->monitor.link.succ))
156                 {
157                         size_t free = monitor_checkStack(p->monitor.stack_base, p->monitor.stack_size);
158
159                         if (free < 0x20)
160                                 kprintf("MONITOR: WARNING: Free stack for process '%s' is only %u chars\n",
161                                                 p->monitor.name, (unsigned int)free);
162
163                         timer_delay(500);
164                 }
165         }
166 }
167
168
169 void monitor_start(size_t stacksize, cpustack_t *stack)
170 {
171         proc_new(monitor, NULL, stacksize, stack);
172 }
173
174 #endif /* CONFIG_KERN_MONITOR */