Earlier quoted context omitted.
A more accurate way to describe this is that Windows' (NT onward) core execution context model is a bunch of threads that by default share memory, whereas Unixen have a core task context model of a bunch of threads that by default do not share memory. Both systems are implemented using threads as the execution context, but in Unix, the history means that that you fork+exec most of the time, resulting in a two tasks t…
That's actually less accurate, not more. It's a post-hoc revision that conflates Unix with Linux. The Unix model was invented over a decade before the idea of multithreading percolated into mainstream operating systems at all. The reason that Windows NT started as it did, was that OS/2 had come out in 1987, with kernel threads, and the idea of multithreading had taken root. SunOS 5 gained threading, too. Windows NT a…
Moving beyond fork() + exec()
241–250 of 358 posts
Re: Moving beyond fork() + exec()
#242Earlier quoted context omitted.
If you want the isolation features of a separate process, you can’t substitute it with a single multithreaded COM server process. .NET tried this with app domains, which are now deprecated.
App Domains were in process, which isn't was I am talking about with outproc COM. Also App Domains are partially back in .NET Core, isolation features aren't there, but code unloading is, via AssemblyLoadContext.
Re: Moving beyond fork() + exec()
#243Related to the discussion: "A fork() in the road": https://www.microsoft.com/en-us/research/wp-content/uploads/... > ABSTRACT > The received wisdom suggests that Unix’s unusual combination of fork() and exec() for process creation was an inspired design. In this paper, we argue that fork was a clever hack for machines and programs of the 1970s that has long outlived its usefulness and is now a liability. We catalog t…
Re: Moving beyond fork() + exec()
#244Earlier quoted context omitted.
I kinda disagree, though I do see the usefulness here. While fork/exec can be useful in some cases, it'd be honestly pretty neat if the APIs took a pidfd argument (maybe with 0 meaning current process). Only program is setuid/setgid binaries I suppose but maybe this case is better handled by special casing `exec`. For example pidfd_t ps = spawn(); // creates a process stopped (kernel does this anyway by default) setu…
Maybe, a few people proposed this. It is a lot better than a single spawn call. But how often would one actually need this? And what are the semantics? Refer arguments (e.g. file descriptors) to the current process or the other one? How are cross-permissions handled? It seems a lot of complexity... Someones proposed a ptrace_syscall which could achieve the same thing.
Well, the idea is that it'd probably be close to the default API for spawning processes (and could even be the bedrock for posix_spawn and friends in libc (and potentially even "simple" fork cases[1])). fork/clone would be the special case
In most cases, most programs don't need special setup. Something like `ptrace_syscall` would also work for this and would be probably the way to do it with the backwards compat limitations of nowadays
ptrace-ability seems to be generally how permissions for this sort of thing are handled in general (see also procfs, process_vm_writev, ptrace, etc). The complication is a little bit around setuid programs but either you could special case execve to imply SIGCONT for setuid or have execve also imply a SIGCONT as well
[1]: Probably would be rare for a compiler to optimize it though
Re: Moving beyond fork() + exec()
#245Earlier quoted context omitted.
I'm not talking about glibc implementation details. I'm talking about how mixing fork(2) with threads creates harmful race conditions. The forked child has only 1 thread in its process. If the parent's threads are holding a lock or are in the middle of mutating a shared data structure, you're fucked, because those threads are no longer running in your child's copy of the address space and will not finish their work.…
Again, you're talking about userspace now. Not kernel-imposed constraints. A userspace program is always free to deadlock itself; fork doesn't change that.
This means if the program is multi threaded, you cannot rely on calling malloc in the child, because at the time of the fork another thread could have happened to be inside malloc doing manipulations on the global heap.
Which means, practically speaking, "don't allocate memory between fork and exec".
If you want to be overly literal as you have been, you can call mmap and it will give you new pages, but who is really doing that? Not the random shared library code you might want to call into. Hell, even a lot of libc calls malloc.
Which means it's not safe to do a random library call between fork and exec.
See where I'm going with this? That's if your program is multi threaded. If it isn't, these things are most likely fine.
Re: Moving beyond fork() + exec()
#246Earlier quoted context omitted.
Linux has worked pretty hard to optimize fork(). This doesn’t mean that fork() is a good idea. Windows does not historically depend on fork(), so there was no native fork(), so Cygwin kludged it up.
Actually, there is a native fork. There had to be, as POSIX personality support was a part of the Windows NT 3.1 design. What there wasn't was a Win32 form of fork. The Native API for Windows NT allowed it quite straightforwardly.
Though actually iirc werfault uses NtCreateUserProcess() to clone processes when writing out crash dumps to this day
Re: Moving beyond fork() + exec()
#247Earlier quoted context omitted.
That's actually less accurate, not more. It's a post-hoc revision that conflates Unix with Linux. The Unix model was invented over a decade before the idea of multithreading percolated into mainstream operating systems at all. The reason that Windows NT started as it did, was that OS/2 had come out in 1987, with kernel threads, and the idea of multithreading had taken root. SunOS 5 gained threading, too. Windows NT a…
PaulDavisThe1st is saying that the Unix pattern of forking a process (and not calling exec) was an early form of multi-threading (or multi-processing), but unlike threads in NT and later pthreads, they didn't share memory and communication between them required some form of IPC.
This obviously changed as pthreads came into being, and at this point, I suspect that the typical use for threads-sharing-memory and threads-not-sharing-memory is the same on most platforms.
A reminder that the task_t data structure describes threads and processes not just in Linux, but earlier Unixen also.
Re: Moving beyond fork() + exec()
#248Earlier quoted context omitted.
whereas Unixen have a core task context model of a bunch of threads that by default do not share memory. How are those not simply child processes? I don't understand your use of the word 'threads' here. Does the Unix world not distinguish between threads and processes? In Win32, threads exist within processes, and you can create new threads or child processes.
Actually on Windows a process is a thread with additional information. The unit of execution is the thread. On the UNIX world it depends on which UNIX you are talking about. Linux has a similar model to Windows NT nowadays, hence clone() as key primitive. Other UNIXes have different approaches.
Re: Moving beyond fork() + exec()
#249Re: Moving beyond fork() + exec()
#250Earlier quoted context omitted.
Nothing about the UNIX shell is reliant on the fork model. Windows processes have stdio handles as well.
A lot of features of UNIX shells are build around pipe and dup and the fork + exec model. One can certainly implement in differently, but it is - like UNIX in general - very nice and elegant.
Pipes and redirections don’t need fork + exec. Neither do subshells.