Inferno OS Wiki
Advertisement

НАЗВАНИЕ[]

plumbmsg - сигнальный модуль протокола plumber

ВВОД

include "plumbmsg.m";
plumbmsg := load Plumbmsg Plumbmsg->PATH;
#импортируются данные и функции из сигнального модуля, так что они могут применяться внутри этого кода под своими именами
Msg: import plumbmsg; 

Msg: adt
{
src: string;
dst: string; 
dir: string;
kind: string;
attr: string;
data: array of byte;

#к этим функциям обращаются приложения 
send: fn(msg: self ref Msg): int;
recv: fn(): ref Msg;

#эти функции используются в plumb, send и recv
pack: fn(msg: self ref Msg): array of byte;
unpack: fn(b: array of byte): ref Msg;
};

Attr: adt
{
name: string;
val: string;
};

#Специальные функции, см. ОПИСАНИЕ
init: fn(willsend: int, rcvport: string, maxdata: int): int;
shutdown: fn();
string2attrs: fn(s: string): list of ref Attr;
attrs2string: fn(l: list of ref Attr): string;
lookup: fn(attrs: list of ref Attr, name: string): (int, string);


ОПИСАНИЕ[]

Plumbmsg - это интерфейс, реализующий `общение` между приложениями внутри протокола plumber(8) посредством `сигналов`. Благодаря ему, приложения могут считывать входящие сигналы из логического порта, и отсылать сигналы другим приложениям (см. ниже раздел ФАЙЛЫ).


Приведенный кусок кода, содержит программный вызов модуля, а также набор функций и две структуры абстрактного типа adt: Msg и Attr, которые могут содержать поля любых типов данных и любые функции. К функции Init приложение обращается только один раз - в момент запуска, чтобыустановить и настроить соединение с протоколом. Приложение может на выбор: послать сигнал, получить его или же и то, и другое одновременно. Конечно же, сам plumber к тому времени уже должен быть запущен и ожидать запросы от приложений. Стоитеще разотметить, что протокол можно использовать под различными операционными системами, даже если они не предлагаю привычный пользовательский интерфейс, поскольку протокол оперирует исключительно файлами и адресами в памяти.


Специальные функции[]

Init - функция инициализации. В случае если приложение собирается послать сигнал через plumber, значение переменной willsend должно отличаться от нуля, тогда функция Init откроет необходимый канал; в других случаях значение переменной должно равняться нулю. Если же приложение собирается принять сигнал, переменная rcvport укажет имя логического порта, откуда его следует считать, кроме того, это имя должно быть известно протоколу(оно должно быть указанов переменной dest, см. plumbing(6)); функция Init откроет необходимый канал. Параметр maxdata определяет в байтах максимально возможный размер сигнала, который приложение может принять. Для приложений не имеющих возможности принимать сигналы переменная rcvport устанавливается в nil. Если по каким-то причинам соединение с протоколом былоустановлено некоректно, функция Init возвращает значение `-1` , в частности, если plumber не запущен или имя порта ввода-вывода неизвестно протоколу; в остальных случаях функция возвращает неотрицательные значения. В любом случае необходимо тщательно проверять конфиг на предмет ошибок.


Shutdown сигнализирует протоколу закрыть порт rcvport. An application must call it before it exits if it has an active input port. // помогите с переводом!


String2attrs - берет строку, содержащую список, элементами которого являются пары атрибутов 'name=value', разделенные пробелами, и возвращает список, элементами которого являются ссылки на структуру Attr. Таким образом, строка структурируется, в результате чего каждый элемент списка может быть запрошен по отдельности.


Attr2string - осуществляет обратную процедуру, превращая структуру Attr в строку вида: name=value name=value . . . и т.д.


Lookup - ищет в строке attr (является параметром сигнала и содержится в Msg) атрибут name и, в случае успеха, возвращает tuple вида (1, value). Если параметр name не найден, функция возвращает (0, nil ).


Ниже приведен фрагмент кода программы, которая устанавливает исходящее соединение для приложения `edit`:

plumbed := 0;

plumbmsg = load Plumbmsg Plumbmsg->PATH;

if(plumbmsg->init(1, "edit", 1000) >= 0) plumbed = 1;

