4 ms·
On linux at least, and probably most other unixes, it is implemented with fork/exec. In fact, there are two execs, one to start the shell, and one for the shell
by thayne 3y ago
On linux at least, and probably most other unixes, it is implemented with fork/exec. In fact, there are two execs, one to start the shell, and one for the shell to start the actual program. And depending on your command, and the shell implementation you might have another fork as well.
- adrian_b 3y agoHow it is implemented is irrelevant. The Standard C function system() is defined to execute a shell process and its semantics do not depend on how a process is executed by the host operating system. Obviously in any UNIX-derived OS a shell process must be executed via fork and exec, and the shell itself executes children processes also via fork and exec. Under other operating systems no fork or exec are used. What matters is that system() is not defined as a combination of fork with exec, but it does a more complex operation, with a greater overhead, and which works more or less in the same way under any OS. As others have mentioned, POSIX does have a wrapper for fork and exec, which is posix_spawn().
- thayne 3y ago> its semantics do not depend on how a process is executed by the host operating system Implementation details can leak though. For example on unix, if your process uses a lot of memory, a fork can result in an out of memory error, if there isn't enough memory left on the system to copy the parent process memory. And afaict things like how file descriptors are inherited are implementation defined. > which works more or less in the same way under any OS Even ignoring subtle differences in how subprocesses are spawned, there is the little issue that shell escaping and argument splitting works differently on different OSes, or even different shells on the same OS.
- adrian_b 3y agoBecause the differences mentioned by you between shells and OSes are unavoidable, the C standard specifies that the interpretation of the character string passed as an argument of the system() function is implementation-defined and it must be documented by any implementation of the standard C library. This does not change the fact that whether a system() function implementation uses or does not use fork and exec is neither specified by the function definition nor relevant for the user, and in any case system() is not the function that should be used when the intention is to simplify some code that otherwise would invoke fork and exec.
- thayne 3y ago> This does not change the fact that whether a system() function implementation uses or does not use fork and exec is neither specified by the function definition nor relevant for the user I agree that it isn't specified, but it can be relevant for the user, depending on what the user is doing. > in any case system() is not the function that should be used when the intention is to simplify some code that otherwise would invoke fork and exec Which was my original point. system doesn't save you from the problems of fork/exec, because depending on the system, it might be using fork/exec anyway, and adds additional limitations and caveats on top.
- lgg 3y agoposix_spawn() is specified such that it is possible (but does not required!) it to be implemented in terms of [v]fork() and exec(). On macOS it is a syscall and is generally faster than using vfork() and exec(). It also has a number of extensions like POSIX_SPAWN_CLOEXEC_DEFAULT, POSIX_SPAWN_SETEXEC, and `posix_spawn_file_actions_addchdir_np()` that allow it to actually be used in many cases where other systems need to resort to fork() and exec().