Waiting for value change at shared memory

I have a shared memory between c and rust projects and it works, that is, c is writing to shared memory and rust is reading from it.
Now I'd like to make it so rust is reading only if that value changed since last read. How to do it?
Thank you

I don't think you can do it in C without OS support. So, probably not in Rust either.

I'm ok with having os support, like condvar waitforobject etc.

If you can't change the C code to just set a flag any time it writes memory (exactly how would depend on the threading situation), there's a way to detect the write itself, which is called a write barrier (mostly unrelated to the far more common term memory barrier), and they are not for the faint of heart.

This article covers them quite well: Generational Garbage Collection, Write Barriers/Write Protection and userfaultfd(2) | by Martin Cracauer | Medium

@simonbuchan I do have to possibility to change from C any flag I want in that shared mem. My problem is, how do I wait for that change on the rust side.

You'd have to use a signal handler to catch the SIGSEGV from the C code trying to write to the protected memory.

The signal handler would use some mechanism to wake a waiting thread or future in rust to continue. Coordinating shared state between normal code and signal handlers is notoriously subtle though, so that might be a bit tricky in itself.

If you can change the C code, and you don't have any threading going on, simply set a boolean that the Rust side can read and reset.

If you do have threading going on, then it depends on what behavior you want, but the simplest is a to have a mutex protecting the data buffer, then doing the same thing as above inside the lock on both sides. You should check the appropriate crate for your platform to create and lock it's mutex consistently on both sides (I believe Rust has it's own implementation?), probably pthread_mutex_init in libc - Rust or CreateMutexW in windows::Win32::System::Threading - Rust and friends. Check the platform documentation for exact usage, but it's pretty much just init, lock, unlock and free.

If you need fancier behavior, you'll need to figure exactly what that is first, but getting it working with that first.

Both C and Rust support condvars: on C side that's std::condition_variable, on Rust side it's std::sync::Condvar. But everything have to happen on one side.

So either your Rust program have to call small helper function which would wait or C side should call small function which would signal.

Signals from C to Rust via SIGSEGV would work, too, but that's like moving cargo from New York to Los Angeles by sending it to the Moon first: possible but very complicated and expensive thus probably not what you want.

2 Likes

Another probably-too-complicated option is to use a pipe: C sends a message to the write side when the shared memory has been updated, and Rust blocks on trying to read from the other end (or uses select, epoll, etc.)

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.