From 44c34026b26a93a9b75414733309400d33357aea Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Mon, 10 Nov 2008 17:58:33 +0200 Subject: [PATCH] clone() call working. Tested exit(), clone() and fork() mixture running about 22 threads, processes. --- tasks/libposix/fork.c | 4 +-- tasks/mm0/include/syscalls.h | 1 + tasks/mm0/main.c | 4 +++ tasks/mm0/src/clone.c | 6 ++++- tasks/mm0/src/task.c | 8 ++---- tasks/test0/main.c | 6 ++++- tasks/test0/src/clone.c | 42 ------------------------------- tasks/test0/src/clonetest.c | 49 ++++++++++++++++++++++++++++++++++++ 8 files changed, 68 insertions(+), 52 deletions(-) delete mode 100644 tasks/test0/src/clone.c create mode 100644 tasks/test0/src/clonetest.c diff --git a/tasks/libposix/fork.c b/tasks/libposix/fork.c index 435a9fd..d4319e9 100644 --- a/tasks/libposix/fork.c +++ b/tasks/libposix/fork.c @@ -65,8 +65,8 @@ int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) l4_set_tag(L4_IPC_TAG_CLONE); /* Write the args as in usual ipc */ - write_mr(L4SYS_ARG0, flags); - write_mr(L4SYS_ARG1, (unsigned long)child_stack); + write_mr(L4SYS_ARG0, (unsigned long)child_stack); + write_mr(L4SYS_ARG1, flags); /* Perform an ipc but with different return logic. See implementation. */ if ((ret = arch_clone(PAGER_TID, PAGER_TID)) < 0) { diff --git a/tasks/mm0/include/syscalls.h b/tasks/mm0/include/syscalls.h index 54219b1..cb885b9 100644 --- a/tasks/mm0/include/syscalls.h +++ b/tasks/mm0/include/syscalls.h @@ -32,6 +32,7 @@ int sys_shmdt(struct tcb *requester, const void *shmaddr); int sys_shmget(key_t key, int size, int shmflg); int sys_fork(struct tcb *parent); +int sys_clone(struct tcb *parent, void *child_stack, unsigned int clone_flags); void sys_exit(struct tcb *task, int status); #endif /* __MM0_SYSARGS_H__ */ diff --git a/tasks/mm0/main.c b/tasks/mm0/main.c index 1146845..034bc69 100644 --- a/tasks/mm0/main.c +++ b/tasks/mm0/main.c @@ -126,6 +126,10 @@ void handle_requests(void) ret = sys_fork(sender); break; } + case L4_IPC_TAG_CLONE: { + ret = sys_clone(sender, (void *)mr[0], (unsigned int)mr[1]); + break; + } case L4_IPC_TAG_EXIT: { /* An exiting task has no receive phase */ sys_exit(sender, (int)mr[0]); diff --git a/tasks/mm0/src/clone.c b/tasks/mm0/src/clone.c index 2091e4d..e9a6525 100644 --- a/tasks/mm0/src/clone.c +++ b/tasks/mm0/src/clone.c @@ -122,10 +122,14 @@ int do_clone(struct tcb *parent, unsigned long child_stack, unsigned int flags) child->stack_end = child_stack; child->stack_start = 0; - /* Set child's stack pointer */ memset(&exregs, 0, sizeof(exregs)); + + /* Set child's stack pointer */ exregs_set_stack(&exregs, child_stack); + /* Set child's clone return value to 0 */ + exregs_set_mr(&exregs, MR_RETURN, 0); + /* Do the actual exregs call to c0 */ if ((err = l4_exchange_registers(&exregs, child->tid)) < 0) BUG(); diff --git a/tasks/mm0/src/task.c b/tasks/mm0/src/task.c index 4e3ad69..6ea5af8 100644 --- a/tasks/mm0/src/task.c +++ b/tasks/mm0/src/task.c @@ -61,13 +61,9 @@ struct tcb *find_task(int tid) { struct tcb *t; - list_for_each_entry(t, &global_tasks.list, list) { - /* A temporary precaution */ - BUG_ON(t->tid != t->spid); - if (t->tid == tid) { + list_for_each_entry(t, &global_tasks.list, list) + if (t->tid == tid) return t; - } - } return 0; } diff --git a/tasks/test0/main.c b/tasks/test0/main.c index be045c2..3f5d5b1 100644 --- a/tasks/test0/main.c +++ b/tasks/test0/main.c @@ -63,7 +63,11 @@ void main(void) } printf("Testing clone syscall...\n"); - clonetest(); + if ((pid = fork()) < 0) + printf("Error forking...\n"); + /* Child does the clonetest(). All of them will exit */ + if (pid == 0) + clonetest(); while (1) wait_pager(0); diff --git a/tasks/test0/src/clone.c b/tasks/test0/src/clone.c deleted file mode 100644 index 9528e06..0000000 --- a/tasks/test0/src/clone.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Clone test. - */ - -#include -#include -#include -#include -#include -#include - -int my_thread_func(void *arg) -{ - printf("Cloned child running...\n"); - printf("PID: %d\n", getpid()); - _exit(0); -} - -int clonetest(void) -{ - pid_t childid; - void *child_stack; - - if ((child_stack = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, 0, 0)) == MAP_FAILED) { - printf("MMAP failed.\n"); - _exit(1); - } else { - printf("Mapped area starting at %p\n", child_stack); - } - ((int *)child_stack)[-1] = 5; /* Test mapped area */ - - printf("Cloning...\n"); - - if ((childid = clone(my_thread_func, child_stack, - CLONE_PARENT | CLONE_FS | CLONE_VM | CLONE_THREAD | CLONE_SIGHAND, 0)) < 0) { - perror("CLONE failed.\n"); - } else { - printf("Cloned a new thread with child pid %d\n", childid); - } - return 0; -} - diff --git a/tasks/test0/src/clonetest.c b/tasks/test0/src/clonetest.c new file mode 100644 index 0000000..2ac63a5 --- /dev/null +++ b/tasks/test0/src/clonetest.c @@ -0,0 +1,49 @@ +/* + * Clone test. + */ +#include +#include +#include +#include +#include +#include + +int clone_global = 0; + +int my_thread_func(void *arg) +{ + printf("Cloned child %d running...\n", getpid()); + for (int i = 0; i < 25; i++) + clone_global++; + printf("Cloned child exiting with global increased to: %d. (Should be just about 100 at final)\n", clone_global); + _exit(0); +} + +int clonetest(void) +{ + pid_t childid; + void *child_stack; + + /* Parent loops and calls clone() to clone new threads. Children don't come back from the clone() call */ + for (int i = 0; i < 4; i++) { + if ((child_stack = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, 0, 0)) == MAP_FAILED) { + printf("MMAP failed.\n"); + _exit(1); + } else { + printf("Mapped area starting at %p\n", child_stack); + } + ((int *)child_stack)[-1] = 5; /* Test mapped area */ + + printf("Cloning...\n"); + + if ((childid = clone(my_thread_func, child_stack, + CLONE_PARENT | CLONE_FS | CLONE_VM | CLONE_THREAD | CLONE_SIGHAND, 0)) < 0) { + perror("CLONE failed.\n"); + } else { + printf("Cloned a new thread with child pid %d\n", childid); + } + } + _exit(0); + return 0; +} +