Thread: C Clone wait to exit problem

  1. #1
    Registered User
    Join Date
    Mar 2020
    Posts
    7

    C Clone wait to exit problem

    hello
    im trying to create a new thread using clone function ... everything looks ok but it's not working !!

    Code:
    #define _GNU_SOURCE
    #include <sched.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <wait.h>
    
    #define THREAD_MEMORY_SIZE      1024
    
    int
    child_func(void * data) {
        static const char msg[] = "Child process is called\n";
    
        write(0, msg, sizeof(msg) - 1);
    
        exit(0);
    }
    
    int
    main() {
        int pid;
        void * memory;
    
        static const char ERROR_MEMORY_ALLOC_FAILED[]   = "ERROR-> Memory allocation failed\n";
        static const char ERROR_CLONE_FAILED[]          = "ERROR-> Unable to create a new child process\n";
    
        if((memory = malloc(THREAD_MEMORY_SIZE)) == NULL) {
            write(0, ERROR_MEMORY_ALLOC_FAILED, sizeof(ERROR_MEMORY_ALLOC_FAILED) - 1);
            exit(1);
        }
    
        if((pid = clone(child_func, (memory + THREAD_MEMORY_SIZE),
                        CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PARENT | CLONE_THREAD | CLONE_IO, NULL)) < 0) {
            free(memory);
            write(0, ERROR_CLONE_FAILED, sizeof(ERROR_CLONE_FAILED) - 1);
            exit(1);
        }
    
        waitpid(pid, NULL, __WCLONE);
    
        free(memory);
        exit(0);
    }
    here i created a thread and the thread function (child_func) Must be called and it Must write "Child process is called " message but nothing happen !!

    what is the problem !!! ? i think there is a problem in (waitpid) section !!! i think even by calling waitpid, the parent is not wait for child to exit or (execute) !

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Quote Originally Posted by rtfm
    int clone(int (*fn)(void *), void *child_stack,
    int flags, void *arg, ...
    /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
    ...
    Linux 2.4 and earlier
    In Linux 2.4 and earlier, clone() does not take arguments ptid, tls, and ctid.
    Unless you have a truly fossil kernel, then you're missing parameters.

    Maybe it's barfing because of all the garbage addresses you're not specifying.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Mar 2020
    Posts
    7
    Quote Originally Posted by Salem View Post
    Unless you have a truly fossil kernel, then you're missing parameters.

    Maybe it's barfing because of all the garbage addresses you're not specifying.
    They only needed when you have special flags like child set id and ... that's what i heard !

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    OK, couple of things in testing.

    1. 1024 bytes is nowhere near enough for a stack. Try it with 1MB

    2. It seems wait() isn't all that it should be - maybe it's one of the many clone flags you pass.

    Code:
    #define _GNU_SOURCE
    #include <sched.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <wait.h>
    
    #define THREAD_MEMORY_SIZE      (1024*1024)
    
    int
    child_func(void * data) {
        static const char msg[] = "Child process is called\n";
    
        write(0, msg, sizeof(msg) - 1);
    
        exit(0);
    }
    
    int
    main() {
        int pid;
        void * memory;
    
        static const char ERROR_MEMORY_ALLOC_FAILED[]   = "ERROR-> Memory allocation failed\n";
        static const char ERROR_CLONE_FAILED[]          = "ERROR-> Unable to create a new child process\n";
    
        if((memory = malloc(THREAD_MEMORY_SIZE)) == NULL) {
            write(0, ERROR_MEMORY_ALLOC_FAILED, sizeof(ERROR_MEMORY_ALLOC_FAILED) - 1);
            exit(1);
        }
    
        if((pid = clone(child_func, (memory + THREAD_MEMORY_SIZE),
                        CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PARENT | CLONE_THREAD | CLONE_IO, NULL)) < 0) {
            free(memory);
            write(0, ERROR_CLONE_FAILED, sizeof(ERROR_CLONE_FAILED) - 1);
            exit(1);
        }
    
        printf("child pid=%d, my pid=%d\n",pid,getpid());
        waitpid(pid, NULL, __WCLONE);
        sleep(1);
    
        free(memory);
        exit(0);
    }
    
    $ gcc -Wall -g foo.c
    $ ./a.out 
    child pid=6392, my pid=6391
    Child process is called
    $ ./a.out 
    child pid=6394, my pid=6393
    Child process is called
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Mar 2020
    Posts
    7
    Quote Originally Posted by Salem View Post
    OK, couple of things in testing.

    1. 1024 bytes is nowhere near enough for a stack. Try it with 1MB

    2. It seems wait() isn't all that it should be - maybe it's one of the many clone flags you pass.

    Code:
    #define _GNU_SOURCE
    #include <sched.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <wait.h>
    
    #define THREAD_MEMORY_SIZE      (1024*1024)
    
    int
    child_func(void * data) {
        static const char msg[] = "Child process is called\n";
    
        write(0, msg, sizeof(msg) - 1);
    
        exit(0);
    }
    
    int
    main() {
        int pid;
        void * memory;
    
        static const char ERROR_MEMORY_ALLOC_FAILED[]   = "ERROR-> Memory allocation failed\n";
        static const char ERROR_CLONE_FAILED[]          = "ERROR-> Unable to create a new child process\n";
    
        if((memory = malloc(THREAD_MEMORY_SIZE)) == NULL) {
            write(0, ERROR_MEMORY_ALLOC_FAILED, sizeof(ERROR_MEMORY_ALLOC_FAILED) - 1);
            exit(1);
        }
    
        if((pid = clone(child_func, (memory + THREAD_MEMORY_SIZE),
                        CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PARENT | CLONE_THREAD | CLONE_IO, NULL)) < 0) {
            free(memory);
            write(0, ERROR_CLONE_FAILED, sizeof(ERROR_CLONE_FAILED) - 1);
            exit(1);
        }
    
        printf("child pid=%d, my pid=%d\n",pid,getpid());
        waitpid(pid, NULL, __WCLONE);
        sleep(1);
    
        free(memory);
        exit(0);
    }
    
    $ gcc -Wall -g foo.c
    $ ./a.out 
    child pid=6392, my pid=6391
    Child process is called
    $ ./a.out 
    child pid=6394, my pid=6393
    Child process is called
    it's works now but this is not the problem ! when you put the parent on sleep, you give enough time to child to complete ... it's not true to do it with sleep ! it's 'wait' or 'waitpid' function duty .. by calling waitpid, program must wait until 'child_func' exit ... this is the problem !!!! waitpid or wait or wai4 functions are not working here ! and they can't hold parent process for child_func to exit ... this is my problem ...

  6. #6
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    Check the return value of waitpid. That may give you a clue what the problem is.

    Edit: Also, in the future, report what you expect to happen and what actually happens. Writing stuff like Must write "Child process is called " isn't clear whether that happens or is what you want to happen (at least to me).

  7. #7
    Registered User
    Join Date
    Mar 2020
    Posts
    7
    Quote Originally Posted by christop View Post
    Check the return value of waitpid. That may give you a clue what the problem is.

    Edit: Also, in the future, report what you expect to happen and what actually happens. Writing stuff like Must write "Child process is called " isn't clear whether that happens or is what you want to happen (at least to me).
    it's very simple usage of clone function ! nothing special ! also i checked the value of waitpid and it returns (-1) which is invalid child id !!! but it's looks valid !!!!

  8. #8
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    Ok, then if waitpid returns -1 (which doesn't necessarily mean "invalid child id"), that means you need to check errno for the error code (I probably should have said so in my previous post).

    You could also try calling waitpid with a pid of -1 to make it wait for "any" child process and do the same (check the return value and errno).

  9. #9
    Registered User
    Join Date
    Mar 2020
    Posts
    7
    Quote Originally Posted by christop View Post
    Ok, then if waitpid returns -1 (which doesn't necessarily mean "invalid child id"), that means you need to check errno for the error code (I probably should have said so in my previous post).

    You could also try calling waitpid with a pid of -1 to make it wait for "any" child process and do the same (check the return value and errno).
    still there is a problem in waitpid with the provided pid from clone .... and we need to check why ! because maybe we going to have 10 threads and we need to wait for only 5 of them (special pid list) ! not all of them ...

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Well this works as I would expect.
    But then again, it sets all the flags to 0.
    Code:
    #define _GNU_SOURCE
    #include <sched.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <wait.h>
    
    #define THREAD_MEMORY_SIZE      (1024*1024)
    
    int
    child_func(void * data) {
        static const char msg[] = "Child process is called\n";
        pid_t pid = getpid();
        pid_t ppid = getppid();
        char buff[100];
        sprintf(buff,"Child: pid=%d, ppid=%d\n",pid,ppid);
    
        write(0, msg, sizeof(msg) - 1);
        write(0, buff, strlen(buff));
        return 1;
    }
    
    int
    main() {
        int pid;
        void * memory;
    
        static const char ERROR_MEMORY_ALLOC_FAILED[]   = "ERROR-> Memory allocation failed\n";
        static const char ERROR_CLONE_FAILED[]          = "ERROR-> Unable to create a new child process\n";
    
        if((memory = malloc(THREAD_MEMORY_SIZE)) == NULL) {
            write(0, ERROR_MEMORY_ALLOC_FAILED, sizeof(ERROR_MEMORY_ALLOC_FAILED) - 1);
            exit(1);
        }
    
        int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
                    CLONE_PARENT | CLONE_THREAD | CLONE_IO;
        flags = 0;
        flags |= SIGCHLD;
        if((pid = clone(child_func, (memory + THREAD_MEMORY_SIZE), flags, NULL)) < 0) {
            free(memory);
            write(0, ERROR_CLONE_FAILED, sizeof(ERROR_CLONE_FAILED) - 1);
            exit(1);
        }
    
        int status;
        int r = waitpid(pid, &status, 0);
        printf("Parent: pid=%d, ppid=%d\n",getpid(),getppid());
        printf("waitpid returned %d, child status=%d\n",r,status);
    
        free(memory);
        exit(0);
    }
    
    $ ./a.out 
    Child process is called
    Child: pid=5239, ppid=5238
    Parent: pid=5238, ppid=4696
    waitpid returned 5239, child status=256
    $ ./a.out 
    Child process is called
    Child: pid=5241, ppid=5240
    Parent: pid=5240, ppid=4696
    waitpid returned 5241, child status=256
    But if I use the flags you specified, then it all goes to pot.
    After several attempts, I saw this.
    Code:
    $ ./a.out 
    Child process is called
    Parent: pid=5333, ppid=4696
    Child: pid=5333, ppid=4696
    waitpid returned -1, child status=0
    pid and ppid are the same with your set of flags.
    You can't successfully wait() for yourself.

    And it's just a race condition between them to see which exits first - which is why you only ever see part of the total expected output.

    So, what are you trying to achieve that pthread cannot?

    This is what a clone() call looks like when called from pthread_create.
    Code:
    clone(child_stack=0x7fcf18630ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, 
    parent_tidptr=0x7fcf186319d0, tls=0x7fcf18631700, child_tidptr=0x7fcf186319d0) = 5023
    strace is your friend.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  11. #11
    Registered User
    Join Date
    Mar 2020
    Posts
    7
    Quote Originally Posted by Salem View Post
    Well this works as I would expect.
    But then again, it sets all the flags to 0.
    Code:
    #define _GNU_SOURCE
    #include <sched.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <wait.h>
    
    #define THREAD_MEMORY_SIZE      (1024*1024)
    
    int
    child_func(void * data) {
        static const char msg[] = "Child process is called\n";
        pid_t pid = getpid();
        pid_t ppid = getppid();
        char buff[100];
        sprintf(buff,"Child: pid=%d, ppid=%d\n",pid,ppid);
    
        write(0, msg, sizeof(msg) - 1);
        write(0, buff, strlen(buff));
        return 1;
    }
    
    int
    main() {
        int pid;
        void * memory;
    
        static const char ERROR_MEMORY_ALLOC_FAILED[]   = "ERROR-> Memory allocation failed\n";
        static const char ERROR_CLONE_FAILED[]          = "ERROR-> Unable to create a new child process\n";
    
        if((memory = malloc(THREAD_MEMORY_SIZE)) == NULL) {
            write(0, ERROR_MEMORY_ALLOC_FAILED, sizeof(ERROR_MEMORY_ALLOC_FAILED) - 1);
            exit(1);
        }
    
        int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
                    CLONE_PARENT | CLONE_THREAD | CLONE_IO;
        flags = 0;
        flags |= SIGCHLD;
        if((pid = clone(child_func, (memory + THREAD_MEMORY_SIZE), flags, NULL)) < 0) {
            free(memory);
            write(0, ERROR_CLONE_FAILED, sizeof(ERROR_CLONE_FAILED) - 1);
            exit(1);
        }
    
        int status;
        int r = waitpid(pid, &status, 0);
        printf("Parent: pid=%d, ppid=%d\n",getpid(),getppid());
        printf("waitpid returned %d, child status=%d\n",r,status);
    
        free(memory);
        exit(0);
    }
    
    $ ./a.out 
    Child process is called
    Child: pid=5239, ppid=5238
    Parent: pid=5238, ppid=4696
    waitpid returned 5239, child status=256
    $ ./a.out 
    Child process is called
    Child: pid=5241, ppid=5240
    Parent: pid=5240, ppid=4696
    waitpid returned 5241, child status=256
    But if I use the flags you specified, then it all goes to pot.
    After several attempts, I saw this.
    Code:
    $ ./a.out 
    Child process is called
    Parent: pid=5333, ppid=4696
    Child: pid=5333, ppid=4696
    waitpid returned -1, child status=0
    pid and ppid are the same with your set of flags.
    You can't successfully wait() for yourself.

    And it's just a race condition between them to see which exits first - which is why you only ever see part of the total expected output.

    So, what are you trying to achieve that pthread cannot?

    This is what a clone() call looks like when called from pthread_create.
    Code:
    clone(child_stack=0x7fcf18630ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, 
    parent_tidptr=0x7fcf186319d0, tls=0x7fcf18631700, child_tidptr=0x7fcf186319d0) = 5023
    strace is your friend.
    hello
    im working on this function for 4 days !!! and used strace and ... i also checked the pthread_create flags ..... here you set the flags but then you zero them .... in fact, here the flags are just (0|SIGCHLD) ... i test this my self without CLONE_THREAD|CLONE_PARENT flags and it's worked .... there is no problem when we use this flags

    Code:
    CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD|CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_IO|CLONE_SIGHAND

    even wait4 works for my flags !!! my problem is when using (CLONE_THREAD|CLONE_PARENT) flags to create a thread not child process, wait4 is not working any more

  12. #12
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Please explain why you desperately need CLONE_PARENT in your flags?
    CLONE_PARENT (since Linux 2.3.12)
    If CLONE_PARENT is set, then the parent of the new child (as returned by getppid(2)) will be the same as that of the calling process.
    All this does is give two things the same pid, such that it becomes impossible to use any of the wait() system calls for one of them to find out what the other is up to.

    You need a different way of finding out when one of them has exited.

    Either you give up CLONE_PARENT, or you give up using wait() to figure out when the child has exited.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  13. #13
    Registered User
    Join Date
    Mar 2020
    Posts
    7
    Quote Originally Posted by Salem View Post
    Please explain why you desperately need CLONE_PARENT in your flags?


    All this does is give two things the same pid, such that it becomes impossible to use any of the wait() system calls for one of them to find out what the other is up to.

    You need a different way of finding out when one of them has exited.

    Either you give up CLONE_PARENT, or you give up using wait() to figure out when the child has exited.
    Im trying to create a thread not a child process like fork ! because by adding CLONE_THREAD flag, you creating a thread ! and thread has better performance (No new process) than creating a new process !
    im not talking about CLONE_PARENT ... in fact, the problem is from creating a THREAD by using CLONE_THREAD flag ... there is no problem when i don't use CLONE_THREAD flag .... and wait4 works fine ...
    but the problem starts from the moment i add CLONE_THREAD flag .... wait4 can't wait for it any more and crash happen !

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Are you even reading the manual page?
    CLONE_THREAD (since Linux 2.4.0-test8)
    If CLONE_THREAD is set, the child is placed in the same thread group as the calling process. To make the remainder of the discussion of CLONE_THREAD
    more readable, the term "thread" is used to refer to the processes within a thread group.

    Thread groups were a feature added in Linux 2.4 to support the POSIX threads notion of a set of threads that share a single PID.
    If it's a single pid, then the wait() system calls are useless for you.

    Again, explain why you're not using pthread_create et al to do this for you. It's just a bad re-invention of the wheel at the moment.

    Code:
    clone(child_stack=0x7fcf18630ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|
    CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, 
    parent_tidptr=0x7fcf186319d0, tls=0x7fcf18631700, child_tidptr=0x7fcf186319d0) = 5023
    futex(0x7fcf186319d0, FUTEX_WAIT, 5023, NULL) = -1 EAGAIN (Resource temporarily unavailable)
    Yes that's right Dorothy, actual pthreads using CLONE_THREAD also make use of the extra child_tidptr to assist with inter-thread synchronisation through the form of a futex.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Exit problem
    By harq in forum C++ Programming
    Replies: 4
    Last Post: 11-28-2005, 09:32 PM
  2. loop-exit problem
    By duvernais28 in forum C Programming
    Replies: 4
    Last Post: 02-01-2005, 08:26 PM
  3. Exit Windows problem
    By cfrost in forum Windows Programming
    Replies: 7
    Last Post: 08-18-2004, 05:21 PM
  4. BreakOut clone problem
    By cMADsc in forum Game Programming
    Replies: 4
    Last Post: 01-20-2003, 02:24 PM
  5. easy problem with strchr-clone
    By Unregistered in forum C Programming
    Replies: 2
    Last Post: 01-03-2002, 01:45 PM

Tags for this Thread