Skip to content

Instantly share code, notes, and snippets.

@siviae
Created March 12, 2014 15:41
Show Gist options
  • Save siviae/9509433 to your computer and use it in GitHub Desktop.
Save siviae/9509433 to your computer and use it in GitHub Desktop.
OS lecture summary
Ян. Лекция 3.
План:
1. память -> mmap, fork
2. -> vfs - virtual file system (упрощённая семантика read, write)
__________________________
Process r = (r,mmn)~>Context (secure process)
r - регистр
mmn - таблица маппинга из виртуальных адресов в физические
Хотим чтобы для каждого процесса mmn был свой. pid (!-> - функция с явным конечным представлением)!-> ProcInfo
ProcInfo = record{
mmu::VMA //
pid::pid_t
...
}
MMU - memory management unit
Context = record {
tag: SysCallTag,
args: Args(tag),
continuation: Process(Res(tag))
}
что такое ядро?
по сути, цикл while, у которого есть список процессов, которые нужно запустить и оно их по очереди дёргает.
//todo почитать исходник с первой лекции, который Ян присылал
как реализовать mmap?
kvma - kernel virtual memory ?
mmu - просто функция в духе "если страница закеширована - смапить, иначе закешировать и смапить"
эффективно реализуется деревом отрезков
когда производим mmap - он делается лениво(ставит пометку, чтобы маппинг произошёл при первом обращении)
Файловые системы
Они хранят описание файлов в виде
inode{
type
...
поля, зависящие от типа
size
atime
ctime(creation)
mtime(modification)
size_in_blocks
body :: set<block>, block - номер блока на диске
et cetera
}
эта информация для xfs.., ntfs и прочих юниксовых. в FAT всё по другому
type = enum {
f/file/r, //common,regular file
d/directory, // таблица из двух полей: имя и inode. Таким образом, директория просто отображает имена файлов в inode других файлов
L/symlink, //ссылка, в виде строки пути к файлу. обработка происходит таким образом: есть путь, состоящий из директорий. мы прыгаем
по симлинкам в пути можно проходить по дефолту 7 раз
c //character device - можно читать просто по символам
b // block device - имеют право не разрешать читать меньше, чем блоком.
fifo //именованный pipe - два файловых дескриптора, связанных номером в ядре - нужны, для реализации | .
Собственно | - это и есть пайп(труба).
Можно организовать, чтобы многие к этому пайпу подключались, а кто-то один читал
socket //наоборот, один пишет, все читают
}
каждый девайс нумеруется определённым номером, состоящим из двух интов: тип и номер. "номер шины и номер девайса на шине для старых систем"
где-то захардкожен путь корневой inode - и от него вся файловая система парсится.
Namespaces
идея - хотим монтировать одну директорию на другую (перевешивать поддерево).
mount(bdevFD::file_descriptor, path::String) - открывает файл как файловую систему и подвешивает её к директории по пути.
что делает ядро? просто нужно системе найти соответствующий драйвер для файловой системы, драйвер запускается, открывает девайс,
выдаёт наружу хэндл ФС с тем же интерфейсом, что и VFS: open/close/read/write.
что делать дальше?
как вариант - добавить тип inode fileSystem, и некоторые файловые системы это поддерживают, но ни одна операционка не реализовывает.
но в реальных юниксах делают namespace:
("путь", хэндл ФС , номер рутовой inode в fs).
если хотим open по монтированной системе - ищем нужный триплет из неймспейсе, открываем хэндл и дальше работаем с ним.
интересный спецэффект - если мы открыли файл в директории, а потом туда что-то примонтировали - мы без проблем продолжаем работать.
и вообще, любая операция будет продолжать работать, как будто мы ничего не примонтировали. (потому что ..)
у inode есть счётчик ссылок
nlinks - сколько директорий ссылаются на эту inode
ещё один список поддерживается ядром - сколько текущих открытых файловых дескрипторов указывает на эту inode. inode удаляются, когда оба списка - нули.
что такое файловый дескриптор? просто int с точки зрения процесса.
внутри procInfo -
таблица файловых дескрипторов pwd:: fdobj
fdtable:: int-> fdobj
fdobj = record {
type = сужение inode.type.values (f,d,l,pipe(получается из сокетов, фифо и прочая))
закэшированный(fs,
inodenumber)
}
с точки зрения процесса, файловый дескриптор - просто int, с точки зрения ядра - некий fdobj
У файлов есть !права(режимы записи/запуска и прочая). (в частности, в fdobj они записаны).
Есть указатель на текущую позицию считывания(offset). В директории - текущий элемент директории.
dup2(int,int);
Взять файловый дескриптор с первым номером и скопировать его во второй. После этого оба будут указывать на один fdobj.
Соответственно, меняется fdobj - меняются оба дескриптора.
fork целиком копирует всё, кроме (pid)
На самом деле fdtable:: int !-> (*fdobj, flags); flags только один - CLOSE_ON_EXEC
!!! Семантика read(fd, buffer, len); //запиши по адресу buffer не больше , чем len byte из соотв. ресурса.
read возвращает, сколько реально байтов было скопировано.
Если есть 1+ процесс, у которого есть ссылка на fdobj, который может писать в этот ресурс. Если на данный момент этот процесс не может ничего прочитать и больше есть ещё процессы, которые пишут в этот pipe, то процессы ждут, пока в пайп что-нибудь не запишут. Если же такий процессов нет, то всем процессорам, которые читают, получают eof.
если read вернёт 0 - то это eof.
Cемантика write(resource,buf,len);
res = write(resource,buf,len); - возвращает, сколько реально байт записалось в процессе ввыполнения функции
<0 - ошибки
=0 - тоже ошибки
pipe реализован как ring-буфер! то есть, конец как бы спаян с началом.
Файл - это буфер, про который считается, что в него никто не может писать?
Типа ДЗ: продумать
0. PLT OS - читаем исходник, выкидываем, пишем такой же сами, если не понимаем - repeat
1. MMU в PLT OS
2.как на самом деле реализована приостановка процессов на пайпе(read и write в ringbuffer) - как эту семантику реализовать
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment