This is the mail archive of the libc-hacker@sources.redhat.com mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix IA-64


Hi!

This patch makes IA-64 port work again, with the exception of expected
math failures and tst-cancel5 make check passes.
linuxthreads/sysdeps/ia64/tls.h is really just a small part, I had no time
to make full TLS working ATM on IA-64.
I've removed SPARC bits from the patch set, because I hit a linker bug
and thus will have to redo part of those changes.

2002-12-21  Jakub Jelinek  <jakub@redhat.com>

	* sysdeps/unix/sysv/linux/ia64/sysdep.h (INLINE_SYSCALL,
	INTERNAL_SYSCALL, INTERNAL_SYSCALL_ERROR_P, INTERNAL_SYSCALL_ERROR):
	Define. Patch by Richard Henderson and Jes Sorensen.
	(PSEUDO): Remove unnecessary ;;.
	* elf/rtld.c (dl_main): Initialize TLS even if no PT_TLS segments
	are found unless TLS_INIT_TP_EXPENSIVE.  Use NONTLS_INIT_TP.
	* sysdeps/generic/libc-tls.c (__libc_setup_tls): Use NONTLS_INIT_TP
	if not initializing thread pointer.
	[!USE_TLS && NONTLS_INIT_TP] (__pthread_initialize_minimal): New.
	* sysdeps/generic/libc-start.c (__pthread_initialize_minimal): Don't
	make it weak also if NONTLS_INIT_TP.
	* sysdeps/unix/common/pause.c: Handle cancellation.

linuxthreads/
	* libc_pthread_init.c: Include stdlib.h.
	* sysdeps/i386/tls.h (tcbhead_t): Add multiple_threads member.
	(TLS_INIT_TP_EXPENSIVE): Define.
	* sysdeps/pthread/bits/libc-lock.h (__libc_maybe_call,
	__libc_maybe_call2): In _LIBC check SHARED define.
	* sysdeps/ia64/tls.h: New file.
	* sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h: New file.
	* sysdeps/unix/sysv/linux/ia64/Makefile: New file.
	* sysdeps/x86_64/tls.h (TLS_INIT_TP_EXPENSIVE): Define.
	* Makefile (tests): Add tst-cancel[1-6].
	(tests-reverse): Add tst-cancel5.
	Link libc.so before libpthread.so for tests-reverse.
	* tst-cancel1.c: New file.
	* tst-cancel2.c: New file.
	* tst-cancel3.c: New file.
	* tst-cancel4.c: New file.
	* tst-cancel5.c: New file.
	* tst-cancel6.c: New file.

nptl/
	* Makefile (tests-reverse): Use $(objpfx)../libc.so instead of
	$(common-objpfx)libc.so.
	* tst-cancel4.c (tf_write, tf_writev): Increase buf sizes so that
	it is bigger than pipe buffer size even on arches with bigger
	page size.
	(tf_usleep): Cast usleep argument to useconds_t to avoid warnings.

--- libc/elf/rtld.c.jj	2002-12-20 13:34:41.000000000 +0100
+++ libc/elf/rtld.c	2002-12-20 16:02:39.000000000 +0100
@@ -1157,7 +1157,7 @@ of this helper program; chances are you 
      an old kernel that can't perform TLS_INIT_TP, even if no TLS is ever
      used.  Trying to do it lazily is too hairy to try when there could be
      multiple threads (from a non-TLS-using libpthread).  */
-  if (GL(dl_tls_max_dtv_idx) > 0)
+  if (GL(dl_tls_max_dtv_idx) > 0 || !TLS_INIT_TP_EXPENSIVE)
     {
       struct link_map *l;
       size_t nelem;
@@ -1565,8 +1565,12 @@ cannot allocate TLS data structures for 
      we need it in the memory handling later.  */
   GL(dl_initial_searchlist) = *GL(dl_main_searchlist);
 
+#ifndef NONTLS_INIT_TP
+# define NONTLS_INIT_TP do { } while (0)
+#endif
+
 #ifdef USE_TLS
-  if (GL(dl_tls_max_dtv_idx) > 0 || USE___THREAD)
+  if (GL(dl_tls_max_dtv_idx) > 0 || USE___THREAD || !TLS_INIT_TP_EXPENSIVE)
     {
       /* Now that we have completed relocation, the initializer data
 	 for the TLS blocks has its final values and we can copy them
@@ -1579,7 +1583,9 @@ cannot allocate TLS data structures for 
       if (__builtin_expect (lossage != NULL, 0))
 	_dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
     }
+  else
 #endif
+    NONTLS_INIT_TP;
 
   {
     /* Initialize _r_debug.  */
--- libc/linuxthreads/libc_pthread_init.c.jj	2002-12-18 02:15:55.000000000 +0100
+++ libc/linuxthreads/libc_pthread_init.c	2002-12-20 17:23:42.000000000 +0100
@@ -17,9 +17,10 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <locale.h>
+#include <stdlib.h>
 #include <string.h>
 #include <tls.h>
-#include <locale.h>
 #include "internals.h"
 #include <sysdep-cancel.h>
 
--- libc/linuxthreads/sysdeps/i386/tls.h.jj	2002-12-10 15:08:36.000000000 +0100
+++ libc/linuxthreads/sysdeps/i386/tls.h	2002-12-20 16:00:18.000000000 +0100
@@ -39,6 +39,7 @@ typedef struct
 			   thread descriptor used by libpthread.  */
   dtv_t *dtv;
   void *self;		/* Pointer to the thread descriptor.  */
+  int multiple_threads;
 } tcbhead_t;
 #endif
 
@@ -192,6 +193,10 @@ TLS_DO_MODIFY_LDT_KERNEL_CHECK(						   
     TLS_SETUP_GS_SEGMENT (_descr, secondcall);				      \
   })
 
