int __getosreldate(void) { static int osreldate; char *temp; if (osreldate == 0) { if ((temp = getenv("OSVERSION"))) { osreldate = atoi(temp); return (osreldate); } osreldate = __kernel_getosreldate (); } return (osreldate); }
int __clone (int (*fn) (void *), void *child_stack, int flags, void *arg) { int rfork_flags = RFPROC; if (fn == NULL || child_stack == NULL) { __set_errno (EINVAL); return -1; } /* This implementation of clone() does not support all Linux flags. */ if (flags & ~(CSIGNAL | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VFORK | CLONE_SYSVSEM)) { __set_errno (EINVAL); return -1; } if ((flags & CSIGNAL) != SIGCHLD) { if (__kernel_getosreldate() >= 802510) /* we slightly cheat here, */ /* the 9.x snapshot prior to r223966 does not support it too */ { if ((flags & CSIGNAL) & ~RFTSIGMASK) { __set_errno (EINVAL); return -1; } rfork_flags |= (RFTSIGZMB | RFTSIGFLAGS(flags & CSIGNAL)); } else { if ((flags & CSIGNAL) & ~RFTHPNMASK) { __set_errno (EINVAL); return -1; } if ((flags & CSIGNAL) == 0) rfork_flags |= (RFLINUXTHPN | ((SIGCHLD) << RFTHPNSHIFT)); else rfork_flags |= (RFLINUXTHPN | ((flags & CSIGNAL) << RFTHPNSHIFT)); } } if (flags & CLONE_VM) rfork_flags |= RFMEM; if (flags & CLONE_FS) /* Sharing the filesystem related info (umask, cwd, root dir) is not supported by rfork. Ignore this; let's hope programs will set their umask and cwd before spawning threads. */ ; if (flags & CLONE_SYSVSEM) /* Ignore this; it has been introduced into linuxthreads in post 2.4 glibc */ ; if (!(flags & CLONE_FILES)) rfork_flags |= RFFDG; if (flags & CLONE_SIGHAND) { rfork_flags |= RFSIGSHARE; /* Also set the undocumented flag RFTHREAD. It has the effect that when the thread leader exits, all threads belonging to it are killed. */ rfork_flags |= RFTHREAD; } if (flags & CLONE_VFORK) rfork_flags |= RFPPWAIT; return __start_thread (rfork_flags, child_stack, fn, arg); }