Category Archives: Linux/Unix

Лёд тронулся!

Written by elwood

Недавно я наткнулся на проблему с рендерингом console framework в стандартном эмуляторе терминала для KDE – Konsole. Проблема заключалась в том, что при перемещении окошек влево в терминале с шириной, равной или меньше ширины буфера экрана, справа от окна появлялись артефакты:

До этого я тестировал в других эмуляторах терминала (gnome-terminal, xterm, putty), и таких проблем не возникало никогда. После некоторых исследований стало ясно, что это бага в самом Konsole. Я был очень удивлён и не питал особых надежд на то, что такой баг можно легко воспроизвести, а тем более убедить мейнтейнеров проекта. Во всяком случае прикладывать к багрепорту аттач с программой на моно, которая внутри неочевидно (для мейнтейнеров) работает, имело бы мало смысла. Поэтому я решил попробовать сделать тестовую программу на чистом Си, минимального размера, но чтобы проблема была наглядно продемонстрирована. И это получилось ! Текст программы можно посмотреть в описании бага. Демонстрация проблемы была наглядна:

После этого я попросил в конференции гентоводов проверить, воспроизводится ли проблема у них. Пользователи Gentoo устанавливают одни из самых последних билдов программ, поэтому проверка у них – это важно. Оказалось, что баг действительно воспроизводится. Прошла неделя, я потихоньку уже сам стал разбираться в исходниках Konsole, научился собирать из исходников, логировать данные в момент обновления экрана, и вот сегодня – баг получил статус CONFIRMED, а значит, и некоторый шанс на то, что им кроме меня кто-то займётся.

Расширяем терминологию

Written by elwood

На работе коллега Тимур Шакуров придумал шикарнейшее словечко ПРОКАСТ для обозначения всяких длинных полумагических команд наподобие следующей:

<@insomnia> Нужно выполнить всего три команды, чтобы поставить Gentoo
<@insomnia> cfdisk /dev/hda && mkfs.xfs /dev/hda1 && mount /dev/hda1 /mnt/gentoo/ && chroot /mnt/gentoo/ && env-update && . /etc/profile && emerge sync && cd /usr/portage && scripts/bootsrap.sh && emerge system && emerge vim && vi /etc/fstab && emerge gentoo-dev-sources && cd /usr/src/linux && make menuconfig && make install modules_install && emerge gnome mozilla-firefox openoffice && emerge grub && cp /boot/grub/grub.conf.sample /boot/grub/grub.conf && vi /boot/grub/grub.conf && grub && init 6
<@insomnia> это первая

Для тех, кто не в курсе, что такое ПРОКАСТ:

Нашёл баг в Mono

Written by elwood

На днях простудился, и пока сидел дома, вспомнил о своей библиотеке для создания консольных окошек в псевдографике. Одна из самых важных задач в её разработке – сделать её совместимой с Linux, потому как в Windows такого рода инструменты в принципе мало кому могут пригодиться. И чтобы она работала под Linux в Mono, я в своё время потратил немало времени. Научил её выводить в терминал псевдографику (сейчас для этого используется ncurses, но только как буфер для вывода), потом разобрался с тем, как обрабатывать пользовательский ввод (для этого я попробовал LibTermKey, и мне понравилось). Кстати, особенности реализации event-driven модели для консольного ввода я уже описывал в заметке об eventfd.

А в этот раз я исследовал проблему того, что после выхода из программы у терминала, из-под которого она запускалась (и gnome-terminal, и xterm), сбивались настройки, и в нём становилось невозможно работать до тех пор, пока пользователь не выполнял команду stty sane.

mono-bug

После локализации воспроизведения проблемы в отдельном консольном приложении выяснилось забавное. Если внутри блока работы с ncurses (между вызовами initscr() и endwin() ) выполнить один из read-методов консоли (Console.ReadLine(), Console.ReadKey()), то терминал убивается после выхода из приложения. Если же read-методы не вызывать вообще, то всё завершается корректно. Но если один из read-методов вызвать до инициализации ncurses, то всё тоже работает хорошо, и уже не важно, сколько раз и где после этого будут вызваны “опасные” read-методы. То есть, первый вызов read-методов в Mono Runtime имеет какие-то побочные эффекты, приводящие к таким последствиям.

// If uncomment next line - all will work OK
// May be first access to Console.ReadKey(Line) or Console.KeyAvailable
// has side effects and modifies current term settings
 
//bool x = Console.KeyAvailable;
 
IntPtr stdscr = initscr ();
cbreak ();
noecho ();
nonl ();
intrflush (stdscr, false);
keypad (stdscr, true);
start_color ();
mvaddstr (4, 5, "Test string!");
refresh ();
 
// If remove this line and dont call reading methods inside ncurses code -
// all will work OK. But after first call (if reading method called before ncurses init)
// we can call it safe.
Console.ReadLine (); // or Console.ReadKey()
 
endwin ();

Но ведь не будешь же вызывать Console.ReadKey() при старте приложения, прося пользователя нажать клавишу, чтобы всё у нас было хорошо 🙂 К счастью, оказалось достаточно обратиться к свойству Console.KeyAvailable, чтобы выполнить эту инициализацию “первого чтения”. Таким образом, проблема была побеждена малой кровью.

Однако, я всё-таки собрался с силами и оформил баг в багзилле Mono. Надеюсь, это поведение будет исправлено, или хотя бы документировано (если так оно и должно работать).