diff options
Diffstat (limited to 'nptl/sysdeps/unix/sysv')
6 files changed, 342 insertions, 38 deletions
diff --git a/nptl/sysdeps/unix/sysv/linux/Makefile b/nptl/sysdeps/unix/sysv/linux/Makefile index 6078e2ded1..9e0df9801b 100644 --- a/nptl/sysdeps/unix/sysv/linux/Makefile +++ b/nptl/sysdeps/unix/sysv/linux/Makefile @@ -26,6 +26,7 @@ gen-as-const-headers += lowlevelcond.sym lowlevelrwlock.sym \ lowlevelbarrier.sym unwindbuf.sym \ lowlevelrobustlock.sym pthread-pi-defines.sym \ structsem.sym +tests += tst-setgetname endif ifeq ($(subdir),posix) diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S index a6d6bc460a..b74e4b5419 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S @@ -505,9 +505,9 @@ __pthread_cond_timedwait: #endif call __lll_unlock_wake jmp 11b - cfi_adjust_cfa_offset(-FRAME_SIZE) #ifndef __ASSUME_FUTEX_CLOCK_REALTIME + cfi_adjust_cfa_offset(-FRAME_SIZE) .Lreltmo: /* Get internal lock. */ movl $1, %edx @@ -742,7 +742,6 @@ __pthread_cond_timedwait: # endif call __lll_lock_wait jmp 106b - cfi_adjust_cfa_offset(-FRAME_SIZE) #endif .size __pthread_cond_timedwait, .-__pthread_cond_timedwait diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h b/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h index 51e021df59..d711dc6cf1 100644 --- a/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h +++ b/nptl/sysdeps/unix/sysv/linux/powerpc/powerpc64/sysdep-cancel.h @@ -31,6 +31,14 @@ # define DASHDASHPFX(str) __##str # endif +#if _CALL_ELF == 2 +#define CANCEL_FRAMESIZE (FRAME_MIN_SIZE+16+48) +#define CANCEL_PARM_SAVE (FRAME_MIN_SIZE+16) +#else +#define CANCEL_FRAMESIZE (FRAME_MIN_SIZE+16) +#define CANCEL_PARM_SAVE (CANCEL_FRAMESIZE+FRAME_PARM_SAVE) +#endif + # undef PSEUDO # define PSEUDO(name, syscall_name, args) \ .section ".text"; \ @@ -44,52 +52,52 @@ PSEUDO_RET; \ .size DASHDASHPFX(syscall_name##_nocancel),.-DASHDASHPFX(syscall_name##_nocancel); \ .Lpseudo_cancel: \ - stdu 1,-128(1); \ - cfi_adjust_cfa_offset (128); \ + stdu 1,-CANCEL_FRAMESIZE(1); \ + cfi_adjust_cfa_offset (CANCEL_FRAMESIZE); \ mflr 9; \ - std 9,128+16(1); \ - cfi_offset (lr, 16); \ + std 9,CANCEL_FRAMESIZE+FRAME_LR_SAVE(1); \ + cfi_offset (lr, FRAME_LR_SAVE); \ DOCARGS_##args; /* save syscall args around CENABLE. */ \ CENABLE; \ - std 3,112(1); /* store CENABLE return value (MASK). */ \ + std 3,FRAME_MIN_SIZE(1); /* store CENABLE return value (MASK). */ \ UNDOCARGS_##args; /* restore syscall args. */ \ DO_CALL (SYS_ify (syscall_name)); \ mfcr 0; /* save CR/R3 around CDISABLE. */ \ - std 3,120(1); \ - std 0,128+8(1); \ - cfi_offset (cr, 8); \ - ld 3,112(1); /* pass MASK to CDISABLE. */ \ + std 3,FRAME_MIN_SIZE+8(1); \ + std 0,CANCEL_FRAMESIZE+FRAME_CR_SAVE(1); \ + cfi_offset (cr, FRAME_CR_SAVE); \ + ld 3,FRAME_MIN_SIZE(1); /* pass MASK to CDISABLE. */ \ CDISABLE; \ - ld 9,128+16(1); \ - ld 0,128+8(1); /* restore CR/R3. */ \ - ld 3,120(1); \ + ld 9,CANCEL_FRAMESIZE+FRAME_LR_SAVE(1); \ + ld 0,CANCEL_FRAMESIZE+FRAME_CR_SAVE(1); /* restore CR/R3. */ \ + ld 3,FRAME_MIN_SIZE+8(1); \ mtlr 9; \ mtcr 0; \ - addi 1,1,128; \ - cfi_adjust_cfa_offset (-128); \ + addi 1,1,CANCEL_FRAMESIZE; \ + cfi_adjust_cfa_offset (-CANCEL_FRAMESIZE); \ cfi_restore (lr); \ cfi_restore (cr) # define DOCARGS_0 # define UNDOCARGS_0 -# define DOCARGS_1 std 3,128+48(1); DOCARGS_0 -# define UNDOCARGS_1 ld 3,128+48(1); UNDOCARGS_0 +# define DOCARGS_1 std 3,CANCEL_PARM_SAVE(1); DOCARGS_0 +# define UNDOCARGS_1 ld 3,CANCEL_PARM_SAVE(1); UNDOCARGS_0 -# define DOCARGS_2 std 4,128+56(1); DOCARGS_1 -# define UNDOCARGS_2 ld 4,128+56(1); UNDOCARGS_1 +# define DOCARGS_2 std 4,CANCEL_PARM_SAVE+8(1); DOCARGS_1 +# define UNDOCARGS_2 ld 4,CANCEL_PARM_SAVE+8(1); UNDOCARGS_1 -# define DOCARGS_3 std 5,128+64(1); DOCARGS_2 -# define UNDOCARGS_3 ld 5,128+64(1); UNDOCARGS_2 +# define DOCARGS_3 std 5,CANCEL_PARM_SAVE+16(1); DOCARGS_2 +# define UNDOCARGS_3 ld 5,CANCEL_PARM_SAVE+16(1); UNDOCARGS_2 -# define DOCARGS_4 std 6,128+72(1); DOCARGS_3 -# define UNDOCARGS_4 ld 6,128+72(1); UNDOCARGS_3 +# define DOCARGS_4 std 6,CANCEL_PARM_SAVE+24(1); DOCARGS_3 +# define UNDOCARGS_4 ld 6,CANCEL_PARM_SAVE+24(1); UNDOCARGS_3 -# define DOCARGS_5 std 7,128+80(1); DOCARGS_4 -# define UNDOCARGS_5 ld 7,128+80(1); UNDOCARGS_4 +# define DOCARGS_5 std 7,CANCEL_PARM_SAVE+32(1); DOCARGS_4 +# define UNDOCARGS_5 ld 7,CANCEL_PARM_SAVE+32(1); UNDOCARGS_4 -# define DOCARGS_6 std 8,128+88(1); DOCARGS_5 -# define UNDOCARGS_6 ld 8,128+88(1); UNDOCARGS_5 +# define DOCARGS_6 std 8,CANCEL_PARM_SAVE+40(1); DOCARGS_5 +# define UNDOCARGS_6 ld 8,CANCEL_PARM_SAVE+40(1); UNDOCARGS_5 # ifdef IS_IN_libpthread # ifdef SHARED diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c b/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c index ace858fd13..4ac913c3be 100644 --- a/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c +++ b/nptl/sysdeps/unix/sysv/linux/powerpc/pt-longjmp.c @@ -41,13 +41,8 @@ void __novmx_longjmp (jmp_buf env, int val) __novmx__libc_longjmp (env, val); } -# if __WORDSIZE == 64 -symbol_version (__novmx_longjmp,longjmp,GLIBC_2.3); -symbol_version (__novmx_siglongjmp,siglongjmp,GLIBC_2.3); -# else -symbol_version (__novmx_longjmp,longjmp,GLIBC_2.0); -symbol_version (__novmx_siglongjmp,siglongjmp,GLIBC_2.0); -# endif +compat_symbol (libpthread, __novmx_longjmp, longjmp, GLIBC_2_0); +compat_symbol (libpthread, __novmx_siglongjmp, siglongjmp, GLIBC_2_0); #endif /* defined SHARED && SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)) */ void @@ -62,5 +57,5 @@ __vmx_siglongjmp (jmp_buf env, int val) __libc_siglongjmp (env, val); } -versioned_symbol (libc, __vmx_longjmp, longjmp, GLIBC_2_3_4); -versioned_symbol (libc, __vmx_siglongjmp, siglongjmp, GLIBC_2_3_4); +versioned_symbol (libpthread, __vmx_longjmp, longjmp, GLIBC_2_3_4); +versioned_symbol (libpthread, __vmx_siglongjmp, siglongjmp, GLIBC_2_3_4); diff --git a/nptl/sysdeps/unix/sysv/linux/tst-setgetname.c b/nptl/sysdeps/unix/sysv/linux/tst-setgetname.c new file mode 100644 index 0000000000..d80bf01a7b --- /dev/null +++ b/nptl/sysdeps/unix/sysv/linux/tst-setgetname.c @@ -0,0 +1,301 @@ +/* Test pthread_setname_np and pthread_getname_np. + Copyright (C) 2013 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; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. */ +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <string.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +/* New name of process. */ +#define NEW_NAME "setname" + +/* Name of process which is one byte too big + e.g. 17 bytes including null-terminator */ +#define BIG_NAME "....V....X....XV" + +/* Longest name of a process + e.g. 16 bytes including null-terminator. */ +#define LONGEST_NAME "....V....X....X" + +/* One less than longest name with unique + characters to detect modification. */ +#define CANARY_NAME "abcdefghijklmn" + +/* On Linux the maximum length of the name of a task *including* the null + terminator. */ +#define TASK_COMM_LEN 16 + +long +gettid (void) +{ + return syscall(__NR_gettid); +} + +/* On Linux we can read this task's name from /proc. */ +int +get_self_comm (long tid, char *buf, size_t len) +{ + int res = 0; +#define FMT "/proc/self/task/%lu/comm" + char fname[sizeof (FMT) + 8]; + sprintf (fname, FMT, (unsigned long) tid); + + int fd = open (fname, O_RDONLY); + if (fd == -1) + return errno; + + ssize_t n = read (fd, (void *) buf, len); + if (n < 0) + res = errno; + else + { + if (buf[n - 1] == '\n') + buf[n - 1] = '\0'; + else if (n == len) + res = ERANGE; + else + buf[n] = '\0'; + } + + close (fd); + return res; +} + +int +do_test (int argc, char **argv) +{ + pthread_t self; + int res; + int ret = 0; + char name[TASK_COMM_LEN]; + char name_check[TASK_COMM_LEN]; + + memset (name, '\0', TASK_COMM_LEN); + memset (name_check, '\0', TASK_COMM_LEN); + + /* Test 1: Get the name of the task via pthread_getname_np and /proc + and verify that they both match. */ + self = pthread_self (); + res = pthread_getname_np (self, name, TASK_COMM_LEN); + + if (res == 0) + { + res = get_self_comm (gettid (), name_check, TASK_COMM_LEN); + if (res == 0) + { + if (strncmp (name, name_check, strlen (BIG_NAME)) == 0) + printf ("PASS: Test 1 - pthread_getname_np and /proc agree.\n"); + else + { + printf ("FAIL: Test 1 - pthread_getname_np and /proc differ" + " i.e. %s != %s\n", name, name_check); + ret++; + } + } + else + { + printf ("FAIL: Test 1 - unable read task name via proc.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 1 - pthread_getname_np failed with error %d\n", res); + ret++; + } + + /* Test 2: Test setting the name and then independently verify it + was set. */ + res = pthread_setname_np (self, NEW_NAME); + + if (res == 0) + { + res = get_self_comm (gettid (), name_check, TASK_COMM_LEN); + if (res == 0) + { + if (strncmp (NEW_NAME, name_check, strlen (BIG_NAME)) == 0) + printf ("PASS: Test 2 - Value used in pthread_setname_np and" + " /proc agree.\n"); + else + { + printf ("FAIL: Test 2 - Value used in pthread_setname_np" + " and /proc differ i.e. %s != %s\n", + NEW_NAME, name_check); + ret++; + } + } + else + { + printf ("FAIL: Test 2 - unable to read task name via proc.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 2 - pthread_setname_np failed with error %d\n", res); + ret++; + } + + /* Test 3: Test setting a name that is one-byte too big. */ + res = pthread_getname_np (self, name, TASK_COMM_LEN); + + if (res == 0) + { + res = pthread_setname_np (self, BIG_NAME); + if (res != 0) + { + if (res == ERANGE) + { + printf ("PASS: Test 3 - pthread_setname_np returned ERANGE" + " for a process name that was too long.\n"); + + /* Verify the old name didn't change. */ + res = get_self_comm (gettid (), name_check, TASK_COMM_LEN); + if (res == 0) + { + if (strncmp (name, name_check, strlen (BIG_NAME)) == 0) + printf ("PASS: Test 3 - Original name unchanged after" + " pthread_setname_np returned ERANGE.\n"); + else + { + printf ("FAIL: Test 3 - Original name changed after" + " pthread_setname_np returned ERANGE" + " i.e. %s != %s\n", + name, name_check); + ret++; + } + } + else + { + printf ("FAIL: Test 3 - unable to read task name.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 3 - Wrong error returned" + " i.e. ERANGE != %d\n", res); + ret++; + } + } + else + { + printf ("FAIL: Test 3 - Too-long name accepted by" + " pthread_setname_np.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 3 - Unable to get original name.\n"); + ret++; + } + + /* Test 4: Verify that setting the longest name works. */ + res = pthread_setname_np (self, LONGEST_NAME); + + if (res == 0) + { + res = get_self_comm (gettid (), name_check, TASK_COMM_LEN); + if (res == 0) + { + if (strncmp (LONGEST_NAME, name_check, strlen (BIG_NAME)) == 0) + printf ("PASS: Test 4 - Longest name set via pthread_setname_np" + " agrees with /proc.\n"); + else + { + printf ("FAIL: Test 4 - Value used in pthread_setname_np and /proc" + " differ i.e. %s != %s\n", LONGEST_NAME, name_check); + ret++; + } + } + else + { + printf ("FAIL: Test 4 - unable to read task name via proc.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 4 - pthread_setname_np failed with error %d\n", res); + ret++; + } + + /* Test 5: Verify that getting a long name into a small buffer fails. */ + strncpy (name, CANARY_NAME, strlen (CANARY_NAME) + 1); + + /* Claim the buffer length is strlen (LONGEST_NAME). This is one character + too small to hold LONGEST_NAME *and* the null terminator. We should get + back ERANGE and name should be unmodified. */ + res = pthread_getname_np (self, name, strlen (LONGEST_NAME)); + + if (res != 0) + { + if (res == ERANGE) + { + if (strncmp (CANARY_NAME, name, strlen (BIG_NAME)) == 0) + { + printf ("PASS: Test 5 - ERANGE and buffer unmodified.\n"); + } + else + { + printf ("FAIL: Test 5 - Original buffer modified.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 5 - Did not return ERANGE for small buffer.\n"); + ret++; + } + } + else + { + printf ("FAIL: Test 5 - Returned name longer than buffer.\n"); + ret++; + } + + /* Test 6: Lastly make sure we can read back the longest name. */ + res = pthread_getname_np (self, name, strlen (LONGEST_NAME) + 1); + + if (res == 0) + { + if (strncmp (LONGEST_NAME, name, strlen (BIG_NAME)) == 0) + { + printf ("PASS: Test 6 - Read back longest name correctly.\n"); + } + else + { + printf ("FAIL: Test 6 - Read \"%s\" instead of longest name.\n", + name); + ret++; + } + } + else + { + printf ("FAIL: Test 6 - pthread_getname_np failed with error %d\n", res); + ret++; + } + + return ret; +} + +#include <test-skeleton.c> diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S b/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S index 2cc84c189b..b4e4dcf90c 100644 --- a/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S +++ b/nptl/sysdeps/unix/sysv/linux/x86_64/cancellation.S @@ -22,7 +22,7 @@ #include "lowlevellock.h" #ifdef IS_IN_libpthread -# if defined SHARED && defined DO_VERSIONING && !defined NO_HIDDEN +# if defined SHARED && !defined NO_HIDDEN # define __pthread_unwind __GI___pthread_unwind # endif #else |