История изменений
Исправление 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? Где-то столько же.