ВПнМ, примеры задач/Задача 3
Материал из ESyr's Wiki.
Содержание |
[править] Задача
Дано:
- исходный текст функции
- свойства корректности
Требуется построить корректную модель функции, адекватную заданному свойству корректности. Требуется построить модель с двумя процессами: ядром, отвечающим на эти системные вызовы; функцией, работающей в цикле. Системные вызовы и ответ на них моделируются посылкой сообщения ядру и приёмом сообщения от ядра соответственно.
Результат:
- текст модели на языке Promela
- скриншот диаграммы состояний, полученной в результате моделирования (первые 40 шагов)
- вывод моделирования (первые 40 шагов)
[править] Вариант 1
[править] Исходный текст функции
PRIVATE int DspVersion[2];
PRIVATE int dsp_init()
{
int i, s;
if(dsp_reset () != OK) {
dprint("sb16: No SoundBlaster card detected\n");
return -1;
}
DspVersion[0] = DspVersion[1] = 0;
dsp_command(DSP_GET_VERSION); /* Get DSP version bytes */
for(i = 1000; i; i--) {
if(sb16_inb(DSP_DATA_AVL) & 0x80) {
if(DspVersion[0] == 0) {
DspVersion[0] = sb16_inb(DSP_READ);
} else {
DspVersion[1] = sb16_inb(DSP_READ);
break;
}
}
}
if(DspVersion[0] < 4) {
dprint("sb16: No SoundBlaster 16 compatible card detected\n");
return -1;
}
dprint("sb16: SoundBlaster DSP version %d.%d detected\n", DspVersion[0], DspVersion[1]);
/* set SB to use our IRQ and DMA channels */
mixer_set(MIXER_SET_IRQ, (1 << (SB_IRQ / 2 - 1)));
mixer_set(MIXER_SET_DMA, (1 << SB_DMA_8 | 1 << SB_DMA_16));
/* register interrupt vector and enable irq */
if ((s=sys_irqsetpolicy(SB_IRQ, IRQ_REENABLE, &irq_hook_id )) != OK)
panic("SB16DSP", "Couldn't set IRQ policy", s);
if ((s=sys_irqenable(&irq_hook_id)) != OK)
panic("SB16DSP", "Couldn't enable IRQ", s);
DspAvail = 1;
return OK;
}
[править] Свойства корректности
Модель должна быть адекватной для проверки спецификации: всегда при вызове sys_irqenable верно DspVersion[0] < 4
[править] Решение
[править] Модель
#define OK 0
#define NOT_OK 1
#define SYS_IRQPOLICY 1
#define SYS_IRQENABLE 2
int DspVersion[2];
chan to_kernel_channel = [0] of {byte};
chan from_kernel_channel = [0] of {byte};
active proctype kernel()
{
int msg;
do
:: to_kernel_channel?msg ->
{
if
:: (msg == SYS_IRQPOLICY) ->
{
if
:: from_kernel_channel!OK;
:: from_kernel_channel!NOT_OK;
fi;
}
:: (msg == SYS_IRQENABLE) ->
{
if
:: from_kernel_channel!OK;
:: from_kernel_channel!NOT_OK;
fi;
}
:: (msg == SYS_END) -> break;
:: else -> skip;
fi;
}
od;
}
active proctype dsp_init()
{
do
::
byte result;
DspVersion[0] = 0;
DspVersion[1] = 0;
if
:: DspVersion[0] = 0;
:: DspVersion[0] = 1;
:: DspVersion[0] = 5;
fi;
if
:: DspVersion[1] = 0;
:: DspVersion[1] = 1;
fi;
if :: (DspVersion[0] < 4) ->
{
goto return;
}
:: else -> skip;
fi;
/* sys_irqsetpolicy(SB_IRQ, IRQ_REENABLE, &irq_hook_id); */
to_kernel_channel!SYS_IRQPOLICY;
from_kernel_channel?result;
if
:: (result != OK) ->
{
goto return;
}
:: else -> skip;
fi;
/* sys_irqenable(&irq_hook_id) */
to_kernel_channel!SYS_IRQENABLE;
from_kernel_channel?result;
if :: (result != OK) ->
{
goto return;
}
:: else -> skip;
fi;
return:
skip;
od;
}
[править] Вывод симулирования
% spin -p -u40 model.pml
spin: line 34 "model.pml", Error: undeclared variable: SYS_END saw '')' = '41''
Starting kernel with pid 0
0: proc - (:root:) creates proc 0 (kernel)
Starting dsp_init with pid 1
0: proc - (:root:) creates proc 1 (dsp_init)
1: proc 1 (dsp_init) line 43 "model.pml" (state 38) [DspVersion[0] = 0]
2: proc 1 (dsp_init) line 48 "model.pml" (state 2) [DspVersion[1] = 0]
3: proc 1 (dsp_init) line 50 "model.pml" (state 6) [DspVersion[0] = 0]
4: proc 1 (dsp_init) line 56 "model.pml" (state 7) [.(goto)]
5: proc 1 (dsp_init) line 56 "model.pml" (state 10) [DspVersion[1] = 0]
6: proc 1 (dsp_init) line 61 "model.pml" (state 11) [.(goto)]
7: proc 1 (dsp_init) line 61 "model.pml" (state 17) [((DspVersion[0]<4))]
8: proc 1 (dsp_init) line 64 "model.pml" (state 14) [goto return]
9: proc 1 (dsp_init) line 92 "model.pml" (state 37) [(1)]
10: proc 1 (dsp_init) line 94 "model.pml" (state 39) [.(goto)]
11: proc 1 (dsp_init) line 43 "model.pml" (state 38) [DspVersion[0] = 0]
12: proc 1 (dsp_init) line 48 "model.pml" (state 2) [DspVersion[1] = 0]
13: proc 1 (dsp_init) line 50 "model.pml" (state 6) [DspVersion[0] = 1]
14: proc 1 (dsp_init) line 56 "model.pml" (state 7) [.(goto)]
15: proc 1 (dsp_init) line 56 "model.pml" (state 10) [DspVersion[1] = 0]
16: proc 1 (dsp_init) line 61 "model.pml" (state 11) [.(goto)]
17: proc 1 (dsp_init) line 61 "model.pml" (state 17) [((DspVersion[0]<4))]
18: proc 1 (dsp_init) line 64 "model.pml" (state 14) [goto return]
19: proc 1 (dsp_init) line 92 "model.pml" (state 37) [(1)]
20: proc 1 (dsp_init) line 94 "model.pml" (state 39) [.(goto)]
21: proc 1 (dsp_init) line 43 "model.pml" (state 38) [DspVersion[0] = 0]
22: proc 1 (dsp_init) line 48 "model.pml" (state 2) [DspVersion[1] = 0]
23: proc 1 (dsp_init) line 50 "model.pml" (state 6) [DspVersion[0] = 1]
24: proc 1 (dsp_init) line 56 "model.pml" (state 7) [.(goto)]
25: proc 1 (dsp_init) line 56 "model.pml" (state 10) [DspVersion[1] = 0]
26: proc 1 (dsp_init) line 61 "model.pml" (state 11) [.(goto)]
27: proc 1 (dsp_init) line 61 "model.pml" (state 17) [((DspVersion[0]<4))]
28: proc 1 (dsp_init) line 64 "model.pml" (state 14) [goto return]
29: proc 1 (dsp_init) line 92 "model.pml" (state 37) [(1)]
30: proc 1 (dsp_init) line 94 "model.pml" (state 39) [.(goto)]
31: proc 1 (dsp_init) line 43 "model.pml" (state 38) [DspVersion[0] = 0]
32: proc 1 (dsp_init) line 48 "model.pml" (state 2) [DspVersion[1] = 0]
33: proc 1 (dsp_init) line 50 "model.pml" (state 6) [DspVersion[0] = 5]
34: proc 1 (dsp_init) line 56 "model.pml" (state 7) [.(goto)]
35: proc 1 (dsp_init) line 56 "model.pml" (state 10) [DspVersion[1] = 1]
36: proc 1 (dsp_init) line 61 "model.pml" (state 11) [.(goto)]
37: proc 1 (dsp_init) line 61 "model.pml" (state 17) [else]
38: proc 1 (dsp_init) line 65 "model.pml" (state 16) [(1)]
39: proc 1 (dsp_init) line 69 "model.pml" (state 18) [.(goto)]
40: proc 1 (dsp_init) line 69 "model.pml" (state 19) [to_kernel_channel!1]
40: proc 0 (kernel) line 17 "model.pml" (state 1) [to_kernel_channel?msg]
-------------
depth-limit (-u40 steps) reached
#processes: 2
DspVersion[0] = 5
DspVersion[1] = 1
40: proc 1 (dsp_init) line 70 "model.pml" (state 20)
40: proc 0 (kernel) line 19 "model.pml" (state 18)
2 processes created
[править] Пояснения
[править] Абстрагирование
В модели необходимо абстрагироваться ото всего, что не влияет на спецификацию. При этом надо учитывать, что, на первый взгляд посторонние переменные могут значимо влиять на поток управления и при их абстрагировании корректность и адекватность модели могут нарушаться.
[править] Недетерминизм
Если необходимо проверить все возможные варианты, индуцированные различными значениями переменных, надо выделить различимые множества значений этих переменных, выбрать по одному значению из каждого множества (допустим в результате выбрали числа i1, i2, i3) и записать нечто следующее:
if :: var = i1; :: var = i2; :: var = i3; fi;
Что означает случайный выбор одного из перечисленных значений. При верификации будут проверены все возможные варианты, при симуляции выбирается (случайно, интерактивно или в соответствии с трассой) один из них.
[править] Имитирование системных вызовов
Допустим, у нас есть два процесса, ядро и некое приложение. Приложение по ходу работы осуществляет вызовы к ядру, ядро возвращает результат. Фактически, это можно представит, как взаимодействие двух процессов путём использования двух каналов --- по которому передаются данные от приложения к ядру и обратно. Существует несколько вариантов реализации подобного поведения.
[править] Полезная строка на шелле для обрезания вывода spin
При помощи следующей нехитрой строчки можно ограничить вывод spin десятью пересылками:
MKTEMP=`mktemp`;\
sed -n 0,/^$(echo $(spin -p task3.pml | tee ${MKTEMP} | grep 'from?' | \
head -n 10\
| tail -n 1 | cut -d: -f 1) + 1 | bc)\:/p ${MKTEMP} | head -n -1 > log.txt; rm ${MKTEMP}
У выделенного head ключом -n <количество> можно задать другое количество строк для обрезания.



