Читать «UNIX: взаимодействие процессов» онлайн - страница 88
Уильям Ричард Стивенс
Листинг 5.24. Функция mq_notify
//my_pxmsg_mmap/mq_notify.с
1 #include "unpipc.h"
2 #include "mqueue.h"
3 int
4 mymq_notify(mymqd_t mqd, const struct sigevent *notification)
5 {
6 int n;
7 pid_t pid;
8 struct mymq_hdr *mqhdr;
9 struct mymq_info *mqinfo;
10 mqinfo = mqd;
11 if (mqinfo->mqi magic != MQI_MAGIC) {
12 errno = EBADF;
13 return(-1);
14 }
15 mqhdr = mqinfo->mqi_hdr;
16 if ((n = pthread_mutex_lock(&mqhdr->mqh_lock)) != 0) {
17 errno = n;
18 return(-1);
19 }
20 pid = getpid();
21 if (notification == NULL) {
22 if (mqhdr->mqh_pid == pid) {
23 mqhdr->mqh_pid = 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->mqh_pid = pid;
33 mqhdr->mqh_event = *notification;
34 }
35 pthread_mutex_unlock(&mqhdr->mqh_lock);
36 return(0);
37 err:
38 pthread_mutex_unlock(&mqhdr->mqh_lock);
39 return(-1);
40 }
Снятие процесса с регистрации
20-24 Если второй аргумент представляет собой нулевой указатель, вызвавший процесс снимается с регистрации. Если он не зарегистрирован, никакой ошибки не возвращается.
Регистрация вызвавшего процесса
25-34 Если какой-либо процесс уже зарегистрирован, мы проверяем, существует ли он, отправкой ему сигнала с кодом 0 (называемого нулевым сигналом — null signal). Это обычная проверка на возможность ошибки, на самом деле при этом никакого сигнала процессу не отправляется, но при его отсутствии возвращается ошибка с кодом ESRCH. Если какой-либо процесс уже зарегистрирован на уведомление, функция возвращает ошибку EBUSY. В противном случае сохраняется идентификатор процесса вместе с его структурой sigevent.
ПРИМЕЧАНИЕ
Наш метод проверки существования вызвавшего процесса не идеален. Процесс мог завершить работу, а его идентификатор мог быть использован другим процессом.
Функция mq_send
В листинге 5.25 приведен текст первой половины нашей функции mqsend.
Инициализация
14-29 Мы получаем указатели на используемые структуры и блокируем взаимное исключение для данной очереди. Проверяем, не превышает ли размер сообщения максимально допустимый для данной очереди.
Проверка очереди на пустоту и отправка уведомления
30-38 Если мы помещаем первое сообщение в пустую очередь, нужно проверить, не зарегистрирован ли какой-нибудь процесс на уведомление об этом событии и нет ли потоков, заблокированных в вызове mq_receive. Для проверки второго условия мы воспользуемся сохраняемым функцией mq_receive счетчиком mqh_nwait, содержащим количество потоков, заблокированных в вызове mq_receive. Если этот счетчик имеет ненулевое значение, мы не отправляем уведомление зарегистрированному процессу. Для отправки сигнала SIGEV_SIGNAL используется функция sigqueue. Затем процесс снимается с регистрации.