Розділ 18. Винятки#
Виняток уособлює собою різновид виняткової ситуації; поява такої
ситуації (під час виконання програми) уособлюється випадком винятку
(Exception Occurrence). Коли при виконанні певної конструкції виникає
виняток, решта виконання цієї конструкції припиняється і виконується
відповідний обробник винятків. Якщо конструкція не має обробника
винятків, то виняток поширюється. Поширення винятку означає
його повторне виникнення у найближчому динамічному охоплюючому
контексті виконання [AAR95, розділ 11-4]. Якщо виняток не
оброблено у тілі задачі, він не поширюється далі (оскільки немає
динамічно охоплюючого контексту виконання). Якщо виняток стався під час
активації задачі, то активатор створить виняток Tasking_Error
[AAR95,
розділ 11-4]. Існує наперед визначена бібліотека, яка надає
додаткові можливості для винятків (Ada.Exceptions
).
Структури даних#
Ідентифікатор винятку#
Кожен окремий виняток представляється окремим значенням типу
Exception_Id
. Спеціальне значення Null_Id
не представляє жодного
винятку і є початковим значенням типу Exception_Id
за
замовчуванням. Кожен випадок винятку представляється значенням типу
Exception_Occurrence
. Аналогічно, Null_Occurrence
не представляє
жодного випадку винятку і є початковим значенням типу Exception_Occurrence
за замовчуванням.
У середовищі виконання GNAT ідентифікатор винятку реалізовано як
доступ до запису (Exception_Data_Ptr
). На рисунку 18.1 показано поля
цього запису. Поле Not_Handled_By_Others
використовується для того,
щоб відрізнити визначені користувачем винятки від внутрішніх винятків
часу виконання (наприклад, переривання задачи), які не можуть бути
оброблені обробниками користува. Поле Lang
визначає мову, на якій оголошено виняток (за замовчуванням
«Ada»). Наступні два поля використовуються для зберігання повної
назви винятку. Це ім’я складається з префікса (повний шлях до
області видимості, де оголошено винятка) та імені винятка.
Останнє поле використовується для створення зв’язаних списків
ідентифікаторів винятків (описано у розділі 18.1.2).
Рисунок 18.1: Запис ідентифікатора винятку
Коли виникає виняток, відповідний випадок винятку зберігається під час
виконання GNAT у полі Compiler_Data
(Дані компілятора) у ATCB. Тип
даних цього поля - запис; поле Current_Exception
цього запису
зберігає випаток винятку.
Рисунок 18.2: Ідентифікатор події.
Поле Exception_Raised
має значення True
, щоб вказати, що виняток
дійсно було викинуто. Коли виняток викидається вперше, це поле має
значення False
; потім, коли він пізніше обробляється підпрограмою
GNARL Raise_Current_Exception
, це поле має значення True
. Це
дозволяє програмі розрізняти, чи має вона справу з повторним
викидом винятку.
Таблиця винятків#
Через правила видимості винятків у мові Ada (виняток може бути невидимим, хоча обробляється others обробником, повторно викидається, а потім знову стає видимим для іншої області видимості) необхідно використовувати глобальну таблицю винятків (Exceptions Table). Для ефективної обробки винятків у середовищі виконання Ada використовується хеш-таблиця (див. рисунок 18.3).
Рисунок 18.3: Хеш-таблиця.
Як читач може бачити, використовується таблиця доступу до
ідентифікаторів винятків. Для обробки колізій використовується простий
зв’язаний список ідентифікаторів винятків. Поле HTable_Ptr
використовується для зв’язування ідентифікаторів винятків.
Коли в задачі виникає виняток, необхідно знайти відповідний ідентифікатор винятку. Тому обчислюється хеш-функція, і отриманий в результаті зв’язаний список обходить для пошуку ідентифікатора винятку. Потім його посилання зберігається в ATCB задачі. Це посилання зберігається в ATCB до тих пір, поки виняток не буде оброблено (хоча виняток може бути невидимим у деяких обробниках винятків).
Підпрограми часу виконання#
GNARL.Raise#
Мова Ada дозволяє викинути виняток двома різними способами: (1)
за допомогою оператора raise і (2) за допомогою процедури
Ada.Exceptions.Raise_Exception
, яка дозволяє програмісту зв’язати
повідомлення з винятком. В обох випадках компілятор генерує виклик
функції GNARL, яка виконує наступні дії:
Заповнити виняток ATCB.
Відкласти припинення (abortion).
Якщо встановлено обробник винятків, перейдіть до нього.
В іншому випадку (коли нема обробника винятків) завершити виконання програми.
Підсумок#
У цій главі представлено основні концепції реалізації обробки винятків у GNAT. Ідентифікатор винятку - це доступ до запису, де зберігається повна назва винятку. Виникнення винятку зберігається у ATCB. Всі винятки зберігаються у хеш-таблиці.