LINUX.ORG.RU

Алан Кокс больше не желает заниматься подсистемой TTY ядра Linux

 , , , ,


0

0

После довольно острой критики со стороны Линуса Торвальдса, Алан Кокс заявил, что не собирается больше работать над подсистемой TTY в Linux, так как сыт этим всем по горло.

Этому событию предшествовала очередная дискуссия «кривой userspace vs. кривое ядро» (Кокс отстаивал первую точку зрения), в ходе которой Линус заметил, что постоянно винить пользовательские программы в том, что ядро ломается, и предлагать починить их все вместо починки ядра — как минимум непорядочно и по-идиотски.

Ответ Алана Кокса на пришедшее некоторое время спустя письмо подтверждает, что он принял решение прекратить поддержку TTY на полном серьезе.

>>> С чего все началось

★★★★★

Проверено: maxcom ()
Последнее исправление: cetjs2 (всего исправлений: 1)
Ответ на: комментарий от alx_me

Мне говорит: «Ты – предатель. Вот перед тобой приходил паренек,
он просил: «Командир! Обещай, когда сто процентный ожог
получу, ногу взрывом оторвет, а затем ее фантом с ума сведет
меня своей болью, а затем убьет, обещай, что потом,
как в конце американских фильмов про войну, обещай, майор,
что мой гроб обязательно покрывать будет наш триколор!»
Вот он – истинный патриот! А ты мне тут говоришь, что государство –
это лишь иллюзия, претендующая на твое жизненное пространство».

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

> Вопрос стратегам. Понятно когда целая армия проводит операцию по спасению единственного солдата. Сложнее когда людей несколько (неудачный случай с посольством США в Иране), а сколько необходимо людей, чтобы закрыть прорваный противником фронт и спасти 300 тысяч? И самый главный вопрос - где их взять? Есть ли в мировой истории удачные случаи?

Ну че вы блин как маленькие? Когда средства есть - спасают. Когда средств нет - не спасают. Когда ум и опыт есть - операция получается, когда нет - не получается. Чтобы спасая одного ухлопать сотню - много ума не надо. Летом 1941 года у СССРа было столько проблем, что спасти Киев не получилось. Хотя очень хотелось. За предложение оставить Киев Сталин снял Жукова с должности начальника генштаба. Потом все равно пришлось Киев отдавать и Жукова возвращать. Примерно в то же время был Ковентри. Черчилль мог бы предотвратить этот налет и связанные с ним жертвы, но тогда немцы бы узнали, что их коды раскрыты. Поскольку война только начиналась, Черчилль предпочел Ковентри сдать а коды оставить.

Простите за офтопик. По топику - Линус с Коксом без нас разберутся. Проблема та же самая - и в том и в другом варианте кто-то пострадает. Сейчас нужно решить что делать, чтобы пострадали по минимуму. Всё как всегда.

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

> Линус с Коксом без нас разберутся. Проблема та же самая - и в том и в другом варианте кто-то пострадает. Сейчас нужно решить что делать, чтобы пострадали по минимуму.

Пока что дело выглядит так, что единственный человек, который мог сделать эту работу, ушел. Причем tty layer остался в сломанном состоянии. Понятно, что проблемный патч откатят, но даже Мольнар боится соваться в tty :/

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

Насколько я понял проблема собственно обратная. по POSIX, close() обязан закончится только в случае если данные упали на сторадж и вернуть ошибку cache flush. emax заложился на это поведение как для файлов - так и для пайпов. В результате пришедший SIGCHILD означает что close завершился и данных в трубе уже не будет. После патча Кокса - было нарушено это условие. close стал возвращать управление до того как данные дойдут до другой стороны трубы (она в этом случае выступает в роли persistent storage) и терять ошибку записи. побочным эфектом этого бага - явился race - когда SIGCHILD приходит раньше чем данные зашедулят для передачи на другую сторону трубы. В результате emax вполне законно считает что данных больше не будет - а Alan Cox идет править свой патч, ибо ради крайне редкого deadlock на userland у баговой прикладухе (вдруг закрыли пайп с двух сторон) - ломать posix поведение - не стоит.

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