+/* Indicate that dynamic linker shouldn't try to initialize TLS even
+   when no PT_TLS segments are found in the program and libraries
+   it is linked against.  */
+#  define TLS_INIT_TP_EXPENSIVE 1
 
 /* Return the address of the dtv for the current thread.  */
 #  define THREAD_DTV() \
--- libc/linuxthreads/sysdeps/pthread/bits/libc-lock.h.jj	2002-12-20 13:35:37.000000000 +0100
+++ libc/linuxthreads/sysdeps/pthread/bits/libc-lock.h	2002-12-20 17:33:13.000000000 +0100
@@ -97,7 +97,7 @@ typedef pthread_key_t __libc_key_t;
 #if defined _LIBC && defined IS_IN_libpthread
 # define __libc_maybe_call(FUNC, ARGS, ELSE) FUNC ARGS
 #else
-# ifdef __PIC__
+# if defined __PIC__ || (defined _LIBC && defined SHARED)
 #  define __libc_maybe_call(FUNC, ARGS, ELSE) \
   (__extension__ ({ __typeof (FUNC) *_fn = (FUNC); \
                     _fn != NULL ? (*_fn) ARGS : ELSE; }))
@@ -106,7 +106,7 @@ typedef pthread_key_t __libc_key_t;
   (FUNC != NULL ? FUNC ARGS : ELSE)
 # endif
 #endif
-#if defined _LIBC && !defined NOT_IN_libc && defined __PIC__
+#if defined _LIBC && !defined NOT_IN_libc && defined SHARED
 # define __libc_maybe_call2(FUNC, ARGS, ELSE) \
   ({__libc_pthread_functions.ptr_##FUNC != NULL \
     ? __libc_pthread_functions.ptr_##FUNC ARGS : ELSE; })
--- libc/linuxthreads/sysdeps/ia64/tls.h.jj	2002-12-20 14:01:54.000000000 +0100
+++ libc/linuxthreads/sysdeps/ia64/tls.h	2002-12-20 20:39:50.000000000 +0100
@@ -0,0 +1,64 @@
+/* Definitions for thread-local data handling.  linuxthreads/IA-64 version.
+   Copyright (C) 2002 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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#ifndef _TLS_H
+#define _TLS_H
+
+#ifndef __ASSEMBLER__
+
+# include <pt-machine.h>
+# include <stddef.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  void *pointer;
+} dtv_t;
+
+
+/* FIXME: Only temporary.  When TLS is supported on IA-64,
+   pthread_descr struct needs to be immediately below r13 and
+   at r13 a struct { dtv_t *dtv; void *private; }.  */
+typedef struct
+{
+  void *tcb;		/* Pointer to the TCB.  Not necessary the
+			   thread descriptor used by libpthread.  */
+  dtv_t *dtv;
+  void *self;		/* Pointer to the thread descriptor.  */
+  int multiple_threads;
+} tcbhead_t;
+#endif /* __ASSEMBLER__ */
+
+#undef USE_TLS
+
+#if USE_TLS
+
+#else
+
+#define NONTLS_INIT_TP \
+  do { 								\
+    static const tcbhead_t nontls_init_tp			\
+      = { .multiple_threads = NULL };				\
+    __thread_self = (__typeof (__thread_self)) &nontls_init_tp;	\
+  } while (0)
+
+#endif /* USE_TLS */
+
+#endif	/* tls.h */
--- libc/linuxthreads/sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h.jj	2002-12-20 14:00:36.000000000 +0100
+++ libc/linuxthreads/sysdeps/unix/sysv/linux/ia64/sysdep-cancel.h	2002-12-20 22:18:54.000000000 +0100
@@ -0,0 +1,107 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <sysdep.h>
+#include <tls.h>
+#ifndef ASSEMBLER
+# include <linuxthreads/internals.h>
+#endif
+
+#define MULTIPLE_THREADS_OFFSET	24
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)				      \
+.text;									      \
+ENTRY (name)								      \
+     adds r14 = MULTIPLE_THREADS_OFFSET, r13;;				      \
+     ld4 r14 = [r14];							      \
+     mov r15 = SYS_ify(syscall_name);;					      \
+     cmp4.ne p6, p7 = 0, r14;						      \
+(p6) br.cond.spnt .Lpseudo_cancel;;					      \
+     break __BREAK_SYSCALL;;						      \
+     cmp.eq p6,p0=-1,r10;						      \
+(p6) br.cond.spnt.few __syscall_error;					      \
+     ret;;								      \
+.Lpseudo_cancel:							      \
+     .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(args);   \
+     alloc loc0 = ar.pfs, args, 5, args, 0;				      \
+     mov loc1 = rp;;							      \
+     CENABLE;;								      \
+     mov loc2 = r8;							      \
+     COPY_ARGS_##args							      \
+     mov r15 = SYS_ify(syscall_name);					      \
+     break __BREAK_SYSCALL;;						      \
+     mov loc3 = r8;							      \
+     mov loc4 = r10;							      \
+     mov out0 = loc2;							      \
+     CDISABLE;;								      \
+     cmp.eq p6,p0=-1,loc4;						      \
+(p6) br.cond.spnt.few __syscall_error_##args;				      \
+     mov r8 = loc3;							      \
+     mov rp = loc1;							      \
+     mov ar.pfs = loc0;							      \
+.section .gnu.linkonce.t.__syscall_error_##args, "ax";			      \
+.global __syscall_error_##args;						      \
+.hidden __syscall_error_##args;						      \
+__syscall_error_##args:							      \
+     mov loc4 = r1;;							      \
+     br.call.sptk.many b0 = __errno_location;;				      \
+     st4 [r8] = loc3;							      \
+     mov r1 = loc4;							      \
+     mov rp = loc1;							      \
+     mov r8 = -1;							      \
+     mov ar.pfs = loc0;							      \
+     ret;								      \
+.previous;								      \
+.Lpseudo_end:
+
+# ifdef IS_IN_libpthread
+#  define CENABLE	br.call.sptk.many b0 = __pthread_enable_asynccancel
+#  define CDISABLE	br.call.sptk.many b0 = __pthread_disable_asynccancel
+# else
+#  define CENABLE	br.call.sptk.many b0 = __libc_enable_asynccancel
+#  define CDISABLE	br.call.sptk.many b0 = __libc_disable_asynccancel
+# endif
+
+#define COPY_ARGS_0	/* Nothing */
+#define COPY_ARGS_1	COPY_ARGS_0 mov out0 = in0;
+#define COPY_ARGS_2	COPY_ARGS_1 mov out1 = in1;
+#define COPY_ARGS_3	COPY_ARGS_2 mov out2 = in2;
+#define COPY_ARGS_4	COPY_ARGS_3 mov out3 = in3;
+#define COPY_ARGS_5	COPY_ARGS_4 mov out4 = in4;
+#define COPY_ARGS_6	COPY_ARGS_5 mov out5 = in5;
+#define COPY_ARGS_7	COPY_ARGS_6 mov out6 = in6;
+
+# ifndef ASSEMBLER
+#  define SINGLE_THREAD_P \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,				      \
+				   p_header.data.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P \
+  adds r14 = MULTIPLE_THREADS_OFFSET, r13 ;; ld4 r14 = [r14] ;; cmp4.ne p6, p7 = 0, r14 ;;
+# endif
+
+#elif !defined ASSEMBLER
+
+/* This code should never be used but we define it anyhow.  */
+# define SINGLE_THREAD_P (1)
+
+#endif
--- libc/linuxthreads/sysdeps/unix/sysv/linux/ia64/Makefile.jj	2002-12-20 19:07:20.000000000 +0100
+++ libc/linuxthreads/sysdeps/unix/sysv/linux/ia64/Makefile	2002-12-20 19:07:14.000000000 +0100
@@ -0,0 +1,3 @@
+ifeq ($(subdir),linuxthreads)
+libpthread-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask
+endif
--- libc/linuxthreads/sysdeps/x86_64/tls.h.jj	2002-12-10 15:08:39.000000000 +0100
+++ libc/linuxthreads/sysdeps/x86_64/tls.h	2002-12-20 16:00:54.000000000 +0100
@@ -109,6 +109,11 @@ typedef struct
     _result ? "cannot set %fs base address for thread-local storage" : 0;     \
   })
 