Если инициализация проходит успешно, переменная plumbed принимает значение равное единице, и протокол устанавливает исходящее соединение для указанного приложения, иначе plumbed устанавливается в ноль, указывая приложению даже не пытаться запрашивать исходящее соединение.


Структура Msg содержит параметры сигнала, которые транслируются от приложения к приложению, и используются связанными функциями.

src - приложение, сгенерировавшее сигнал
dst - порт-вывода, куда протокол должен переслать сигнал. На практике, это поле зачастую оставляют пустым, оставляя протоколу право создать порт автоматически согласно правилам (см. plumbing(6))
dir - рабочий каталог (например, содержащий файл с данными).
kind - формат данных. Вообще-то, `text' - единственный тип данных, понятный приложениям, тем не менее, протоколимеет возможностьмаршрутизировать любой тип данных.
attr - строка, содержащая пары `name=value` ( например, click=7 trick=33), разделенные пробелами. Normally the value should be created using attrs2string and parsed using string2attrs.
data - поле данных, содержимое сигнала. Прим.: еслиформат данныхkind установлен вположение`text`, а поле данныхпредставленострокой `s` , то параметр data будет представлен массивом байтов соответствующей длины`array of byte s` (фактически, речь идет о преобразовании UTF8 в UTF16, что соответствует преобразованию строки в массив байтов для удобства представления ее в памяти; вообще, создание массива - один из двух имеющихся в языке Limbo способов динамического выделения памяти).

При формировании сигналов модули и функции протокола пользуются возможностями языка Limbo, такими как ссылка-референс ref, которая, например, легко и непринужденно позволяет создать копию структуры и присвоить ее элементам желаемые значения:

msg := ref Msg("WmSh", "", workdir->init(), "text", attr, array of byte text);

Прием и отправка сигналов внутри протокола осуществляется двумя связанными функциями:

m.send( msg ) - записывает сигнал вфайл (канал) ввода-вывода и возвращает количество записанных байтов (результат системной функции write модуля Sys, см. sys-read(2), которая и реализует запись). Если протокол не может маршрутизировать сигнал, функция возвращает значение `-1`, в остальных случаях - неотрицательное число.

Msg.recv() - считывает сигнал из файла, которым представлен порт-ввода отдельного приложения, предварительно созданного (речь о файл-порте) функцией Init. Как только сигнал поступил и считан, функция возвращает ссылку на структуру Msg, содержащую параметры сигнала.

Формат записи сигналов[]

Формат сигналов в том виде, в каком он транслируется, и в каком его используют связанные функции, приведен здесь для ясности и на случай, если эта информация окажется полезной для интерпретации сигналов вне Inferno. Сигналы имеют фиксированный формат: пять текстовых строк, содержащих соответствующие элементы структуры Msg в UTF формате, затем длина data в десятичном формате (N - общее количество байтов), после которой размещается содержимое data в байтовом представлении:

source\n
destination\n
directory\n
kind\n
attributes\n
N\n
N bytes of data

**\n - стандартное смещение коретки наследующую строку Таким образом, все параметры и данные записываются в файл выбранного канала в приведенной выше форме. Непосредственно запись и чтение осуществляются функциями модуля Sys (см. sys-read(2)), но перед тем, как передать параметры сигнала на запись, а также после прочтения содержимого, сигнальный модуль либо формирует байтовый массив, либо трансформирует его в элементы структуры Msg c помощью следующих функций:

m.pack() - функция pack формирует из элементов структуры Msg массив байт длиной m для дальнейшего использования системной функцией write (см. sys-read(2)).

Msg.unpack( b ) - функция unpack совершает обратное действие, преобразуя массив байтов b в точную копию исходной структуры Msg, записанную вфайл ранее.

ФАЙЛЫ[]

/chan/plumb.input - канал ввода-вывода для передачи сигналов внутри протокола

/chan/plumb.rcvport - канал для передачи сигнала, перенаправленного в логический порт с именем rcvport (можно самим определить для каждого приложения, либо предоставить возможность протоколу проделать это автоматически)

ИСХОДНЫЙ КОД

/appl/lib/plumbmsg.b

Ошибки и Баги

Shutdown should not be needed: the plumber(8), as a file server, must know that a particular client has vanished. //поленился перевести, т.к. интуитивно понятно

Advertisement