> Насколько я понял проблема собственно обратная

Обратная чему? Я описал ровно то же, что и ты, за исключением вот этого:

> по POSIX, close() обязан закончится только в случае если данные упали на сторадж

...потому что по POSIX close ничего такого не обязан. Собственно, в этом и причина конфликта (и я считаю, что Линус прав, и после SIGCHLD данные должны быть готовы для чтения).

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

> ВНЕЗАПНО ldisc планируется. Раньше такого вроде не было - наверное, следствие работы Алана.

Вроде как да.

We really don't want to mark the pty as a low-latency device, because as Alan points out, the ->write method can be called from an IRQ (ppp?), and that means we can't use ->low_latency=1 as we take mutexes in the low_latency case.

So rather than using low_latency to force the written data to be pushed to the ldisc handling at 'write()' time, just make the reader side (or the poll function) do the flush when it checks whether there is data to be had.

This also fixes the problem with lost data in an emacs compile buffer (bugzilla 13815), and we can thus revert the low_latency pty hack (commit 3a54297478e6578f96fd54bf4daa1751130aca86: "pty: quickfix for the pty ENXIO timing problems").

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

Обязан обязан. иначе не получиш статус последнего IO и есть шанс потерять данные. А так хотя бы есть возможность уведомить приложение что данные не записались >>>>

If fildes refers to the master side of a pseudo-terminal, and this is the last close, a SIGHUP signal shall be sent to the controlling process, if any, for which the slave side of the pseudo-terminal is the controlling terminal. It is unspecified whether closing the master side of the pseudo-terminal FLUSHES all queued input and output.

собственно master side как раз на стороне gcc (в случае emacs).

When there is an outstanding cancelable asynchronous I/O operation against fildes when close() is called, that I/O operation may be canceled. An I/O operation that is not canceled completes as if the close() operation had not yet occurred. All operations that are not canceled shall complete as if the close() blocked until the operations completed.

Тут опять же все что прозрачно - если мы еще не начали IO - и позвали close(), то можем оборвать (но не обязаны, а точки зрения сохранности данных вобще не должны). Опять же "All operations that are not canceled shall complete as if the close() blocked until the operations completed."

цитаты взяты по http://www.opengroup.org/onlinepubs/009695399/.

сколько шума было когда ext4 и delayed allocations - теряли файлы, сейчас же сделано практически тоже самое - приложению не дают возможности проконтролировать код завершения close() и нарушают эту семантику.

Als
()

Боже, какие глупости тут говорятся! Такое ощущение, что в теме нет ни одного UNIX программиста.

ОБЕ ошибки указывают на проблему в реализации tty в ядре, поскольку новое поведение противоречит стандартам и практике UNIX (и posix). Если менять так, как хочет Алан, то linux уже не будет иметь права называться unix-like, поскольку будет очень далек от него в самом первом, с чего начинался — в терминале.

Во-первых, emacs. По стандарту close(2) выполняет flush() и не заканчивается, пока данные не будут полностью /получены/ на приемном конце, либо, если /приемник/ умер, получить SIGHUP (и ECONNRESET), либо что-нибудь вроде ENOSPC, либо EINTR, если закончилось место/пришел сигнал. Ситуация, когда сделавшее close(2) приложение завершилось раньше чем /получены/ (не отправлены) все данные, нарушает как стандарты, так и историческое поведение, а равно и здравый смысл (/серийный/ /синхронный/ ВВ).

Во-вторых, KDE. Любое линейное устройство в UNIX может работать либо в каноническом, либо в неканоническом режиме обработке ввода, на выбор приложения (либо только в каноническом, но это редко). Режим задается функциями termios (terminfo). По умолчанию любое линейное устройство работает в _каноническом_ режиме: весь /ввод/ обрабатывается /построчно/, разделителями являются \n, EOL или EOF (либо до достижения MAX_INPUT или MAX_CANON). Любой read(2) с tty в буфер огромного размера будет блокирующим, и вернет по завершении РОВНО одну СТРОКУ (до разделителя), либо MAX_(INPUT|CANON) байт. Следующее чтение вернет следующую СТРОКУ, даже если в буфере чтения их сотни.

Алан решил сломать оба поведения: сделать /линейные/ устройства (а) по умолчания асинхронными (как минимум по close(2), а где ещё проблемы вскроются, кто знает?) и (б) оставить только /псевдо/ неканонический режим линейных устройств. А если вспомнить, что в неканоническом режине не работают последовательности ERASE и KILL, то как редактировать строки ДО их прочтения приложением?

Вы вообще представляете, как работать с неканоническим /интерактивным/ tty? Читать по одному символу за раз, и самому ловить \n? Или блокироваться «бесконечно» на чтении — алло, а кто заранее знает длину строки, которую через сутки введет пользователь? Ставить таймауты, вешать на tty select() и перед каждым чтением узнавать длину буфера? Вы представляете сколько ПО переписывать, и как усложнится простейший код:

input = open("/dev/tty", O_RDONLY);
while (size_t str_len = read(input, buf, MAX_INPUT) {
...
}
close(input);


Короче, Алан явно облажался. Сломал совместимость со /всеми/ интерактивными unix-программами. Тут надо скорее говорить, «почему не глючит остальное ПО», чем «почему глючат kdesu и emacs».

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

> По стандарту close(2) выполняет flush()

Опс, виноват. Это fclose() делает fflush(), а close() напротив: освобождает дестриптор и /отбрасывает/ данные в асинхронной очереди. Зато предшествующий ему блокирующий синхронный write() на линейном устройстве передаст всё, либо вернет меньшее количество, чем было в буфере, но эту ситуацию передающее приложение поймает и передаст остаток.

Алан не close() сломал, а write() сделал асинхронным, но в семантике синхронного.

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

> По стандарту close(2) выполняет flush() и не заканчивается, пока данные не будут полностью /получены/ на приемном конце

> ...

> Опс, виноват. Это fclose() делает fflush(), а close() напротив: освобождает дестриптор и /отбрасывает/ данные в асинхронной очереди.

Мде. Такие вот UNIX-программисты.

> Любой read(2) с tty в буфер огромного размера будет блокирующим,

Если только его не сделают неблокирующимся... как это делает Emacs %)

> Алан не close() сломал, а write() сделал асинхронным, но в семантике синхронного.

Ну, ждем следующего "Опс, виноват".

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

> Обязан обязан. иначе не получиш статус последнего IO и есть шанс потерять данные

"Статус IO" от write - это признак, что данные помещены в кэш или другой буфер ОС. Того, что "данные упали на сторадж", ни write, ни close не гарантируют. Специально для гарантии придуманы fsync и fdatasync.

> master side как раз на стороне gcc (в случае emacs).

Просто праздник...

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

> Понятно когда целая армия проводит операцию по спасению единственного солдата.

Не знаю мне кажется, что армия не будет спасать одного какого-то конкретного человека, рискуя при этом потерять всю армию в окружении. И когда начинают на полном серьезе это пропагандировать, мне кажется, что это походит на лицемерие.

Мол, иди служить к нам в армию (или езжай жить в нашу страну) - мы тебя из любой заваружи достанем и каждый день мороженое давать будем.

Про стратегию ничего сказать не смогу. Мне кажется невозможно со стороны понять, что чувствовали люди от решения которых зависели жизни людей. А что чувствовали они сами скорей всего не расскажут тоже.

sign
()
Ответ на: комментарий от tailgunner

> Мде. Такие вот UNIX-программисты.

Ты ведь понимаешь, что я мог удалить ошибочное сообщение, и переписать. Но не стал. Да, каюсь, руки с мыслями не синхронно работали. (смайлик)

> Если только его не сделают неблокирующимся... как это делает Emacs %)

Ты ведь понимаешь, что этот фрагмент описания касается не той ошибки в реализации tty, которая выявилась благодаря emacs? Ему вообще плевать на строко-ориентированный ВВ — он пытается прочитать весь ответ компилятора. И напарывается на то, что благодаря непродуманным действиям разработчика write() вдруг ни с того ни с сего становится буферизованным. Хотя стандарт требует, чтобы после завершения write() переданные данные уже лежали там, куда предназначались. Если функция вернула n>0, то эти n байт уже должны лежать в файле, и быть доступными для read(). В случае tty write() вернет столько байт, сколько прочитали на другом конце. Если это не так, то драйвер tty крив.

