WINE/Разработчику/ФайловыеБлокировки
Содержание
Файловые блокировки
На самом деле речь пойдёт о режимах разделения файлов с другими задачами.
Взаимодействие подсистем при замещении блокировок
http://download.etersoft.ru/pub/people/lav/www/LockWINE.png
Как я понимаю блокирование
Для Windows:
Если файл открыт на чтение, его могут блокировать все, также открывающие его на чтение. При попытке заблокировать на запись будет ошибка.
Если файл открыт на запись, заблокировать область можно только если она уже не заблокирована любым образом.
По-другому:
- Если мы читаем - не даём никому туда писать
- Если мы пишем - не даём никому туда писать и читать
Результаты тестов в Linux
На данный момент по результатам запуска тестовых программ, можно сделать следующие выводы:
- Установка блокировок в одном процессе ВСЕГДА успешна. Т.е. попытка повторно заблокировать область блокированную ранее в этом же процессе завершается успешно
- Блокировки НА ЧТЕНИЕ разрешено ставить многим процессам, если при этом не стоит блокировка на запись.
- Блокировки НА ЗАПИСЬ разрешено ставить только одному процессу. Соответственно если хоть один процесс создал блокировку на чтение, то попытка установить блокирование на запись будет НЕ удачной.
- Блокирование НА ЧТЕНИЕ возможно только если файл открыт на чтение или на чтение-запись
- Блокирование НА ЗАПИСЬ возможно только если файл открыт на запись или на чтение-запись
- При блокировании на чтение несколькими процессами F_GETLK возвращает pid первого заблокировавшего процесса. Если при этом первый процесс разблокировал занятую область, то F_GETLK будет возвращать pid следующего процесса и так пока все процессы установившие блокировку на чтение не снимут её.
Таблицы отображения режимов в блокировки файлов
#define LOCKOFFSET (0xffffffff - 10) ... memset (&lock, 0, sizeof(lock)); lock.l_type = F_WRLCK; rw = fcntl (fd, F_SETLK, &lock);
Для CreateFile:
offset | |
0 |
LOCKOFFSET +? |
FILE_SHARE_READ |
LOCKOFFSET + 1 |
FILE_SHARE_WRITE |
LOCKOFFSET +2 |
FILE_SHARE_DELETE |
LOCKOFFSET +4 |
Access |
offset |
0 |
LOCKOFFSET + ? |
GENERIC_READ (0x8...) |
LOCKOFFSET + 5 |
GENERIC_WRITE (0x4...) |
LOCKOFFSET + 6 |
unlink |
LOCKOFFSET + 7 |
Комментарий
По поводу значения LOCKOFFSET - старший бит знаковый, поэтому ?0xfffffff? Иначе не работает fcntl...
Возможные варианты реализации:
- Общий сервер для файловых операций (параллельно с локальным)
- Вспомогательный сервер файловых операций (к которому обращаются локальные сервера)
- Использование отображения в блокирование областей
- Хранить в файле (разделяемой памяти), ориентируясь по инодам
- Модуль ядра для этой синхронизации
- Патч к ядру для расширения функциональности
- Написать тестовую программу на SHARING (взять из WINE?) и проверить в Windows/WINE.
Этап |
generic |
sharemode |
|
1 |
GENERIC_READ |
0 |
failed все попытки CreateFile |
2 |
GENERIC_READ |
SHARE_READ |
failed все попытки CreateFile с GENERIC_WRITE и failed с GENERIC_READ если нет FILE_SHARE_READ |
3 |
GENERIC_READ |
SHARE_WRITE |
failed если нет FILE_SHARE_WRITE |
4 |
GENERIC_WRITE |
0 |
failed все попытки CreateFile |
5 |
GENERIC_WRITE |
SHARE_READ |
failed если нет FILE_SHARE_READ |
6 |
GENERIC_WRITE |
SHARE_WRITE |
failed если нет FILE_SHARE_WRITE |
- Написать реализацию отображения блокировок (в wineserver) и проверить в WINE тестовую программу
Блокировки должны наводиться с помощью LockFile. Для LockFile: Проверить, отображает ли WINE блокируемую область в ядро.
За проверку режима разделения файла отвечает check_sharing в файле wine/server/fd.c
- По возможности блокирование перенести в libwine из wineserver
Старое
- Проверить файловые блокировки в WINE
- Построить на них SHARING
- Другой процесс закроет файл - отразится ли у всех?