Что делать
Ага. Хуй. Ну вот я принял новое подключение, а как мне тогда сказать обёртке, чтобы она добавила его в еполл? Сука
По итогу, я осознал, что просто запутался в собственных абстракциях. Добавил новый стейт таски EV_SERVER, который отлавливает конкретно обёртка еполла, и сама принимает подключение. Плюс вынес туда же арены с тасками, склеив таски вместе с собственно клиентами. Получилось стройненько
Что делать
Я докатился по итогу до своего аллокатора. В glibc, конечно, и маллок умный, и юзает под капотом арены, но у меня чуть более специализированный кейс, поэтому могу себе позволить. Всё равно потом забенчмаркаю оба варианта, может, и выкину нахуй Но тут встала…
С аренами решил оставить отдельно список, кстати. Это уже больше мелкие твики, которые буду пробовать тогда, когда я смогу оценить, какие преимущества либо проблемы это создаст. А то решение проблемы в вакууме какое-то
Наконец отдебажил эту хуйню.
В общем, виноваты оказались, как всегда, арены.
Во-первых, я выделял вообще всё пространство арены целиком. Поэтому, когда размер объекта не кратен размеру арены, я выделял под последний элемент частично за пределами аллоцированной зоны. Первый проёб.
Во-вторых, arena_acquire(), чтобы получить указатель, где можно схоронить нужный объект, возвращал результат list_pop() из списка доступных поинтеров. Только вот, я не учёл, что list_pop() возвращает указатель на элемент внутри списка, а не сам элемент. То есть, в списке память хранится, как void*, а я в неё совал void*, так что по итогу память в списке имела тип void**. Вот как раз его и возвращал мне list_pop(). А я возвращал пользователю вместо указателя на свободное место в арене. Так ладно это, возвращал поинтеры с промежутком в 8 байт, равное как раз таки исходному
В общем, охуел я знатно, конечно. Зато теперь вынес ещё и закрытие сокета из ивентлупа в обёртку, что позволит ещё лучше всё это дело в io_uring потом батчить
В общем, виноваты оказались, как всегда, арены.
Во-первых, я выделял вообще всё пространство арены целиком. Поэтому, когда размер объекта не кратен размеру арены, я выделял под последний элемент частично за пределами аллоцированной зоны. Первый проёб.
Во-вторых, arena_acquire(), чтобы получить указатель, где можно схоронить нужный объект, возвращал результат list_pop() из списка доступных поинтеров. Только вот, я не учёл, что list_pop() возвращает указатель на элемент внутри списка, а не сам элемент. То есть, в списке память хранится, как void*, а я в неё совал void*, так что по итогу память в списке имела тип void**. Вот как раз его и возвращал мне list_pop(). А я возвращал пользователю вместо указателя на свободное место в арене. Так ладно это, возвращал поинтеры с промежутком в 8 байт, равное как раз таки исходному
sizeof(void*). Поэтому, у меня таски перекрывали друг дружку. Из-за этого мне поебенило состояние серверной таски. Таску с поебененным состоянием получал ивентлуп. Видит - хуйня какая-то, и логгирует баг. А логгер-то я не имплементировал, у меня там заглушка. Выходит, что я вызывал функцию по рандомному адресу в памяти. Отсюда и sigill. В общем, охуел я знатно, конечно. Зато теперь вынес ещё и закрытие сокета из ивентлупа в обёртку, что позволит ещё лучше всё это дело в io_uring потом батчить
Что делать
Photo
ТУПОЙ СЫН ГОВНА БЛЯТЬ
Когда клиент отключается, я добавляю таску в очередь на дисконнект, чтобы этим занялся враппер (дабы ивентлуп своими грязными ручками не прикасался к тому, что ему не принадлежит).
Соответственно, после этого я пытаюсь заменить таску на новую активную. Если не получается - просто инкрементируй значение inactives (чтобы потом по нему определить, пустая ли очередь активных ивентов, и тогда еполл встанет на ожидание до тех пор, пока новые не появятся)
И Я ЗАБЫЛ ОБОЗНАЧИТЬ САМУ ТАСКУ КАК НЕАКТИВНУЮ БЛЯЯЯЯЯЯЯЯЯТЬ
Из-за чего, соответственно, каждый раз, как я на неё натыкался - пытался из неё что-то прочитать. Каждый раз ловлю EOF. Каждый раз добавляю в очередь на дисконнект. И каждый раз обёртка пыталась её по второму, третьему, etc. кругу её освободить. Ёбаный пиздос
Когда клиент отключается, я добавляю таску в очередь на дисконнект, чтобы этим занялся враппер (дабы ивентлуп своими грязными ручками не прикасался к тому, что ему не принадлежит).
Соответственно, после этого я пытаюсь заменить таску на новую активную. Если не получается - просто инкрементируй значение inactives (чтобы потом по нему определить, пустая ли очередь активных ивентов, и тогда еполл встанет на ожидание до тех пор, пока новые не появятся)
И Я ЗАБЫЛ ОБОЗНАЧИТЬ САМУ ТАСКУ КАК НЕАКТИВНУЮ БЛЯЯЯЯЯЯЯЯЯТЬ
Из-за чего, соответственно, каждый раз, как я на неё натыкался - пытался из неё что-то прочитать. Каждый раз ловлю EOF. Каждый раз добавляю в очередь на дисконнект. И каждый раз обёртка пыталась её по второму, третьему, etc. кругу её освободить. Ёбаный пиздос
Что делать
How did they know?
Кстати долго ебался-ебался, пока не понял, что проблема состоит лишь в том, что у меня ивентлуп в какой-то момент, за отсутствием новых активных тасок, каким-то чудом снимает флаг неактивности с инактивной таски, которую я уже освободить успел
Перенёс очищение флага в обёртку, чтобы только при получении ивента из еполла его снимать, и всё зафурыкало. Правда, теперь он не выдерживает потока из тсп стресстестера
Перенёс очищение флага в обёртку, чтобы только при получении ивента из еполла его снимать, и всё зафурыкало. Правда, теперь он не выдерживает потока из тсп стресстестера
Что делать
Кстати долго ебался-ебался, пока не понял, что проблема состоит лишь в том, что у меня ивентлуп в какой-то момент, за отсутствием новых активных тасок, каким-то чудом снимает флаг неактивности с инактивной таски, которую я уже освободить успел Перенёс очищение…
А не выдерживает потому, что, оказывается, надо принимать подключения из серверного сокета до тех пор, пока EAGAIN не словишь. Иначе тебе больше никогда не придёт ивент, из-за чего accept-loop стопорится