Главная страница Взаимодействие нетривиальных процессов Листинг 5.19 (продолжение) 112 if (еггпо - ENOENT && (oflag & 0 CREAT)) 113 goto again: 114 goto err; 115 } 116 /* проверяем, что инициализация завершена */ 117 for (i = 0; i < IX TRIES: i++) { 118 if (stat(pathname. &statbuff) == -1) { 119 if (errno == ENOENT && (oflag & 0 CREAT)) { 120 close(fcl); 121 goto again: 122 } 123 goto err: 124 } 125 if ((statbuff.st mocle & S IXUSR) - 0) 126 break; 127 sleep(l); 128 } 129 if (i == IX TRIES) { 130 errno = ETIMEDOUT; 131 goto err; 132 } 133 filesize - statbuff.st size: 134 mptr = mmap(NULL. filesize. PROT READ PROT WRITE. IP SHARED. fd. 0); 135 if (mptr == IP FAILED) 136 goto err: 137 close(fd): 138 /* выделяем одну mymq info{} для каждого вызова open */ 139 if ( (mqinfo = malloc(sizeof(struct mymqjnfo))) == NULL) 140 goto err: 141 mqinfo->mqi hdr = (struct mymq hdr *) mptr: 142 mqinfo->raqi magic - MQLMAGIC; 143 mqinfo->raqi flags = nonblock; 144 return((mymqd t) mqinfo): 145 pthreaderr: 146 errno = i: 147 err: 148 /* не даем следующим вызовам изменить errno */ 149 save errno = errno: 150 if (created) 151 unlinlc(pathnarae); 152 if (mptr i- MAPJAILED) 153 munniap(mptf, filesize); 154 if (mqinfo 1= NULL) 155 free(mqinfo): 156 close(fd): 157 errno = save errno: 158 return((mymqd t) -1): 159 } Открытие существующей очереди сообщений 109-115 Здесь мы завершаем работу, если флаг 0 CREAT не был указан или если он был указан, но очередь уже существовала. В любом случае, мы открываем су- ществующую очередь сообщений. Для этого мы открываем для чтения и записи файл, в котором она содержится, функцией open и отображаем его содержимое в адресное пространство процесса (шар). ПРИМЕЧАНИЕ - Наша реализация сильно упрощена в том, что касается режима открытия файла. Даже если вызвавший процесс указывает флаг 0 RDONLY, мы должны дать возможность доступа для чтения и записи при открытии файла командой open и при отображении его в память командой mmap, поскольку невозможно считать сообщение из очереди, не изменив содержимое файла. Аналогично невозможно записать сообщение в очередь, не имея доступа на чтение. Обойти эту проблему можно, сохранив режим открытия (0 RDONLY, 0 WRONLY, 0 RDWR) в структуре mq info и проверяя этот режим в каждой из функций. Например, mq receive должна возвращать ошибку, если в mq info хранится значение 0 WRONLY. Проверка готовности очереди 116-132 Нам необходимо дождаться, когда очередь будет проинициализирована (в случае, если несколько потоков сделают попытку открыть ее приблизительно одновременно). Для этого мы вызываем stat и проверяем разрешения доступа к файлу (поле st mode структуры stat). Если бит user-execute сброшен, очередь уже проинициализирована. Этот участок кода обрабатывает другую возможную ситуацию гонок. Предположим, что два потока разных процессов попытаются открыть очередь приблизительно одновременно. Первый поток создает файл и блокируется при вызове 1 seek в листинге 5.18. Второй поток обнаруживает, что файл уже существует, и переходит к метке exists, где он вновь открывает файл функцией open и при этом блокируется. Затем продолжается выполнение первого потока, но его вызов шар в листинге 5.18 не срабатывает (возможно, он превысил лимит использования памяти), поэтому он переходит на метку err и удаляет созданный файл вызовом unl i пк. Продолжается выполнение второго потока, но если бы мы вызывали fstat вместо stat, он бы вышел по тайм-ауту в цикле for, ожидая инициализации файла. Вместо этого мы вызываем stat, которая возвращает ошибку, если файл не существует, и, если флаг 0 CREAT был указан при вызове mq open, мы переходим на метку again (листинг 5.17) для повторного создания файла. Эта ситуация гонок заставляет нас также проверять, не возвращается ли при вызове open ошибка ENOENT. Отображение файла в память; создание и инициализация структуры mqjnfo 133-144 Файл отображается в память, после чего его дескриптор может быть закрыт. Затем мы выделяем место под структуру mq i nf о и инициализируем ее. Возвращаемое значение представляет собой указатель на эту структуру. Обработка ошибок 145-148 При возникновении ошибок происходит переход к метке err, а переменной errno присваивается значение, которое должно быть возвращено функцией mq open. Мы аккуратно вызываем функции для очистки памяти от выделенных объектов. чтобы переменная еггпо не изменила свое значение в случае возникновения ошибки в этих функциях. Функция mq close в листинге 5.20 приведен текст нашей функции mq close. Листинг 5.20. Функция mq close / /niy pxnisg mmap/niq cl ose. с 1 #1nclucle unpipc.h 2 #inclucle mqueue.h 3 int 4 mymq close(mymqcl t mqd) 6 long msgsize. filesize; 7 struct mymq hdr *mqhdr: 8 struct mymq attr *attr; 9 struct rnymqjnfo *mqinfo: 10 mqinfo = mqd: 11 if (mqinfo->mqi magic !- MQI MAGIC) { 12 errno = EBADF; 13 return(-l): 14 } 15 mqhdr = mqinfo->mqi hdr; 16 attr = &mqhdr->mqh attr: 17 if (mymq notify(mqd. NULL) != 0) /* снятие вызвавшего процесса с регистрации */ 18 return(-l); 19 msgsize = MSGSIZE(attr->mq msgsize); 20 filesize - sizeofCstruct mymq hdr) + (attr->mq maxmsg * 21 (SizeofCstruct rnymsg hdr) + msgsize)); 22 if (munmap(mqinfo->mqi hdr. filesize) == -1) 23 return(-l): 24 mqinfo->mqi magic = 0; /* на всяки11 случа11 */ 25 free(mqinfo); 26 return(O); 27 } Получение указателей на структуры 10-16 Проверяется правильность переданных аргументов, после чего получаются указатели на область, занятую отображенным в память файлом (mqlidr), и атрибуты (в структуре mq lidr). Сброс регистрации вызвавшего процесса 17-18 Для сброса регистрации на уведомление вызвавшего процесса мы вызываем mq notify. Если процесс был зарегистрирован, он будет снят с уведомления, но если нет - ошибка не возвращается. Отключение отображения файла и освобождение памяти 19-25 Мы вычисляем размер файла для вызова munmap и освобождаем память, используемую структурой mqi nf о. На случай, если вызвавший процесс будет про-
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |