0

I'm trying to run an application in C, but the only way I could find that is reasonably easy to use works like this:

system("command here");

It works, of course, but it's really slow (especially when repeating this a lot). I'm just wondering if there is a way of running a program without having to interact with a shell, something like python's subprocess module.

I have heard of execl, and I would use that (forking it first, of course), but I'm wondering if there is a simpler way that wouldn't require forking first.

EDIT: I also want to be able to know the return code of the program

6
  • Python, being built on C, will just be wrapping that functionality. All you need to do is define your own function to fork and exec, then use that wherever you need it. Commented Mar 30, 2013 at 3:40
  • @Dave, yes, of course, but how would I know the return code of the program? Commented Mar 30, 2013 at 3:42
  • You can waitpid (with WNOHANG if you want to be asynchronous) which will give you the exit status once it has closed. Commented Mar 30, 2013 at 3:46
  • (and, to be clear, the pid is what you get from fork if you are in the main program. And you get 0 if you are in the child program) Commented Mar 30, 2013 at 3:47
  • 1
    @Gabe, hmm, interesting... but it really doesn't look too nice (I think fork/execl would be easier to read)... Commented Mar 30, 2013 at 4:17

2 Answers 2

2

If neither system() nor popen() provides the mechanism you need, then the easy way to do it is with fork() and execv() (or, perhaps, execl(), but the argument list must be fixed at compile time, not variable, to use it). Really! It is not hard to do fork() and exec(), and any alternative will encapsulate that processing.

The Python subprocess module is simply hiding fork() and exec() for you behind a convenient interface. That's probably appropriate for a high-level language like Python. C is a lower-level language and doesn't really need the complexity.

The hard way to do it is with posix_spawn(). You have to create arguments to describe all the actions you want done in the child between the fork() and the exec(), which is far harder to set up than it is to simply do the fork(), make the changes, and then use exec() after all. This (posix_spawn()) is what you get when you design the code to spawn a child process without visibly using fork() and exec() and ensure that it can handle almost any reasonable circumstance.

You'll need to consider whether you need to use wait() or waitpid() or a variant to determine when the child is complete. You may need to consider whether to handle the SIGCHLD signal (which will notify you when a child dies).

Sign up to request clarification or add additional context in comments.

Comments

2

As I'm sure you already know, system already employs the fork/exec strategy. I understand you want to circumvent the shell and are looking for a simple approach, I'm just saying you could just as easily write a function to wrap the fork/exec pattern as is done in system. Indeed it would probably be most straightforward to just do that. An alternative as Gabe mentioned in the comments is posix_spawn.

A faster (but apparently discouraged) alternative is vfork() / exec, but this is generally discouraged and is obsolete in the latest POSIX standards.

4.3BSD; POSIX.1-2001 (but marked OBSOLETE). POSIX.1-2008 removes the specification of vfork().

It's meant to be immediately followed by an exec or _exit. Otherwise all kinds of weird bugs can arise since the virtual memory pages and page tables aren't duplicated (child uses same data/heap/stack segments). The parent/calling process blocks until the child execs or _exits. Regular fork's modern implementations have copy-on-write semantics which approach the speed of vfork, without the potential bugs incurred by vfork's memory sharing semantics.

If you want even further control over memory-sharing semantics and process inheritance, and the consequent potential speed-up (and are on Linux), look into clone() (wrapper for system-call sys_clone()) which is what some process-creating system calls delegate their work to. Be sure to carefully comb over all of the various flags.

You can use waitpid to get the exit status of the process.

3 Comments

vfork() is weird; the rules for accurate use are very stringent; it is easy to get it wrong.
@JonathanLeffler Indeed. Hopefully I made this clear enough to the OP so that they may more carefully weigh their options.
POSIX 2024 has removed vfork().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.