Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Богатырев А. Весь текст 1009.15 Kb

Хрестоматия по программированию на Си в Unix

Предыдущая страница Следующая страница
1 ... 41 42 43 44 45 46 47  48 49 50 51 52 53 54 ... 87
            lock.l_len    = (size_t) SIZE;

            if(fcntl(fd, F_SETLKW, &lock) <0)
                    perror("F_SETLKW");
            printf("\twrite:%s locked\n", myname);

            sprintf(buffer, "%s #%02d", myname, trial);
            printf ("\twrite:%s \"%s\"\n", myname, buffer);

            lseek (fd, (off_t) OFFSET, SEEK_SET);
            write (fd, buffer, SIZE);

            sleep (PAUSE);

            lock.l_type   = F_UNLCK;
            if(fcntl(fd, F_SETLKW, &lock) <0)
                    perror("F_SETLKW");

            printf("\twrite:%s unlocked\n", myname);

            trial++;
    }

    void readAccess(){
            flock_t lock;

            printf("Read:%s #%d\n", myname, trial);

            lock.l_type   = F_RDLCK;
            lock.l_whence = SEEK_SET;
            lock.l_start  = (off_t)  OFFSET;
            lock.l_len    = (size_t) SIZE;

            if(fcntl(fd, F_SETLKW, &lock) <0)
                    perror("F_SETLKW");
            printf("\tread:%s locked\n", myname);

            lseek(fd, (off_t) OFFSET, SEEK_SET);
            read (fd, buffer, SIZE);

            printf("\tcontents:%s \"%*.*s\"\n", myname, SIZE, SIZE, buffer);
            sleep (PAUSE);

            lock.l_type   = F_UNLCK;
            if(fcntl(fd, F_SETLKW, &lock) <0)
                    perror("F_SETLKW");

            printf("\tread:%s unlocked\n", myname);

            trial++;
    }

А. Богатырев, 1992-95                  - 244 -                              Си в UNIX

Исследуя выдачу этой программы, вы можете обнаружить, что READ-области могут перекры-
ваться;  но  что никогда не перекрываются области READ и WRITE ни в какой комбинации.
Если идет чтение процессом A - то запись процессом B дождется разблокировки A (чтение
-  не  будет  дожидаться).   Если идет запись процессом A - то и чтение процессом B и
запись процессом B дождутся разблокировки A.

6.9.2.
UNIX SVR4 имеет еще один интерфейс для блокировки файлов: функцию lockf.

    #include 

    int lockf(int fd, int operation, size_t size);

Операция operation:
F_ULOCK
     Разблокировать указанный сегмент файла (это может  снимать  один  или  несколько
     замков).
F_LOCK
F_TLOCK
     Установить замок. При этом,  если  уже  имеется  чужой  замок  на  запрашиваемую
     область, F_LOCK блокирует процесс, F_TLOCK - просто выдает ошибку (функция возв-
     ращает -1, errno устанавливается в EAGAIN).
-    Ожидание отпирания/запирания замка может быть прервано сигналом.
-    Замок устанавливается следующим образом: от текущей  позиции  указателя  чтения-
     записи  в  файле fd (что не похоже на fcntl, где позиция задается явно как пара-
     метр в структуре); длиной size. Отрицательное значение size означает  отсчет  от
     текущей  позиции к началу файла. Нулевое значение - означает "от текущей позиции
     до конца файла".  При этом "конец файла" понимается именно как конец, а  не  как
     текущий  размер  файла.   Если  файл  изменит размер, запертая область все равно
     будет простираться до конца файла (уже нового).
-    Замки, установленные процессом, автоматически  отпираются  при  завершении  про-
     цесса.
F_TEST
     Проверить наличие замка.  Функция возвращает 0, если замка нет; -1  в  противном
     случае (заперто).
Если устанавливается замок, перекрывающийся с уже установленным, то  замки  объединя-
ются.

    было:     ___________#######____######__________

    запрошено:______________##########______________

    стало:    ___________#################__________

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

    было:     ___________#################__________

    запрошено:______________XXXXXXXXXX______________

    стало:    ___________###__________####__________

