Главная страница Взаимодействие нетривиальных процессов Листинг 12.5 (продолжение) 9 if (argc != 2) 10 err quit( usage: incr dev zero <#loops> ); 11 nloop = atoi(argv[l]): 12 /* открываем /dev/zero и отображаем в память */ 13 fd - Open( /dev/zero , 0 RDWR); 14 ptr =Mmap(NULL, sizeof(int), PROT REAO PROT WRITE, MAP SHAREO, fd, 0): 15 Close(fd); 6-11 Автоматическая переменная zero больше не используется, как и аргумент командной строки, задававший имя создаваемого файла. 12-15 Мы открываем файл /dev/zero и передаем его дескриптор функции mmap. Область памяти будет гарантированно проинициализирована нулями. 12.6. Обращение к объектам, отображенным в память Когда в память отображается обычный файл, размер полученной области (второй аргумент вызова mmap), как правило, совпадает с размером файла. Например, в листинге 12.3 размер файла устанавливается равным размеру структуры shared вызовом write и это же значение размера области используется при отображении его в память. Однако эти два параметра - размер файла и размер области памяти, в которую он отображен, - могут и отличаться. Для детального изучения особенностей функции mmap воспользуемся программой в листинге 12.6. Листинг 12.6. Отображение файла: размер файла совпадает с размером области памяти shtti/testl.c 1 finclude unpipc.h 2 int 3 ttiain(int argc, char **argv) 5 int fd, i; 6 char *ptr: 7 size t filesize, mmapsize. pagesize: 8 if (argc != 4) 9 err quit( usage: testl <pathnanie> <filesize> <mmapsize> ); 10 filesize = atoi(argv[2]): 11 mmapsize = atoi(argv[3]): 12 /* открытие файла, установка его размера */ 13 fd = Open(argv[l], 0 ROWR 0 CREAT OJRUNC. FILE M(X)E): 14 Lseek(fd, filesize-1. SEEK SET): 15 Write(fd, , 1); 16 ptr Mmap(NULL. mmapsize. PROT READ PROT WRITE, MAP SHAREO, fd. 0); 17 Close(fd); 18 pagesize - Sysconf( SC PAGESIZE): 19 printf( PAGESIZE - ld\n . (long) pagesize); 20 for (i = 0; i < ttiaxCfilesize. mmapsize); i += pagesize) { 21 printf( ptr[d] = d\n . i. ptr[i]); 22 ptr[i] = 1: 23 printf( ptr[ d] d\n . i + pagesize - 1. ptr[i + pagesize - 1]): 24 ptr[i + pagesize - 1] = 1; 25 } 26 printf( ptr[ d] = d\n , i, ptr[i]): 27 exitCO); 28 } Аргументы командной строки 8-11 Аргументы командной строки задают полное имя создаваемого и отображаемого в память файла, его размер и размер области памяти. Создание, открытие, урезание файла; установка его размера 12-15 Если файл не существует, он будет создан. Если он существует, его длина будет установлена равной нулю. Затем размер файла устанавливается равным указанному размеру путем вызова 1 seek для установки текущей позиции, равной требуемому размеру минус 1 и записи 1 байта. Отображение файла в память 16-17 Файл отображается в память, причем размер области задается последним аргументом командной строки. Затем дескриптор файла закрывается. Вывод размера страницы памяти 18-19 Размер страницы памяти получается вызовом sysconf и выводится на экран. Чтение и запись в область отображения 20-26 Считываются и выводятся данные из области памяти, в которую отображен файл. Считываются первый и последний байты каждой страницы этой области памяти. Все значения должны быть нулевыми. Затем первый и последний байты каждой страницы устанавливаются в 1. Одно из обращений к памяти может привести к отправке сигнала процессу, что приведет к его заверщению. После заверщения цикла for мы добавляем еще одно обращение к следующей странице памяти, что должно заведомо привести к ошибке и заверщению программы (если ошибка не возникла раньше). Рассмотрим первую ситуацию: размер файла совпадает с размером области памяти, но эта величина не кратна размеру страницы памяти в данной реализации: Solaris % Is -1 foo foo: No such file or directory Solaris % testl foo 5000 5000 PAGESIZE = 4096 ptr[0] = 0 ptr[4095] = 0 ptr [4096] = 0 ptr [8191] = О Segmentation Fault(coredump) Solaris % Is -1 foo -rw-r--r-- 1 rstevens otherl 5000 Mar 20 17:18 foo Solaris od -b -A d foo 0000000 001 ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО 0000016 ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО * 0004080 ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО 001 0004096 001 ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО 0004112 ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО ООО * 0005000 Размер страницы памяти составляет 4096 байт, и мы смогли обратиться ко всему содержимому второй страницы (индексы 4096-8191), но обращение к третьей странице (8192) приводит к отправке сигнала SIGSEGV, о чем интерпретатор оповещает сообщением Segmentation Fault. Хотя мы и установили значение ptr[8191] = 1, оно не было записано в файл и его размер остался равным 5000 байт. Ядро позволяет считывать и записывать данные в ту часть последней страницы, которая не относится к отображенному файлу (поскольку защита памяти осуществляется ядром постранично), но изменения в этой области памяти не будут скопированы в файл. А вот относящиеся к файлу изменения (индексы 0,4095 и 4096) были скопированы в него, в чем мы убедились, воспользовавшись программой od (параметр -Ь при вызове последней указывает на необходимость выводить значения байтов в восьмеричном формате, а параметр -А d позволяет выводить адреса в десятичном формате). На рис. 12.8 изображена схема памяти для данного примера. размер файла сдвиг: О 4999 индекс: О 4999 5000 8191 остаток I область отображения послодней гярашш \ обращение приводит к этой области можно обращаться-SIGSV размер, указываемый при вызове mmap Рис. 12.8. Размер отображаемого файла совпадает с размером области памяти Запустив этот пример в Digital Unix 4.0В, получим тот же результат, но размер страницы памяти в этой системе равняется 8192 байт: alpha Is -1 foo foo not found alpha % testl foo 5000 5000
|
© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования. |