festin писал(а): ↑03.09.2009 16:29
Есть у меня пара показателей в статусбаре, которые работают подобным образом:
Код: Выделить всё
cmd_string = '/usr/local/bin/mocp -i | iconv -c -f utf-8 -t koi8-r'
local moc = io.popen(cmd_string, "r")
дальше все парсится и выводится.
Проблема в том, что иногда (сильно размыто, иногда раз в 5-7 секунд) выводится, что-нибудь вроде "(null)" или "disconnected". Это значит, что из потока прочитано nil.
Если команду, вывод которой парсит скрипт, многократно выполнять в консоли - никаких проблем нет.
В чем может быть причина "пустого вывода"?
Состояние программ при этом не меняется (плеер играет, соединения висят как надо).
Тоже наткнулись на эту проблему? В общем, причина такая.
Вы заметили у функций ввода-вывода в POSIX (read(), write(), ...) одну из возможных ошибок - EINTR, "Прервано сигналом"? При использовании этих функций, программа, получившая эту ошибку, просто делает ещё одну попытку чтения/записи. А теперь прочитайте описание функций ввода-вывода в C99 (scanf(), printf(), ...). Видите надпись о том, что в случае _любой_ ошибки дескриптор переводится в состояние ferror(), и даже после clearerr() состояние потока неопределено? Так вот, ошибка EINTR - не исключение. Поэтому, использование в одной программе сигналов и описанных в C99 функций ввода-вывода запрещено, вместо них нужно использовать функции ввода-вывода POSIX.
Lua, согласно их политике, не должен зависеть от ОС, а значит, должен использовать только функции, описанные в C99. Именно через них реализована и библиотека ввода-вывода в Lua. Как следствие, функции ввода-вывода Lua нельзя использовать в программе, использующей сигналы. Ion использует сигналы для реализации таймеров в статусбаре. Отсюда и проблемы - если сигнал срабатывает во время полученя данных от mocp, канал переходит в состояние ошибки, и дальнейшее чтение из него невозможно. Даже если сбросить ошибку (не уверен, что это реализовано в Lua), часть данных пропадёт.
Есть следующие решения проблемы.
1) Во всех таймерах сделать период обновления как можно более длительным, чтобы сигналы посылались как можно реже. Разумеется, это неудобно, т.к. это означает очень редкое обновление статусбара. Но это самое простое решение.
2) Не использовать ввод-вывод. Сделает невозможным отображение статуса moc.
3) При чтении ответа от mocp, определять, получен ли он полностью, и если нет, закрывать канал и вызывать io.popen() заново. При слишком частых сигналах таймера может приводить к подвисанию статусбара (т.к. никто не гарантирует, что сигнал не прервёт и следующую попытку, и идущую за следующей, и т.д.)
4) Переписать Ion3 так, чтобы он реализовывал таймеры каким-то другим способом, без сигналов. Бррр. Я пас.
5) Переписать библиотеку ввода-вывода Lua так, чтобы она использовала функции POSIX. Мой случай. Разумеется, в апстрим мои исправления не приняли (см. выше о политике Lua), но, если хотите, могу выложить здесь патч.