![]() |
![]() |
Главная страница Взаимодействие нетривиальных процессов Листинг 5.16 (продолжение) 28 struct niymq hclr *mqi hclr; /* начало отображаемого фа11ла */ 29 long mqi niagic: /* магическое значение после инициализации */ 30 int mqi flags: /* флаги для данного процесса */ 31 }: 32 #clefine MQI MAGIC 0x98765432 33 /* размер сообщения округляется для подгонки */ 34 #define MSGSIZE(i) ((((i) + sizeof(long)-l) / sizeof(long)) * sizeof(long)) Структура nriq hdr 8-18 Эта структура хранится в самом начале отображаемого файла и содержит всю информацию об очереди. Поле mq f 1 ags структуры mqii attr не используется, поскольку флаги (единственный определенный флаг используется для отключения блокировки) должны обрабатываться для каждого открывающего очередь процесса в отдельности, а не для очереди в целом. Поэтому флаги хранятся в структуре mq i nf0. О прочих полях этой структуры мы будем говорить в связи с их использованием различными функциями. Обратите внимание, что все переменные, называемые нами индексными (поля этой структуры mqii iiead и mqli f гее, а также поле msg next следующей структуры), содержат индексы байтов относительно начала отображаемого в память файла. Например, размер структуры mq lidr в системе Solaris 2.6 - 96 байт, поэтому индекс первого сообщения, располагающегося сразу за заголовком, имеет значение 96. Каждое сообщение на рис. 5.2 занимает 20 байт (12 байт на структуру msg iidr и 8 байт на данные), поэтому индексы следующих трех сообщений имеют значения 116, 136 и 156, а размер отображаемого в память файла - 176 байт. Индексы используются для обработки двух связных списков, хранящихся в этом файле: в одном из списков (mqii iiead) хранятся все сообщения, имеющиеся в данный момент в очереди, а в другом (mqli f гее) - все незаполненные сообщения. Мы не можем использовать настоящие указатели на области памяти (адреса) при работе со списком, поскольку отображаемый файл может находиться в произвольной области памяти для каждого из процессов, работающих с ним (как показано в листинге 13.5). Структура msg hdr 19-25 Эта структура располагается в начале каждого сообщения в отображаемом файле. Любое сообщение может принадлежать либо к списку заполненных, либо к списку свободных сообщений, и поле msgnext содержит индекс следующего сообщения в этом списке (или О, если сообщение является в этом списке последним). Переменная msg len хранит реальную длину данных в сообщении, которая в нашем примере с рис. 5.2 может иметь значение от О до 7 байт включительно. В переменную msg prio отправителем помещается значение приоритета сообщения. Структура mqjnfo 26-32 Экземпляр такой структзфы динамически создается функцией mq open при открытии очереди и удаляется mq close. Поле mqi lidr указывает на отображае- мый файл (адрес начала файла возвращается шар). Указатель на эту структуру имеет основной в нашей реализации тип mqd t, он принимает значение, возвращаемое mq open. Поле mqi magi с принимает значение MQI MAGIC в момент инициализации структуры. Это значение проверяется всеми функциями, которым передается указатель типа mqd t, что дает им возможность удостовериться, что указатель действительно указывает на структуру типа mq i nf о. niqi f 1 ags содержит флаг отключения блокировки для открывшего очередь процесса. Макрос MSGSIZE 33-34 В целях выравнивания содержимого файла (alignment) мы располагаем начало каждого сообщения так, чтобы его индекс был кратен размеру длинного целого. Следовательно, если максимальный размер сообщения не допускает такого выравнивания, мы добавляем к нему от 1 до 3 байт, как показано на рис. 5.2. При этом предполагается, что размер длинного целого - 4 байт (что верно для Solaris 2.6). Если размер длинного целого 8 байт (в Digital Unix 4.0В), нам придется добавлять к каждому сообщению от 1 до 7 байт. Функция mq open В листинге 5.17 приведен текст первой части функции mq open, создающей новую очередь сообщений или открывающей существующую. Листинг 5.17. Функция mq open: первая часть niy pxmsg mmap/mq open. с 1 #inclucle unpipc.h 2 #inclucle mqueue.h 3 #inclucle <stclarg.h> 4 Idefine MAXJRIES 10 5 struct niymq attr defattr = 6 { 0. 128. 1024. 0 }: 7 rnymqd t 8 niymq open(const char *pathnanie. int oflag. ...) 10 int 1. fd. nonblock. created. save errno; 11 long msgsize. filesize. index; 12 vajist ap; 13 mode t mode; 14 int8 t *mptr; 15 struct stat statbuff; 16 struct mymq hdr *mqhdr; 17 struct rnymsg hdr *msghdr; 18 struct mymq attr *attr: 19 struct rnymqjnfo *mqinfo; 20 pthread mutexattr t mattr; 21 pthread condattr t cattr; 22 created - 0; 23 nonblock = oflag & OJONBLOCK: продолжение Листинг 5.7 (продолжение) 24 oflag &= -0 NONBLOCK: 25 mptr = (int8 t *) MAPJAILED: 26 mqinfo = NULL: 27 again: 28 if (oflag & 0 CREAT) { 29 va start(ap. oflag): /* ap инициализируется последним аргументом */ 30 mode = va arg(ap. va mode t) & -SJXUSR; 31 attr = va arg(ap. struct mymq attr *): 32 va end(ap): 33 /* открытие с установкой бита user-execute */ 34 fd = open (pathname, oflag OJXCL 0 RDWR. mode ) S IXUSR): 35 if (fd < 0) { 36 if (errno == EEXIST && (oflag & OJXCL) = 0) 37 goto exists: /* уже существует. OK */ 38 else 39 return((mymqd t) -1): 40 } 41 created = 1: 42 /* при создании файла он инициализируется */ 43 if (attr =- NULL) 44 attr - &defattr: 45 else { 46 if (attr->mq maxmsg <= 0 attr->mq msgsize <= 0) { 47 errno = EINVAL; 48 goto err: 49 } 50 } Обработка списка аргументов переменного размера 29-32 Функция может быть вызвана либо с двумя, либо с четырьмя аргументами в зависимости от того, указан ли флаг 0 CREAT. Если флаг указан, третий аргумент имеет тип mode t, а это простой системный тип, являющийся одним из целых типов. При этом мы столкнемся с проблемой в BSD/OS, где этот тип данных определен как unsigned siiort (16 бит). Поскольку целое в этой реализации занимает 32 бита, компилятор С увеличивает аргумент этого типа с 16 до 32 бит, потому что все короткие целые в списке аргументов увеличиваются до обычных целых. Но если мы укажем mode t при вызове va arg, он пропустит 16 бит аргумента в стеке, если этот аргумент был увеличен до 32 бит. Следовательно, мы должны определить свой собственный тип данных, va mode t, который будет целым в BSD/OS и типом model в других системах. Эту проблему с переносимостью решают приведенные ниже строки нашего заголовка unpi рс. ii (листинг В. 1): #ifdef bsdi #define va mode t int #el se #define va mode t mode t #endif 30 Мы сбрасываем бит user-execute (S IXUSR) в переменной mode по причинам, которые будут вскоре раскрыты. Создание новой очереди сообщений 33-34 Создается обычный файл с именем, указанным при вызове функции, и устанавливается бит user-execute.
|
© 2000 - 2025 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |