Assert () and panic ()
Let's first look at assert (). You may have been using this function for a long time, but previously you used a ready-made assert, which can be easily used as long as it contains a header file. Now everything has to be self-reliant, but don't worry, it is not difficult to write an Assert function. See the following code:
12 # define assert
13 # ifdef assert
14 void assertion_failure (char * exp, char * file, char * base_file, int line );
15 # define assert (exp) if (exp );/
16 else assertion_failure (# exp, _ file __, _ base_file __, _ line __)
17 # else
18 # define assert (exp)
19 # endif
Note the following three macros: _ file _, _ base_file _, and _ line _. Their meanings are as follows: [1].
_ File __: the input file is expanded. Here, it tells us which file has an exception.
_ Base_file __: the file name that can be considered to be passed to the compiler. For example, in M. C contains N. h, while n. if an Assert function in H fails, _ file _ is N. h ,__ base_file _ is M. c.
_ Line __: it is expanded into the current row number.
After understanding the meanings of these macros, the remaining assertion_failure () function is easy. Its function is to print out the location where the error occurs:
42 Public void assertion_failure (char * exp, char * file, char * base_file, int line)
43 {
44 printl ("% C) lost assert (% s) failed: lost file: Lost % s, encrypted base_file: Lost % s, lost ln % d ",
45 mag_ch_assert,
46 exp, file, base_file, line );
47
48 /**
49 * If assertion fails in a task, the system will halt before
50 * printl () returns. If it happens in a user proc, printl () will
51 * return like a common routine and arrive here.
52 * @ see sys_printx ()
53 *
54 * we use a forever loop to prevent the proc from going on:
55 */
56 spin ("assertion_failure ()");
57
58/* shocould never arrive here */
59 _ ASM _ volatile _ ("ud2 ");
60}
Note that a little trick is used here, that is, an improved printing function called printl (), which is actually a macro defined as printf, however, the printf here is slightly different from the previous chapter. It will call a system call called printx and finally call the function sys_printx (), which is located in TTY. c:
181 public int sys_printx (INT _ unused1, int _ unused2, char * s, struct proc * p_proc)
182 {
183 const char * P;
184 char ch;
185
186 char reenter_err [] = "? When k_reenter partition is invalid incorrect partition for unknown reason ";
187 reenter_err [0] = mag_ch_panic;
188
189 /**
190 * @ note code in both ring 0 and ring 1 ~ 3 may invoke printx ().
191 * If this happens in Ring 0, no linear-physical address mapping
192 * is needed.
193 *
194 * @ attention the value of 'K _ reenter' is tricky here. When
195 *-# printx () is called in Ring 0
196 *-k_reenter> 0. When code in Ring 0 callprintx (),
197 * an 'interrupt re-enter' will occur (printx () generates
198 * a software interrupt). Thus 'K _ reenter' will be increased
199 * by 'kernel. ASM: save' and be greater than 0.
200 *-# printx () is called in ring 1 ~ 3
201 *-k_reenter = 0.
202 */
203 If (k_reenter = 0)/* printx () called in ring <1 ~ 3> */
204 P = va2la (proc2pid (p_proc), S );
205 else if (k_reenter> 0)/* printx () called in ring <0> */
206 P = s;
207 else/* This shocould not happen */
208 p = reenter_err;
209
210 /**
211 * @ note if assertion fails in any task, the system will be halted;
212 * if it fails in a user proc, it'll return like any normal syscall
213 * does.
214 */
215 if (* P = mag_ch_panic) |
216 (* P = mag_ch_assert & p_proc_ready <& proc_table [nr_tasks]) {
217 disable_int ();
218 char * V = (char *) v_mem_base;
219 const char * q = p + 1;/* + 1: Skip the magic char */
220
221 while (v <(char *) (v_mem_base + v_mem_size )){
222 * V ++ = * q ++;
223 * V ++ = red_char;
224 if (! * Q ){
225 while (INT) V-v_mem_base) % (scr_width * 16 )){
226/** v ++ = '';*/
227 v ++;
228 * V ++ = gray_char;
229}
230 q = p + 1;
231}
232}
233
234 _ ASM _ volatile _ ("hlt ");
235}
236
237 while (CH = * P ++ )! = 0 ){
238 If (CH = mag_ch_panic | CH = mag_ch_assert)
239 continue;/* skip the magic char */
240
241 out_char (tty_table [p_proc-> nr_tty]. p_console, CH );
242}
243
244 return 0;
245}
It is easy to see that sys_printx () will first determine whether the first character is a preset "Magic char". If yes, it will perform special response processing. Our assertion_failure () uses mag_ch_assert as "Magic char ". When sys_printx () finds that the first character of the input string is mag_ch_assert, it also determines whether the process called by the system is a system process (task) or a user process (User proc ), if it is a system process, the entire system is stopped, and the strings to be printed are printed everywhere. If it is a user process, the printed strings are returned like a normal printx call, at that time, the user process will enter an endless loop because of the call to the function spin () in assertion_failure. In other words, the Assert failure of the system process will cause the system to stop, and the failure of the user process will only stop itself.