@@ -1,3 +1,23 @@
+2016-04-16 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ * sysdeps/unix/sysv/linux/Makefile [$(subdir) == nptl] (test): Remove
+ tst-getpid2.
+ (test): Add tst-clone2.
+ * sysdeps/unix/sysv/linux/tst-clone2.c: New file.
+ * sysdeps/unix/sysv/linux/aarch64/clone.S (__clone): Do not change
+ pid/tid fields for CLONE_VM.
+ * sysdeps/unix/sysv/linux/arm/clone.S: Likewise.
+ * sysdeps/unix/sysv/linux/i386/clone.S: Likewise.
+ * sysdeps/unix/sysv/linux/mips/clone.S: Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S: Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S: Likewise.
+ * sysdeps/unix/sysv/linux/s390/s390-32/clone.S: Likewise.
+ * sysdeps/unix/sysv/linux/s390/s390-64/clone.S: Likewise.
+ * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Likewise.
+ * sysdeps/unix/sysv/linux/sparc/sparc64/clone.S: Likewise.
+ * sysdeps/unix/sysv/linux/x86_64/clone.S: Likewise.
+ * sysdeps/unix/sysv/linux/tst-getpid2.c: Remove file.
+
2016-04-16 Robin van der Vliet <info@robinvandervliet.com>
[BZ #19400]
@@ -42,7 +42,7 @@ sysdep_headers += sys/mount.h sys/acct.h sys/sysctl.h \
bits/socket_type.h bits/syscall.h bits/sysctl.h \
bits/mman-linux.h
-tests += tst-clone tst-fanotify tst-personality
+tests += tst-clone tst-clone2 tst-fanotify tst-personality
# Generate the list of SYS_* macros for the system calls (__NR_* macros).
@@ -194,7 +194,7 @@ CFLAGS-gai.c += -DNEED_NETLINK
endif
ifeq ($(subdir),nptl)
-tests += tst-setgetname tst-align-clone tst-getpid1 tst-getpid2 \
+tests += tst-setgetname tst-align-clone tst-getpid1 \
tst-thread-affinity-pthread tst-thread-affinity-pthread2 \
tst-thread-affinity-sched
endif
@@ -72,17 +72,15 @@ thread_start:
cfi_undefined (x30)
mov x29, 0
- tbnz x11, #CLONE_THREAD_BIT, 3f
- mov x0, #-1
- tbnz x11, #CLONE_VM_BIT, 2f
+ tbnz x11, #CLONE_VM_BIT, 1f
+
mov x8, #SYS_ify(getpid)
svc 0x0
-2:
mrs x1, tpidr_el0
sub x1, x1, #PTHREAD_SIZEOF
str w0, [x1, #PTHREAD_PID_OFFSET]
str w0, [x1, #PTHREAD_TID_OFFSET]
-3:
+1:
/* Pick the function arg and execute. */
mov x0, x12
@@ -70,19 +70,16 @@ PSEUDO_END (__clone)
1:
.fnstart
.cantunwind
- tst ip, #CLONE_THREAD
- bne 3f
+ tst ip, #CLONE_VM
+ bne 2f
GET_TLS (lr)
mov r1, r0
- tst ip, #CLONE_VM
ldr r7, =SYS_ify(getpid)
- ite ne
- movne r0, #-1
- swieq 0x0
+ swi 0x0
NEGOFF_ADJ_BASE (r1, TID_OFFSET)
str r0, NEGOFF_OFF1 (r1, TID_OFFSET)
str r0, NEGOFF_OFF2 (r1, PID_OFFSET, TID_OFFSET)
-3:
+2:
@ pick the function arg and call address off the stack and execute
ldr r0, [sp, #4]
ldr ip, [sp], #8
@@ -40,7 +40,6 @@
#define SYS_clone 120
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
.text
ENTRY (__clone)
@@ -108,7 +107,7 @@ L(thread_start):
cfi_undefined (eip);
/* Note: %esi is zero. */
movl %esi,%ebp /* terminate the stack frame */
- testl $CLONE_THREAD, %edi
+ testl $CLONE_VM, %edi
je L(newpid)
L(haspid):
call *%ebx
@@ -124,9 +123,6 @@ L(here):
.subsection 2
L(newpid):
- testl $CLONE_VM, %edi
- movl $-1, %eax
- jne L(nomoregetpid)
movl $SYS_ify(getpid), %eax
ENTER_KERNEL
L(nomoregetpid):
@@ -131,9 +131,8 @@ L(thread_start):
/* The stackframe has been created on entry of clone(). */
/* Check and see if we need to reset the PID. */
- LONG_L a0,(PTRSIZE*2)(sp)
- and a1,a0,CLONE_THREAD
- beqz a1,L(restore_pid)
+ and a1,a0,CLONE_VM
+ beqz a1,L(restore_pid)
L(donepid):
/* Restore the arg for user's function. */
@@ -153,12 +152,8 @@ L(donepid):
#endif
L(restore_pid):
- and a1,a0,CLONE_VM
- li v0,-1
- bnez a1,L(gotpid)
li v0,__NR_getpid
syscall
-L(gotpid):
READ_THREAD_POINTER(v1)
INT_S v0,PID_OFFSET(v1)
INT_S v0,TID_OFFSET(v1)
@@ -76,13 +76,11 @@ ENTRY (__clone)
crandc cr1*4+eq,cr1*4+eq,cr0*4+so
bne- cr1,L(parent) /* The '-' is to minimise the race. */
- andis. r0,r28,CLONE_THREAD>>16
- bne+ r0,L(oldpid)
- andi. r0,r28,CLONE_VM
- li r3,-1
- bne- r0,L(nomoregetpid)
+ /* If CLONE_VM is set does not update the pid/tid field. */
+ andi. r0,r29,CLONE_VM
+ bne+ cr0,L(oldpid)
+
DO_CALL(SYS_ify(getpid))
-L(nomoregetpid):
stw r3,TID(r2)
stw r3,PID(r2)
L(oldpid):
@@ -78,13 +78,11 @@ ENTRY (__clone)
crandc cr1*4+eq,cr1*4+eq,cr0*4+so
bne- cr1,L(parent) /* The '-' is to minimise the race. */
- andis. r0,r29,CLONE_THREAD>>16
+ /* If CLONE_VM is set do not update the pid/tid field. */
+ rldicl. r0,r29,56,63 /* flags & CLONE_VM. */
bne+ cr0,L(oldpid)
- andi. r0,r29,CLONE_VM
- li r3,-1
- bne- cr0,L(nomoregetpid)
+
DO_CALL(SYS_ify(getpid))
-L(nomoregetpid):
stw r3,TID(r13)
stw r3,PID(r13)
L(oldpid):
@@ -54,13 +54,10 @@ error:
PSEUDO_END (__clone)
thread_start:
- tmh %r3,1 /* CLONE_THREAD == 0x00010000 */
- jne 1f
- lhi %r2,-1
tml %r3,256 /* CLONE_VM == 0x00000100 */
- jne 2f
+ jne 1f
svc SYS_ify(getpid)
-2: ear %r3,%a0
+ ear %r3,%a0
st %r2,PID(%r3)
st %r2,TID(%r3)
1:
@@ -55,13 +55,10 @@ error:
PSEUDO_END (__clone)
thread_start:
- tmh %r3,1 /* CLONE_THREAD == 0x00010000 */
+ tmll %r3,256 /* CLONE_VM == 0x00000100 */
jne 1f
- lhi %r2,-1
- tml %r3,256 /* CLONE_VM == 0x00000100 */
- jne 2f
svc SYS_ify(getpid)
-2: ear %r3,%a0
+ ear %r3,%a0
sllg %r3,%r3,32
ear %r3,%a1
st %r2,PID(%r3)
@@ -25,7 +25,6 @@
#include <sysdep.h>
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
pid_t *ptid, void *tls, pid_t *ctid); */
@@ -80,15 +79,10 @@ END(__clone)
.type __thread_start,@function
__thread_start:
- sethi %hi(CLONE_THREAD), %l0
- andcc %g4, %l0, %g0
+ andcc %g4, CLONE_VM, %g0
bne 1f
- andcc %g4, CLONE_VM, %g0
- bne,a 2f
- mov -1,%o0
set __NR_getpid,%g1
ta 0x10
-2:
st %o0,[%g7 + PID]
st %o0,[%g7 + TID]
1:
@@ -25,7 +25,6 @@
#include <sysdep.h>
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
pid_t *ptid, void *tls, pid_t *ctid); */
@@ -77,15 +76,11 @@ END(__clone)
.type __thread_start,@function
__thread_start:
- sethi %hi(CLONE_THREAD), %l0
- andcc %g4, %l0, %g0
+ andcc %g4, CLONE_VM, %g0
bne,pt %icc, 1f
- andcc %g4, CLONE_VM, %g0
- bne,a,pn %icc, 2f
- mov -1,%o0
set __NR_getpid,%g1
ta 0x6d
-2: st %o0,[%g7 + PID]
+ st %o0,[%g7 + PID]
st %o0,[%g7 + TID]
1:
mov %g0, %fp /* terminate backtrace */
new file mode 100644
@@ -0,0 +1,178 @@
+/* Test if CLONE_VM does not change pthread pid/tid field.
+ Copyright (C) 2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sched.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <tls.h> /* for THREAD_* macros. */
+
+static int sig;
+static int pipefd[2];
+
+static int
+f (void *a)
+{
+ close (pipefd[0]);
+
+ pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
+ pid_t tid = THREAD_GETMEM (THREAD_SELF, tid);
+
+ while (write (pipefd[1], &pid, sizeof pid) < 0)
+ continue;
+ while (write (pipefd[1], &tid, sizeof tid) < 0)
+ continue;
+
+ return 0;
+}
+
+
+static int
+clone_test (int clone_flags)
+{
+ sig = SIGRTMIN;
+ sigset_t ss;
+ sigemptyset (&ss);
+ sigaddset (&ss, sig);
+ if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0)
+ {
+ printf ("sigprocmask failed: %m\n");
+ return 1;
+ }
+
+ if (pipe2 (pipefd, O_CLOEXEC))
+ {
+ printf ("sigprocmask failed: %m\n");
+ return 1;
+ }
+
+ pid_t ppid = getpid ();
+
+#ifdef __ia64__
+ extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base,
+ size_t __child_stack_size, int __flags,
+ void *__arg, ...);
+ char st[256 * 1024] __attribute__ ((aligned));
+ pid_t p = __clone2 (f, st, sizeof (st), clone_flags, 0);
+#else
+ char st[128 * 1024] __attribute__ ((aligned));
+#if _STACK_GROWS_DOWN
+ pid_t p = clone (f, st + sizeof (st), clone_flags, 0);
+#elif _STACK_GROWS_UP
+ pid_t p = clone (f, st, clone_flags, 0);
+#else
+#error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+#endif
+ close (pipefd[1]);
+
+ if (p == -1)
+ {
+ printf ("clone failed: %m\n");
+ return 1;
+ }
+
+ pid_t pid, tid;
+ if (read (pipefd[0], &pid, sizeof pid) != sizeof pid)
+ {
+ printf ("read pid failed: %m\n");
+ kill (p, SIGKILL);
+ return 1;
+ }
+ if (read (pipefd[0], &tid, sizeof tid) != sizeof tid)
+ {
+ printf ("read pid failed: %m\n");
+ kill (p, SIGKILL);
+ return 1;
+ }
+
+ close (pipefd[0]);
+
+ int ret = 0;
+
+ /* For CLONE_VM glibc clone implementation does not change the pthread
+ pid/tid field. */
+ if ((clone_flags & CLONE_VM) == CLONE_VM)
+ {
+ if ((ppid != pid) || (ppid != tid))
+ {
+ printf ("parent pid (%i) != received pid/tid (%i/%i)\n",
+ (int)ppid, (int)pid, (int)tid);
+ ret = 1;
+ }
+ }
+ /* For any other flag clone updates the new pthread pid and tid with
+ the clone return value. */
+ else
+ {
+ if ((p != pid) || (p != tid))
+ {
+ printf ("child pid (%i) != received pid/tid (%i/%i)\n",
+ (int)p, (int)pid, (int)tid);
+ ret = 1;
+ }
+ }
+
+ int e;
+ if (waitpid (p, &e, __WCLONE) != p)
+ {
+ puts ("waitpid failed");
+ kill (p, SIGKILL);
+ return 1;
+ }
+ if (!WIFEXITED (e))
+ {
+ if (WIFSIGNALED (e))
+ printf ("died from signal %s\n", strsignal (WTERMSIG (e)));
+ else
+ puts ("did not terminate correctly");
+ return 1;
+ }
+ if (WEXITSTATUS (e) != 0)
+ {
+ printf ("exit code %d\n", WEXITSTATUS (e));
+ return 1;
+ }
+
+ return ret;
+}
+
+int
+do_test (void)
+{
+ /* It first checks the clone implementation without any flag, which will
+ make the child new pid to be cached on its pthread structure. */
+ int ret = clone_test (0);
+ /* Then check if clone with CLONE_VM avoid caching it since memory is
+ shared between parent and it might overwrite parent's pthread
+ structure. */
+ ret += clone_test (CLONE_VM);
+ return ret;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
deleted file mode 100644
@@ -1,2 +0,0 @@
-#define TEST_CLONE_FLAGS CLONE_VM
-#include "tst-getpid1.c"
@@ -24,7 +24,6 @@
#include <asm-syntax.h>
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
/* The userland implementation is:
int clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg),
@@ -92,14 +91,11 @@ L(thread_start):
the outermost frame obviously. */
xorl %ebp, %ebp
- testq $CLONE_THREAD, %rdi
+ andq $CLONE_VM, %rdi
jne 1f
- testq $CLONE_VM, %rdi
- movl $-1, %eax
- jne 2f
movl $SYS_ify(getpid), %eax
syscall
-2: movl %eax, %fs:PID
+ movl %eax, %fs:PID
movl %eax, %fs:TID
1: