Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОСиСП теория 4 семестра - методичка слайдов Бранцевич Петр Юльянович 2009.doc
Скачиваний:
170
Добавлен:
15.06.2014
Размер:
1.75 Mб
Скачать

2.7 Векторный ввод/вывод

Векторный ввод/вывод – это способ ввода/вывода, когда системный вызов записывает или считывает данные из потока данных в вектор буферов.

#include <sys/uio.h>

ssize_t readv(int fd, const struct iovec *iov, int count);

ssize_t writev(int fd, const struct iovec *iov, int count);

Первый системный вызов читает, а второй – записывает указанное число данных, находящееся в буферах, определенных вторым параметром в дескриптор первого параметра. В качестве третьего параметра используется количество сегментов, которое считывается или записывается (0<count<IOV_MAX=1024).

Каждый сегмент имеет такую структуру: первый параметр указывает на буфер, второй – на размер (количество байтов для обмена).

struct iovec

{ void *iov_base;

size_t iov_len; }

Пример использования векторного ввода/вывода:

#include <stdio.h>

#include <sys/types.h>

#include <fentf.h>

#include <string.h>

#include <sys/uio.h>

int main()

{

struct iovec iov[3];

ssize_t nr;

int fd;

char *buf[]={“AAAAAAAAA\n”, “BBBBB\n”, “CCCCCCC\n”};

fd=open(“fil1.txt”, O_WRONLY|O_CREAT|O_TRUNC);

if (fd==-1)

{ perror(“open”);

return(1); }

for (i=0; i<3; i++)

{ iov[i].iov_base=buf[i];

iov[i].iov_len=strlen(buf[i]); }

nr=writev(fd,iov,3);

if (nr==-1)

{ perror(“writev”);

return(1); }

printf(“Записаны %d байт \n”, nr);

if (close(fd))

{ perror(“close”);

return(1); }

}

Производится запись в файл трех строк массива. Для этого сначала открывается файл и проверяется, чтобы не было ошибок. Формируются сегменты данных (в первом поле указывается адрес, во втором – количество байт). Далее системный вызов writev записывает в буфера (указанный адрес) то количество, которое надо записать. Анализ возвращаемых значений проводится с помощью числа записанных байт (nr).

Применение функции векторного ввода/вывода предназначено для повышения производительности операций обмены за счет внутренней системной оптимизации выполняемых действий. Помимо этого первый оператор обмена может заменить несколько операторов ввода/вывода.

2.8 Файлы, отображающиеся в памяти

Альтернатива стандартному вводу/выводу является интерфейс представленный ядром ОС, который позволяет приложению отображать файл в память, то есть создавать соответствие один к одному между адресом в памяти и словом в файле. За счет такого механизма программа может обращаться файлу через память как к любым другим данным, находящимся в памяти.

Имеется механизм прозрачного отображения действий по отношению к данным в области памяти не данные, находящиеся в файле на диске:

#include <sys/mman.h>

void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);

Этот системный вызов запрашивает у ядра ОС разрешение на отображение этих len байтов из файла fd, начиная со смещения в файле offset. Разрешение на доступ отображает параметр prot, а допустимые возможности определяет flags.

Далее представлены возможные значения prot:

PROT_READ, страница доступна для считывания

PROT_WRITE, страница доступна для записи

PROT_EXEC, страница доступна для выполнения

PROT_NONE, доступ к странице запрещен

Допустимые варианты flags:

MAP_FIXED, позволяет считать первый параметр, а если ядро не может разместить данные по указанному адресу, то выводит сообщение об ошибке

MAP_PRIVATE, отображение приватно для файла по отношению к процессу, изменения не видны для других процессов и не повторяются в физическом файле

MAP_SHAKE, действие видны для остальных процессов и отображаются на физических файлах

Первый же параметр addr служит для того, чтобы определять место в ОП, куда лучше всего отображать данные в файл. Если в качестве данного параметра представлено значение NULL (или 0), то ОС сама выбирает, куда отображать данные.

void *p;

. . .

p=mmap(0,len,PROT_READ,MAP_SHADER,fd,0);

Возвращает системный вызов фактический адрес в памяти, куда будет производиться отображение.

Отображение ведется по страницам. Страница – это наименьшая единица памяти, которая может обладать собственным разрешением и поведением. Отображения области памяти должны быть кратны размеру страницы, и оба параметра addr и offset должны быть выровнены на границе страницы.

Если параметр len не кратен страницам, для отображения формы области памяти с числом страниц, которое обеспечивает разрешение больше len, но ближнее по числу страниц. Но при этом пользовательский процесс не может выходить за границу len.

Для того, чтобы узнать размер страницы:

#include <unistd.h>

long sysconf(int name);

long page_size=sysconf(_SC_PAGESIZE);

В случае успешного завершения функции mmap возвращается адрес отображения в памяти, а в случае ошибки значение MAP_FAILED и устанавливает значения errno:

EACCESS – файл, указанный при помощи файлового дескриптора fd, не является обычным файлом или же режим, в котором открыт файл, конфликтует со значением prot или flags

EAGAIN – файл заблокирован

EBADF – значение fd не является допустимым

EINVAL – один или несколько параметров имеют недопустимое значение

ENFILE – достигнуто максимальное количество открытых файлов

ENODEV – используемая файловая система не поддерживает отображение в память

ENOMEM – у процесса недостаточно памяти

EOVERFLOW – выход за пределы адресного пространства

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fentl.h>

#include <unistd.h>

#include <sys/mman.h>

int main(int argc,char *argv[]) {

struct stat sb;

off_t len;

char *p;

int fd;

if (argc<2) //проверяет корректность вызова

{ printf(“Ошибка вызова программы \n”);

return(1); }

fd=open(argv[1],O_RDONLY); //открытие файла

if (fd==-1)

{ perror(“open”);

return(1); }

if (fstat(fd,&sb)==-1)

{ perror(“fstat”);

return(1); }

if (!S_ISREG(sb.st_mode))

{ prinf(“Это %s не файл \n”,argv[1]);

return(1); }

p=mmap(0,sb.st_size,PROT_READ,MAP_SHARED,fd,0); //отображение

в память, второй параметр указывает на размер файла

if (p==MAP_FAILED) //ошибка

{ perror(“mmap”);

return(1); }

if (close(fd)==-1) //закрытие fd

{ perror(“close”);

return(1); }

for (len=0; len<sb.st_size; len++)

putchr(p[len]); //байты из области p

if (munmap(p,sb.st_size)==-1) //закрытие области отображения,

указывается адрес начала и размер области

{ perror(“munmap”);

return(1); }

}

Программа принимает в качестве аргумента имя текстового файла и выводит содержимое этого файла на экран дисплея.

Достоинствами системного вызова mmap можно назвать то, что при его использовании не требуется дополнительное копирования, выполняемое при вызове read и write, что процесс выполнения действий достигается путем прямой работы с ОП, что для поиска необходимых данных в отображении необходимо просто манипулировать указателем, а действия по позиционированию производить не требуется. Но отображение системного вызова mmap занимает целое число страниц, в памяти оно не должно выходить за пределы адресного пространства процесса, а манипулирование отображения в памяти требует определенной затраты ядра ОС.

Вызов синхронизации файла с отображением

#include <sys/mman.h>

int msync(void *addr, size_t len, int flags);

Где flags может иметь следующие значения:

MS_ASYNC – т.е. асинхронно (изначально вызывается завершение, а потом ОС завершает запись)

MS_INVALIDATE – указывает, что все кэшированные ранее копии отображения аннулируются и синхронизируется текущее состояние данных

MS_SYNC – синхронизация выполняется синхронно

Сброс на диск всех изменений, внесенных в файл, отображается в память. В физический файл записывается или все содержимое области отображения, или участок области отображения. Синхронизация же производится, начиная с адреса addr, размером len, flags - флаги управления проведения синхронизации.

В случае успеха системный вызов msync возвращает значение 0. В случае ошибки – -1. Переменная errno может принимать следующие значения:

EINVAL – параметр flags включает оба значения, MS_SYNC и MS_ASYNC; установлен бит, отличный от трех допустимых флагов, или значение addr не выровнено по размеру страницы

ENOMEM – указанная область памяти (или ее часть) не входит в отображение

Каждый файл представляется структурой inode, которой присваивается адрес при помощи уникального для файловой системы числового значения, называемого номером inode (inode number). Inode — это и физический объект, находящийся на диске в Unix-подобной файловой системе, и концептуальная сущность, представляемая структурой данных в ядре Linux. В inode хранятся метаданные (metadata), связанные с файлом, такие, как разрешения на доступ к файлу, временная отметка, указывающая время последнего доступа к файлу, владелец, группа и размер файла, а также местоположение данных файла.

Далее приведены системные вызовы для получения значений метаданных файла:

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

int stat(const char *path, struct stat *buf);

int fstst(int fd, struct stat *buf);

int lstat(const char *path, struct stat *buf);

Где параметр path – это полный путь к файлу, а fd – открытый файловый дескриптор.

Следует заметить, что системный вызов lstat отличается от stat тем, что он позволяет получить информацию о файле типа символьная ссылка.

При успешном завершении вызовов возвращается 0 и в структуру stat (рассмотренную ниже) помещаются метаданные, а при ошибке возвращается значение -1 и устанавливаются коды ошибок.

struct stat

{

  1. dev_t st_dev; //устройство, на котором хранится файл

  2. ino_t st_ino; //номер inode (индексного дескриптора)

  3. mode_t st_mode; //режимы использования файла

  4. nlink_t st_nlink; //число жестких ссылок

  5. uid_t st_uid; //идентификатор пользователя владельца

  6. gid_t st_gid; //идентификатор группы владельца

  7. dev_t st_rdev; //если этот файл – устройство, то описано устройство, которое файл представляет

  8. off_t st_size; //размер файла в байтах

  9. blksize_t st_blksize; //размер блока для эффективной реализации ввода/вывода

  10. blkcnt_ st_blocks; //число блоков физической файловой системы, которое

занимает файл

  1. time_t st_atime; //время последнего доступа к файлу

  2. time_t st_mtime; //время последней модификации метаданных файла

  3. time_t st_ctime; //время последней изменения файла

}

В случае успеха все три вызова возвращают значение 0 и записывают мета­данные файла в предоставленную им структуру stat. В случае ошибки они воз­вращают -1 и присваивают переменной errno одно из следующих значений:

EACCESS – у вызывающего процесса отсутствуют разрешения на поиск для одного из каталогов в пути path (только для функций stat () и lstat ()).

EBADF – недопустимое значение fd (только для функции fstat()).

EFAULT – параметр path или buf содержит недопустимый указатель.

ELOOP – параметр path включает слишком много символических ссылок (только для функций stat() и Istat()).

ENAMETOOLONG – слишком длинное значение параметра path (только для функций stat() и Istat()).

ENOENT – компонент пути path не существует (только для функций stat() и Istat()).

ENOMEM – недостаточно памяти для выполнения данного запроса.

ENOTDIR – компонент пути path не является каталогом (только для функций stat() и Istat()).

Использование вызовов для получения значений метаданных файла:

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

static short o_ar[9]={0400,0200,0100,0040,0020,0010,0004,0002,0001}

static char perms[10]= “rwxrwxrwx”

int filedata(const char *pathname)

{

struct stat statbuf;

char d[10];

int j;

if (stat(pathname,&statbuf)==-1)

{ printf(“Ошибка stat %s\n”,pathname);

return(-1); }

for (j=0; j<9; j++)

{ if (statbuf.st_mode & o_ar[j]) d[j]=perms[j];

else d[j]=’-1’; }

d[9]=’\0’;

printf(“файл %s : \n”, pathname);

printf(“размер %ld байт \n”,statbuf.st_size);

printf(“User_id %d, Group_id %d\n”,statbuf.st_uid,statbuf.st_gid);

printf(“Права доступа: %s\n”,d);

return(0);

}

st_mode может принимать значения:

S_ISDIR - каталог

S_ISCHR - символьное устройство

S_ISBLK – блочное устройство

S_ISREG – простой файл

S_ISFIFO - канал

S_ISLINK – ссылка

S_ISSOCK – сокет

Есть системные вызовы, которые позволяют изменить права доступа к файлу:

#include <sys/types.h>

#include <sys/stat.h>

int chmod(const char *path, mode_t mode);

int fcmod(int fd, mode_t mode);

Пример такого вызова: chmod(“./text1.t”,S_TRUSR|S_IWUSR)

