Литмир - Электронная Библиотека

Первый зафиксированный факт переоблучения, случившийся в Онкологическом Центре в Marietta (штат Джорджия) в июне 1985 г., просто отрицался и не был должным образом исследован: производитель с цифрами оценки рисков в руках утверждал, что на данной системе это просто невозможно. По странному совпадению, проведенный сеанс облучения не был документирован, так как почему-то вышел из строя принтер; в результате поданный родственниками пациента иск не получил хода ввиду отсутствия документальных доказательств, хотя доза облучения по оценкам была превышена в 100 раз.

Следующий инцидент, случившийся в июле того же года в Онкологическом Центре Онтарио как раз был задокументирован хорошо, но производитель не смог воспроизвести ситуацию, и ее отнесли на счет случайного сбоя аппаратуры; в ПО сомнений по-прежнему просто не было. И трагические инциденты продолжились.

Очередной из них произошел в Онкологическом Центре Восточного Техаса в марте 1986 г. В данном случае процессом управляла опытный оператор, проведшая уже более 500 подобных сеансов. Она быстро ввела предписанные параметры, после чего заметила, что вместо режима облучения электронными лучами заказала лучи рентгеновские (которыми пользовали большинство пациентов). Коррекция требовала исправления всего одной буквы; нажав кнопку, она вошла в режим редактирования, скорректировала в нужном месте «x» на «e», затем несколькими нажатиями клавиши «Return» (благо, все остальные параметры были введены правильно) достигла нижней (командной) строки экрана, убедилась, что против каждого введенного параметра горит «VERIFIED», а статус системы ожидаемый («BEAM READY»), и выдала команду начать процесс облучения. Однако, неожиданно система встала, на консоли высветилось сообщение «MALFUNCTION 54», а статус системы изменился на «TREATMENT PAUSE», что свидетельствовало о проблеме невысокой степени серьезности. Висевшая тут же бумага с кодами ошибок «исчерпывающе» поясняла, что «MALFUNCTION 54» означает «dose input 2». Забегая вперед, укажем, что много позже, во внутренней документации производителя было обнаружено, что это сообщение выдавалось в случае «ненадлежащей дозы облучения» причем, как для слишком большой, так и для слишком малой, что само по себе странно (да и просто недопустимо ведь ситуации принципиально разные).

Озадаченная операторша взглянула на высветившееся количество отпущенной дозы и увидела, что оно пренебрежимо мало. Поэтому она без долгих раздумий выдала команду на продолжение процесса, после чего вся описанная выше ситуация повторилась.

Тем временем пациент, который возлежал на столе в изолированном от оператора помещении, испытал некое подобие электрического шока. Он тоже был опытным (для него это был девятый сеанс), поэтому понял, что творится что-то неладное. Однако, дать сразу же знать об этом оператору через специально для того предназначенные видео и аудио средства он не смог: как выяснилось, видео было по непонятным причинам отключено, а аудиоканал просто неисправен.

После повторного шокового удара пациент вскочил и нимало шокировал уже операторшу, начав ломиться в стеклянные двери ее помещения. Поначалу его и лечили от электрошока (он умер через пять месяцев). Позднейшее моделирование ситуации показало, что пациент получил менее чем за 1 сек. на участок позвоночника в 1 кв. см. дозу в диапазоне от 16500 до 25000 рад (в то время, как ему было предписано принять в этом сеансе 180 рад, а всего 6000 рад за шесть с половиной недель).

Прибывший из AECL инженер, несмотря на все усилия, оказался не в состоянии воспроизвести ситуацию, хотя заверил, что переоблучение в принципе невозможно. Были успешно прогнаны все тесты, система снова вступила в эксплуатацию, и через три недели инцидент повторился во всех деталях с тем же трагическим результатом. Только после этого установка была выведена из эксплуатации, и началось углубленное расследование, шедшее, кстати, очень трудно. Опуская множество деталей, приведем его итоги, интересные с программистской точки зрения.

Особенности ПО как предпосылки для инцидентов