А kdesu создает свой pty, и работает в canonical mode. «Also, no matter how many bytes are requested in the read() call, at most one line shall be returned» ( http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap11.html#tag_11... ). Это СТАНДАРТНОЕ поведение в любом Юниксе. Но Алан выше стандартов, зачем ему соответствие POSIX?

Что, давайте сделаем Линукс несовместимым с юниксами и поломаем весь юзерспейс?

baka-kun ★★★★★
()
Ответ на: комментарий от tailgunner

> "Статус IO" от write - это признак, что данные помещены в кэш или другой буфер ОС.

А вот по стандарту это признак того, что данные лежат по месту назначения, и немедленно доступны для чтения. Хотя для tty «implementation may provide a buffering mechanism; as such, when a call to write() completes, all of the bytes written have been scheduled for transmission to the device», так обычно не поступают для pty, поскольку остается вопрос, что делать с close(), который /обязан/ вычистить все данные отложенные для передачи, но ещё не доставленные. И что делать со случаями, аналогичными emacs, когда родитель получает SIGCHLD и вполне обоснованно считает, что от потомка ждать больше нечего, ведь тот умер.

baka-kun ★★★★★
()
Ответ на: комментарий от tailgunner

> Ну, ждем следующего "Опс, виноват".

Кстати, спасибо тебе за сарказм. Да, память подводит: я, оказывается, забыл о такой мелочи, как «process to close a terminal device file shall cause any output to be sent to the device and any input to be discarded». То есть close() в случае tty|pty обязан сперва отправить отправить /до места назначения/ весь вывод.

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

>> Мде. Такие вот UNIX-программисты.

>Ты ведь понимаешь, что я мог удалить ошибочное сообщение


Дело ведь не в ошибке - все ошибаются. Дело в апломбе.

> благодаря непродуманным действиям разработчика write() вдруг ни с того ни с сего становится буферизованным.


Вот же ты любитель играть с терминами. Да весь ввод/вывод на pty - это сплошные буферы. Просто чистки Алана повысили латентность этих буферов - вполне решаемая проблема.

> Но Алан выше стандартов, зачем ему соответствие POSIX?


Я подозреваю, что Алан тоже неплохо знает стандарты и старается им следовать. То, что при разработке он гонял стандартную тестовую сюиту POSIX, это как бы подтверждает. Даже в lkml Алана обвиняли не в том, что он сделал несоответствующую POSIX реализацию, а в том, что он поломал приложения, опиравшиеся на "традиционную UNIX-реализацию". То есть мы имеем 2 соответствующие стандарту реализации, одна из которых не соотвествует традиции, в этом весь конфликт.

>> "Статус IO" от write - это признак, что данные помещены в кэш или другой буфер ОС.


> А вот по стандарту это признак того, что данные лежат по месту назначения


В случае pty это "место назначения" не очень хорошо определено. Если бы в стандарте было прямо написано "close на pty делает все записанные в него данные доступными на чтение другой стороне", всё было бы чётко.

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

> Дело ведь не в ошибке - все ошибаются. Дело в апломбе.

Это же лор. :)

> Вот же ты любитель играть с терминами. Да весь ввод/вывод на pty - это сплошные буферы.

Приложению плевать на реализацию, оно рассчитывает, что все записанных данные доступны на чтение из любого приложения немедленно. Даже буферизированный stdio отключает буфер, если определяет ввод-вывод на интерактивное устройство (isatty(3)). Более того, после завершения close(2) любое приложение имеет полное право считать, что данные уже прочитаны.

> чистки Алана повысили латентность этих буферов - вполне решаемая проблема.

Там более глубокая проблема: стандарт на termios требует, чтобы к окончанию close(2) все записанные в tty данные были уже в устройстве.

> Алан тоже неплохо знает стандарты и старается им следовать.

