Исключения
Многие процессоры используют механизм, родственный прерываниям, для обработки не только внешних, но и внутренних событий: мы с вами уже сталкивались с исключительными ситуациями (exception) отсутствия страницы и ошибки доступа в процессорах с виртуальной памятью, а также некоторыми другими – ошибкой шины при доступе к невыровненным словам, заполнению и очистке регистрового окна у SPARC и т. д.
Большинство современных процессоров предоставляют исключения при неизвестном коде операции, делении на ноль, арифметическом переполнении или, например, выходе значения операнда за допустимый диапазон в таких операциях, как вычисление логарифма, квадратного корня или арксинуса.
Исключительные ситуации обрабатываются аналогично внешним прерываниям: исполнение программы останавливается, и управление передается на процедуру-обработчик, адрес которой определяется природой исключения.
Отличие состоит в том, что прерывания обрабатываются после завершения текущей команды, а возврат из обработчика приводит к исполнению команды, следующей за прерванной. Исключение же приводит к прекращению исполнения текущей команды (если в процессе исполнения команды мы уже успели создать какие-то побочные эффекты, они отменяются), и сохраненный счетчик команд указывает на прерванную инструкцию. Возврат из обработчика, таким образом, приводит к попытке повторного исполнения операции, вызвавшей исключение.
Благодаря этому, например, обработчик страничного отказа может подкачать с диска содержимое страницы, вызвавшей отказ, перенастроить таблицу дескрипторов и повторно исполнить операцию, которая породила отказ. Обработчик исключения по неопределенному коду операции может использоваться для эмуляции расширений системы команд.
Например, при наличии арифметического сопроцессора операции с плавающей точкой исполняются им, а при отсутствии – пакетом эмулирующих подпрограмм. Благодаря этому может обеспечиваться полная бинарная совместимость между старшими (имеющими сопроцессор) и младшими (не имеющими его) моделями одного семейства компьютеров.
Исключения, возникающие при исполнении привилегированных команд в пользовательском режиме, могут использоваться системой виртуальных машин. Работающее в виртуальной машине ядро ОС считает, что исполняется в системном режиме. На самом же деле оно работает в пользовательском режиме, а привилегированные команды (переключения режима процессора, настройка диспетчера памяти, команды ввода/вывода) приводят к вызову СВМ.
При грамотной реализации обработчиков таких исключений их обработка произойдет полностью прозрачно для породившей эти исключения программы. Конечно, "подкачка" страницы с диска или программная эмуляция плавающего умножения займет гораздо больше времени, чем простое обращение к памяти или аппаратно реализованное умножение, но, наверное, потребитель вычислительной системы знал, что делал, когда устанавливал недостаточное количество памяти или приобретал машину без сопроцессора.
— Регулярная проверка качества ссылок по более чем 100 показателям и ежедневный пересчет показателей качества проекта.
— Все известные форматы ссылок: арендные ссылки, вечные ссылки, публикации (упоминания, мнения, отзывы, статьи, пресс-релизы).
— SeoHammer покажет, где рост или падение, а также запросы, на которые нужно обратить внимание.
SeoHammer еще предоставляет технологию Буст, она ускоряет продвижение в десятки раз, а первые результаты появляются уже в течение первых 7 дней. Зарегистрироваться и Начать продвижение
Многие другие исключения, такие, как деление на ноль, обычно бессмЬ1с ленно обрабатывать повторной попыткой деления на какое-то другое число В этом случае целесообразно возвратить управление не на команду, вызвавшую исключение, а в какую-то другую точку. Вопрос, впрочем, в том, куда именно следует возвращаться. Понятно, что код, который может восстановиться в случае деления на ноль, сильно зависит от контекста, в котором произошла ошибка (пример 6.2).
Пример 6.2. Обработка исключения Floating underflow (антипереполнение при операциях с плавающей точкой)
#tinclude <setjmp.h> static jmp_buf fpe_retry; void fpe_handler (int sig) { 4> __fpreset (); longjmp (fpe__retry, -1); int compare_pgms (Image * imgO, Image * img1) { int xsize=256, ysize=256; int i, j, pO, pi, pd; double avg, avgsq, scale, smooth; scale= (double) xsize* (double) ysize; avg = 0.0; avgsq = 0.0; /* Подавить возможные антипереполнения */ signal (SIGFPE, fpe_handler); for(i=0; i<ysize; i smooth = (double) (imgO › picture [i*xsize] -imgl › picture [i*xsize]); for(j=0; j<xsize; j++) { pO=imgO › picture [ j+i*xsize]; pl=imgl › picture [ j+i*xsize]; pd=(p0-p1); if (setjmp (fpe_retry) == 0) { smooth = smooth* (1. 0-SMOOTH_FACTOR) + (double) pd*SMOOTH_FACTOR; vq += smooth; avgsq += smooth*smooth; eise smooth=0. 0; if (Setjmp(fpe_retry) == 0) Aspersion = avgsq/scale-avg*avg/ (scale*scale); else dispersion = 0.0; signal (SIGFPE, SIGJDFL); }