В комплексе не использовалась какая-либо стандартная операционная система: была разработана специальная мультизадачная ОС реального времени, для компьютера PDP-11/23 с 32Kбайт и написанная на языке ассемблера. Специальный планировщик координировал деятельность всех одновременно исполняющихся процессов. Задачи, запускавшиеся каждые 0.1 сек., разделялись на «критические», исполнявшиеся первыми, и «некритические». К критическим отнесены три приоритетных задачи (рис. 1):

* «Servo», ответственная за все операции, связанные с эмиссией радиационных пучков и доставкой их к месту назначения;

* «Housekeeper», выполнявшая верификацию всех параметров и ответственная за блокировку работы в случае возникновения нештатной ситуации, а также за сообщения о таких ситуациях;

* «Treat», управлявшая самим процессом лечения, который был разделен на 8 операционных фаз. В зависимости от значения переменной Tphase вызывалась одна из восьми подпрограмм, по окончании работы которой Treat в зависимости от значений нескольких разделяемых с другими критическими и некритическими задачами переменных, вырабатывала план на новый цикл.

Мифы о безопасном ПО: уроки знаменитых катастроф - _21_1.png
Рис. 1. Взаимодействие задач и подпрограмм в ПО для Therac-25.

Одна из вызываемых Treat подпрограмм Datent (Data entry) через разделяемую «флаговую» переменную Data_entry_complete взаимодействует с «некритической» задачей Keyboard Handler, которая управляет вводом информации с клавиатуры, исполняясь параллельно с Treat. Keyboard Handler распознает момент окончания ввода и сигнализирует об этом, изменяя значение Data_entry_complete. В свою очередь, Datent проверяет значение этой переменной. Если оно не изменилось, то значение Tphase остается равным «1», и на следующем цикле Treat опять запустит Datent; если же значение Data_entry_complete изменилось, то Datent меняет значение Tphase с «1» на «3»; в результате после окончания работы Datent монитор Treat вызовет подпрограмму Set Up Test, выполняющую проверку считающихся уже установленными параметров.

Необходимо упомянуть еще одну переменную MEOS (Mode/Energy Offset), разделяемую между Datent, Keyboard Handler и еще одной некритической задачей Hand. Старшие байты MEOS используются подпрограммой Datent для установки одного из двух режимов облучения и величины энергии испускаемого потока, в то время как младшие используются параллельно работающей задачей Hand для установки коллиматора в положение, соответствующее выбранному режиму и энергии.

Оператор мог после ввода параметров режима и энергии редактировать эти величины по отдельности. Однако, здесь присутствовал тонкий момент разработчики установили: об окончании процесса ввода (и редактирования!) параметров свидетельствует то, что все параметры заданы и курсор находится в командной строке, на предмет чего каждые 8 сек. (величина выбрана, исходя из некоторых технических соображений, связанных с инерционностью приборов) производится опрос переменной Data_entry_complete. Если в пределах этих 8 сек. курсор покидает командную строку и после быстрого редактирования параметров успевает вернуться на нее, то Keyboard Handler этого события просто не заметит, и соответственно, никак переменную Data_entry_ complete не изменит.

Иными словами, потенциально существует возможность для следующей последовательности действий:

* Keyboard Handler отследил местонахождение курсора на командной строке и установил флаг Data_entry_complete;

* затем оператор изменил данные в MEOS;

* не заметив этого (если к моменту опроса курсор оказался вновь на командной строке), Keyboard Handler не переустанавливает флаг Data_entry_complete;

* тогда Datent уже не способна обнаружить изменение MEOS она свою работу закончивает, установив Tphase=3 (а не Tphase=1, чтобы отработать еще один цикл и учесть изменения);

* тем временем, параллельно работающая Hand устанавливает коллиматор в положение, соответствующее младшим байтам MEOS (их установила ранее Datent), которые могли находиться в противоречии со старшими байтами этой разделяемой переменной (как раз и подвергшимся редактированию!).

4
{"b":"115212","o":1}