1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define _GNU_SOURCE
17 #include <stdarg.h>
18 #include <unistd.h>
19 #include <sched.h>
20 #include <signal.h>
21 #include "pthread_impl.h"
22 #include "syscall.h"
23 #include "libc.h"
24
25 struct __clone_args {
26 int (*func)(void *);
27 void *arg;
28 };
29
__start_child(void * clone_args)30 static int __start_child(void *clone_args)
31 {
32 int status;
33 sigset_t set;
34 int (*func)(void *) = ((struct __clone_args *)clone_args)->func;
35 void *arg = ((struct __clone_args *)clone_args)->arg;
36
37 __block_all_sigs(&set);
38 pthread_t self = __pthread_self();
39 self->tid = __syscall(SYS_gettid);
40 self->robust_list.off = 0;
41 self->robust_list.pending = 0;
42 self->next = self->prev = self;
43 __thread_list_lock = 0;
44 libc.threads_minus_1 = 0;
45 libc.exit = 0;
46 signal(SIGSYS, arm_do_signal);
47 __restore_sigs(&set);
48
49 status = func(arg);
50 exit(status);
51 }
52
clone(int (* func)(void *),void * stack,int flags,void * arg,...)53 int clone(int (*func)(void *), void *stack, int flags, void *arg, ...)
54 {
55 int ret;
56 va_list ap;
57 pid_t *ptid, *ctid;
58 void *tls;
59 void *mmap_stack = NULL;
60 void *clone_stack = stack;
61 int (*clone_func)(void *) = func;
62 struct __clone_args *clone_args = (struct __clone_args *)arg;
63
64 va_start(ap, arg);
65 ptid = va_arg(ap, pid_t *);
66 tls = va_arg(ap, void *);
67 ctid = va_arg(ap, pid_t *);
68 va_end(ap);
69
70 if (!(flags & (CLONE_VM | CLONE_VFORK))) {
71 if (func) {
72 if (!stack) {
73 mmap_stack = __mmap(0, __default_stacksize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
74 if (mmap_stack == MAP_FAILED) {
75 errno = ENOMEM;
76 return -1;
77 }
78 clone_args = (struct __clone_args *)((char *)mmap_stack + __default_stacksize);
79 } else {
80 clone_args = (struct __clone_args *)stack;
81 }
82 clone_args = (struct __clone_args *)((uintptr_t)clone_args - ((uintptr_t)clone_args % sizeof(uintptr_t)));
83 clone_args = (struct __clone_args *)((char *)clone_args - sizeof(struct __clone_args));
84 clone_args->func = clone_func;
85 clone_args->arg = arg;
86 clone_func = __start_child;
87 clone_stack = (void *)clone_args;
88 }
89 }
90 ret = __syscall_ret(__clone(clone_func, clone_stack, flags, (void *)clone_args, ptid, tls, ctid));
91 if (mmap_stack) {
92 __munmap(mmap_stack, __default_stacksize);
93 }
94 return ret;
95 }
96