Search code examples
clinuxparametersclonemanpage

How can a caller properly use the clone() system call by specifying multiple arguments?


I'm doing some research on the clone() system call and I was hoping someone could explain to me why a caller is allowed to pass multiple arguments at the end of this system call?

Looking at the documentation in the Linux man-pages the syntax for the system call is as follows:

int clone(int (*fn)(void *), void *stack, int flags, void *arg, ...
                 /* pid_t *parent_tid, void *tls, pid_t *child_tid */ );

It appears to me, the first parameter expected is a function address that returns an integer int and that function can only accept one argument, a void pointer (void *). However, following the last parameter, void *arg which I believe is the void pointer you would want to pass to your function, there is an ellipsis operator ... which I thought in C indicates that multiple arguments can be specified.

Given that the function you pass in the first parameter can only take in one argument, how would the caller take advantage of any more arguments added to the end of this system call?

To better my understanding I compiled and ran the code below. It works just fine, as far as I can tell, but I have no idea how or why anyone would have a use for something like extraParm

#define STACK 8192
int do_something(void *somevar){
        printf("Parent pid: %d\n Child pid : %d\n", getppid(), getpid());
        printf("Our variable passed : %d\n", *(int *)somevar);
        return 0;
}
int main() {
        void *stack = malloc(STACK);    
        int inputParm = 11;
        void *inputPtr = &inputParm;
        char extraParm[ ] = "Extra Parameter"; 
        if(!stack) {
                perror("Malloc Failed");
                exit(0);
        }
        if( clone( &do_something, (char *)stack + STACK, SIGCHLD, inputPtr, extraParm) < 0 ){
                perror("Clone Failed");
                exit(0);
        }
        printf("Clone call current pid : %d\n", getpid());
        sleep(1);      
        free(stack);
        return 0;
}

Output:

Clone call current pid : 545
Parent pid: 545
 Child pid : 546
Our variable passed : 11

I must be misinterpreting something, any clarification would be greatly appreciated


Solution

  • The additional arguments are optional arguments used to specify additional operations of the clone operation. They're only used if particular flags are set in the flags argument. If you don't set any of those flags, you don't need to supply the additional arguments.

    If you set the CLONE_PARENT_SETTID flag, the child's thread ID will be stored in the location that parent_tid points to in the parent process.

    If you set the CLONE_SETTLS flag, the tls argument will be used as the address of the thread-local storage descriptor.

    If you set the CLONE_CHILD_SETTID flag, the child's thread ID will be stored in the location that child_tid points to in the child process.

    It's done this way for backward compatibility. These arguments weren't in the original clone() system call, but were added in later Linux versions. They're optional so that older code will continue to compile.