У меня проблема с использованием монитора io_add_watch
в python (через gobject). Я хочу сделать неблокирующее чтение всего буфера после каждого уведомления. Вот код (сокращенный немного):gobject io monitoring + nonblocking reads
class SomeApp(object):
def __init__(self):
# some other init that does a lot of stderr debug writes
fl = fcntl.fcntl(0, fcntl.F_GETFL, 0)
fcntl.fcntl(0, fcntl.F_SETFL, fl | os.O_NONBLOCK)
print "hooked", gobject.io_add_watch(0, gobject.IO_IN | gobject.IO_PRI, self.got_message, [""])
self.app = gobject.MainLoop()
def run(self):
print "ready"
self.app.run()
def got_message(self, fd, condition, data):
print "reading now"
data[0] += os.read(0, 1024)
print "got something", fd, condition, data
return True
gobject.threads_init()
SomeApp().run()
Вот трюк - когда я запустить программу без отладочного активированного, я не получаю got_message
звонков. Когда я пишу много материала для stderr, проблема исчезает. Если я не пишу ничего кроме отпечатков, видимых в этом коде, я не получаю сигналы stdin messsage. Еще одна интересная вещь заключается в том, что когда я пытаюсь запустить одно и то же приложение с отладкой stderr, но через strace
(чтобы проверить, есть ли какие-либо вызовы fcntl/ioctl, которые я пропустил), проблема появляется снова.
Итак, вкратце: если я пишу много для stderr первым без strace, io_watch
работ. Если я пишу много с strace, или вообще не пишу, io_watch
не работает.
Часть «некоторые другие функции» занимает некоторое время, поэтому, если я наберу текст до того, как увижу вывод «подключен 2», а затем нажмите «ctrl + c» после «ready», вызывается обратный вызов get_message
, но read call выбрасывает EAGAIN, поэтому буфер кажется пустым.
журнал Strace связан с стандартного ввода:
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
fcntl(0, F_GETFL) = 0xa002 (flags O_RDWR|O_ASYNC|O_LARGEFILE)
fcntl(0, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC|O_LARGEFILE) = 0
fcntl(0, F_GETFL) = 0xa802 (flags O_RDWR|O_NONBLOCK|O_ASYNC|O_LARGEFILE)
Кто-нибудь есть какие-то идеи о том, что происходит здесь?
EDIT: Еще одна подсказка. Я попытался реорганизовать приложение, чтобы сделать чтение в другом потоке и передать его обратно через канал. Это «вид» работает:
...
rpipe, wpipe = os.pipe()
stopped = threading.Event()
self.stdreader = threading.Thread(name = "reader", target = self.std_read_loop, args = (wpipe, stopped))
self.stdreader.start()
new_data = ""
print "hooked", gobject.io_add_watch(rpipe, gobject.IO_IN | gobject.IO_PRI, self.got_message, [new_data])
def std_read_loop(self, wpipe, stop_event):
while True:
try:
new_data = os.read(0, 1024)
while len(new_data) > 0:
l = os.write(wpipe, new_data)
new_data = new_data[l:]
except OSError, e:
if stop_event.isSet():
break
time.sleep(0.1)
...
Удивительно, что, если я просто поставить один и тот же текст в новой трубе, все начинает работать. Проблема заключается в том, что:
- первая строка не «заметил» на всех - я получаю только второй и последующие строки
- это Fugly
Может быть, даст кому-то еще ключ на почему это происходит?
Он возвращает True в реальном коде. Неважно, если это не называется, это вообще не называется - даже один раз. – viraptor