smplr

What you don't see is that ACS_BULLET symbol (the dot)
next to the word "smplr" is blinking VERY FAST to show
how I async I am.

#C #ncurses #sndio #openbsd #libevent
Fun and probably cryptic but libevent + curses thing in C.

I am using libevent with timed events
to make my curses program be dynamic.
I was noticing that I could go down to low microsecond
values and I my display was still only "ticking"
like maybe half a second or at the fastest a tenth
of a second.

And what I found is I was using the timeout(3000);
call in the curses setup. This makes getch() not block.
getch() is how curses takes user input.

As usual in hindsight this was what was effectively
defining the lowest resplution tick possible.
That timeout() means that getch() will wait that
long to see if a user has typed something.
(basically) ... wait is the same as saying it blocks
for that long.

long story short if I lowered the timeout to like 30
like timeout(30); then my ticks started blinking
really fast :)

See the events have nothing to do with user input.
They are just timed events that repeat.
But the whenever i called getch() it would
effectively block for that 3000 milliseconds *

TLDR: I can have the frames per second of my curses
code be "really fast" now.


* I just looked it up while typing this.
man 3 timeout. The parameter is milliseconds.


#curses #libevent #c
I'm so happy I could cry after being on a roller coaster
of trying to figure this out.
I came close to bailing a few times.


van:~/code/scm/cev$ ./main.exe add
add-event...
f:0x92ee931d220
cb2 (defined in scheme, and called in C)
cb_func_2 called 1 times.
cb2 (defined in scheme, and called in C)
cb2 (defined in scheme, and called in C)
cb2 (defined in scheme, and called in C)
cb2 (defined in scheme, and called in C)
cb2 (defined in scheme, and called in C)
cb2 (defined in scheme, and called in C)
cb2 (defined in scheme, and called in C)
cb2 (defined in scheme, and called in C)
cb2 (defined in scheme, and called in C)
cb2 (defined in scheme, and called in C)
^C



This is the libevent C library on OpenBSD ...
...
calling into scheme functions.
That output is from scheme code.
The libevent library is C and takes callbacks to
do it's event triggered stuff.
I defined a C compatible callback from scheme code.

I added an event callback that fires every second.
So that means libevent is running and every second
it executes a callback function that is written in scheme.

:)

This means I can do high level scheme stuff, and use
the low level libevent lib.
(I assume this would work with any C event lib like libev
or libuv, but as an OpenBSD zealout for the time
being I am using the one sanctioned by them.)

#openbsd #scheme #chicken #libevent
This might (and does to me) seem obvious in hindsight.

But learning to program in #C and learning #ncurses AND
using #libevent made it not obvious.

Like I am refactoring constantly in this state of learning and
programming. I build up working code, and then see some
bad patterns and throw whole sections away and re-work them.

So I was at a place where the other stuff was relatively organized
and I liked how the app was working, but the screen was flickering.

And IME so far ncurses WINDOW(s) are not localized enough to
ameliorate that. To be clear I was only clearing my main WINDOW,
but the whole screen would flicker. That is why I am leaning towards
just not using clear and/or minimizing it.

It's also interesting too that I use tmux.
tmux also uses libevent and ncurses? but doesn't flicker.
But I am not comparing what I am doing to tmux :)
It's just interesting.
Пример типичной системно-прикладной разработки, реализация своей «очереди сообщений» (event loop).
Использованием
#epoll, вместо «традиционных» select & poll, для асинхронной работы через polling’а (и мультиплексирования).

Отслеживание файловых дескрипторов через
#epoll выглядит более современно, меньше копирования памяти между user space и kernel space. А при появлении ожидаемых данных можно напрямую переходить к объекту или структуре данных, что важно при наблюдении за несколькими файлами и\или соединениями. Устраняется поиск «сработавшего» файлового дескриптора в индексных массивах, полноценное О(1) во всех случаях. Можно сразу же работать с теми экземплярами объектов, которые оборачивают тот файл или udp-поток, tcp-, quic-соединение, где появились новые данные.

Есть несколько готовых к использованию «очередей сообщений» (event loop'ов) —
#libev, #libuv, #libevent. Для некоторых агент-серверные решений и брокера #RabbitMQ это подходит. Однако, в некоторых случаях AMQP-библиотеки не скрещиваются с уже готовыми «очередями сообщений». Потому что агентская часть может активно использовать асинхронно-реактивное программирование с хорошей и проверенной «горизонтальной масштабируемостью». Т.е. на агентской части выполняется много работы и реализация сделана через sharing nothing многопоточность. Это такая парадигма, когда не просто достигается не только горизонтальная масштабируемость через lock-free\wait-free, а так же исключается много вредного, как тот же cache ping-pong или false sharing. Внутри агентов идёт своё управление потоками с выделениями памяти. Не только в плане «динамической памяти» (heap, аллокаторы а-ля #jemalloc от #Facebook), но и приколами вокруг pinning страниц, учёта #NUMA и даже huge pages(меньше промахов в #TLB).

Почему бы не использовать epoll?
Библиотека не обязана вычитывает данные целиком из потока (сокета), а может забирает данные лишь до тех пор, пока не насытится автомат состояний (finite-state machine). Например, выполняется парсинг сущностей AMQP-протокола, которые, по мере накопления, передаются в обработчики указанные клиентом библиотеки.
И это плохо соотносится с тем, что используя
#epoll надо выбирать какой вариант оповещений использовать:
• «по уровню» (level-triggered),
• «по фронту» (edge-triggered).

Особенности поведения отдельно взятой библиотеки может не позволять использовать работу «по фронту» (edge-triggered), т.к. библиотека не вычитывает полностью все данные из файловых дескрипторов.

Можно быть хоть пять раз technical lead и всё это прекрасно знать, но следует помнить, что как только в коде появляется флаг EPOLLET, то необходимо проводить аудит работы с потоками данных. Это избавляет команду от многих заморочек вокруг тестирования и ковыряния с каким-то совершенно непонятным поведением кода.

Про
«Edge Triggered Vs Level Triggered interrupts»

#programming #linux #softdev #трудовыебудни
Edge Triggered Vs Level Triggered interrupts

Discussion: Level triggered: as long as the IRQ line is asserted, you get an interrupt request. When you serve the interrupt and return, ...

К вопросу использования #epoll вместо хорошо знакомых и «традиционных» select & poll. Т.е. асинхронной работы с чем-либо посредством polling’а и мультиплексирования.

Недавно пришлось заниматься реализацией очереди событий для AMQP-CPP. В одном из продуктов решено сделать связь агентских частей с основным «контроллером» через #AMQP, в качестве брокера #RabbitMQ (всё стандартно, обычный кластер и TLS-соединения).

Вот только агенты продукта активно используют асинхронно-реактивное программирование с хорошей «горизонтальной масштабируемостью». Когда достигнуто полноценное sharing nothing, не просто горизонтальная масштабируемость через lock-free или wait-free и закон Амдала. Исключается много всего и сразу, как старый-добрый cache ping-pong, так и печаль с false sharing.

Отсюда внутри агентов и своё управление потоками с выделениями памяти. Не только в плане heap (динамической памяти, со своими аллокаторами а-ля #jemalloc от #Facebook), но и приколы вокруг узлов #NUMA и даже huge pages (снижающих «давление» на #TLB, меньше промахов).

Первая же проблема выплыла почти сразу — не реально использовать библиотеку AMQP-CPP с уже предоставляющейся поддержкой #libev, #libuv, #libevent. Несовместимы эти очереди сообщений с имеющейся моделью управления потоками и организации задач на агентах.

Почему был взят epoll

Подход используемый в #epoll выглядит более современно, меньше копирований памяти между user space и kernel space. А при появлении данных в отслеживаемом файловом дескрипторе можно напрямую перейти по указателю на объект класса или структуру данных. Тем самым обходиться без поиска дескриптора по индексным массивам/контейнерам. Сразу же работать с экземплярами объектов оборачивающих нужное #tcp -соединение, того самого, в которое и пришли данные.

И тут обозначилась вторая проблема, что используема AMQP-библиотека не вычитывает данные целиком из потока сокета. Например, забирает данные лишь до тех пор, пока не насытится автомат состояний (finite-state machine), выполняющий парсинг сущностей AMQP-протокола.

Используя #epoll приходится выбирать на какой вариант обработки событий ориентироваться:

  • срабатывание оповещений «по уровню» (level-triggered),
  • выбрасывания событий «по фронту» (edge-triggered).

И беда с библиотекой в очередной раз показала, что нельзя использовать работу «по фронту» (edge-triggered) не изучив досконально работу подсистемы отвечающей за вычитывание данных из файловых дескрипторов. И появление флага EPOLLET в коде является маркером, о том, чтобы проводить аудит использовавшихся решений.

Про Edge Triggered Vs Level Triggered interrupts можно почитать в https://venkateshabbarapu.blogspot.com/2013/03/edge-triggered-vs-level-triggered.html)

#programming #linux #трудовыебудни

Akkoma

#tmux wykrzacza się z #libevent 2.2.1 (alpha). Niestety, komunikat błędu wypisywany jest na nowym terminalu, a tmux od razu go zamyka i czyści ekran.

Próbowałem wydostać tekst poprzez przekierowanie wyjścia, poprzez logi tmuksa, nie udało się nawet przy pomocy strace (!). Dopiero #asciinema dało radę.

Kolejne zastosowanie dla tego świetnego programu. Szczerze polecam!

https://github.com/tmux/tmux/issues/3572

#Gentoo

Assertion ret == 0 failed in sigfd_free_sigevent with libevent-2.2.1 · Issue #3572 · tmux/tmux

Issue description After rebuilding tmux against libevent-2.2.1-alpha (we're testing to catch early issues), tmux is crashing immediately after opening a new session, with the following assertion: /...

GitHub

#tmux crashes with #libevent 2.2.1 (alpha). However, the assertion message only gets printed inside the new terminal, and tmux closes it immediately and clears the screen.

I couldn't manage to get the message via redirecting output, via tmux logs, even via strace (!). Finally, I've figured out to use #asciinema.

Another great use case for this great program. Kudos!

https://github.com/tmux/tmux/issues/3572

#Gentoo

Assertion ret == 0 failed in sigfd_free_sigevent with libevent-2.2.1 · Issue #3572 · tmux/tmux

Issue description After rebuilding tmux against libevent-2.2.1-alpha (we're testing to catch early issues), tmux is crashing immediately after opening a new session, with the following assertion: /...

GitHub

Today's #Gentoo fun:

tmux fails to build with #libevent 2.2.1. It fails because of incompatible declaration of forkpty() in compat.h.

Looking into compat.h. forkpty() is declared there if HAVE_FORKPTY is false.

Looking into config.log. forkpty() is not found because configure tries to link random test programs to -levent_core@CMAKE_DEBUG_POSTFIX@.

At this point, you can guess what the problem is: https://github.com/libevent/libevent/issues/1459

#CMake #autotols

*.pc files have unexpanded `@CMAKE_DEBUG_POSTFIX@` when built via autotools · Issue #1459 · libevent/libevent

To reproduce: $ ./autogen.sh $ ./configure -C $ grep POSTFIX *.pc libevent_core.pc:Libs: -L${libdir} -levent_core@CMAKE_DEBUG_POSTFIX@ libevent_extra.pc:Libs: -L${libdir} -levent_extra@CMAKE_DEBUG_...

GitHub

#glibc 2.36 introduces arc4random(). This makes #libevent switch from bundled to system ARC4 when rebuilt. Good so far.

However, glibc doesn't support arc4random_addrandom(), so libevent… removes evutil_secure_rng_add_bytes() and changes its ABI, effectively breaking installed #Tor (#Gentoo is especially affected).

Upstream argues that leaving the function as no-op is bad for #security However, when it's gone, Tor just skips the call.

https://github.com/libevent/libevent/issues/1393
https://gitlab.torproject.org/tpo/core/tor/-/blob/main/src/lib/evloop/compat_libevent.c#L483-485

libevent failed to build from source on Debian Bookworm with glibc 2.36 · Issue #1393 · libevent/libevent

Hello, I'm digging up an old question about evutil_secure_rng_add_bytes. I'm maintaining the package libevent in Debian, and lately I had a failed to build from source (FTBFS) for libevent ...

GitHub