Здравствуйте, Sinclair, Вы писали:
V>>Структуру АПИ можно сделать классом в C# и подавать по обычной ссылке, а можно сделать value-типом и подавать через ref, а можно сделать ref struct, т.е. ограничить время жизни на стеке. А можно просто IntPtr и заниматься сериализацией-десериализацией.
S>По-моему, нормальный вариант — только один. Если API принимает struct, то мы и отдаём struct.
Или class, если требуется сохранить затем.
S>ref struct нужен для очень специальных сценариев.
Практически всегда, если данные не предназначены для последующего хранения, вплоть до того, что могут ссылаться на невалидную область памяти.
S>К сожалению, нормального способа работы со структурами переменного размера в дотнете/С# я не вижу.
S>То есть можно сделать враппер вокруг byte[], который работает при помощи MemoryMarshal, и даже приемлемо по эффективности (после JIT все эти обращения к MemoryMarhshal.Cast<byte, IntPtr>(data.AsSpan().Slice(sizeof(int))[index] превращаются в in-place инструкции типа LEA), но код выглядит, мягко говоря, нечитаемым.
В select в линухах подаются битовые массивы, поэтому stackalloc решает вопрос.
Длина битовых массивов идёт первым аргументом — как максимальный номер хендла.
Но вообще г-но мамонта этот select, из времён, когда 640 кB хватало на всё.
S>Да дело даже не в этом. В платформе АПИ объектно-ориентирован — есть множество "типов" хэндлов, которые могут обрабатываться единым образом.
S>В дотнете выбрана совершенно другая иерархия типов, из-за которой у сокета и файла нет ничего общего.
Дотнет унаследовал группы системных объектов от Windows, поэтому невозможно ожидать сигнала готовности сокета и файла в одной группе.
S>Поэтому крайне сложно реализовать библиотеку, которая бы, к примеру, умела ждать на разнородном наборе объектов.
В виндах это делается через IOCP.
Правда, ноль гибкости — один раз привязал сокет к completion port и с концами.
V>>В общем, туда как начинаешь вникать — всё за всё цепляется, принимать решения сложно, как всегда бывает, когда однозначно хорошего решения нет.
V>>Каждый божий раз выбираешь некий набор компромиссов из альтернативных их наборов.
S>Ну, да.
Но мне тут периодически пытаются доказать, что это не так. ))
V>>Можно пройтись глазами по хелперу нейтивного вызова, ссылку я дал.
V>>Сравнить с вызовом managed-кода, когда просто в RAX загружается значение переменной и просто делается call RAX.
S>Ну по идее так и должно быть. Если маршалинга нет (а для достижения этого есть все предпосылки), то должно делаться именно это.
А как же замкнуть фрейм стека для GC?
V>>Он не справляется даже в показанном простейшем случае.
V>>Я периодически открываю issue-s в дотнете, но тут рука пока не поднялась, бо явно не самый нужный сценарий для отрасли, хотя был бы полезен конкретно мне. ))
S>Лучше открывать pull request
Такие у меня тоже есть в текущем дотнете, но по-мелочи.
В RuiJIT сейчас чёрт ногу сломит, его надо серьёзно переделывать.
S>В основном — именно благодаря рослину. Тот компилятор, который был до него, не имело смысла опенсорсить — количество потенциальных контрибуторов туда было бы нулевым, особенно с учётом трудностей отладки.
ХЗ, именно в то время опенсорсный GCC развивался бешенными темпами, что аж догнал MSVC.