Taco Steemers

A personal blog.

Minimal Linux and Windows process spawn test

I am working on a small backup utility meant to add value to other, proper backup utilities. At the least, I want this program to run on any vanilla install of a (semi-) recent Linux or Windows desktop version. I would also like to keep a small file-size, and prefer not to depend on any non-standard libraries. The language of choice is C. The planned functionality of this program requires spawning different processes, without destroying the original process.

For that reason, I have looked in to writing the simplest cross-platform way of doing so. Before I started to look for information on launching new processes in C, running on a Linux and/or Windows OS, I had expected to find several examples of possible approaches. This turned out not to be the case, and so I had the pleasure of finding my own solution. Naturally, it was only after finishing my code sample that I stumbled upon the Wikipedia page for "Spawn (computing)" , which contains a lot of useful information.

For spawning a different process that runs beside the current process, the fork function in combination with a function from the exec family appears to be the standard on Linux operating systems. fork() duplicates the running process, but execv() loads a different process image into the duplicate process. My preference to not depend on any non-standard libraries excludes a solution such as the Cygwin dll , which I am told would support fork() under Windows. Instead, I wrote some platform specific code that makes use of the _spawnv function. If you are not familiar with it yet, be sure to read that page before using it. The page contains important information on the environment of the spawned process. The second and third arguments of execv() and _spawnv() respectively, are the arguments (argv) for the new program. That is what the v in the function names refers to.

I have probably overlooked something that a practiced C programmer would not. If you find anything to improve, feel free to get in contact or fork the github gist .

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef _WIN32
    #include <process.h> /* Required for _spawnv */
    #include <windows.h>
    /* We make getpid() work in a similar 
        way on Windows as it does on Linux */
    #define getpid() GetCurrentProcessId()
#endif
#ifdef __linux__
    #include <unistd.h>
#endif

void spawn_new_process(char * const *argv);
int pid;

int main(int argc, char *argv[])
{
    pid = getpid();
    if(argc > 1 && strcmp(argv[1],"the_new_process") == 0)
    {
        printf("[%d] This is a new process, and not a fork.\n", pid);
    }    
    else
    {
        printf("[%d] This is the original process.\n", pid);
        char *new_args[2];
        new_args[0] = argv[0];
        new_args[1] = "the_new_process";
        spawn_new_process((char * const *)new_args);
    }
    return(0);
}

void spawn_new_process(char * const *argv)
{
    #ifdef _WIN32
        /* This code block will also be reached on a 
           64 bit version of a Windows desktop OS */
        _spawnv(_P_NOWAIT, argv[0], (const char * const *)argv);
    #endif


    #ifdef __linux__
        pid = getpid();

        /* Create copy of current process */
        pid = fork();

        /* The parent`s new pid will be 0 */
        if(pid != 0)
        {
            /* We are now in a child progress 
               Execute different process */
            printf("[%d] Child (fork) process will call exec.\n",
                 pid);
            execv(argv[0], argv);


            /* This code will never be executed */
            printf("[%d] Child (fork) process is exiting.\n", pid);
            exit(EXIT_SUCCESS);
        }
    #endif

    /* We are still in the original process */
    printf("[%d] Original process is exiting.\n", pid);
    exit(EXIT_SUCCESS);
}

When run on Linux, we get the following output:

prompt> minimal_fork_test
[22166] This is the original process.
[22167] Child (fork) process will call exec.
[0] Original process is exiting.
[22166] This is a new process, and not a fork.
prompt>

When run under Windows, we get the following output:

prompt>minimal_fork_test
[14800] This is the original process.
[14800] Original process is exiting.

prompt>[14808] This is a new process, and not a fork.