□ fcntl(fildes, F_GETFD) - этот вызов возвращает флаги дескриптора файла, как определено в файле fcntl.h. К ним относится FD_CLOEXEC, определяющий, закрыт ли дескриптор файла после успешного вызова одного из системных вызовов семейства exec.
□ fcntl(fildes, F_SETFD, flags) - этот вызов применяется для установки флагов дескриптора файла, как правило, только FD_CLOEXEC.
□ fcntl(fildes, F_GETFL) и fcntl(fildes, F_SETFL, flags) - эти вызовы применяются, соответственно, для получения и установки флагов состояния файла и режимов доступа. Вы можете извлечь режимы доступа к файлу с помощью маски O_ACCMODE, определенной в файле fcntl.h. Остальные флаги включают передаваемые значения в третьем аргументе вызову open с использованием O_CREAT. Учтите, что вы не можете задать все флаги. В частности, нельзя задать права доступа к файлу с помощью вызова fcntl.
Вызов fcntl также позволяет реализовать блокировку файла. См. более подробную информацию в разделе 2 интерактивного справочного руководства или главу 7, в которой мы обсуждаем блокировку файлов.
mmap
Система UNIX предоставляет полезное средство, позволяющее программам совместно использовать память, и, к счастью, оно включено в версию 2.0 и более поздние версии ядра Linux. Функция mmap (для отображения памяти) задает сегмент памяти, который может читаться двумя или несколькими программами и в который они могут записывать данные. Изменения, сделанные одной программой, видны всем остальным.
Вы можете применить то же самое средство для работы с файлами, заставив все содержимое файла на диске выглядеть как массив в памяти. Если файл состоит из записей, которые могут быть описаны структурами на языке С, вы сможете обновлять файл с помощью методов доступа к массиву структур.
Это становится возможным благодаря применению сегментов виртуальной памяти с набором особых прав доступа. Чтение из сегмента и запись в него заставляет операционную систему читать соответствующую часть файла на диске и писать данные в нее.
Функция mmap создает указатель на область памяти, ассоциированную с содержимым файла, доступ к которому осуществляется через открытый дескриптор файла.
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
Изменить начальную позицию порции данных файла, к которым выполняется обращение через совместно используемый сегмент, можно, передавая параметр off. Открытый дескриптор файла задается в параметре fildes. Объем данных, к которым возможен доступ (т. е. размер сегмента памяти), указывается в параметре len.
Параметр addr можно использовать для запроса конкретного адреса памяти. Если он равен нулю, результирующий указатель формируется автоматически. Последний вариант рекомендуется, потому что в противном случае трудно добиться переносимости; диапазоны доступных адресов в разных системах отличаются.
Параметр prot используется для установки прав доступа к сегменту памяти. Он представляет собой результат поразрядной операции or, примененной к следующим константам:
□ PROT_READ - сегмент может читаться;
□ PROT_WRITE - в сегмент можно писать;
□ PROT_EXEC - сегмент может выполняться;
□ PROT_NONE - к сегменту нет доступа.
Параметр flags контролирует, как изменения, сделанные программой в сегменте, отражаются в других местах; его возможные значения приведены в табл. 3.7.
Таблица 3.7
| Константа | Описание |
|---|---|
| MAP_PRIVATE | Сегмент частный, изменения локальные |
| MAP_SHARED | Изменения сегмента переносятся в файл |
| MAP_FIXED | Сегмент должен располагаться по заданному адресу addr |
Функция msync вызывает запись изменений в части или во всем сегменте памяти обратно а отображенный файл (или считывание из файла).
#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);
Корректируемая часть сегмента задается передачей начального адреса addr и размера len. Параметр flags управляет способом выполнения корректировки с помощью вариантов, приведенных в табл. 3.8.
Таблица 3.8
| Константа | Описание |
|---|---|
| MS_ASYNC | Выполнять запись асинхронно |
| MS_SYNC | Выполнять запись синхронно |
| MS_INVALIDATE | Обновить другие отражения этого файла так, чтобы они содержали изменения, внесенные этим вызовом |
Функция munmap освобождает сегмент памяти.
#include <sys/mman.h>
int munmap(void *addr, size_t len);
В программе mmap.с из упражнения 3.5 показан файл из структур, которые будут корректироваться с помощью функции mmap и обращений в стиле массива. Ядро Linux версий, меньших 2.0, не полностью поддерживает применение функции mmap. Программа работает корректно в системе Sun Solaris и других системах.
Упражнение 3.5. Применение функции mmap
1. Начните с определения структуры RECORD и создайте NRECORDS вариантов, в каждый из которых записывается собственный номер. Они будут добавлены в конец файла records.dat.
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdlib.h>
typedef struct {
int integer;
char string[24];
} RECORD;
#define NRECORDS (100)
int main() {
RECORD record, *mapped;
int i, f;
FILE *fp;
fp = fopen("records.dat", "w+");
for (i=0; i<NRECORDS; i++) {
record.integer = i;
sprintf(record.string, "RECORD-%d", i);
fwrite(&record, sizeof(record), 1, fp);
}
fclose(fp);
2. Далее измените целое значение записи с 43 на 143 и запишите его в строку 43-й записи.
fp = fopen("records.dat", "r+");
fseek(fp, 43*sizeof(record), SEEK_SET);
fread(&record, sizeof(record), 1, fp);
record.integer =143;
sprintf(record.string, "RECORD-%d", record.integer);
fseek(fp, 43*sizeof(record), SEEK_SET);
fwrite(&record, sizeof(record), 1, fp);
fclose(fp);
3. Теперь отобразите записи в память и обратитесь к 43-й записи для того, чтобы изменить целое на 243 (и обновить строку записи), снова используя отображение в память.
f = open("records.dat", O_RDWR);
mapped = (RECORD *)mmap(0, NRECORDS*sizeof(record),
PROT_READ|PROT_WRITE, MAP_SHARED, f, 0);
mapped[43].integer = 243;
sprintf(mapped[43].string, "RECORD-%d", mapped[43].integer);
msync((void *)mapped, NRECORDS*sizeof(record), MS_ASYNC);
munmap((void *)mapped, NRECORDS*sizeof(record));
close(f);
exit(0);
}
В главе 13 вы встретитесь с еще одним средством совместного использования памяти - разделяемой памятью System V.