|  | /* clone_linux.c -- consistent wrapper around Linux clone syscall | 
|  |  | 
|  | Copyright 2016 The Go Authors. All rights reserved. | 
|  | Use of this source code is governed by a BSD-style | 
|  | license that can be found in the LICENSE file.  */ | 
|  |  | 
|  | #include <errno.h> | 
|  | #include <sys/syscall.h> | 
|  |  | 
|  | #include "runtime.h" | 
|  |  | 
|  | long rawClone (unsigned long flags, void *child_stack, void *ptid, | 
|  | void *ctid, void *regs) | 
|  | __asm__ (GOSYM_PREFIX "syscall.rawClone") | 
|  | __attribute__ ((no_split_stack)); | 
|  |  | 
|  | long | 
|  | rawClone (unsigned long flags, void *child_stack, void *ptid, void *ctid, void *regs) | 
|  | { | 
|  | #if defined(__arc__) || defined(__aarch64__) || defined(__arm__) || defined(__mips__) || defined(__hppa__) || defined(__powerpc__) || defined(__score__) || defined(__i386__) || defined(__xtensa__) | 
|  | // CLONE_BACKWARDS | 
|  | return syscall(__NR_clone, flags, child_stack, ptid, regs, ctid); | 
|  | #elif defined(__s390__) || defined(__cris__) | 
|  | // CLONE_BACKWARDS2 | 
|  | return syscall(__NR_clone, child_stack, flags, ptid, ctid, regs); | 
|  | #elif defined(__microblaze__) | 
|  | // CLONE_BACKWARDS3 | 
|  | return syscall(__NR_clone, flags, child_stack, 0, ptid, ctid, regs); | 
|  | #elif defined(__sparc__) | 
|  |  | 
|  | /* SPARC has a unique return value convention: | 
|  |  | 
|  | Parent -->  %o0 == child's  pid, %o1 == 0 | 
|  | Child  -->  %o0 == parent's pid, %o1 == 1 | 
|  |  | 
|  | Translate this to look like a normal clone.  */ | 
|  |  | 
|  | # if defined(__arch64__) | 
|  |  | 
|  | #  define SYSCALL_STRING						\ | 
|  | "ta	0x6d;"							\ | 
|  | "bcc,pt	%%xcc, 1f;"						\ | 
|  | " mov	0, %%g1;"						\ | 
|  | "sub	%%g0, %%o0, %%o0;"					\ | 
|  | "mov	1, %%g1;"						\ | 
|  | "1:" | 
|  |  | 
|  | #  define SYSCALL_CLOBBERS						\ | 
|  | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",			\ | 
|  | "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",		\ | 
|  | "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",		\ | 
|  | "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",		\ | 
|  | "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46",		\ | 
|  | "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62",		\ | 
|  | "cc", "memory" | 
|  |  | 
|  | # else /* __arch64__ */ | 
|  |  | 
|  | #  define SYSCALL_STRING						\ | 
|  | "ta	0x10;"							\ | 
|  | "bcc	1f;"							\ | 
|  | " mov	0, %%g1;"						\ | 
|  | "sub	%%g0, %%o0, %%o0;"					\ | 
|  | "mov	1, %%g1;"						\ | 
|  | "1:" | 
|  |  | 
|  | #  define SYSCALL_CLOBBERS						\ | 
|  | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",			\ | 
|  | "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",		\ | 
|  | "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",		\ | 
|  | "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",		\ | 
|  | "cc", "memory" | 
|  |  | 
|  | # endif /* __arch64__ */ | 
|  |  | 
|  | register long o0 __asm__ ("o0") = (long)flags; | 
|  | register long o1 __asm__ ("o1") = (long)child_stack; | 
|  | register long o2 __asm__ ("o2") = (long)ptid; | 
|  | register long o3 __asm__ ("o3") = (long)ctid; | 
|  | register long o4 __asm__ ("o4") = (long)regs; | 
|  | register long g1 __asm__ ("g1") = __NR_clone; | 
|  |  | 
|  | __asm __volatile (SYSCALL_STRING : | 
|  | "=r" (g1), "=r" (o0), "=r" (o1) : | 
|  | "0" (g1), "1" (o0), "2" (o1), | 
|  | "r" (o2), "r" (o3), "r" (o4) : | 
|  | SYSCALL_CLOBBERS); | 
|  |  | 
|  | if (__builtin_expect(g1 != 0, 0)) | 
|  | { | 
|  | errno = -o0; | 
|  | o0 = -1L; | 
|  | } | 
|  | else | 
|  | o0 &= (o1 - 1); | 
|  |  | 
|  | return o0; | 
|  |  | 
|  | #else | 
|  | return syscall(__NR_clone, flags, child_stack, ptid, ctid, regs); | 
|  | #endif | 
|  | } |