Главная страница Взаимодействие нетривиальных процессов Листинг 5.24 (продолжение) 23 mqhdr->niqh picl = 0; /* снятие вызвавшего процесса с регистрации */ 24 } /* если вызвавший процесс не зарегистрирован - 61К */ 25 } else { 26 if (mqhdr->mqh pid != 0) { 27 if (kill(mqhdr->mqh pid, 0) != -1 errno != ESRCH) { 28 errno - EBUSY; 29 goto err; 30 } 31 } 32 mqhdr->mqhj)1d = pid; 33 mqhdr->mqh event = *notification; 34 } 35 pthread mutex unlock(&mqhdr->mqh lock); 36 return(O); 37 err: 38 pthread mutex unlock(&mqhdr->mqh lock); 39 return(-l); 40 } Снятие процесса с регистрации 20-24 Если второй аргумент представляет собой нулевой указатель, вызвавший процесс снимается с регистрации. Если он не зарегистрирован, никакой ошибки не возвращается. Регистрация вызвавшего процесса 25-34 Если какой-либо процесс уже зарегистрирован, мы проверяем, существует ли он, отправкой ему сигнала с кодом О (называемого нулевым сигналом - null signal). Это обычная проверка на возможность ошибки, на самом деле при этом никакого сигнала процессу не отправляется, но при его отсутствии возвращается ошибка с кодом ESRCH. Если какой-либо процесс уже зарегистрирован на уведомление, функция возвращает ошибку EBUSY. В противном случае сохраняется идентификатор процесса вместе с его структурой sigevent. ПРИМЕЧАНИЕ Наш метод проверки существования вызвавшего процесса не идеален. Процесс мог завершить работу, а его идентификатор мог быть использован другим процессом. Функция mq send в листинге 5,25 приведен текст первой половины нашей функции mq send. Инициализация 14-29 Мы ползпаем указатели на используемые структуры и блокируем взаимное исключение для данной очереди. Проверяем, не превышает ли размер сообщения максимально допустимый для данной очереди. Проверка очереди на пустоту и отправка уведомления 30-38 Если мы помещаем первое сообщение в пустую очередь, нужно проверить, не зарегистрирован ли какой-нибудь процесс на уведомление об этом событии и нет ПРИМЕЧАНИЕ Вызов sigqueue для отправки сигнала приводит к передаче сигнала SI QUEUE обработчику сигнала в структуре типа siginfo t (раздел 5.7), что неправильно. Отправка правильного значения si code (а именно SI MESGQ) из пользовательского процесса осуществляется в зависимости от реализации. Нас. 433 стандарта IEEE 1996 [8] отмечается, что для отправки этого сигнала из пользовательской библиотеки необходимо воспользоваться скрытым интерфейсом механизма отправки сигналов. Проверка заполненности очереди 39-48 Если очередь переполнена и установлен флаг 0 NONBLOCK, мы возвращаем ошибку с кодом EAGAIN. В противном случае мы ожидаем сигнала по условной переменной mqh wai t, который, как мы увидим, отправляется функцией mq recei ve при считывании сообщения из переполненной очереди. ПРИМЕЧАНИЕ - Наша реализация упрощает ситуацию с возвращением ошибки EINTR при прерывании вызова mq send сигналом, перехватываемым вызвавшим процессом. Проблема в том, что функция pthread cond wait не возвращает ошибки при возврате из обработчика сигнала: она может вернуть либо О (что рассматривается как ложное пробуждение), либо вообще не завершить работу. Все эти проблемы можно обойти, но это непросто. В листинге 5.26 приведена вторая половина функции mq send. К моменту ее выполнения мы уже знаем о наличии в очереди свободного места для нашего сообщения. Листинг 5.25. Функция mq send: первая половина niy pxmsg mmap/mq sencl. с 1 #inclucle unpipc.h 2 #inclucle mqueue.h 3 int 4 mymq sencl(mymqcl t mqd, const char *ptr. size t len, unsigned int prio) 6 int n: 7 long index, freeindex; 8 int8 t *mptr; 9 struct sigevent *sigev; 10 struct mymq hdr *mqhdr; 11 struct mymq attr *attr; 12 struct rnymsg hdr *msghdr, *nmsghdr, *pmsghdr; 13 struct mymq info *mqinfo; 14 mqinfo = mqd: продолжение ли потоков, заблокированных в вызове mq recei ve. Для проверки второго условия мы воспользуемся сохраняемым функцией niq recei ve счетчиком mqh nwai t, содержащим количество потоков, заблокированных в вызове niq recei ve. Если этот счетчик имеет ненулевое значение, мы не отправляем уведомление зарегистрированному процессу. Для отправки сигнала SIGE\/ SIGNAL используется функция sigqueue. Затем процесс снимается с регистрации. Листинг 5.25 (продолжение) 15 if (mqinfo->niqi niagic != MQI MAGIC) { 16 еггпо = EBADF-, 17 return(-l); 18 } 19 mqhdr = mqinfo->mqi hdr; /* указатель типа struct */ 20 mptr = (int8 t *) mqhdr; /* указатель на байт */ 21 attr = &mqhdr->mqh attr: 22 if ( (n = pthread mutexJock(&mqhdr->mqhJock)) != 0) { 23 errno = n; 24 return(-l); 25 } 26 if (len > attr->mq msgsize) { 27 errno - EMSGSIZE; 28 goto err; 29 } 30 if (attr->mq curmsgs == 0) { 31 if (mqhdr->mqh pid != 0 && mqhdr->mqh nwait = 0) { 32 sigev = &mqhdr->mqh event; 33 if (sigev->sigev notify == SIGEV SIGNAL) { 34 sigqueue(mqhdr->mqh pid, sigev->sigev signo, 35 sigev->slgev value); 36 } 37 mqhdr->mqh pid = 0; /* снятие с регистрации */ 38 } 39 } else if (attr->mq cunnsgs >= attr->mq maxmsg) { 40 /* 4queue is full */ 41 if (mqinfo->mqi flags & OJONBLOCK) { 32 errno = EAGAIN: 43 goto err; 44 } 45 /* ожидание освобождения места в очереди */ 46 while (attr->mq curmsgs >= attr->mq maxmsg) 47 pthread cond wait(&mqhdr->mqh wait, &mqhdr->mqh lock): 48 } Листинг 5.26. Функция mq send: вторая половина my pxmsg mmap/mq send.с 49 /* nmsghdr будет указывать на новое сообщение*/ 50 if ( (freeindex = mqhdr->mqh free) == 0) 51 err dump( mymq send: curmsgs = Id; free = 0 , attr->mq curmsgs); 52 nmsghdr = (struct mymsg hdr *) &mptr[freeindex]: 53 nmsghdr->msg prio = prio: 54 nmsghdr->msg len = len; 55 memcpy(nmsghdr + 1, ptr, len); /* копирование сообщения в очередь */ 56 mqhdr->mqh free = nmsghdr->msg next: /* новое начало списка пустых сообщений */ 57 /* поиск места в списке для нового сообщения */ 58 index = mqhdr->mqh head; 59 pmsghdr = (struct mymsg hdr *) &(mqhdr->mqh head): 60 while (index != 0) { 61 msghdr = (struct mymsg hdr *) &mptr[index]; 62 if (prio > msghdr->msg prio) { 63 nmsghdr->msg next = index; 64 pmsghdr->msg next = freeindex:
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |