У меня есть данные, хранящиеся в памяти, которые я хочу открыть. Я создаю временный файл и fork xdg-open
на ubuntu, чтобы открыть файл, используя стандартное приложение. Я хочу удалить временный файл после закрытия программы. Проблема в том, что сам xdg-open
открывает другой процесс и немедленно завершает работу. Следовательно, я не знаю, какой процесс открыл файл. Я попытался получить эксклюзивную блокировку с помощью flock
а также попытался unlink
файл после того, как я подождал 20 srcs (чтобы убедиться, что другой процесс сначала открывает файл), вызовы преуспевают, а открытая программа просто закрывает файл. Я хочу подождать, пока программа не будет закрыта, а затем удалите файл. Кто-нибудь знает, как это сделать?
Вы можете использовать либо inotify (см. man 7 inotify
), либо файловую аренду (см. man 2 fcntl
, Leases section), чтобы обнаружить, когда другие процессы открывают и закрывают файл (с помощью inotify), или определяют, открыт ли файл другими процессами (файл сдает в аренду).
Основная проблема заключается в том, что xdg-open
обычно является скриптом, который исследует среду (и, возможно, целевой файл), затем выполняет двоичный файл (который, в свою очередь, может проверить целевой файл и выполнить другой двоичный файл), и возможно, что один или больше этапов здесь вилка и немедленно выйти, при этом процесс клиента продолжает цепочку.
Это означает, что момент времени, когда system()
возвращает, в основном не имеет значения. Целевой файл может быть или не быть открыт потенциальным приложением в этой точке; мы просто не знаем и не знаем этого.
Один из вариантов - создать отдельную группу процессов (сеанс) и контролировать сеанс, сохраняя исходный файл до тех пор, пока существует группа процессов. Однако предполагается, что ни один из скриптов или двоичных файлов в цепочке xdg-open
создает свои собственные сеансы. (Я не знаю, делают ли они, существует так много различных реализаций - каждая среда рабочего стола использует свой собственный двоичный файл, а xdg-open
- это оболочка совместимости).
На практике это означало бы замену system()
вашей собственной реализацией с использованием fork()
, setsid()
, exec*()
и waitpid()
и waitid()
; последний в цикле с коротким сном для обнаружения, когда в группе процессов больше нет процессов.
Другой вариант - выполнить команду, затем (fork дочерний процесс) дождаться определенного периода - скажем, до тех пор, пока средний пользователь может терпеть дождаться загрузки файла; несколько секунд, другими словами -, затем начните проверку, все еще используется файл. После того, как файл больше не используется, он может быть отсоединен.
С помощью функции inotify()
вы должны назначить часы перед выполнением команды xdg-open
, а затем следить за тем, как открывается и закрывается. Поскольку возможно, что xdg-open
проверяет целевой файл на выбор приложения, вы не можете предположить, что первое закрытие является окончательным закрытием; вам также нужно дождаться определенного периода, указанного выше, чтобы убедиться, что приложение-открытая цепочка завершена. Затем, если столько закрытий, сколько было открыто, файл может быть отсоединен. В противном случае вы будете ждать оставшихся закрытий и отключите файл после последнего.
При аренде файлов метод немного проще, но также более ограничен. Вы можете получать только файлы в обычных файлах, принадлежащих самому пользователю. Вы можете получить аренду для чтения только в том случае, если файл не открыт для записи каким-либо процессом (включая другие дескрипторы этого же процесса). Вы можете получить аренду записи только в том случае, если файл вообще не открыт каким-либо процессом (включая другие дескрипторы файлов этим же процессом). В то время как вы держите аренду, любой другой процесс, открывающий файл (если вы держите аренду в лизинге) или пытаетесь его изменить (если вы держите на нем чтение или запись на нем), вызовет сигнал SIGIO
(по умолчанию, вы может изменить его на сигнал в реальном времени), который должен быть отправлен владельцу аренды. Он имеет до /proc/sys/fs/lease-break-time
секунд, чтобы понизить или отпустить аренду, пока ядро не сломает его принудительно; в течение этого времени модификатор openener/file будет заблокирован при вызове open()
/truncate()
.
Перед выполнением xdg-open
вы можете попытаться получить аренду записи в файле. Если это удастся, вы знаете, что это единственный дескриптор открытого файла. После xdg-open
аренда будет нарушена, когда файл будет открыт (или проверен одним из двоичных файлов); вы можете просто освободить аренду до звонка, чтобы избежать хлопот. По прошествии подходящего количества секунд после выполнения xdg-open
- количество времени, которое человек ожидал, когда приложение начнет открывать файл, - вы начинаете периодически проверять, открыт ли файл другим процессом пытаясь получить право на запись на него. Если листинг записи удался, и прошло достаточно времени, когда вы запустили xdg-open
, то вы знаете, что либо "пользователь-пользователь" стал бы слишком расстроен, чтобы ждать больше времени для открытия файла или приложения уже закрыл файл, и поэтому файл может быть отсоединен.
Все вышеперечисленное можно объединить, чтобы получить как параноик, как вы хотите, но лично я считаю, что подход, моделирующий поведение человека, является наиболее надежным. Я бы лично сделал ограничение по времени (и записывал интервал попытки аренды) легко настраиваемым, с примерно 10 секундами и 1 секундой по умолчанию, соответственно.
Наконец, если использование ресурсов вызывает беспокойство, я рекомендую написать отдельный вспомогательный двоичный файл, чтобы управлять этим для вас. В основном, вместо запуска xdg-open [OPTIONS] FILENAME
, вы запускаете /usr/lib/myapp/open DELAY INTERVAL [OPTIONS] FILENAME
. /usr/lib/myapp/open
двоичные вилки и немедленно выходят. Детский процесс выполняет xdg-open
и реализует описанную выше процедуру, чтобы дождаться, пока файл не будет отсоединен. Каждый из двоичных файлов /usr/lib/myapp/open
требует очень мало данных (минимальный размер резидентного набора) и ресурсов (они в основном спят), поэтому даже имея несколько десятков из них в памяти, не будет сильно стекать даже на встроенная машина Linux.
Если есть интерес, я мог бы добавить пример реализации C /usr/lib/myapp/open
здесь. (Просто дайте мне знать, какой из трех подходов наиболее интересен - мониторинг группы процессов, inotify или файл).
Когда xdg-open не полагается на суффикс, вы можете использовать
fd = open(filename, O_RDONLY|O_CLOEXEC);
unlink(filename);
system("xdg-open /proc/%u/fd/%u", getpid(), fd); /* pseudo-code! system is not printf() like! */
close(fd);
xdg-open
(или двоичный файл, который он вызывает для открытия файла) разветвляется для выполнения фактического приложения в дочернем процессе и завершает сам, вызов system()
может вернуться, и дескриптор закрывается (и, следовательно, исчезает) перед фактическим Приложение может попробовать открыть его. В зависимости от того, как реализован xdg-open
- обычно это скрипт, который выполняет двоичный файл, зависящий от среды рабочего стола, - это может работать или не работать.