Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion on the possible implementation of SIGEV_THREAD #2466

Open
ChrysoliteAzalea opened this issue Jul 29, 2024 · 2 comments
Open

Discussion on the possible implementation of SIGEV_THREAD #2466

ChrysoliteAzalea opened this issue Jul 29, 2024 · 2 comments

Comments

@ChrysoliteAzalea
Copy link

Hello everyone!

On Linux, there is struct sigevent that allows configuring asynchronous notification for some events (such as asynchronous input/output completion, timer expiration or message delivery on POSIX message queue). It supports for types: SIGEV_NONE (nothing happens when event occurs, it has to be polled manually), SIGEV_SIGNAL (a signal is delivered to a process when event occurs), SIGEV_THREAD (a function is called on a designated thread when event occurs), SIGEV_THREAD_ID (a signal is delivered to a thread when event occurs, currently only used by timers). However, nix provides no API for SIGEV_THREAD, and on libc, struct sigevent is exposed in a strange way (instead of exposing an union, it only exposes the "thread ID" part of it). SIGEV_THREAD is provided by glibc in userspace, therefore, I'm proposing to implement it in userspace too. As I see, on Linux, it can be implemented in this way:

  • Reserve a real-time signal for sigevent notifications
  • Create a thread to manage such notifications
  • Create an instance of eventfd or unnamed pipe to send notifications
  • Install a signal handler for immediate notifications, such handler should retrieve the notification information using the si_value() function for siginfo_t structure and send it to a thread
  • Upon receiving a notification, a thread should take action by invoking a user-provided closure

What do you think?

@SteveLauC
Copy link
Member

Hi, thanks for this feature request! 😃

and on libc, struct sigevent is exposed in a strange way (instead of exposing an union, it only exposes the "thread ID" part of it).

That's because Rust did not support C union back in the day, so they cheated and defined it as a struct.

Nix correctly defines the sigevent for FreeBSD but not Linux (in PR: #1731), this is something we should not do, we should always use the symbols from the libc crate, we did this because the libc crate cannot accept breaking changes at that time.

Initial libc PR: rust-lang/libc#2813

Rebase of the above PR: rust-lang/libc#3630

The libc crate is working on its 1.0 release, which will accept breaking changes, so I think it makes sense now to move the libc PR 3630 forward and remove the FFI definitions from Nix.

As I see, on Linux, it can be implemented in this way

If we have everything ready, I guess we don't need to manually implement this in Nix, right?

@ChrysoliteAzalea
Copy link
Author

If we have everything ready, I guess we don't need to manually implement this in Nix, right?

If we can define struct sigevent correctly in the Rust code, sure. However, the C API isn't very convenient to use from the Rust code (it accepts a pointer to function and a value that is a union with types int and void*). I'm currently looking for a way to adapt it to Rust closures (similar to what std::thread::spawn() does) -- take a closure and run it on a glibc thread when event happens. It can be done by supplying a pointer to pre-defined function to a struct sigevent, and this function would use the sigev_value field to lookup and invoke a closure. However, this closure would probably have to implement the core::ops::Fn trait, because it can be invoked several times (for example, for timers).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants