Что делать
120 subscribers
209 photos
3 videos
4 files
133 links
Не смешно
Download Telegram
Ну нихуя себе
На удивление, на С очень легко пересесть. Накодил пока всего 35 часов (что на 5 часов больше раста, хы), но успел сорвать бинго: сегфолт, ошибка арифметики, память повреждал (пытался деаллоцировать буфер на стэке), даже в глибц маллок паниковал (ассерт проваливался). Никакие строки тебе не пишут, где это произошло, просто грустный Segmentation fault (core dumped). Ну, поплачь, мол. Но у тебя всегда есть valgrind, который тебе даст полный расклад таро: и утечки (даже расскажет, что еще можно спасти, а что уже навечно проебано), и сколько байт суммарно аллоцировано было, и где у тебя аномальное поведение (чтения out of bounds, откуда seg* прилетают - вот тут уже с файлами и строчками!), что спасает примерно всегда. CMake так и не осилил, зато есть прекрасный meson, в котором и тесты есть (в тестах тащу ассерты из unity нет, не тот, что игровой движок). Нюансы, конечно, остаются с внешними зависимостями - я пока обхожусь .wrap-файлами месона (по сути, в файлик кидаешь линк на репозиторий, и при билде тебе его склонируют и докинут к компиляции). И, собственно... А жить-то можно!

Да, еще остаются УБ, которые так с первого взгляда и не назовешь. Приколы препроцессора, от которых даже варнингов нет, и которые нужно просто понимать. Не очень удобно с отсутствием неймспейсов, у тебя по итогу вырабатывается жава-стиль с длинными именами. Но это и правда простой язык. Он учится за пару дней, и ты можешь просто сесть, и начать на нем программировать. Из нюансов, правда, я часа 2 над месоном сидел, пытался заставить его работать, но это, по сути, единоразовая инвестиция.

А вот интеграция с ИДЕ хуйня - цлион регулярно перезапускать приходится, потому что этот гидроцефал в очередной раз не может понять, откуда берется юнити в тестах.
1
Forwarded from localhost
Наглядное сравнение превосходства нового Intel 12900K над AMD 5950X

IT-юмор | Чат | Предложка
🔥1
Последний щитпост, честно
Фанфакт: под линупсом, socket() возвращает файловый дескриптор, равный наименьшему незанятому числу для процесса

иными словами, я могу завести просто массив для подключений, и адресовать его файловым дескриптором! Просто охуенно.
👍1
https://idea.popcount.org/2016-11-01-a-brief-history-of-select2/

Там даже гоферов упоминают. Правда, в сравнении с 3BSD, которая вышла, когда ещё мой дед родиться не успел
Оказывается, thread-local переменные как понятие появились из Итаниумов (тех самых интеловских VLIW процов, которые по итогу обосрались), и только потом распространилось на другие архитектуры
В С, способ хранения строковых констант зависит от имплементации. Ну, то есть, они все хранятся в data-секции (text?), но вот как именно - уже зависит. Например, с некоторыми компиляторями (в некоторых ситуациях), одинаковые строковые литералы в разных местах могут ссылаться на одно и то же место. В таком случае, код
char* str1 = "Hey";
str1[1] = 'o';
puts("Hey");

может вывести как Hey, так и Hoy, в зависимости от компилятора и/или флагов компиляции.

Вот такие пироги.
Что делать
В С, способ хранения строковых констант зависит от имплементации. Ну, то есть, они все хранятся в data-секции (text?), но вот как именно - уже зависит. Например, с некоторыми компиляторями (в некоторых ситуациях), одинаковые строковые литералы в разных местах…
упд: под линуксом (по крайней мере, арчем) это выдает сегфолт, потому что секция readonly. Вероятно, можно это поведение настроить. Не знаю, как ещё обстоят дела на других ядрах - нт и бсд. Но сука интересно
Собственно, вот пилю я вебсервер на С. Пришлось мне свой ивентлуп возводить, сделал простенькую схему и обернул это дело в еполл. Потом думаю ещё io_uring в эту схему добавить.

А мне вот что интересно стало: чисто технически, у меня, при ебанутой нагрузке, спокойно может аллокатор отъебнуть. Ну, то есть, маллок просто нулевой указатель вернёт, скорее всего, по причине недостатка памяти. И произойдет это прямо в ивентлупе. Что делать?

Можно сыграть дурачка, и просто словить закономерный сегфолт. Возможно, я получу неопределённое поведение (не языка, а именно мой код не пойми как себя поведёт, ведь он думает, что я, например, всё-таки добавил значение в массив). В общем, малоприятная вещь.

Но у меня появилась вот какая идея: войти в некий temporary emergency state. Это когда прекращается обработка всех запросов, просто реаллоцируется вообще всё, чтобы оптимизировать неиспользуемое пространство когда-то выросших буферов, да и в целом память дефрагментировать (ведь, скорее всего, проблема именно в этом). Если требуется агрессивная чистка, то дополнительно столько-то процентов подключений поубивать.

Думается мне, может сработать. Ведь просто уходить в ребут - идея тоже так себе, потому что, как минимум, если такое произошло - ко мне практически сразу завалится большая часть оравы обратно. Вот уж accept-loop охуеет. Равно как и счастливчики, которые успели подключиться первыми, я-то буду занят исключительно тем, чтобы и остальных принять)

В общем, задачка интересная.
Что делать
Собственно, вот пилю я вебсервер на С. Пришлось мне свой ивентлуп возводить, сделал простенькую схему и обернул это дело в еполл. Потом думаю ещё io_uring в эту схему добавить. А мне вот что интересно стало: чисто технически, у меня, при ебанутой нагрузке…
В общем, когда я пытался заснуть, в полусне мне пришло осознание, что я в любом случае не смогу память адекватно дефрагментировать. Мне же нужно будет где-то аллоцировать промежуточный буфер, чтобы данные скопировать. А он тоже должен быть достаточно большим. А коль память фрагментирована, то достаточно большим сделать не получится, да и на стэк особо не поскладируешь. В общем, наверное, я просто обрублю все подключения и деаллоцирую всё, что понавыделять успел.

Да, не получится так же гладко, как если бы я просто временно перестал их обслуживать, но единственный способ. Авось так хоть немного на плаву получится остаться. А сисадмины пусть сами уже разбираются, почему у них сервер захлёбывается.
Почему побитовая логика вся выглядит так страшно
Что делать
Почему побитовая логика вся выглядит так страшно
Суть вообще вот в чём. Поскольку я делаю сервер асинхронным, то мне нужен ивентлуп. Пока что он работает на еполле. Еполл я взял в edge-triggered режиме. Иными словами - ивент прилетает лишь раз, пока я не дойду до конечной (не получу при чтении либо записи ошибку EAGAIN), после чего он возникнет снова после того, как станет доступным. Поэтому у меня есть массив со всеми тасками, и массив поменбше, в котором хранятся только те таски, с которыми нужно что-то делать. У каждой таски, в свою очередь, есть состояние - READ, WRITE, INACTIVE.

Чтобы не мудрить всякого говна с массивом активных тасок, я просто сделал его самопополняющимся. Как это работает: обёртка (в данном случае, еполл) вызывает ивентлуп (ev_invoke()), и передаёт в неё все новые ивенты. Мы в ивентлупе пробегаемся по всем текущим активным таскам, если состояние READ - читаем из сокета данные, кладём в замыкание. Если write - вызываем соответствующее замыкание, и возвращенный массив байт кладём в сокет. Если при чтении либо записи возникает ошибка EAGAIN, мы просто сохраняем где-то недочитанные/недописанные байтики, ставим состояние INACTIVE. При этом, если у нас есть какие-то новые ивенты, мы такую неактивную таску заменяем новой, активной, и обрабатываем уже её. Если новых ивентов нет, просто оставляем в таком состоянии, она тоже будет заменена на активную, только при следующей итерации.

А вот побитовая логика понадобилась вот зачем. Сверху есть логическая ошибка - если состояние таски в инактив устанавливается, как тогда понять, на каком моменте мы в предыдущий раз остановились - на чтении, или на записи? Вот и получается так, что как только таска становится неактивной, мы больше никогда её не обработаем. Будем постоянно скипать либо заменять другими активными.

Поэтому я решил сделать состояние в виде флагов. READ = 0b001, WRITE = 0b010, и INACTIVE, соответственно, 0b100. Таким образом, если сокет истощился (EAGAIN, иными словами), мы просто добавляем флаг инактива (нижняя строчка). При этом, когда приходит пора заменить таску другой активной, мы этот флаг снимаем (та страшная штука на второй строчке). Таким образом, даже если таска заменяется самой собою, то логика остаётся прежней
Какие есть тулзы, чтобы интерактивно данными по голому тсп перекидываться? А то мне надо ивентлуп как-то тестировать, для начала - ручками смотреть
Итак, я потратил 86 часов на tcp echo сервер
Так. Вот у меня таски лежат в одном пуле. Пул - арены, свободные ячейки в которых лежат в очереди. Получается О(1) вставка и удаление, шикардос. А вот у меня есть net_client, интерфейс для сетевого подключения. В интерфейсе лежит void* env, по сути - указатель на контекст для имплементации, который будет передаваться в методы (лежат как указатели на функции). Есть tcp клиент как имплементация net клиента. А теперь непосредственно проблема: инстанс tcp клиента у меня аллоцируется на хипе. Ну, то есть, это никак не амортизируется, хотя спокойно может. И теперь мне надо думать, как мне так по-умному либо аллокатор прокидывать, либо ещё как-то выкручиваться. Пиздец, мемори менеджмент - сложна.