Would it be possible to make a multithreaded runtime like Go goroutines or Rust’s Tokio with Ravenscar?

The same way you would modify the compiler and SPARK prover?

Co-routines are scheduled in a more deterministic way than time-shared ones. They also cannot do certain things normal tasks can. From that follow the restrains one have to put on them in order to, for example, prevent deadlocks. I believe that for co-routines one could lift the constraint that a task cannot be started dynamically. If not, then not.

On the other hand the number of entries might be zero. One normally does not communicate with co-routines and access discriminant would probably suffice for most applications.

It is a serious thing. You should probably start penning an AI.

From my experience I can say that co-routines would be far more useful than all Ada amendments put together since Ada 2005. Implementation of communication protocols in an asynchronous data-driven way is extremely tedious and error-prone.

1 Like

You can write package specs with SPARK annotations enabled (SPARK_Mode => On) and the appropriate contracts, then hide the package bodies from SPARK using SPARK_Mode => Off. This allows the package to be used from SPARK code, but allows for more freedom in the implementation.

1 Like

@dmitry-kazakov @Irvise @markhermeling
In case any of you are interested, I ended up doing some stuff with AI and getting a multithreaded runtime with coroutines on top of Tasks working with pure Ada and SPARK (albiet with some assembly, since the coroutines are stackful coroutines, based on GitHub - edubart/minicoro: Single header stackful cross-platform coroutine library in pure C. · GitHub, and need some assembly to do the stack stuff)

However, I’m planning on rewriting the whole thing by hand since I’ve proven that this can all work under SPARK (except for the assembly/C FFI), and I don’t want to share the code publicly until I have done so. As such, if you would like access to this repository, DM me (or just respond with your github username on this thread I guess) and I can add you to the repository and you can take a look.

I wouldn’t mind if you would want to fork the repository and make it public if you want either, as long as you credit me of course lol.

I’m curious if you guys can figure out a way to either remove the assembly or make the remaining C FFI SPARK provable

3 Likes

Actually, on further reflection, I’m not totally sure if stapling together a Tokio style runtime on top of Ada really makes sense.

It feels a bit silly to claim its completely SPARK proven when there is still bare assembly being called.

I’m going to try a different approach of running a “fake os” runtime on top of Linux/Windows and report back.

Well, I was wondering if having some fixed set of workers via Tasks, and then functions to schedule work atop those Tasks, would make sense. In that case, you can have your semi-natural uncolored call styles, and then Tasks/Protected Objects would take care of the work behind the scenes. It likely would be gnarly versus just using Tasks directly, but it could be interesting as well.

The use cases are massively concurrent computations:

  • Network server. The number of sockets is far greater than the number of system threads.
  • Number crunching. For example a parallel multiplication of large arbitrary precision numbers. A worker set based implementation is easily beaten by a non-parallel algorithm. (see a test in the Simple Components)

Otherwise, certainly an implementation of co-routines should support a pool of carrier tasks backed by OS threads. However that would make SPARK proofs harder, I guess.

I feel you. However, as far as I know, even AdaCore has had to verify some of their C/ASM for some systems just because that was the only way to do it. For example, the boot system for an MCU is generally written in ASM. Yes, it is a small file, but you just cannot write that in Ada (unless you do a ton of hacks to your code, compiler and linker) and it would most likely just be Ada calling some inlined assembly. So, do not feel bad about it.

Also, you can have proven code that runs on top of unproven C/ASM code but still guard against it. If you want some examples of that, please, take a look at SPARKlib and its C bindings.

Actually, this is another thing that is done in the industry. You get an accepted/certified OS (VxWorks, PikeOS, RTMES…) and use thorse primitives. That way, you know that your code is using certified code and you can proof things on top of that. So this is not too bad tbh.

If you do not want a full OS implementation, use a library, such as LibUV https://libuv.org/ which is used by a large number of projects and it is very mature.

Finally, @SweetAda has done some amazing work in terms of multicore/multiprocessing without any OS or libraries. Things are so efficient that you could even try to use some of his ideas for your work. Take a look at SweetAda/application/test-qemu-aarch64.adb at 985e3bafbda7510d1eb91ea6ec5b8b7de54411c8 · gabriele-galeotti/SweetAda · GitHub and all the code that it needs SweetAda/platforms/QEMU-AArch64 at master · gabriele-galeotti/SweetAda · GitHub

Best regards,
Fer

P.S: feel free to add me to your repo, but I really do not have much time nowadays :confused: (username: Irvise)

2 Likes

I sent an invite for my async runtime repo.
Additionally, I’ve been also prototyping a fork of GitHub - pmderodat/ada-generators: Experimental support for coroutines-based generators in Ada · GitHub and trying to get it to SPARK proven level, but it hasn’t be super succesful so far since theres a lot of global state manipulation.
I’ll add you to that as well.

1 Like

One (basic and obvious) tip. Try to minimise the global state. If you cannot, then try to change the “global” state to scoped state. By scoped, try to make it so that global state becomes “package level” or “task family level” or “different structs instead of a single struct with a lot of data” or vice versa (this last point). It can sometimes help.

Best regards,
Fer

1 Like

I can’t find it now but I came across commentary a while back from a long time ago on the mailing list about GNAT saying something like

After much work from University… we have finally replaced Ada threads with Posix threads. They’re slightly less light weight but the OS compatibility benefits are welcome.

going to share the work i did on the async runtime stuff

(NOTE: A lot of this is AI generated, so take this with a grain of salt)