I added an implementation of posix_spawn and its utility functions. It uses vfork/fork with execve/execvpe. The child status is eventually returned over a pipe to the parent.
The test usecase only covers the use of posix_spawn without file actions or spawnattr.

vfork is removed from issue 7 of POSIX, because when you have posix_spawn and a fork that does copy-on-write, there is really no need for it. So, it seems safe to forget about it and focus on making our fork implementation efficient (if it isn't already).

posix_spawn() could use a kern_vfork() (nothing POSIX) instead of fork(), because it's not really needed to copy the process memory when exec() is used just after. Out of memory on fork() seem very common.

IMO fork() isn't efficient to be used for posix_spawn(), an alternative would be nice.

The idea in Linux is to implement fork with copy-on-write, so no need to actually copy any of the data when forking (just the memory mapping needs to be copied and made read-only). However this would conflict with our "don't overcommit memory" management.

So, a vfork-style syscall to be used inside posix_spawn may be useful. But it seems one can get in a lot of trouble when multiple threads are involved, for example (in principle, vfork should block all of them in the parent until the child is done with its exec or exit). This is why making fork() as quick as possible may actually be a better idea.

However this would conflict with our "don't overcommit memory" management.

+1 to our "don't overcommit memory" system. Linux's model makes sense for servers where "usually" overcommitted memory is not a problem, but fork failures due to OOM would be; whereas non-overcommission makes more sense for GUI OSes where users expect applications to not be killed for no apparent reason under high-memory-usage scenarios.

But it seems one can get in a lot of trouble when multiple threads are involved, for example (in principle, vfork should block all of them in the parent until the child is done with its exec or exit).

How so? Since page tables and alternative threads are not copied, can't we just copy everything but the virtual address space (well, including the stack of course)? It doesn't sound too difficult to implement vfork(), actually.