LINUX.ORG.RU

История изменений

Исправление byko3y, (текущая версия) :

Посмотрел putStr / hPutStr / writeBlocks / writeCharBuffer / flushWriteBuffer / IODevice.write / c_write. Всё на нормальном Haskell’е кроме c_write, который тривиален

Поздравляю, ты запутался в трех соснах. Справедливости ради, я сам бы сразу не догадался, если бы не знал заранее работу IO в GHC. Дело в том, что упомянутое тобой c_write (которое тупо обертка над write) вызывается либо из prodServiceThread менеджера ввода-вывода, либо hPutBufNonBlocking. Последнее, в свою очередь, уже ниоткуда не вызывается из стандартной либы, потому что делает неблокирующую операцию, которая непонятно когда закончится и непонятно что делать с ее буфером — оно оставлено для собственных реализаций асинхронного ввода-вывода. Штатные же функции используют hPutBuf, в котором стэк вызова примерно такой:

hPutBuf =>
    hPutBuf' h ptr count True => -- canblock = true
        bufWrite =>
            writeChunk =>
                writeRawBuffer =>
                    write_rawBuffer -- Сначала пишется в буфер до заполнения
                    threadWaitWrite =>
                        waitForWriteEvent

Дальше уже работает менеджер ввода-вывода из GHC.Conc. Справедливости ради, таки в RTS оно зашито только под форточками — это rts/win32/AsyncIO.c и rts/win32/IOManager.c. Хз почему я запомнил, что остальное тоже на сишке.

Ну вот сколько я потратил сейчас на разбор цепочки? Где-то час. Сколько у меня ушло на разбор ввода-вывода libc? Где-то столько же.

Исходная версия byko3y, :

Посмотрел putStr / hPutStr / writeBlocks / writeCharBuffer / flushWriteBuffer / IODevice.write / c_write. Всё на нормальном Haskell’е кроме c_write, который тривиален

Поздравляю, ты запутался в трех соснах. Справедливости ради, я сам бы сразу не догадался, если бы не знал заранее работу IO в GHC. Дело в том, что упомянутое тобой c_write (которое тупо обертка над write) вызывается либо из prodServiceThread менеджера ввода-вывода, либо hPutBufNonBlocking. Последнее, в свою очередь, уже ниоткуда не вызывается из стандартной либы, потому что делает неблокирующую операцию, которая непонятно когда закончится и непонятно что делать с ее буфером — оно оставлено для собственных реализаций асинхронного ввода-вывода. Штатные же функции используют hPutBuf, в котором стэк вызова примерно такой:

hPutBuf =>
    hPutBuf' h ptr count True => -- canblock = true
        bufWrite =>
            writeChunk =>
                writeRawBuffer =>
                    write_rawBuffer -- Сначала пишется в буфер до заполнения
                    threadWaitWrite =>
                        waitForWriteEvent

Дальше уже работает менеджер ввода-вывода из GHC.Conc и примитивные операции GHC.Conc.waitForReadEvent/waitForWriteEvent. Справедливости ради, таки в RTS оно зашито только под форточками — это rts/win32/AsyncIO.c и rts/win32/IOManager.c. Хз почему я запомнил, что остальное тоже на сишке.

Ну вот сколько я потратил сейчас на разбор цепочки? Где-то час. Сколько у меня ушло на разбор ввода-вывода libc? Где-то столько же.