| 3334 | #ifdef ARCH_MM_MMU |
| 3335 | |
| 3336 | long _sys_clone(void *arg[]) |
| 3337 | { |
| 3338 | struct rt_lwp *lwp = 0; |
| 3339 | rt_thread_t thread = RT_NULL; |
| 3340 | rt_thread_t self = RT_NULL; |
| 3341 | int tid = 0; |
| 3342 | rt_err_t err; |
| 3343 | |
| 3344 | unsigned long flags = 0; |
| 3345 | void *user_stack = RT_NULL; |
| 3346 | int *new_tid = RT_NULL; |
| 3347 | void *tls = RT_NULL; |
| 3348 | /* |
| 3349 | musl call flags (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
| 3350 | | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS |
| 3351 | | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_DETACHED); |
| 3352 | */ |
| 3353 | |
| 3354 | /* check args */ |
| 3355 | if (!lwp_user_accessable(arg, sizeof(void *[SYS_CLONE_ARGS_NR]))) |
| 3356 | { |
| 3357 | return -EFAULT; |
| 3358 | } |
| 3359 | |
| 3360 | flags = (unsigned long)(size_t)arg[0]; |
| 3361 | if ((flags & (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SYSVSEM)) |
| 3362 | != (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | CLONE_SYSVSEM)) |
| 3363 | { |
| 3364 | return -EINVAL; |
| 3365 | } |
| 3366 | |
| 3367 | user_stack = arg[1]; |
| 3368 | new_tid = (int *)arg[2]; |
| 3369 | tls = (void *)arg[3]; |
| 3370 | |
| 3371 | if ((flags & CLONE_PARENT_SETTID) == CLONE_PARENT_SETTID) |
| 3372 | { |
| 3373 | if (!lwp_user_accessable(new_tid, sizeof(int))) |
| 3374 | { |
| 3375 | return -EFAULT; |
| 3376 | } |
| 3377 | } |
| 3378 | |
| 3379 | self = rt_thread_self(); |
| 3380 | lwp = self->lwp; |
| 3381 | lwp_ref_inc(lwp); |
| 3382 | if (!user_stack) |
| 3383 | { |
| 3384 | SET_ERRNO(EINVAL); |
| 3385 | goto fail; |
| 3386 | } |
| 3387 | if ((tid = lwp_tid_get()) == 0) |
| 3388 | { |
| 3389 | SET_ERRNO(ENOMEM); |
| 3390 | goto fail; |
| 3391 | } |
| 3392 | |
| 3393 | thread = rt_thread_create(self->parent.name, |
no test coverage detected