alcinnz
alcinnz boosted

Async #Rust is actually awesome! awesome

The last few days I've built a prototype(!) of a global "Hotkey" system e.g.:

Press & Hold LCtrl + Space
=> an async stream starts and only finishes if:
- another key is pressed or
- one of the Hotkeys is released

If it is not clear by now: this is a state-machine, which fits perfectly into Rust's #async model!

And the best part: This is actually the first time I've ever touched async #RustLang! Such a pleasant experience!

1/?

#AsyncRust

Async #Rust is actually awesome! awesome

The last few days I've built a prototype(!) of a global "Hotkey" system e.g.:

Press & Hold LCtrl + Space
=> an async stream starts and only finishes if:
- another key is pressed or
- one of the Hotkeys is released

If it is not clear by now: this is a state-machine, which fits perfectly into Rust's #async model!

And the best part: This is actually the first time I've ever touched async #RustLang! Such a pleasant experience!

1/?

#AsyncRust

Now that #swad 0.7 is released, it's time to prepare a new release of #poser, my own lib supporting #services on #POSIX systems, following a #reactor with #threadpool design.

During development of swad, I moved poser from using strictly only POSIX APIs (with the scalability limits of e.g. #select) to auto-detected support for #kqueue, #epoll, #eventports, #signalfd and #timerfd (so now it could, in theory(!), "compete" with e.g. libevent). I also fixed quite some hidden bugs, and added more base functionality, like a #dictionary using nested hashtables internally, or #async tasks mimicking the async/await pattern known from e.g, #csharp. I also deprecated two features, the periodic and global "service tick" (superseded by individual timers) and the "resolve hosts" property of a "connection" (superseded by a separate resolve class).

I'll have to decide on a few things, e.g. whether I'll remove the deprecated stuff immediately and bump the major version of the "posercore" lib. I guess I'll do just that. I'd also like to add all the web-specific stuff (http 1.0/1.1 server) that's currently part of the swad code as a "poserweb" lib. This would get a major version of 0, indicating a generally unstable API/ABI as of now....

And then, I'd have to decide where certain utility classes belong to. The rate limiter is probably useful for things other than web, so it should probably go to core. What about url encoding/decoding, for example? 🤔

Stay tuned, something will come here, maybe helping you to write a nice service in plain #C 😎:

https://github.com/Zirias/poser

Today, I implemented the #async / #await pattern (as known from #csharp and meanwhile quite some other languages) ...

... in good old #C! 😎

Well, at least sort of.

* It requires some standard library support, namely #POSIX user context switching with #getcontext and friends, which was deprecated in POSIX-1.2008. But it's still available on many systems, including #FreeBSD, #NetBSD, #Linux (with #glibc). It's NOT available e.g. on #OpenBSD, or Linux with some alternative libc.

* I can't do anything about the basic language syntax, so some boilerplate comes with using it.

* It has some overhead (room for extra stacks, even extra syscalls as getcontext unfortunately also always saves/restores the signal mask)

But then ... async/await in C! 🥳

Here are the docs:
https://zirias.github.io/poser/api/latest/class_p_s_c___async_task.html

#C #coding

I finally eliminated the need for a dedicated #thread controlling the pam helper #process in #swad. 🥳

The building block that was still missing from #poser was a way to await some async I/O task performed on the main thread from a worker thread. So I added a class to allow exactly that. The naive implementation just signals the main thread to carry out the requested task and then waits on a #semaphore for completion, which of course blocks the worker thread.

Turns out we can actually do better, reaching similar functionality like e.g. #async / #await in C#: Release the worker thread to do other jobs while waiting. The key to this is user context switching support like offered by #POSIX-1.2001 #getcontext and friends. Unfortunately it was deprecated in POSIX-1.2008 without an obvious replacement (the docs basically say "use threads", which doesn't work for my scenario), but still lots of systems provide it, e.g. #FreeBSD, #NetBSD, #Linux (with #glibc) ...

The posercore lib now offers both implementations, prefering to use user context switching if available. It comes at a price: Every thread job now needs its private stack space (I allocated 64kiB there for now), and of course the switching takes some time as well, but that's very likely better than leaving a task idle waiting. And there's a restriction, resuming must still happen on the same thread that called the "await", so if this thread is currently busy, we have to wait a little bit longer. I still think it's a very nice solution. 😎

In any case, the code for the PAM credential checker module looks much cleaner now (the await "magic" happens on line 174):
https://github.com/Zirias/swad/blob/57eefe93cdad0df55ebede4bd877d22e7be1a7f8/src/bin/swad/cred/pamchecker.c

#C #coding