6.10.  Файлы устройств.
     Пространство дисковой памяти может состоять из  нескольких  файловых  систем  (в
дальнейшем  FS),  т.е.  логических  и/или физических дисков.  Каждая файловая система
имеет древовидную логическую структуру (каталоги, подкаталоги и файлы) и  имеет  свой
корневой  каталог.  Файлы  в каждой FS имеют свои собственные I-узлы и собственную их
нумерацию с 1.  В начале каждой FS зарезервированы:

А. Богатырев, 1992-95                  - 245 -                              Си в UNIX

-    блок для загрузчика - программы, вызываемой аппаратно при включении машины (заг-
     рузчик  записывает  с диска в память машины программу /boot, которая в свою оче-
     редь загружает в память ядро /unix);
-    суперблок - блок заголовка файловой системы, хранящий размер файловой системы (в
     блоках),  размер  блока (512, 1024, ...), количество I-узлов, начало списка сво-
     бодных блоков, и другие сведения об FS;
-    некоторая непрерывная область диска для хранения I-узлов  - "I-файл".

Файловые системы объединяются в единую древовидную иерархию операцией монтирования  -
подключения  корня  файловой системы к какому-то из каталогов-"листьев" дерева другой
FS.
     Файлы в объединенной иерархии адресуются при помощи двух способов:
-    имен, задающих путь в дереве каталогов:

          /usr/abs/bin/hackIt
          bin/hackIt
          ./../../bin/vi

     (этот способ предназначен для программ, пользующихся файлами, а также  пользова-
     телей);
-    внутренних адресов, используемых программами ядра и некоторыми системными  прог-
     раммами.

Поскольку в каждой FS имеется собственная нумерация I-узлов, то файл  в  объединенной
иерархии должен адресоваться ДВУМЯ параметрами:
-    номером (кодом) устройства, содержащего файловую систему,  в  которой  находится
     искомый файл: dev_t i_dev;
-    номером I-узла файла в этой файловой системе: ino_t i_number;

Преобразование имени файла в объединенной файловой иерархии в  такую   адресную  пару
выполняет  в  ядре уже упоминавшаяся выше функция namei (при помощи просмотра катало-
гов):

    struct inode *ip = namei(...);

Создаваемая ею копия I-узла в памяти ядра содержит поля i_dev и i_number (которые  на
самом диске не хранятся!).
     Рассмотрим некоторые алгоритмы работы ядра с файлами.  Ниже они приведены  чисто
схематично  и  в  сильном  упрощении.  Форматы вызова (и оформление) функций не соот-
ветствуют форматам, используемым на самом деле в ядре; верны лишь  названия  функций.
Опущены  проверки  на  корректность, подсчет ссылок на структуры file и inode, блоки-
ровка I-узлов и кэш-буферов от одновременного доступа, и многое другое.
     Пусть мы хотим открыть файл для чтения и прочитать из него некоторую информацию.
Вызовы открытия и закрытия файла имеют схему (часть ее будет объяснена позже):

    #include 
    #include 
    #include 
    int fd_read = open(имяФайла, O_RDONLY){

      int fd; struct inode *ip; struct file *fp; dev_t dev;

      u_error = 0;    /* errno в программе */
    // Найти файл по имени. Создается копия I-узла в памяти:
      ip = namei(имяФайла, LOOKUP);
    // namei может выдать ошибку, если нет такого файла
      if(u_error) return(-1);  // ошибка

    // Выделяется структура "открытый файл":
      fp = falloc(ip, FREAD);
      // fp->f_flag = FREAD; открыт на чтение

А. Богатырев, 1992-95                  - 246 -                              Си в UNIX

      // fp->f_offset = 0;   RWptr
      // fp->f_inode  = ip;  ссылка на I-узел

    // Выделить новый дескриптор
      for(fd=0; fd < NOFILE; fd++)
         if(u_ofile[fd] == NULL ) // свободен
             goto done;
      u_error = EMFILE; return (-1);
    done:
      u_ofile[fd] = fp;

    // Если это устройство - инициализировать его.
    // Это функция openi(ip, fp->f_flag);
      dev = ip->i_rdev;
      if((ip->i_mode & IFMT) == IFCHR)
        (*cdevsw[major(dev)].d_open)(minor(dev),fp->f_flag);
      else if((ip->i_mode & IFMT) == IFBLK)
        (*bdevsw[major(dev)].d_open)(minor(dev),fp->f_flag);
      return fd;  // через u_rval1
    }

    close(fd){
      struct file  *fp = u_ofile[fd];
      struct inode *ip = fp->f_inode;
      dev_t dev = ip->i_rdev;

      if((ip->i_mode & IFMT) == IFCHR)
        (*cdevsw[major(dev)].d_close)(minor(dev),fp->f_flag);
      else if((ip->i_mode & IFMT) == IFBLK)
        (*bdevsw[major(dev)].d_close)(minor(dev),fp->f_flag);

      u_ofile[fd] = NULL;
      // и удалить ненужные структуры из ядра.
    }

Теперь рассмотрим функцию преобразования логических блоков файла в номера  физических
блоков в файловой системе. Для этого преобразования в I-узле файла содержится таблица
адресов блоков. Она устроена довольно сложно - ее начало находится в узле, а  продол-
жение  - в нескольких блоках в самой файловой системе (устройство это можно увидеть в
примере "Фрагментированность файловой системы" в приложении).  Мы для простоты  будем
предполагать,  что  это  просто линейный массив i_addr[], в котором n-ому логическому
блоку файла отвечает bno-тый физический блок файловой системы:

    bno = ip->i_addr[n];

Если файл является интерфейсом устройства, то этот файл не хранит информации в  логи-
ческой  файловой  системе.   Поэтому  у  устройств нет таблицы адресов блоков. Вместо
этого, поле i_addr[0] используется для хранения кода устройства, к которому  приводит
этот специальный файл. Это поле носит название i_rdev, т.е. как бы сделано

    #define i_rdev i_addr[0]

(на самом деле используется union).  Устройства бывают байто-ориентированные, обмен с
которыми  производится  по одному байту (как с терминалом или с коммуникационным пор-
том); и блочно-ориентированные, обмен с которыми возможен только большими порциями  -
блоками  (пример  -  диск).   То,  что файл является устройством, помечено в поле тип
файла

    ip->i_mode & IFMT

А. Богатырев, 1992-95                  - 247 -                              Си в UNIX

одним из значений: IFCHR - байтовое; или IFBLK - блочное.  Алгоритм вычисления номера
блока:

    ushort u_pboff;  // смещение от начала блока
    ushort u_pbsize; // сколько байт надо использовать
    // ushort  - это unsigned short, смотри 
    // daddr_t - это long (disk address)

    daddr_t bmap(struct inode *ip,
                 off_t offset, unsigned count){
      int sz, rem;

      // вычислить логический номер блока по позиции RWptr.
      // BSIZE - это размер блока файловой системы,
      // эта константа определена в 
      daddr_t bno = offset / BSIZE;
      // если BSIZE == 1 Кб, то можно offset >> 10

          u_pboff = offset % BSIZE;
          // это можно записать как offset & 01777

          sz = BSIZE - u_pboff;
          // столько байт надо взять из этого блока,
          // начиная с позиции u_pboff.

          if(count < sz) sz = count;
          u_pbsize = sz;

Если файл представляет собой устройство, то трансляция логических блоков в физические
не  производится - устройство представляет собой "сырой" диск без файлов и каталогов,
т.е. обращение происходит сразу по физическому номеру блока:

          if((ip->i_mode & IFMT) == IFBLK) // block device
             return bno;       // raw disk
          // иначе провести пересчет:

          rem = ip->i_size /*длина файла*/ - offset;
          // это остаток файла.
          if( rem < 0 )  rem = 0;
          // файл короче, чем заказано нами:
          if( rem < sz ) sz = rem;
          if((u_pbsize = sz) == 0) return (-1); // EOF

          // и, собственно, замена логич. номера на физич.
          return ip->i_addr[bno];
    }

Теперь рассмотрим алгоритм read. Параметры, начинающиеся с u_..., на самом деле пере-
даются как статические через вспомогательные переменные в u-area процесса.

    read(int fd, char *u_base, unsigned u_count){
        unsigned srccount = u_count;
        struct   file  *fp = u_ofile[fd];
Предыдущая страница Следующая страница
1 ... 41 42 43 44 45 46 47  48 49 50 51 52 53 54 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама