assert()和panic()
先来看assert()。你或许早就开始使用这个函数,但之前你使用的都是现成的assert,只要包含一个头文件,就可以方便地使用。如今什么都得自力更生了,不过不用怕,写一个assert函数并非难事,见下面的代码:
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
注意其中的__FILE__、__BASE_FILE__和__LINE__这三个宏,它们的意义如下[1]:
__FILE__: 将被展开成当前输入的文件。在这里,它告诉我们哪个文件中产生了异常。
__BASE_FILE__: 可被认为是传递给编译器的那个文件名。比如你在m.c中包含了n.h,而n.h中的某一个assert函数失败了,则__FILE__为n.h,__BASE_FILE__为m.c。
__LINE__: 将被展开成当前的行号。
明白了这几个宏的意义,剩下的assertion_failure()这个函数就显得容易了,它的作用就是将错误发生的位置打印出来:
42 PUBLIC void assertion_failure(char *exp, char *file, char *base_file, int line)
43 {
44         printl(”%c␣␣assert(%s)␣failed:␣file:␣%s,␣base_file:␣%s,␣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         /* should never arrive here */
59         __asm__ __volatile__(”ud2”);
60 }
注意这里使用了一点点小伎俩,那就是使用了一个改进后的打印函数,叫做printl(),它其实就是一个定义成printf的宏,不过这里的printf跟上一章中的稍有不同,它将调用一个叫做printx的系统调用,并最终调用函数sys_printx(),它位于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[] = ”?␣k_reenter␣is␣incorrect␣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 calls printx(),
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 should 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 }
容易看到,sys_printx()将首先判断首字符是否为预先设定的“Magic Char”,如果是的话,则做响应的特殊处理。我们的assertion_failure()就使用了MAG_CH_ASSERT作为“Magic Char”。当sys_printx()发现传入字符串的第一个字符是MAG_CH_ASSERT时,会同时判断调用系统调用的进程是系统进程(TASK)还是用户进程(USER PROC),如果是系统进程,则停止整个系统的运转,并将要打印的字符串打印在显存的各处;如果是用户进程,则打印之后像一个普通的printx调用一样返回,届时该用户进程会因为assertion_failure()中对函数spin()的调用而进入死循环。换言之,系统进程的assert失败会导致系统停转,用户进程的失败仅仅使自己停转。

assert()和panic()相关推荐

  1. Rust编程语言的核心部件

    Rust是一门强调安全.并发.高效的系统编程语言.无GC实现内存安全机制.无数据竞争的并发机制.无运行时开销的抽象机制,是Rust独特的优越特性.它声称解决了传统C语言和C++语言几十年来饱受责难的内 ...

  2. (转)PowerHA完全手册(一,二,三)

    PowerHA完全手册(一) 原文:http://www.talkwithtrend.com/Article/39889-----PowerHA完全手册(一) http://www.talkwitht ...

  3. 进程间通信(IPC)+进程加锁解锁

    [0]README 0.1) source code and text description are from orange's implemention of a os: 0.2) for com ...

  4. InfoQ中文站特供稿件:Rust编程语言的核心部件

    本文为InfoQ中文站特供稿件,首发地址为: http://www.infoq.com/cn/articles/rust-core-components .如需转载,请与InfoQ中文站联系.原文发表 ...

  5. linux oops产生原理,kernel panic , Oops 等cpu异常的分析与定位

    一.kernel panic 二.mips异常机制 三.linuxkernel 对mips异常的处理 四.kernel panic 实例分析 Kernel  panic 内核代码,相比用户层代码更难以 ...

  6. 操作系统真象还原实验记录之实验十二:实现ASSERT

    操作系统真象还原实验记录之实验十二:实现ASSERT,通过makefile完成编译 对应书P367 第8.2节 1.相关基础知识 见书 2.实验代码 完成了开关中断函数.实现assert断言函数用于调 ...

  7. Linux内核oops panic简析

    源码基于:Linux 5.4 0. 前言 内核异常的级别大致分为三个:BUG.oops.panic. BUG 是指那些不符合内核的正常设计,但内核能够检测出来并且对系统运行不会产生影响的问题,比如在原 ...

  8. Solidity 中 revert(), assert() 和 require()

    函数assert和require可以用于检查条件,如果条件不满足则抛出异常. assert(): 函数只能用于测试内部错误,检查不变量,正常的函数代码永远不会产生Panic, 甚至是基于一个无效的外部 ...

  9. Go 知识点(14) — Go 多协程(单个协程触发panic会导致其它所有协程挂掉,每个协程只能捕获到自己的 panic 不能捕获其它协程)

    在多协程并发环境下,我们常常会碰到以下两个问题.假设我们现在有 2 个协程,我们叫它们协程 A 和 B . [问题1]如果协程 A 发生了 panic ,协程 B 是否会因为协程 A 的 panic ...

  10. Python3 try-except、raise和assert解析

    20220221 案例 def product(x):result = 1print(x)count = 0for i in x:try:result *= float(i)except Except ...

最新文章

  1. Oracle 验证A表的2个字段组合不在B表2个字段组合里的数据
  2. c语言 链表 删除节点,C语言实现单链表节点的删除(不带头结点)
  3. Promise之异步调用
  4. su切换到oracle后怎么退出,linux下启动oralce和关闭oracle以及数据库实例化
  5. snort简介以及在Ubuntu下的安装
  6. 二、CSS基础(1)
  7. git常用命令常用场景
  8. 在苹果Mac上的“磁盘工具”中如何修复储存设备?
  9. 互联网产品需求管理思考——统一需求管理
  10. vivado2019.2安装+license添加教程
  11. 总结一个技术总监的教训和经验
  12. STM32F103驱动THM3060读取二代身份证
  13. 免费顺丰快递单号查询API接口demo【快递鸟API接口】
  14. 第三章 代码的坏味道
  15. 为啥将phpstudy打开,却访问不了rips
  16. utf-8的中文是一个汉字占三个字节长度吗?
  17. 操作系统——吸烟者问题
  18. Houdini 求中点,点连成线
  19. java变量的定义有哪些规则_Java变量详解
  20. LTSPICE仿真那些事

热门文章

  1. mongoDB--1 概念
  2. absolute绝对定位的参考坐标和参考对象问题详解
  3. [收藏]深入浅出的《网络socket编程指南》4
  4. docker swarm 常用命令
  5. 队列加分项(选作,根据博客质量加1-5分)(补博客)
  6. maven项目的创建
  7. 导出FLASH用反射的时候要注意的问题
  8. Hadoop、Zookeeper、Hbase分布式安装教程
  9. bitmap格式分析(转)
  10. 最简单的Windows窗体应用程序,它存在什么问题?