«все ошибаются».

> Алана обвиняли не в том, что он сделал несоответствующую POSIX реализацию, а в том, что он поломал приложения, опиравшиеся на "традиционную UNIX-реализацию".

Стандарты возникли не на пустом месте, а всего лишь стремятся отразить и унифицировать «традиционную UNIX-реализацию». Если в tty ломается совместимость с традиционным unix, и это сразу видно в юзерспейсе, то линукс теряет право называться unix-like. Вот так всё просто.

> То есть мы имеем 2 соответствующие стандарту реализации

На мой взгляд одна из них не соответствует POSIX.

> В случае pty это "место назначения" не очень хорошо определено.

Оно определено идеально: физическое устройство, вон та железка, подключенная к последовательному порту (tty), или кусок кода, который эмулирует эту железку (pty).

> Если бы в стандарте было прямо написано "close на pty делает все записанные в него данные доступными на чтение другой стороне", всё было бы чётко.

В стандарте такое поведение описано для write(): все записанные им данные немедленно доступны на чтение из любого места. Стандарт допускает для терминальных устройств буферизацию write(), функция может завершиться до фактической передачи данных, но тем не менее эти данные немедленно доступны устройству на чтение.

Зато тот же стандарт однозначно требует, чтобы к окончанию close() все данные были записаны в устройство, и только после этого произошел дисконнект. Применительно к физическим устройствам это означает, что все данные должны быть переданы, и буфер контроллера порта пуст. Применительно к эмуляции, все отложенные данные должны быть вычитаны эмулятором.

С точки зрения запущенного емаксом gcc (и с точки зрения ядра в этом контексте) сам emacs — терминал, устройство. Да, ядро может буферизировать write(), эмулируя очередь передачи контроллера порта, но при закрытии «shall cause any output to be sent to the device». Заметь, «to the device», а не куда-то ещё, пока device (emacs) не получит все переданные данные, не произойдет рассоединение терминальной линии, функция close() не завершится. И только после того, как все данные переданы и получены устройством (emacs), приложение (gcc) получит возможность спокойно умереть, а ядро получит возможность кинуть родителю SIGCHLD. Так по стандарту, и так работает в любом Unix.

baka-kun ★★★★★
()
Ответ на: комментарий от alx_me

>Пока read не вернёт 0 файл не вычитан

Ты немного не понимаешь, что такое pty и чем он отличается от пайпа: терминал - это такое устройство, в которое может писать множество клиентов. Соответственно, read вернет ноль только тогда, когда другая сторона закроет терминал. В случае с псевдотерминалом такая сторона всего одна: тот, кто создал pty. Емаксовцы все правильно сделали: это вполне логично, что весь вывод поступит к моменту смерти дочернего процесса, так как весь вывод был отправлен на pty к моменту его смерти. Фактически, кроме сигчайлда нет способа узнать, все ли мы уже получили с терминала. Разве что poll с маленьким таймаутом + read после SIGCHLD, но это выглядит очень костыльно.

linuxfan
()

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

frame ★★★
()

ТАк предположим что Алан прав: как поченить тогда емакс без активного ожидания?

stalkerg ★★★★★
()

Алан обиделосо ?

sS ★★★★★
()

А вы когда-нибудь видели как хвост виляет собакой? Нет, потому что собака виляет хвостом. Когда хвост виляет собакой, это значит, что хвост умнее собаки.

opium_inside
()
Ответ на: комментарий от liksys

Раньше или позже, но периодически это нужно делать, тогда система будет живой и развивающейся. Другой вариант - это путь М$, давайте волочь все говно любой давности в целях совместимости. Плюсы есть в обоих случаях, но даже М$ иногда приходится многое ломать, иначе костылей соберется столько, что разобраться в них будет невозможно.

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

Вскрылись два глупых бага в самых лажовых юзер-спейс программах (КДЕ и емэкс), чего суетиться-то? пусть переписывают, как надо правильно делать, ядро-то ещё не релизнуто. Алан абсолютно прав, но хлопать дверью не стоило, проще было объяснить Линусу ситуацию.

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