宏定义:
#define assert(exp) if (exp) ; \
else assertion_failure(#exp, __FILE__, __BASE_FILE__, __LINE__) 这个#exp不知道什么意义
注意其中的__FILE__、__BASE_FILE__和__LINE__这三个宏,它们的意义如下: 这是编译器默认展开的变量。
__FILE__将被展开成当前输入的文件。在这里,它告诉我们哪个文件中产生了异常。
__BASE_FILE__可被认为是传递给编译器的那个文件名。比如你在m.c中包含了n.h,而n.h中的某一个assert函数失败了,则__FILE__为n.h,__BASE_FILE__为m.c。
__LINE__将被展开成当前的行号。
/*****************************************************************************
* assertion_failure
*************************************************************************//**
* Invoked by assert().
* @param exp The failure expression itself.
* @param file __FILE__
* @param base_file __BASE_FILE__
* @param line __LINE__
*****************************************************************************/
PUBLIC void assertion_failure(char *exp, char *file, char *base_file, int line)
{
printl("%c assert(%s) failed: file: %s, base_file: %s, ln%d",
MAG_CH_ASSERT, exp, file, base_file, line);
/**
* If assertion fails in a TASK, the system will halt before
* printl() returns. If it happens in a USER PROC, printl() will
* return like a common routine and arrive here.
* @see sys_printx()
*
* We use a forever loop to prevent the proc from going on:
*/
spin("assertion_failure()");
/* should never arrive here */
__asm__ __volatile__("ud2");
}
/*****************************************************************************
* spin
*****************************************************************************/
PUBLIC void spin(char * func_name)
{
printl("\nspinning in %s ...\n", func_name);
while (1) {}
}
使用了一个改进后的打印函数,叫做printl(),它其实就是一个定义成printf的宏,不过这里的printf跟上一章中的稍有不同,它将调用一个叫做printx的系统调用,并最终调用函数sys_printx ()。
* @note Code in both Ring 0 and Ring 1~3 may invoke printx().
* If this happens in Ring 0, no linear-physical address mapping is needed.
/**
* @note if assertion fails in any TASK, the system will be halted;
* if it fails in a USER PROC, it'll return like any normal syscall does.
*/
sys_printx ()将首先判断首字符是否为预先设定的 “Magic Char”,如果是的话,则做响应的特殊处理。我们的assertion_failure( )就使用了MAG_CH_ASSERT作为 “Magic Char”。当sys_printx ()发现传入字符串的第一个字符是MAG_CH_ASSERT时,会同时判断调用系统调用的进程是系统进程 (TASK)还是用户进程 (USER PROC),如果是系统进程,则停止整个系统的运转,并将要打印的字符串打印在显存的各处;如果是用户进程,则打印之后像一个普通的printx调用一样返回,届时该用户进程会因为assertion_failure( )中对函数spin ( )的调用而进入死循环。换言之,系统进程的assert失败会导致系统停转, 用户进程的失败仅仅使自己停转。