• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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