Оба вызова chmod() и fchmod() устанавливают для файла разрешения, указан­ные при помощи параметра mode. В вызове chmod() параметр path содержит отно­сительный или абсолютный путь к модифицируемому файлу. Для вызова fсhmod() файл указывается при помощи дескриптора fd.

Допустимые значения параметра mode, представляемого непрозрачным целочисленным типом mode_t, те же, что и значения, возвращаемые в поле st_mode структуры stat. Хотя это простые целочисленные значения, они могут иметь разный смысл в разных реализациях Unix. Для форми­рования допустимых значений параметра mode эти константы можно объединять между собой операцией двоичного ИЛИ. Например. (S_IRUSR | S_IRGRP) устанавливает для файла разрешения, предоставляющие возможность чтения файла его владельцу и группе.

Чтобы иметь возможность изменить разрешения файла, действительный идентификатор процесса, вызывающего chmod() или fchmod(), должен совпадать с идентификатором владельца файла или же процесс должен обладать характе­ристикой CAP_F0WNER.

В случае успеха оба вызова возвращают значение 0. В случае ошибки оба воз­вращают -1 и присваивают переменной errno один из следующих кодов ошибки:

EACCESS – у вызывающего процесса нет разрешений на поиск для компонента пути path (только для chmod()).

EBADF – недопустимый дескриптор файла fd (только для fchmod()).

EFAULT – параметр path содержит недопустимый указатель (только для chmod()).

EIO – в файловой системе произошла внутренняя ошибка ввода-вывода. Это очень плохая ситуация, которая может указывать на повреждение диска или файловой системы.

ELOOP – во время разрешения пути path ядро встретило слишком много символиче­ских ссылок (только для chmod()).

ENAMETOOLONG – слишком длинное значение параметра path (только для chmod()).

ENOENT – путь path не существует (только для параметра chmod().

ENOMEM – недостаточно памяти для выполнения данного запроса.

ENOTDIR – компонент пути path не является каталогом (только для chmod()).

EPERM – действительный идентификатор вызывающего процесса не соответствует владельцу файла, и у процесса отсутствует характеристика CAP_FOWNER.

EROFS – файл находится в файловой системе, доступной только для чтения.

В структуре stat в полях st_uid и st_gid хранятся владелец и группа файла со­ответственно. Три системных вызова позволяют пользователю менять эти два значения:

#include <sys/types.h>

#include <unistd.h>

int chown (const char *path, uid_t owner, gid_t group);

int lchown (const char *path, uid_t owner, gid_t group);

int fchown (int fd, uid_t owner, gid_t group): ,

Вызовы chown() и Ichown() определяют владение файлом, указанным при по­мощи пути в параметре path. Они работают одинаково для всех файлов, за исключением символических ссылок.

В случае успеха все три вызова делают владельцем файла пользователя owner, группой файла группу group и возвращают значение 0. Если параметр owner или group равен -1, то соответствующее значение не устанавливается. Только процесс, владеющий характеристикой CAP_CH0WN (обычно это процесс, принадлежащий пользователю root), может менять владельца файла. Владелец файла может сменить группу файла на любую другую, членом которой он явля­ется; процессы с характеристикой CAP_CH0WN имеют право менять группу файла на любое другое значение.

В случае ошибки вызовы возвращают -1 и присваивают переменной errno одно из следующих значений:

EACCESS – у вызывающего процесса отсутствуют разрешения на поиск для компонента пути path (только для chown() и Ichown()).

EBADF – недопустимое значение fd (только для fchown()).

EFAULT – недопустимое значение path (только для chown() и Ichown()).

EIO – внутренняя ошибка ввода-вывода.

ELOOP – во время разрешения пути path ядро встретило слишком много символиче­ских ссылок (только для chown() и Ichown()).

ENAMETOOLONG – слишком длинное значение path (только для chown() и Ichown()).

ENOENT – файл не существует.

ENOMEM – недостаточно памяти для выполнения данного запроса.

ENOTDIR – компонент пути path не является каталогом (только для chown() и lchown()).

EPERM – у вызывающего процесса отсутствуют необходимые права для изменения владельца или группы в соответствии с запросом.

EROFS – файловая система доступна только для чтения.