LINUX.ORG.RU

[pygtk] Как работает glib.io_add_watch?

 


0

1

Приветствую.

Захотел выводить содержимое лог-файлов по мере поступления данных в них. Решил использовать glib.io_add_watch(). Вот что получилось:

class LogBuffer(gtk.TextBuffer):
    def __init__(self):
        super(LogBuffer, self).__init__()

    def load_file(self, filename):
        self.delete(self.get_start_iter(), self.get_end_iter())
        fd = open(filename, 'rb')
        iter = self.get_start_iter()
        for i in fd:
            self.insert(iter, i)
        glib.io_add_watch(fd, glib.IO_IN, self.__on_file_change)

    def __on_file_change(self, fd, condition):
        iter = self.get_end_iter()
        for i in fd:
            self.insert(iter, i)
        return True
Засунул буфер в TextView, скормил ему /var/log/messages. При запуске постоянно дергается __on_file_change(), но данных для чтения само-собой нет. Причем дергается до такой степени постоянно, что даже интерфейс не перерисовывается.

Что за фигня?

★★★★★

>Как работает glib.io_add_watch?

Создается GSource, соответсвующий файловый дескриптор добавляется в вектор просматриваемых дескрипторов, на каждой итерации GMainLoop'а на все дескрипторы делается блокирующий (емнип) poll(), для просигналенных дескрипторов потом из (GSource->dispatch) вызывается юзерский коллбек.

yoghurt ★★★★★
()

замени на return False в __on_file_change. иначе событие не уберется, и будет постоянно висеть, требуя внимания.

ananas ★★★★★
()
Ответ на: комментарий от yoghurt

Извини, неправильно выразился: как работать с glib.io_add_watch?

fat_angel ★★★★★
() автор топика
Ответ на: комментарий от ananas

>замени на return False

Так ведь мне как раз и надо, чтоб он постоянно за файлом следил и сигналил в случае поступления новых данных для чтения.

fat_angel ★★★★★
() автор топика
Ответ на: комментарий от yoghurt

>И, да, кажется тебе нужен GFileMonitor

Похоже на то…

fat_angel ★★★★★
() автор топика
Ответ на: комментарий от fat_angel

http://www.gtk.org/api/2.6/glib/glib-IO-Channels.html#GIOFunc

Returns: the function should return FALSE if the event source should be removed.

Фишка в том, что если возвращать тру, один и тот же ивент будет оставаться в очереди и сигналить. Вернёшь фолс - текущий ивент удалится, а новые так и будут мониториться (как раз случай новых данных для чтения).

Но GFileMonitor лучше, ибо в линаксовой ипостаси оно юзает inotify и вообще больше инфы сообщает

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

> Но GFileMonitor лучше, ибо в линаксовой ипостаси оно юзает inotify и вообще больше инфы сообщает

для уже открытого файла GFileMonitor - не решение.

ananas ★★★★★
()
Ответ на: комментарий от yoghurt

>Вернёшь фолс - текущий ивент удалится, а новые так и будут мониториться

Поменял на False. Теперь, как я и предполагал, он вообще не реагирует на изменения в файле (проверялось на пробном файле, которому скармливались строки через echo).

Сейчас буду мучать GFileMonitor, хотя тащить в свою поделку GIO ох как не хочется.

fat_angel ★★★★★
() автор топика
Ответ на: комментарий от yoghurt

Фишка в том, что если возвращать тру, один и тот же ивент будет оставаться в очереди и сигналить.

Чушь.

Вернёшь фолс - текущий ивент удалится, а новые так и будут мониториться (как раз случай новых данных для чтения).

Читника референца.

baverman ★★★
()

Вот кусок и snaked'овской консоли, которая мониторит вывод запущенного процесса:

def unblock_fd(fd):
    import fcntl, os
    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

def consume_output(editor, proc, on_finish):
    console = get_console_widget(editor)
    buf = console.view.get_buffer()
    buf.delete(*buf.get_bounds())
    unblock_fd(proc.stdout)
    unblock_fd(proc.stderr)

    # Подписываемся на мониторинг нужных дескрипторов
    glib.io_add_watch(proc.stdout, glib.IO_IN|glib.IO_ERR|glib.IO_HUP,
        consume_io, editor, console, proc, on_finish)
    glib.io_add_watch(proc.stderr, glib.IO_IN|glib.IO_ERR|glib.IO_HUP,
        consume_io, editor, console, proc, on_finish)

def consume_io(f, cond, editor, console, proc, on_finish):
    if isinstance(f, int):
        data = os.read(f, 1024)
    else:
        data = f.read()

    if data:
        buf = console.view.get_buffer()
        iter = buf.get_bounds()[1]
        buf.insert(iter, data)
        buf.place_cursor(buf.get_bounds()[1])
        console.view.scroll_mark_onscreen(buf.get_insert())

    if proc.poll() is not None:
        if not getattr(proc, 'consume_done', False):
            proc.consume_done = True
            if pty_master[0] == f:
                pty_master[0] = None
            on_finish()
        # Процесс отработал, поэтому возвращаем False, чтобы
        # остановить мониторинг
        return False 

    # Возвращаем True, чтобы продолжить мониторинг
    return True

baverman ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.