Wed 30 April 2025

💤 Sane C++ April 25

SC

Welcome to the update post for April 2025!
This month has been mostly spent adding Process fork, Async vectorized writes and Memory Dump to Containers!

Process

SC::Process library allows spawning process across all supported platforms with many features, including I/O redirection and setting environment variables / starting directories. This month however it has been gaining a new class called SC::ProcessFork that uses fork on Posix and RtlCloneUserProcess a very well hidden NT Kernel API that we can consider to be some sort of Windows fork.

A fork duplicates a parent process execution state, os handles and private memory.

Its semantics are quite different from platform to platform but on its most common denominator it can be used to carry on "background" operations on snapshots of current program memory. One relevant use case is serializing to disk or network a live, complex and large data structure. Without the fork the program should either:

Fork avoids memory duplication because it will be shared through Copy On Write (COW) mechanisms.
COW ensures that un-modified duplicated memory pages will not occupy additional Physical RAM.

A pair of pipes makes it easy to do some coordination between parent and forked process.

This is not without caveats however for example:

  1. Many API will just not work as expected on the forked process, especially on Windows
  2. Limit API calls in forked process to console IO, network and file I/O (avoid GUI / Graphics)
  3. All threads other than the current one will be suspended in child process (beware of deadlocks)
  4. Create Sockets and FileDescriptors with Inheritable flags if you need them in fork process
  5. Process deadlocks under Windows ARM64 / x86 emulation (use Process::IsWindowsEmulatedProcess)

So we're better using this feature only for very simple use cases, for example:

Foundation

This month the custom allocator system gains a new ability.
Anything SC::Segment based (Vector / String / VectorMap including their Inline variants) can be dumped and restored with a simple cast!
This is very useful for serialization purposes, for network protocols or state persistence to the disk, assuming there's no need to validate the data and/or to version it.

If data can evolve in different "versions" with added and removed field, you should probably look at SC::SerializationBinary.

Once everything is routed through an allocator, this is not difficult to do, but some effort has been spent to make it simple and easy.
Some debate on X has made it clear that this cannot be made fully UB safe under any existing C++ standard version so the usual caveats of "check what your compiler is doing" apply here.

Async

SC::Async library now supports vectorized writes.

This is the ability to atomically write multiple slices of memory with distinct start address and length. It can be useful to reduce the number of syscalls required to execute the writes and also allows avoiding intermediate buffers to compose them in the proper order.

SC::Async unifies such platform differences providing a simpler experience for library users.

Some other changes also have been done, centralizing AsyncRequest start in AsyncEventLoop and unifying AsyncTask for all request types. These changes have been made to prepare for a larger feature that will land next month (surprise!).

Unfortunately some fields have been renamed, soft-breaking the API, but it shouldn't take more than a search and replace for library users to fix the errors. Also the Async API will change again during next weeks so maybe it's a good idea to resume updating next month.

Tools

It's been a while since last refresh to SC::Tools!

SC::Tools are awesome, they just use Sane C++ Libraries to do the typical "scripting" that one would do in bash or python but with zero dependencies!

This month some dependencies have been updated, mainly clang-format, doxygen and 7zip.
Also the SC::Package tool that downloads / clones repos from inside SC::Build scripts is now using shallow cloning, bringing a noticeable speedup!

It's possible to now run SC::Format and build documentation and coverage on Linux instead of macOS only, so that the CI can just use any simple Linux VM instead of a more complex and less available macOS one.

SC::Format uses clang-19 so make sure to use it if you ever plan to send an MR to the project (but the CI will error out immediately anyway, so you will find out very quickly).

The doxygen update was long overdue but every version of doxygen was plagued with some bug breaking the documentation. The 1.12.0 version seems to work better, but if you see anything wrong please open an issue on github.

Build

SC::Build has gained per-file include paths variable expansion for Visual Studio Projects and coverage computation on Linux. Some features like nostdlib++ have been disabled on Linux because they need more love to properly support all combinations of it with the sanitizers.

Repository Restructuring

The repository has been restructured as well, with the SC.cpp unity build file moved to the root of the repo and all tests moved to a Tests subdirectory. Also C bindings for the library now live together with the corresponding C++ library itself. Hopefully this now makes more sense than before.

I know that this will break someone's build, but hey, it's a single file, it shouldn't take that much time to update its path in your build system.

Fixes

And just a single fix that doesn't fit in any of the previous bigger categories!