+/* Indicate that dynamic linker shouldn't try to initialize TLS even
+   when no PT_TLS segments are found in the program and libraries
+   it is linked against.  */
+#  define TLS_INIT_TP_EXPENSIVE 1
+
 /* Return the address of the dtv for the current thread.  */
 #  define THREAD_DTV() \
   ({ struct _pthread_descr_struct *__descr;				      \
--- libc/linuxthreads/Makefile.jj	2002-12-20 13:35:29.000000000 +0100
+++ libc/linuxthreads/Makefile	2002-12-20 22:02:23.000000000 +0100
@@ -72,8 +72,12 @@ endif
 librt-tests = ex10 ex11
 tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 $(librt-tests) ex12 ex13 joinrace \
 	tststack $(tests-nodelete-$(have-z-nodelete)) ecmutex ex14 ex15 ex16 \
-	ex17 ex18 tst-cancel tst-context bug-sleep
+	ex17 ex18 tst-cancel tst-context bug-sleep \
+	tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel4 tst-cancel5 \
+	tst-cancel6
 test-srcs = tst-signal
+# These tests are linked with libc before libpthread
+tests-reverse += tst-cancel5
 
 ifeq ($(build-static),yes)
 tests += tststatic tst-static-locale
@@ -147,8 +151,12 @@ $(objpfx)libpthread.so: $(libc-link.so) 
 # Make sure we link with the thread library.
 ifeq ($(build-shared),yes)
 $(addprefix $(objpfx), \
-  $(filter-out $(tests-static) unload, \
+  $(filter-out $(tests-static) $(tests-reverse) unload, \
     $(tests) $(test-srcs))): $(objpfx)libpthread.so
+# $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so,
+# since otherwise libpthread.so comes before libc.so when linking.
+$(addprefix $(objpfx), $(tests-reverse)): \
+  $(objpfx)../libc.so $(objpfx)libpthread.so
 $(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.so
 $(objpfx)unload: $(common-objpfx)dlfcn/libdl.so
 $(objpfx)unload.out: $(objpfx)libpthread.so
--- libc/linuxthreads/tst-cancel1.c.jj	2002-12-20 22:03:13.000000000 +0100
+++ libc/linuxthreads/tst-cancel1.c	2002-11-26 23:49:41.000000000 +0100
@@ -0,0 +1,150 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
+
+static int cntr;
+
+
+static void
+cleanup (void *arg)
+{
+  if (arg != (void *) 42l)
+    cntr = 42;
+  else
+    cntr = 1;
+}
+
+
+static void *
+tf (void *arg)
+{
+  int err;
+
+  pthread_cleanup_push (cleanup, (void *) 42l);
+
+  err = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+  if (err != 0)
+    {
+      printf ("setcanceltype failed: %s\n", strerror (err));
+      exit (1);
+    }
+
+  err = pthread_mutex_unlock (&m2);
+  if (err != 0)
+    {
+      printf ("child: mutex_unlock failed: %s\n", strerror (err));
+      exit (1);
+    }
+
+  err = pthread_mutex_lock (&m1);
+  if (err != 0)
+    {
+      printf ("child: 1st mutex_lock failed: %s\n", strerror (err));
+      exit (1);
+    }
+
+  /* We should never come here.  */
+
+  pthread_cleanup_pop (0);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int err;
+  pthread_t th;
+  int result = 0;
+  void *retval;
+
+  /* Get the mutexes.  */
+  err = pthread_mutex_lock (&m1);
+  if (err != 0)
+    {
+      printf ("parent: 1st mutex_lock failed: %s\n", strerror (err));
+      return 1;
+    }
+  err = pthread_mutex_lock (&m2);
+  if (err != 0)
+    {
+      printf ("parent: 2nd mutex_lock failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  err = pthread_create (&th, NULL, tf, NULL);
+  if (err != 0)
+    {
+      printf ("create failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  err = pthread_mutex_lock (&m2);
+  if (err != 0)
+    {
+      printf ("parent: 3rd mutex_lock failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  err = pthread_cancel (th);
+  if (err != 0)
+    {
+      printf ("cancel failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  err = pthread_join (th, &retval);
+  if (err != 0)
+    {
+      printf ("join failed: %s\n", strerror (err));
+      return 1;
+    }
+
+  if (retval != PTHREAD_CANCELED)
+    {
+      printf ("wrong return value: %p\n", retval);
+      result = 1;
+    }
+
+  if (cntr == 42)
+    {
+      puts ("cleanup handler called with wrong argument");
+      result = 1;
+    }
+  else if (cntr != 1)
+    {
+      puts ("cleanup handling not called");
+      result = 1;
+    }
+
+  return result;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
--- libc/linuxthreads/tst-cancel2.c.jj	2002-12-20 22:03:13.000000000 +0100
+++ libc/linuxthreads/tst-cancel2.c	2002-11-26 23:49:53.000000000 +0100
@@ -0,0 +1,100 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int fd[2];
+
+
+static void *
+tf (void *arg)
+{
+  /* The buffer size must be larger than the pipe size so that the
+     write blocks.  */
+  char buf[100000];
+
+  if (write (fd[1], buf, sizeof (buf)) == sizeof (buf))
+    {
+      puts ("write succeeded");
+      return (void *) 1l;
+    }
+
+  return (void *) 42l;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  void *r;
+  struct sigaction sa;
+
+  sa.sa_handler = SIG_IGN;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+
+  if (sigaction (SIGPIPE, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  /* This will cause the write in the child to return.  */
+  close (fd[0]);
+
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      printf ("result is wrong: expected %p, got %p\n", PTHREAD_CANCELED, r);
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
--- libc/linuxthreads/tst-cancel3.c.jj	2002-12-20 22:03:13.000000000 +0100
+++ libc/linuxthreads/tst-cancel3.c	2002-11-26 23:49:53.000000000 +0100
@@ -0,0 +1,98 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+static int fd[2];
+
+
+static void *
+tf (void *arg)
+{
+  char buf[100];
+
+  if (read (fd[0], buf, sizeof (buf)) == sizeof (buf))
+    {
+      puts ("read succeeded");
+      return (void *) 1l;
+    }
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t th;
+  void *r;
+  struct sigaction sa;
+
+  sa.sa_handler = SIG_IGN;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+
+  if (sigaction (SIGPIPE, &sa, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+
+  /* This will cause the read in the child to return.  */
+  close (fd[0]);
+
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      return 1;
+    }
+
+  if (r != PTHREAD_CANCELED)
+    {
+      puts ("result is wrong");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
--- libc/linuxthreads/tst-cancel4.c.jj	2002-12-20 22:03:13.000000000 +0100
+++ libc/linuxthreads/tst-cancel4.c	2002-12-20 21:58:50.000000000 +0100
@@ -0,0 +1,461 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* NOTE: this tests functionality beyond POSIX.  POSIX does not allow
+   exit to be called more than once.  */
+
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/select.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+
+/* The following interfaces are defined to be cancellation points but
+   tests are not yet implemented:
+
+     accept()              aio_suspend()      clock_nanosleep()
+     close()               connect()          creat()
+     fcntl()               fsync()            getmsg()
+     getpmsg()             lockf()            mq_receive()
+     mq_send()             mq_timedreceive()  mq_timedsend()
+     msgrcv()              msgsnd()           msync()
+                           open()             pause()
+                           pread()            pthread_cond_timedwait()
+     pthread_cond_wait()   pthread_join()     pthread_testcancel()
+     putmsg()              putpmsg()          pwrite()
+                                              recv()
+     recvfrom()            recvmsg()
+     sem_timedwait()       sem_wait()         send()
+     sendmsg()             sendto()           sigpause()
+     sigsuspend()          sigtimedwait()     sigwait()
+     sigwaitinfo()                            system()
+     tcdrain()
+
+   Since STREAMS are not supported in the standard Linux kernel there
+   is no need to test the STREAMS related functions.
+*/
+
+/* Pipe descriptors.  */
+static int fds[2];
+
+/* Often used barrier for two threads.  */
+static pthread_barrier_t b2;
+
+
+static void *
+tf_read  (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  char buf[100];
+  ssize_t s = read (fds[0], buf, sizeof (buf));
+
+  printf ("%s: read returns with %zd\n", __FUNCTION__, s);
+
+  exit (1);
+}
+
+
+static void *
+tf_readv  (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  char buf[100];
+  struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } };
+  ssize_t s = readv (fds[0], iov, 1);
+
+  printf ("%s: readv returns with %zd\n", __FUNCTION__, s);
+
+  exit (1);
+}
+
+
+static void *
+tf_write  (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  char buf[100000];
+  memset (buf, '\0', sizeof (buf));
+  ssize_t s = write (fds[1], buf, sizeof (buf));
+
+  printf ("%s: write returns with %zd\n", __FUNCTION__, s);
+
+  exit (1);
+}
+
+
+static void *
+tf_writev  (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  char buf[100000];
+  memset (buf, '\0', sizeof (buf));
+  struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } };
+  ssize_t s = writev (fds[1], iov, 1);
+
+  printf ("%s: writev returns with %zd\n", __FUNCTION__, s);
+
+  exit (1);
+}
+
+
+static void *
+tf_sleep (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  sleep (10000000);
+
+  printf ("%s: sleep returns\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_usleep (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  usleep ((useconds_t) ULONG_MAX);
+
+  printf ("%s: usleep returns\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_nanosleep (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  struct timespec ts = { .tv_sec = 10000000, .tv_nsec = 0 };
+  while (nanosleep (&ts, &ts) != 0)
+    continue;
+
+  printf ("%s: nanosleep returns\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_select (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  fd_set rfs;
+  FD_ZERO (&rfs);
+  FD_SET (fds[0], &rfs);
+
+  int s = select (fds[0] + 1, &rfs, NULL, NULL, NULL);
+
+  printf ("%s: select returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_pselect (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  fd_set rfs;
+  FD_ZERO (&rfs);
+  FD_SET (fds[0], &rfs);
+
+  int s = pselect (fds[0] + 1, &rfs, NULL, NULL, NULL, NULL);
+
+  printf ("%s: pselect returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_poll (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  struct pollfd rfs[1] = { [0] = { .fd = fds[0], .events = POLLIN } };
+
+  int s = poll (rfs, 1, -1);
+
+  printf ("%s: poll returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_wait (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Make the program disappear after a while.  */
+      sleep (10);
+      exit (0);
+    }
+
+  int s = wait (NULL);
+
+  printf ("%s: wait returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_waitpid (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Make the program disappear after a while.  */
+      sleep (10);
+      exit (0);
+    }
+
+  int s = waitpid (-1, NULL, 0);
+
+  printf ("%s: waitpid returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_waitid (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Make the program disappear after a while.  */
+      sleep (10);
+      exit (0);
+    }
+
+  siginfo_t si;
+  int s = waitid (P_PID, pid, &si, 0);
+
+  printf ("%s: waitid returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static struct
+{
+  void *(*tf) (void *);
+  int nb;
+} tests[] =
+{
+  { tf_read, 2 },
+  { tf_readv, 2 },
+  { tf_select, 2 },
+  { tf_pselect, 2 },
+  { tf_poll, 2 },
+  { tf_write, 2 },
+  { tf_writev, 2},
+  { tf_sleep, 2 },
+  { tf_usleep, 2 },
+  { tf_nanosleep, 2 },
+  { tf_wait, 2 },
+  { tf_waitid, 2 },
+  { tf_waitpid, 2 },
+};
+#define ntest_tf (sizeof (tests) / sizeof (tests[0]))
+
+
+static int
+do_test (void)
+{
+  if (pipe (fds) != 0)
+    {
+      puts ("pipe failed");
+      exit (1);
+    }
+
+  int cnt;
+  for (cnt = 0; cnt < ntest_tf; ++cnt)
+    {
+      if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0)
+	{
+	  puts ("b2 init failed");
+	  exit (1);
+	}
+
+      /* read(2) test.  */
+      pthread_t th;
+      if (pthread_create (&th, NULL, tests[cnt].tf, NULL) != 0)
+	{
+	  printf ("create for round %d test failed\n", cnt);
+	  exit (1);
+	}
+
+      int r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+
+      struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+      while (nanosleep (&ts, &ts) != 0)
+	continue;
+
+      if (pthread_cancel (th) != 0)
+	{
+	  printf ("cancel in round %d failed\n", cnt);
+	  exit (1);
+	}
+
+      void *status;
+      if (pthread_join (th, &status) != 0)
+	{
+	  printf ("join in round %d failed\n", cnt);
+	  exit (1);
+	}
+      if (status != PTHREAD_CANCELED)
+	{
+	  printf ("thread in round %d not canceled\n", cnt);
+	  exit (1);
+	}
+      printf ("test %d successful\n", cnt);
+
+      if (pthread_barrier_destroy (&b2) != 0)
+	{
+	  puts ("barrier_destroy failed");
+	  exit (1);
+	}
+    }
+
+  return 0;
+}
+
+#define TIMEOUT 60
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
--- libc/linuxthreads/tst-cancel5.c.jj	2002-12-20 22:03:13.000000000 +0100
+++ libc/linuxthreads/tst-cancel5.c	2002-12-14 20:28:32.000000000 +0100
@@ -0,0 +1 @@
+#include "tst-cancel4.c"
--- libc/linuxthreads/tst-cancel6.c.jj	2002-12-20 22:03:13.000000000 +0100
+++ libc/linuxthreads/tst-cancel6.c	2002-12-17 23:47:54.000000000 +0100
@@ -0,0 +1,79 @@
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+static void *
+tf (void *arg)
+{
+  char buf[100];
+  fgets (buf, sizeof (buf), arg);
+  /* This call should never return.  */
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int fd[2];
+  if (pipe (fd) != 0)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  FILE *fp = fdopen (fd[0], "r");
+  if (fp == NULL)
+    {
+      puts ("fdopen failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, fp) != 0)
+    {
+      puts ("pthread_create failed");
+      return 1;
+    }
+
+  sleep (1);
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("pthread_cancel failed");
+      return 1;
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("pthread_join failed");
+      return 1;
+    }
+
+  return r != PTHREAD_CANCELED;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
--- libc/sysdeps/generic/libc-tls.c.jj	2002-12-10 15:08:54.000000000 +0100
+++ libc/sysdeps/generic/libc-tls.c	2002-12-20 20:37:00.000000000 +0100
@@ -135,8 +135,13 @@ __libc_setup_tls (size_t tcbsize, size_t
 	}
 
   if (memsz == 0 && tcbsize <= TLS_INIT_TCB_SIZE)
-    /* We do not need a TLS block and no thread descriptor.  */
-    return;
+    {
+      /* We do not need a TLS block and no thread descriptor.  */
+#ifdef NONTLS_INIT_TP
+      NONTLS_INIT_TP;
+#endif
+      return;
+    }
 
 
   /* We have to set up the TCB block which also (possibly) contains
@@ -249,4 +254,16 @@ __pthread_initialize_minimal (void)
 {
   __libc_setup_tls (TLS_INIT_TCB_SIZE, TLS_INIT_TCB_ALIGN);
 }
+
+#elif defined NONTLS_INIT_TP
+
+/* This is the minimal initialization function used when libpthread is
+   not used.  */
+void
+__attribute__ ((weak))
+__pthread_initialize_minimal (void)
+{
+  NONTLS_INIT_TP;
+}
+
 #endif
--- libc/sysdeps/generic/libc-start.c.jj	2002-12-10 15:08:54.000000000 +0100
+++ libc/sysdeps/generic/libc-start.c	2002-12-20 22:00:08.000000000 +0100
@@ -32,7 +32,7 @@ extern void *__libc_stack_end;
 #ifndef SHARED
 # include <dl-osinfo.h>
 extern void __pthread_initialize_minimal (void)
-# if !(USE_TLS - 0)
+# if !(USE_TLS - 0) && !defined NONTLS_INIT_TP
      __attribute__ ((weak))
 # endif
      ;
@@ -97,7 +97,7 @@ BP_SYM (__libc_start_main) (int (*main) 
      we need to setup errno.  If there is no thread library and we
      handle TLS the function is defined in the libc to initialized the
      TLS handling.  */
-# if !(USE_TLS - 0)
+# if !(USE_TLS - 0) && !defined NONTLS_INIT_TP
   if (__pthread_initialize_minimal)
 # endif
     __pthread_initialize_minimal ();
--- libc/sysdeps/unix/common/pause.c.jj	2001-08-23 18:50:34.000000000 +0200
+++ libc/sysdeps/unix/common/pause.c	2002-12-20 21:33:08.000000000 +0100
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1996 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1996, 2002 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
@@ -18,7 +18,7 @@
 
 #include <signal.h>
 #include <unistd.h>
-
+#include <sysdep-cancel.h>
 
 /* Suspend the process until a signal arrives.
    This always returns -1 and sets errno to EINTR.  */
@@ -26,6 +26,12 @@
 int
 __libc_pause (void)
 {
-  return __sigpause (__sigblock (0), 0);
+  if (SINGLE_THREAD_P)
+    return __sigpause (__sigblock (0), 0);
+
+  int oldtype = LIBC_CANCEL_ASYNC ();
+  int result = __sigpause (__sigblock (0), 0);
+  LIBC_CANCEL_RESET (oldtype);
+  return result;
 }
 weak_alias (__libc_pause, pause)
--- libc/sysdeps/unix/sysv/linux/ia64/sysdep.h.jj	2002-12-10 15:09:30.000000000 +0100
+++ libc/sysdeps/unix/sysv/linux/ia64/sysdep.h	2002-12-20 14:00:36.000000000 +0100
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Jes Sorensen, <Jes.Sorensen@cern.ch>, April 1999.
    Based on code originally written by David Mosberger-Tang
@@ -83,7 +83,7 @@
 #define	PSEUDO(name, syscall_name, args)	\
   ENTRY(name)					\
     DO_CALL (SYS_ify(syscall_name));		\
-	cmp.eq p6,p0=-1,r10;;			\
+	cmp.eq p6,p0=-1,r10;			\
 (p6)	br.cond.spnt.few __syscall_error;
 
 #define DO_CALL(num)				\
@@ -102,11 +102,98 @@
 
 #else /* not __ASSEMBLER__ */
 
-/* Define a macro which expands into the inline wrapper code for a system
-   call.  */
-#if 0
+/* On IA-64 we have stacked registers for passing arguments.  The
+   "out" registers end up being the called function's "in"
+   registers.
+
+   Also, since we have plenty of registers we have two return values
+   from a syscall.  r10 is set to -1 on error, whilst r8 contains the
+   (non-negative) errno on error or the return value on success.
+ */
 #undef INLINE_SYSCALL
-#define INLINE_SYSCALL(name, nr, args...)	__##name (args)
-#endif
+#define INLINE_SYSCALL(name, nr, args...)			\
+  ({								\
+    register long _r8 asm ("r8");				\
+    register long _r10 asm ("r10");				\
+    register long _r15 asm ("r15") = __NR_##name;		\
+    long _retval;						\
+    LOAD_ARGS_##nr (args);					\
+    __asm __volatile ("break %3;;\n\t"				\
+                      : "=r" (_r8), "=r" (_r10), "=r" (_r15)	\
+                      : "i" (__BREAK_SYSCALL), "2" (_r15)	\
+			ASM_ARGS_##nr				\
+                      : "memory" ASM_CLOBBERS_##nr);		\
+    _retval = _r8;						\
+    if (_r10 == -1)						\
+      {								\
+        __set_errno (_retval);					\
+        _retval = -1;						\
+      }								\
+    _retval; })
+
+#undef INTERNAL_SYSCALL
+#define INTERNAL_SYSCALL(name, nr, args...)			\
+  ({								\
+    register long _r8 asm ("r8");				\
+    register long _r10 asm ("r10");				\
+    register long _r15 asm ("r15") = __NR_##name;		\
+    long _retval;						\
+    LOAD_ARGS_##nr (args);					\
+    __asm __volatile ("break %3;;\n\t"				\
+                      : "=r" (_r8), "=r" (_r10), "=r" (_r15)	\
+                      : "i" (__BREAK_SYSCALL), "2" (_r15)	\
+			ASM_ARGS_##nr				\
+                      : "memory" ASM_CLOBBERS_##nr);		\
+    _retval = _r8;						\
+    if (_r10 == -1)						\
+      _retval = -_retval;					\
+    _retval; })
+
+#undef INTERNAL_SYSCALL_ERROR_P
+#define INTERNAL_SYSCALL_ERROR_P(val)	((unsigned long) (val) >= -4095UL)
+
+#undef INTERNAL_SYSCALL_ERRNO
+#define INTERNAL_SYSCALL_ERRNO(val)	(-(val))
+
+#define LOAD_ARGS_0()   do { } while (0)
+#define LOAD_ARGS_1(out0)				\
+  register long _out0 asm ("out0") = (long) (out0);	\
+  LOAD_ARGS_0 ()
+#define LOAD_ARGS_2(out0, out1)				\
+  register long _out1 asm ("out1") = (long) (out1);	\
+  LOAD_ARGS_1 (out0)
+#define LOAD_ARGS_3(out0, out1, out2)			\
+  register long _out2 asm ("out2") = (long) (out2);	\
+  LOAD_ARGS_2 (out0, out1)
+#define LOAD_ARGS_4(out0, out1, out2, out3)		\
+  register long _out3 asm ("out3") = (long) (out3);	\
+  LOAD_ARGS_3 (out0, out1, out2)
+#define LOAD_ARGS_5(out0, out1, out2, out3, out4)	\
+  register long _out4 asm ("out4") = (long) (out4);	\
+  LOAD_ARGS_4 (out0, out1, out2, out3)
+
+#define ASM_ARGS_0
+#define ASM_ARGS_1      ASM_ARGS_0, "r" (_out0)
+#define ASM_ARGS_2      ASM_ARGS_1, "r" (_out1)
+#define ASM_ARGS_3      ASM_ARGS_2, "r" (_out2)
+#define ASM_ARGS_4      ASM_ARGS_3, "r" (_out3)
+#define ASM_ARGS_5      ASM_ARGS_4, "r" (_out4)
+
+#define ASM_CLOBBERS_0	ASM_CLOBBERS_1, "out0"
+#define ASM_CLOBBERS_1	ASM_CLOBBERS_2, "out1"
+#define ASM_CLOBBERS_2	ASM_CLOBBERS_3, "out2"
+#define ASM_CLOBBERS_3	ASM_CLOBBERS_4, "out3"
+#define ASM_CLOBBERS_4	ASM_CLOBBERS_5, "out4"
+#define ASM_CLOBBERS_5	, "out5", "out6", "out7",			\
+  /* Non-stacked integer registers, minus r8, r10, r15.  */		\
+  "r2", "r3", "r9", "r11", "r12", "r13", "r14", "r16", "r17", "r18",	\
+  "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27",	\
+  "r28", "r29", "r30", "r31",						\
+  /* Predicate registers.  */						\
+  "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15",	\
+  /* Non-rotating fp registers.  */					\
+  "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",	\
+  /* Branch registers.  */						\
+  "b6", "b7"
 
 #endif /* not __ASSEMBLER__ */
--- libc/nptl/Makefile.jj	2002-12-20 12:17:13.000000000 +0100
+++ libc/nptl/Makefile	2002-12-20 21:58:19.000000000 +0100
@@ -214,8 +214,10 @@ $(addprefix $(objpfx), \
     $(tests) $(test-srcs))): $(objpfx)libpthread.so \
 			     $(objpfx)libpthread_nonshared.a
 $(objpfx)tst-unload: $(common-objpfx)dlfcn/libdl.so
+# $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so,
+# since otherwise libpthread.so comes before libc.so when linking.
 $(addprefix $(objpfx), $(tests-reverse)): \
-  $(common-objpfx)libc.so $(objpfx)libpthread.so \
+  $(objpfx)../libc.so $(objpfx)libpthread.so \
   $(objpfx)libpthread_nonshared.a
 $(addprefix $(objpfx),$(tests-static)): $(objpfx)libpthread.a
 else
--- libc/nptl/tst-cancel4.c.jj	2002-11-26 23:50:02.000000000 +0100
+++ libc/nptl/tst-cancel4.c	2002-12-20 21:58:50.000000000 +0100
@@ -113,7 +113,7 @@ tf_write  (void *arg)
       exit (1);
     }
 
-  char buf[10000];
+  char buf[100000];
   memset (buf, '\0', sizeof (buf));
   ssize_t s = write (fds[1], buf, sizeof (buf));
 
@@ -133,7 +133,7 @@ tf_writev  (void *arg)
       exit (1);
     }
 
-  char buf[10000];
+  char buf[100000];
   memset (buf, '\0', sizeof (buf));
   struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } };
   ssize_t s = writev (fds[1], iov, 1);
@@ -172,7 +172,7 @@ tf_usleep (void *arg)
       exit (1);
     }
 
-  usleep (ULONG_MAX);
+  usleep ((useconds_t) ULONG_MAX);
 
   printf ("%s: usleep returns\n", __FUNCTION__);
 

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]