| 俊's profile俊俊的共享空间PhotosBlogLists | Help |
俊俊的共享空间
October 01 美国之行收获颇多西雅图,好城市啊
marriott hotel
costco
target
fred meyer
old navy
sears
ross
maple ...
REI
macy's
red robin
March 09 理解特殊的中断-异常2.异常异常是80386在执行指令期间检测到不正常的或非法的条件所引起的。异常与正执行的指令有直接的联系。例如,执行除法指令时,除数等于0。再如,执行指令时发现特权级不正确。当发生这些情况时,指令就不能成功完成。软中断指令“INT n”和“INTO”也归类于异常而不称为中断,这是因为执行这些指令产生异常事件。
80386识别多种不同类别的异常,并赋予每一种类别以不同的中断向量号。异常发生后,处理器就象响应中断那样处理异常。即根据中断向量号,转相应的中断处理程序。把这种中断处理程序称为异常处理程序可能更合适。
根据引起异常的程序是否可被恢复和恢复点不同,把异常进一步分类为故障(Fault)、陷阱(Trap)和中止(Abort)。我们把对应的异常处理程序分别称为故障处理程序、陷阱处理程序和中止处理程序。
故障是在引起异常的指令之前,把异常情况通知给系统的一种异常。80386认为故障是可排除的。当控制转移到故障处理程序时,所保存的断点CS及EIP的值指向引起故障的指令。这样,在故障处理程序把故障排除后,执行IRET返回到引起故障的程序继续执行时,刚才引起故障的指令可重新得到执行。这种重新执行,不需要操作系统软件的额外参与。故障的发现可能在指令开始执行之前,也可能在指令执行期间。如果在指令执行期间检测到故障,那么中止故障指令,并把指令的操作数恢复为指令开始执行之前的值。这可保证故障指令的重新执行得到正确的结果。例如,在一条指令的执行期间,如果发现段不存在,那么停止该指令的执行,并通知系统产生段故障,对应的段故障处理程序可通过加载该段的方法来排除故障,之后,原指令就可成功执行,至少不再发生段不存在的故障。
陷阱是在引起异常的指令之后,把异常情况通知给系统的一种异常。当控制转移到异常处理程序时,所保存的断点CS及EIP的值指向引起陷阱的指令的下一条要执行的指令。下一条要执行的指令,不一定就是下一条指令。因此,陷阱处理程序并不是总能根据保存的断点,反推确定出产生异常的指令。在转入陷阱处理程序时,引起陷阱的指令应正常完成,它有可能改变了寄存器或存储单元。软中断指令、单步异常是陷阱的例子。
中止是在系统出现严重情况时,通知系统的一种异常。引起中止的指令是无法确定的。产生中止时,正执行的程序不能被恢复执行。系统接收中止后,处理程序要重新建立各种系统表格,并可能重新启动操作系统。硬件故障和系统表中出现非法值或不一致的值是中止的例子。 理解中断1.中断对80386而言,中断是由异步的外部事件引起的。外部事件及中断响应与正执行的指令没有关系。通常,中断用于指示I/O设备的一次操作已完成。与8086/8088一样,80386有两根引脚INTR和NMI接受外部中断请求信号。INTR接受可屏蔽中断请求。NMI接受不可屏蔽中断请求。在80386中,标志寄存器EFLAGS中的IF标志决定是否屏蔽可屏蔽中断请求。
外部硬件在通过INTR发出中断请求信号的同时,还要向处理器给出一个8位的中断向量。处理器在响应可屏蔽中断请求时,读取这个由外部硬件给出的中断向量号。处理器对这个中断向量号并没有规定。但在具体的微机系统中,系统必须通过软件和硬件的配合设置,使得给出的这个中断向量号不仅与外部中断源对应,而且要避免中断向量号使用冲突情况的出现。可编程中断控制器芯片8259A可配合80386工作,能够根据设置向处理器提供上述中断向量号,还能处理中断请求的优先级。每个8259A芯片可以支持8路中断请求信号,如果使用9个8259A芯片(一个主片,8个从片),就可使80386在单个引脚INTR上接受多达64个中断源的中断请求信号。
处理器不屏蔽来自NMI的中断请求。处理器在响应NMI中断时,不从外部硬件接收中断向量号。与8086/8088一样,在80386中,不可屏蔽中断所对应的中断向量号固定为2。为了不可屏蔽中断的嵌套,每当接受一个NMI中断,处理器就在内部屏蔽了再次响应NMI,这一屏蔽过程直到执行中断返回指令IRET后才结束。所以,NMI处理程序应以IRET指令结束。 C++ VS JavaC++: 强大功能:模板(GP),继承(OO),封装(OO),异常(除错) 编译的静态性:编译器是根据数据静态类型来处理的 四个步骤:预编译,编译,连接,运行 冯诺伊曼原理要素:代码,数据,堆栈 无非是编译器做了很多幕后工作的C而已,会自动安插代码进去 (等位转型,非等位转型) 1非等位转型会在运行时有所体现,等位转型与运行时的过程无关 2强类型匹配后才能通过编译是为了保护程序员正确编写代码,等位转型操作则是破坏了这种保护机制,但是增加了灵活性,可以欺骗编译器做特殊处理,往往底层的、核心的程序相对来说这种做法比较多,不过需要很多严格区分预编译,编译,连接,和运行时的知识
从编译器的角度理解几个为什么: 1为什么模板类,模板函数全部在h文件里面定义? 2为什么内联函数的定义在h文件里面? 3为什么静态成员的初始化在cpp文件里面?
Win32 API: 记忆性(Windows系统的窗口类结构,窗口结构就是一个佐证) 绝对功能性(无可厚非) OS密切相关性(操纵OS的另一种接口而已) 资源有限性(get-release,create-delete) 冯老原理要素:数据,硬件关联的数据的输入输出(所有的OS均如此) 说明:要记住UI窗口与Windows的USER模块之间的密切关系
Application Framework: MFC:(C++封装Windows API,借用COM API,也可以开发COM组件) ATL:(模板、多继承,C++封装Windows API,借用COM API,适合开发COM组件) 微软的开发人员特别喜欢使用宏,宏虽然容易产生很多问题但是使用的恰当还是很好的 静态结构的初始化依赖于C运行时函数main函数,并且顺序很重要
March 03 new的处理方式(粗糙)new_handler X::currentHandler; // 缺省设置currentHandler 为0(即null)
类X 中的set_new_handler 函数会保存传给它的任何指针,并返回在调用 它之前所保存的任何指针。这正是标准版本的set_new_handler 所做的:
new_handler X::set_new_handler(new_handler p) { new_handler oldHandler = currentHandler; currentHandler = p; return oldHandler; }
全局跟类中一样的方式,类静态数据成员变成全局成员而已。
非类成员形式的operator new 的伪代码看起来会象下面这样: void * operator new(size_t size) // operator new 还可能有其它参数 { if (size == 0) { // 处理0 字节请求时, size = 1; // 把它当作1 个字节请求来处理 } while (1) { 分配size 字节内存; if (分配成功) return (指向内存的指针); // 分配不成功,找出当前出错处理函数 new_handler globalHandler = set_new_handler(0); set_new_handler(globalHandler); if (globalHandler) (*globalHandler)(); else throw std::bad_alloc(); } }
成员形式的operator new 的伪代码看起来会象下面这样: void * X::operator new(size_t size) { new_handler globalHandler = // 安装X 的new_handler std::set_new_handler(currentHandler); void *memory; try { // 尝试分配内存 memory = ::operator new(size); } catch (std::bad_alloc&) { // 恢复旧的new_handler std::set_new_handler(globalHandler); throw; // 抛出异常 } std::set_new_handler(globalHandler); // 恢复旧的new_handler return memory; } |
|
||||
|
|