Исключения
ОС предоставляет сервис, позволяющий программисту регистрировать обработчики для тех или иных событий, как соответствующих аппаратным исключениям, так и порождаемых самой операционной системой, но вызов таких обработчиков всегда осуществляется в два этапа: сначала исполняется обработчик, зарегистрированный ядром (пример 6.4), а он, если сочтет нужным и возможным, переключается в пользовательский контекст и вызывает обработчик, зарегистрированный пользователем. Среда исполнения ЯВУ, в свою очередь, может реализовать и свои обработчики между сервисом операционной системы и средствами, доступными программисту.
Пример 6.4. Обработчик арифметических исключений в ядре Linux.
/* * Iinux/arch/i386/traps.c * * Copyright (С) 1991, 1992 Linus Torvalds * * Поддержка Pentium III FXSR, SSE * Gareth Hughes <gareth@valinux.com>, May 2000 */ void die(const char * str, struct pt_regs * regs, long err) I console_verbose(); spin_lock_irq(&die_lock); Printk("%s: %041x\n", str, err & Oxffff}; show_registers(regs); sPin_unlock_irq(&die_lock); do_exit (SIGSEGV); static inline void die_if_kernel (const char * str, struct pt_regs * regs long err) { if (! (regs › eflags & VM_MASK) &&! (3 & regs › xcs)) die (str, regs, err); static inline unsigned long get_cr2 (void) { unsigned long address; /* получить адрес */ _ asm _ ("movl %%cr2, %0": "=r" (address)); return address; static void inline do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs * regs, long error_code, siginfo_t *info) { if (vm86 && regs › eflags & VM_MASK) goto vm86_trap; if (! (regs › xcs & 3)) goto kernel_trap; trap_signal: { struct task_struct *tsk = current; tsk › thread .error_code = error_code; tsk › thread .trap_no = trapnr; if (info) force_sig_info (signr, info, tsk); else force_sig (signr, tsk); return; kernel_trap: unsigned long fixup = search_exception_table(regs › eip); if (fixup) regs › eip = fixup; else die(str, regs, error_code); return; vm86_trap: { int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, er-ror_code, trapnr); if (ret) goto trap_signal; return; fldefine DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_tt#name(struct pt_regs * regs, long error_code) \ { \ do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ Idefine DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ asmlinkage void do_t#name(struct pt_regs * regs, long error_code) \ { \ siginfo_t info; \ info.si_signo = signr; \ info.si_errno =0; \ info.si_code = sicode; \ info.si_addr = (void *)siaddr; \ do^trap(trapnr, signr, str, 0, regs, error_code, Sinfo); \ } ttdefine DO_VM86_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ (\ do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ } ttdefine DO_VM86__ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ I asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ siginfo_t info; \ info.si_signo = signr; \ info.si_errno =0; \ info.si_code = sicode; \ info.si_addr = (void *)siaddr; \ do_trap(trapnr, signr, str, 1, regs, error_code, sinfo); \ …… DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs › eip) DO_VM86_ERROR(3, SIGTRAP, "int3", int3) DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow) DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO(6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs › eip) DO_VM86_ERROR(7, SIGSEGV, "device not available", device_not_available) DO_ERROR(8, SIGSEGV, "double fault", double_fault) DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coproces-sor_segment_overrun) DO_ERROR(10, SIGSEGV, "invalid TSS", invalidJTSSl DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) DO_ERROR(12, SIGBUS, "stack segment", stack_segment) DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2 ())