NPTL support for m68k/ColdFire
authorMaxim Kuvyrkov <maxim@codesourcery.com>
Fri, 12 Mar 2010 18:50:55 +0000 (19:50 +0100)
committerAndreas Schwab <schwab@linux-m68k.org>
Fri, 12 Mar 2010 18:52:07 +0000 (19:52 +0100)
33 files changed:
ChangeLog.m68k
sysdeps/m68k/dl-machine.h
sysdeps/m68k/dl-tls.h [new file with mode: 0644]
sysdeps/m68k/libc-tls.c [new file with mode: 0644]
sysdeps/m68k/nptl/Makefile [new file with mode: 0644]
sysdeps/m68k/nptl/pthread_spin_lock.c [new file with mode: 0644]
sysdeps/m68k/nptl/pthread_spin_trylock.c [new file with mode: 0644]
sysdeps/m68k/nptl/pthreaddef.h [new file with mode: 0644]
sysdeps/m68k/nptl/tcb-offsets.sym [new file with mode: 0644]
sysdeps/m68k/nptl/tls.h [new file with mode: 0644]
sysdeps/m68k/tls-macros.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/Makefile
sysdeps/unix/sysv/linux/m68k/Versions
sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/clone.S
sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/init-first.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/m68k-helpers.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/m68k-vdso.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/nptl/clone.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/nptl/createthread.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/nptl/fork.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/nptl/vfork.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/m68k/socket.S
sysdeps/unix/sysv/linux/m68k/sysdep.h
sysdeps/unix/sysv/linux/m68k/vfork.S

index d63b88e..32681ff 100644 (file)
@@ -1,5 +1,45 @@
 2010-03-09  Maxim Kuvyrkov  <maxim@codesourcery.com>
 
+       NPTL support for m68k/ColdFire
+       * sysdeps/unix/sysv/linux/m68k/sysdep.h (tls.h): Include.
+       (INTERNAL_SYSCALL): Convert to INTERNAL_SYSCALL_NCS.
+       (PTR_MANGLE, PTR_DEMANGLE): Define.
+       (NEED_STATIC_SYSINFO_DSO): Define.
+       * sysdeps/unix/sysv/linux/m68k/clone.S: Support RESET_PID.
+       * sysdeps/unix/sysv/linux/m68k/m68k-helpers.S: New.
+       * sysdeps/unix/sysv/linux/m68k/Makefile: Add new files to lists.
+       * sysdeps/unix/sysv/linux/m68k/vfork.S: Add SAVE_PID/RESTORE_PID.
+       * sysdeps/unix/sysv/linux/m68k/m68k-vdso.c: New.
+       * sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c: New.
+       * sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h: New.
+       * sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h: New.
+       * sysdeps/unix/sysv/linux/m68k/Versions: Add symbols for NPTL support.
+       * sysdeps/unix/sysv/linux/m68k/init-first.c: New.
+       * sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h: New.
+       * sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h: New.
+       * sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h: New.
+       * sysdeps/unix/sysv/linux/m68k/nptl/clone.S: New.
+       * sysdeps/unix/sysv/linux/m68k/nptl/fork.c: New.
+       * sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h: New.
+       * sysdeps/unix/sysv/linux/m68k/nptl/vfork.S: New.
+       * sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S: New.
+       * sysdeps/unix/sysv/linux/m68k/nptl/createthread.c: New.
+       * sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c: New.
+       * sysdeps/unix/sysv/linux/m68k/socket.S: Update cancelation code.
+       * sysdeps/m68k/dl-tls.h: New.
+       * sysdeps/m68k/libc-tls.c: New.
+       * sysdeps/m68k/tls-macros.h: New.
+       * sysdeps/m68k/dl-machine.h (RTLD_START): Terminate stack frame to
+       generate better backtraces.
+       (elf_machine_type_class, elf_machine_rela): Handle TLS relocations.
+       * sysdeps/m68k/dl-machine.h: Handle TLS relocations.
+       * sysdeps/m68k/nptl/tcb-offsets.sym: New.
+       * sysdeps/m68k/nptl/pthread_spin_trylock.c: New.
+       * sysdeps/m68k/nptl/tls.h: New.
+       * sysdeps/m68k/nptl/pthread_spin_lock.c: New.
+       * sysdeps/m68k/nptl/pthreaddef.h: New.
+       * sysdeps/m68k/nptl/Makefile: New.
+
        * sysdeps/unix/sysv/linux/m68k/bits/sigcontext.h: Remove.
        * sysdeps/unix/sysv/linux/m68k/register-dump.h: Update.
 
index 08a4396..9bc35e7 100644 (file)
@@ -1,5 +1,6 @@
 /* Machine-dependent ELF dynamic relocation inline functions.  m68k version.
-   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1996-2001, 2002, 2003, 2004, 2005, 2010
+   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
@@ -24,6 +25,7 @@
 
 #include <sys/param.h>
 #include <sysdep.h>
+#include <dl-tls.h>
 
 /* Return nonzero iff ELF header is compatible with the running host.  */
 static inline int
@@ -121,6 +123,7 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
        .globl _start\n\
        .type _start,@function\n\
 _start:\n\
+       sub.l %fp, %fp\n\
        move.l %sp, -(%sp)\n\
        jbsr _dl_start\n\
        addq.l #4, %sp\n\
@@ -159,12 +162,16 @@ _dl_start_user:\n\
        .size _dl_start_user, . - _dl_start_user\n\
        .previous");
 
-/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
-   PLT entries should not be allowed to define the value.
+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or
+   TLS variable, so undefined references should not be allowed to
+   define the value.
    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
    of the main executable's symbols, as for a COPY reloc.  */
 #define elf_machine_type_class(type) \
-  ((((type) == R_68K_JMP_SLOT) * ELF_RTYPE_CLASS_PLT)  \
+  ((((type) == R_68K_JMP_SLOT       \
+     || (type) == R_68K_TLS_DTPMOD32 \
+     || (type) == R_68K_TLS_DTPREL32 \
+     || (type) == R_68K_TLS_TPREL32) * ELF_RTYPE_CLASS_PLT)    \
    | (((type) == R_68K_COPY) * ELF_RTYPE_CLASS_COPY))
 
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
@@ -262,6 +269,25 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
        case R_68K_PC32:
          *reloc_addr = value + reloc->r_addend - (Elf32_Addr) reloc_addr;
          break;
+#if defined USE_TLS && !defined RTLD_BOOTSTRAP
+       case R_68K_TLS_DTPMOD32:
+         /* Get the information from the link map returned by the
+            resolv function.  */
+         if (sym_map != NULL)
+           *reloc_addr = sym_map->l_tls_modid;
+         break;
+       case R_68K_TLS_DTPREL32:
+         if (sym != NULL)
+           *reloc_addr = TLS_DTPREL_VALUE (sym, reloc);
+         break;
+       case R_68K_TLS_TPREL32:
+         if (sym != NULL)
+           {
+             CHECK_STATIC_TLS (map, sym_map);
+             *reloc_addr = TLS_TPREL_VALUE (sym_map, sym, reloc);
+           }
+         break;
+#endif /* defined USE_TLS && !defined RTLD_BOOTSTRAP */
        case R_68K_NONE:                /* Alright, Wilbur.  */
          break;
        default:
diff --git a/sysdeps/m68k/dl-tls.h b/sysdeps/m68k/dl-tls.h
new file mode 100644 (file)
index 0000000..f2ce998
--- /dev/null
@@ -0,0 +1,48 @@
+/* Thread-local storage handling in the ELF dynamic linker.  M68K version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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.  */
+
+
+/* Type used for the representation of TLS information in the GOT.  */
+typedef struct
+{
+  unsigned long int ti_module;
+  unsigned long int ti_offset;
+} tls_index;
+
+/* The thread pointer points 0x7000 past the first static TLS block.  */
+#define TLS_TP_OFFSET          0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+   TLS block.  */
+#define TLS_DTV_OFFSET         0x8000
+
+/* Compute the value for a TPREL reloc.  */
+#define TLS_TPREL_VALUE(sym_map, sym, reloc)                           \
+  ((sym_map)->l_tls_offset + (sym)->st_value + (reloc)->r_addend       \
+   - TLS_TP_OFFSET)
+
+/* Compute the value for a DTPREL reloc.  */
+#define TLS_DTPREL_VALUE(sym, reloc)                           \
+  ((sym)->st_value + (reloc)->r_addend - TLS_DTV_OFFSET)
+
+extern void *__tls_get_addr (tls_index *ti);
+
+#define GET_ADDR_OFFSET                (ti->ti_offset + TLS_DTV_OFFSET)
+#define __TLS_GET_ADDR(__ti)   (__tls_get_addr (__ti) - TLS_DTV_OFFSET)
diff --git a/sysdeps/m68k/libc-tls.c b/sysdeps/m68k/libc-tls.c
new file mode 100644 (file)
index 0000000..e865fac
--- /dev/null
@@ -0,0 +1,38 @@
+/* Thread-local storage handling in the ELF dynamic linker.  m68k version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 <csu/libc-tls.c>
+#include <dl-tls.h>
+
+#if USE_TLS
+
+/* On M68K, linker optimizations are not required, so __tls_get_addr
+   can be called even in statically linked binaries.  In this case module
+   must be always 1 and PT_TLS segment exist in the binary, otherwise it
+   would not link.  */
+
+void *
+__tls_get_addr (tls_index *ti)
+{
+  dtv_t *dtv = THREAD_DTV ();
+  return (char *) dtv[1].pointer.val + GET_ADDR_OFFSET;
+}
+
+#endif
diff --git a/sysdeps/m68k/nptl/Makefile b/sysdeps/m68k/nptl/Makefile
new file mode 100644 (file)
index 0000000..f36fc8f
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (C) 2010 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+#
+# 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.
+
+ifeq ($(subdir),csu)
+gen-as-const-headers += tcb-offsets.sym
+endif
diff --git a/sysdeps/m68k/nptl/pthread_spin_lock.c b/sysdeps/m68k/nptl/pthread_spin_lock.c
new file mode 100644 (file)
index 0000000..1cc16c8
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_lock (pthread_spinlock_t *lock)
+{
+  while (atomic_compare_and_exchange_val_acq(lock, 1, 0) != 0)
+   while (*lock != 0)
+    ;
+
+  return 0;
+}
diff --git a/sysdeps/m68k/nptl/pthread_spin_trylock.c b/sysdeps/m68k/nptl/pthread_spin_trylock.c
new file mode 100644 (file)
index 0000000..831bffb
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 <errno.h>
+#include <atomic.h>
+#include "pthreadP.h"
+
+int
+pthread_spin_trylock (pthread_spinlock_t *lock)
+{
+  return atomic_compare_and_exchange_val_acq(lock, 1, 0) ? EBUSY : 0;
+}
diff --git a/sysdeps/m68k/nptl/pthreaddef.h b/sysdeps/m68k/nptl/pthreaddef.h
new file mode 100644 (file)
index 0000000..0a54907
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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.  */
+
+/* Default stack size.  */
+#define ARCH_STACK_DEFAULT_SIZE        (2 * 1024 * 1024)
+
+/* Required stack pointer alignment at beginning.  */
+#define STACK_ALIGN            16
+
+/* Minimal stack size after allocating thread descriptor and guard size.  */
+#define MINIMAL_REST_STACK     2048
+
+/* Alignment requirement for TCB.  */
+#define TCB_ALIGNMENT          16
+
+
+/* Location of current stack frame.  */
+#define CURRENT_STACK_FRAME    __builtin_frame_address (0)
+
+
+/* XXX Until we have a better place keep the definitions here.  */
+#define __exit_thread_inline(val) \
+  INLINE_SYSCALL (exit, 1, (val))
diff --git a/sysdeps/m68k/nptl/tcb-offsets.sym b/sysdeps/m68k/nptl/tcb-offsets.sym
new file mode 100644 (file)
index 0000000..b1bba65
--- /dev/null
@@ -0,0 +1,11 @@
+#include <sysdep.h>
+#include <tls.h>
+
+--
+
+-- Derive offsets relative to the thread register.
+#define thread_offsetof(mem)   (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)
+
+MULTIPLE_THREADS_OFFSET                thread_offsetof (header.multiple_threads)
+PID_OFFSET                     thread_offsetof (pid)
+TID_OFFSET                     thread_offsetof (tid)
diff --git a/sysdeps/m68k/nptl/tls.h b/sysdeps/m68k/nptl/tls.h
new file mode 100644 (file)
index 0000000..c29824c
--- /dev/null
@@ -0,0 +1,171 @@
+/* Definition for thread-local data handling.  NPTL/m68k version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 1
+
+#include <dl-sysdep.h>
+
+#ifndef __ASSEMBLER__
+# include <stdbool.h>
+# include <stddef.h>
+# include <stdint.h>
+
+/* Type for the dtv.  */
+typedef union dtv
+{
+  size_t counter;
+  struct
+  {
+    void *val;
+    bool is_static;
+  } pointer;
+} dtv_t;
+
+#else /* __ASSEMBLER__ */
+# include <tcb-offsets.h>
+#endif /* __ASSEMBLER__ */
+
+/* Signal that TLS support is available.  */
+#define USE_TLS        1
+
+#ifndef __ASSEMBLER__
+
+/* Get system call information.  */
+# include <sysdep.h>
+
+/* The TP points to the start of the thread blocks.  */
+# define TLS_DTV_AT_TP 1
+
+/* Get the thread descriptor definition.  */
+# include <nptl/descr.h>
+
+typedef struct
+{
+  dtv_t *dtv;
+  void *private;
+} tcbhead_t;
+
+/* This is the size of the initial TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_INIT_TCB_SIZE     0
+
+/* Alignment requirements for the initial TCB.  */
+# define TLS_INIT_TCB_ALIGN    __alignof__ (struct pthread)
+
+/* This is the size of the TCB.  Because our TCB is before the thread
+   pointer, we don't need this.  */
+# define TLS_TCB_SIZE          0
+
+/* Alignment requirements for the TCB.  */
+# define TLS_TCB_ALIGN         __alignof__ (struct pthread)
+
+/* This is the size we need before TCB - actually, it includes the TCB.  */
+# define TLS_PRE_TCB_SIZE                                              \
+  (sizeof (struct pthread)                                             \
+   + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
+
+/* The thread pointer (TP) points to the end of the
+   TCB + 0x7000, as for PowerPC and MIPS.  This implies that TCB address is
+   TP - 0x7000.  As we define TLS_DTV_AT_TP we can
+   assume that the pthread struct is allocated immediately ahead of the
+   TCB.  This implies that the pthread_descr address is
+   TP - (TLS_PRE_TCB_SIZE + 0x7000).  */
+# define TLS_TCB_OFFSET        0x7000
+
+/* Install the dtv pointer.  The pointer passed is to the element with
+   index -1 which contain the length.  */
+# define INSTALL_DTV(tcbp, dtvp) \
+  ((tcbhead_t *) (tcbp))[-1].dtv = dtvp + 1
+
+/* Install new dtv for current thread.  */
+# define INSTALL_NEW_DTV(dtv) \
+  (THREAD_DTV () = (dtv))
+
+/* Return dtv of given thread descriptor.  */
+# define GET_DTV(tcbp) \
+  (((tcbhead_t *) (tcbp))[-1].dtv)
+
+/* Code to initially initialize the thread pointer.  This might need
+   special attention since 'errno' is not yet available and if the
+   operation can cause a failure 'errno' must not be touched.  */
+# define TLS_INIT_TP(tcbp, secondcall)                                 \
+  ({                                                                   \
+    INTERNAL_SYSCALL_DECL (err);                                       \
+    int _sys_result;                                                   \
+                                                                       \
+    _sys_result = INTERNAL_SYSCALL (set_thread_area, err, 1,           \
+                                   ((void *) (tcbp)) + TLS_TCB_OFFSET); \
+    INTERNAL_SYSCALL_ERROR_P (_sys_result, err) ? "unknown error" : NULL; })
+
+extern void * __m68k_read_tp (void);
+
+/* Return the address of the dtv for the current thread.  */
+# define THREAD_DTV() \
+  (((tcbhead_t *) (__m68k_read_tp () - TLS_TCB_OFFSET))[-1].dtv)
+
+/* Return the thread descriptor for the current thread.  */
+# define THREAD_SELF \
+  ((struct pthread *) (__m68k_read_tp () - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+/* Magic for libthread_db to know how to do THREAD_SELF.  */
+# define DB_THREAD_SELF \
+  CONST_THREAD_AREA (32, TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Access to data in the thread descriptor is easy.  */
+# define THREAD_GETMEM(descr, member) \
+  descr->member
+# define THREAD_GETMEM_NC(descr, member, idx) \
+  descr->member[idx]
+# define THREAD_SETMEM(descr, member, value) \
+  descr->member = (value)
+# define THREAD_SETMEM_NC(descr, member, idx, value) \
+  descr->member[idx] = (value)
+
+/* l_tls_offset == 0 is perfectly valid on M68K, so we have to use some
+   different value to mean unset l_tls_offset.  */
+# define NO_TLS_OFFSET         -1
+
+/* Get and set the global scope generation counter in struct pthread.  */
+#define THREAD_GSCOPE_FLAG_UNUSED 0
+#define THREAD_GSCOPE_FLAG_USED   1
+#define THREAD_GSCOPE_FLAG_WAIT   2
+#define THREAD_GSCOPE_RESET_FLAG()                                     \
+  do                                                                   \
+    { int __res                                                                \
+       = atomic_exchange_rel (&THREAD_SELF->header.gscope_flag,        \
+                              THREAD_GSCOPE_FLAG_UNUSED);              \
+      if (__res == THREAD_GSCOPE_FLAG_WAIT)                            \
+       lll_futex_wake (&THREAD_SELF->header.gscope_flag, 1, LLL_PRIVATE); \
+    }                                                                  \
+  while (0)
+#define THREAD_GSCOPE_SET_FLAG()                                       \
+  do                                                                   \
+    {                                                                  \
+      THREAD_SELF->header.gscope_flag = THREAD_GSCOPE_FLAG_USED;       \
+      atomic_write_barrier ();                                         \
+    }                                                                  \
+  while (0)
+#define THREAD_GSCOPE_WAIT() \
+  GL(dl_wait_lookup_done) ()
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* tls.h */
diff --git a/sysdeps/m68k/tls-macros.h b/sysdeps/m68k/tls-macros.h
new file mode 100644 (file)
index 0000000..d03d7b9
--- /dev/null
@@ -0,0 +1,70 @@
+/* Macros for accessing thread-local storage.  m68k version.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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.  */
+
+#define TLS_GD(x)                                                      \
+  ({                                                                   \
+    void *__result;                                                    \
+    extern void *__tls_get_addr (void *);                              \
+                                                                       \
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"                  \
+        "lea (-6, %%pc, %0), %0\n\t"                                   \
+        "lea " #x "@TLSGD(%0), %0"                                     \
+        : "=&a" (__result));                                           \
+    (int *) __tls_get_addr (__result); })
+
+#define TLS_LD(x)                                                      \
+  ({                                                                   \
+    char *__tp;                                                                \
+    int __offset;                                                      \
+    extern void *__tls_get_addr (void *);                              \
+                                                                       \
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"                  \
+        "lea (-6, %%pc, %0), %0\n\t"                                   \
+        "lea " #x "@TLSLDM(%0), %0"                                    \
+        : "=&a" (__tp));                                               \
+    __tp = (char *) __tls_get_addr (__tp);                             \
+    asm ("movel #" #x "@TLSLDO, %0"                                    \
+        : "=a" (__offset));                                            \
+    (int *) (__tp + __offset); })
+
+#define TLS_IE(x)                                                      \
+  ({                                                                   \
+    char *__tp;                                                                \
+    int __offset;                                                      \
+    extern void * __m68k_read_tp (void);                               \
+                                                                       \
+    __tp = (char *) __m68k_read_tp ();                                 \
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"                  \
+        "lea (-6, %%pc, %0), %0\n\t"                                   \
+        "movel " #x "@TLSIE(%0), %0"                                   \
+        : "=&a" (__offset));                                           \
+    (int *) (__tp + __offset); })
+
+#define TLS_LE(x)                                                      \
+  ({                                                                   \
+    char *__tp;                                                                \
+    int __offset;                                                      \
+    extern void * __m68k_read_tp (void);                               \
+                                                                       \
+    __tp = (char *) __m68k_read_tp ();                                 \
+    asm ("movel #" #x "@TLSLE, %0"                                     \
+        : "=a" (__offset));                                            \
+    (int *) (__tp + __offset); })
+
index 6bb4f6b..97d9584 100644 (file)
@@ -2,12 +2,18 @@
 
 m68k-syntax-flag = -DMOTOROLA_SYNTAX
 
+ifeq ($(subdir),csu)
+sysdep_routines += m68k-helpers
+endif
+
 ifeq ($(subdir),misc)
 sysdep_routines += mremap
 sysdep_headers += sys/reg.h
 endif
 
 ifeq ($(subdir),elf)
+sysdep_routines += dl-vdso libc-m68k-vdso
+sysdep-rtld-routines += m68k-vdso
 sysdep-others += lddlibc4
 install-bin += lddlibc4
 endif
index 5650f7f..8a941f8 100644 (file)
@@ -32,4 +32,18 @@ libc {
   GLIBC_2.11 {
     fallocate64;
   }
+  GLIBC_2.12 {
+    __m68k_read_tp;
+  }
+  GLIBC_PRIVATE {
+    __vdso_atomic_cmpxchg_32; __vdso_atomic_barrier;
+  }
+}
+
+ld {
+  GLIBC_PRIVATE {
+    __rtld___vdso_read_tp;
+    __rtld___vdso_atomic_cmpxchg_32;
+    __rtld___vdso_atomic_barrier;
+  }
 }
diff --git a/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h b/sysdeps/unix/sysv/linux/m68k/bits/m68k-vdso.h
new file mode 100644 (file)
index 0000000..c361060
--- /dev/null
@@ -0,0 +1,61 @@
+/* Resolve function pointers to VDSO functions.
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 _M68K_VDSO_H
+#define _M68K_VDSO_H
+
+#ifdef SHARED
+
+# ifdef IS_IN_rtld
+# define M68K_VDSO_SYMBOL(name) __rtld_##name
+# define STR_M68K_VDSO_SYMBOL(name) "__rtld_" #name
+# else
+# define M68K_VDSO_SYMBOL(name) name
+# define STR_M68K_VDSO_SYMBOL(name) #name
+# endif
+
+# ifndef __ASSEMBLER__
+
+/* We define __rtld_* copies for rtld.
+   We need them visible in libc to initialize.  */
+#  if defined IS_IN_rtld || !defined NOT_IN_libc
+extern void *__rtld___vdso_read_tp;
+extern void *__rtld___vdso_atomic_cmpxchg_32;
+extern void *__rtld___vdso_atomic_barrier;
+
+/* These stubs are meant to be invoked only from the assembly.  */
+extern void __vdso_read_tp_stub (void);
+extern void __vdso_atomic_cmpxchg_32_stub (void);
+extern void __vdso_atomic_barrier_stub (void);
+#  endif /* IS_IN_rtld || !NOT_IN_libc */
+
+/* RTLD should only use its own copies.  */
+#  ifndef IS_IN_rtld
+extern void *__vdso_read_tp;
+extern void *__vdso_atomic_cmpxchg_32;
+extern void *__vdso_atomic_barrier;
+#  endif /* !IS_IN_rtld */
+
+# endif /* !__ASSEMBLER__ */
+
+#endif /* SHARED */
+
+#endif /* _M68K_VDSO_H */
index a179f8e..401e2ef 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,97,98,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1996,97,98,2002,2010 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab (schwab@issan.informatik.uni-dortmund.de)
 
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
-/* clone is even more special than fork as it mucks with stacks
+/* clone() is even more special than fork() as it mucks with stacks
    and invokes a function in the right context after its all over.  */
 
 #include <sysdep.h>
 #define _ERRNO_H       1
 #include <bits/errno.h>
+#ifdef RESET_PID
+#include <tls.h>
+#endif
+
+#define CLONE_VM      0x00000100
+#define CLONE_THREAD  0x00010000
 
-/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
+/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
+            void *parent_tidptr, void *tls, void *child_tidptr) */
 
         .text
 ENTRY (__clone)
@@ -42,7 +49,17 @@ ENTRY (__clone)
        movel   16(%sp), -(%a1)
 
        /* Do the system call */
-       movel   12(%sp), %d1            /* get flags */
+       movel   12+0(%sp), %d1          /* get flags */
+       movel   %d3, -(%a1)             /* save %d3 and get parent_tidptr */
+       movel   %d3, -(%sp)
+       movel   20+4(%sp), %d3
+       movel   %d4, -(%a1)             /* save %d4 and get child_tidptr */
+       movel   %d4, -(%sp)
+       movel   28+8(%sp), %d4
+       movel   %d5, -(%a1)             /* save %d5 and get tls */
+       movel   %d5, -(%sp)
+       movel   24+12(%sp), %d5
+       /* save %d2 and get stack pointer */
 #ifdef __mcoldfire__
        movel   %d2, -(%a1)
        movel   %d2, -(%sp)
@@ -57,6 +74,9 @@ ENTRY (__clone)
 #else
        exg     %d2, %a1                /* restore %d2 */
 #endif
+       movel   (%sp)+, %d5             /* restore %d5, %d4 and %d3 */
+       movel   (%sp)+, %d4
+       movel   (%sp)+, %d3
 
        tstl    %d0
        jmi     SYSCALL_ERROR_LABEL
@@ -65,11 +85,35 @@ ENTRY (__clone)
        rts
 
 thread_start:
+       cfi_startproc
+       cfi_undefined (pc)      /* Mark end of stack */
        subl    %fp, %fp        /* terminate the stack frame */
+#ifdef RESET_PID
+       /* Check and see if we need to reset the PID.  */
+       movel   %d1, %a1
+       andl    #CLONE_THREAD, %d1
+       jne     donepid
+       movel   %a1, %d1
+       movel   #-1, %d0
+       andl    #CLONE_VM, %d1
+       jne     gotpid
+       movel   #SYS_ify (getpid), %d0
+       trap    #0
+gotpid:
+       movel   %a0, -(%sp)
+       movel   %d0, -(%sp)
+       bsrl    __m68k_read_tp@PLTPC
+       movel   (%sp)+, %d0
+       movel   %d0, PID_OFFSET(%a0)
+       movel   %d0, TID_OFFSET(%a0)
+       movel   (%sp)+, %a0
+donepid:
+#endif
        jsr     (%a0)
        movel   %d0, %d1
        movel   #SYS_ify (exit), %d0
        trap    #0
+       cfi_endproc
 
 PSEUDO_END (__clone)
 
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h b/sysdeps/unix/sysv/linux/m68k/coldfire/nptl/bits/atomic.h
new file mode 100644 (file)
index 0000000..1198bb9
--- /dev/null
@@ -0,0 +1,105 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 _BITS_ATOMIC_H
+#define _BITS_ATOMIC_H 1
+
+#include <stdint.h>
+#include <sysdep.h>
+#include <bits/m68k-vdso.h>
+
+/* Coldfire has no atomic compare-and-exchange operation, but the
+   kernel provides userspace atomicity operations.  Use them.  */
+
+typedef int32_t atomic32_t;
+typedef uint32_t uatomic32_t;
+typedef int_fast32_t atomic_fast32_t;
+typedef uint_fast32_t uatomic_fast32_t;
+
+typedef intptr_t atomicptr_t;
+typedef uintptr_t uatomicptr_t;
+typedef intmax_t atomic_max_t;
+typedef uintmax_t uatomic_max_t;
+
+/* The only basic operation needed is compare and exchange.  */
+/* For ColdFire we'll have to trap into the kernel mode anyway,
+   so trap from the library rather then from the kernel wrapper.  */
+#ifdef SHARED
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)      \
+  ({                                                                   \
+    /* Use temporary variables to workaround call-clobberness of */    \
+    /* the registers.  */                                              \
+    __typeof (mem) _mem = mem;                                         \
+    __typeof (oldval) _oldval = oldval;                                        \
+    __typeof (newval) _newval = newval;                                        \
+    register __typeof (mem) _a0 asm ("a0") = _mem;                     \
+    register __typeof (oldval) _d0 asm ("d0") = _oldval;               \
+    register __typeof (newval) _d1 asm ("d1") = _newval;               \
+    void *tmp;                                                         \
+                                                                       \
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %2\n\t"                  \
+        "lea (-6, %%pc, %2), %2\n\t"                                   \
+        "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)       \
+        "@GOT(%2), %2\n\t"                                             \
+        "movel (%2), %2\n\t"                                           \
+        "jsr (%2)\n\t"                                                 \
+        : "+d" (_d0), "+m" (*_a0), "=&a" (tmp)                         \
+        : "a" (_a0), "d" (_d1));                                       \
+    _d0;                                                               \
+  })
+#else
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)      \
+  ({                                                                   \
+    /* Use temporary variables to workaround call-clobberness of */    \
+    /* the registers.  */                                              \
+    __typeof (mem) _mem = mem;                                         \
+    __typeof (oldval) _oldval = oldval;                                        \
+    __typeof (newval) _newval = newval;                                        \
+    register __typeof (oldval) _d0 asm ("d0")                          \
+      = SYS_ify (atomic_cmpxchg_32);                                   \
+    register __typeof (mem) _a0 asm ("a0") = _mem;                     \
+    register __typeof (oldval) _d2 asm ("d2") = _oldval;               \
+    register __typeof (newval) _d1 asm ("d1") = _newval;               \
+                                                                       \
+    asm ("trap #0"                                                     \
+        : "+d" (_d0), "+m" (*_a0)                                      \
+        : "a" (_a0), "d" (_d2), "d" (_d1));                            \
+    _d0;                                                               \
+  })
+#endif
+
+#ifdef SHARED
+# define atomic_full_barrier()                                  \
+  ({                                                            \
+    void *tmp;                                                  \
+                                                                \
+    asm ("movel #_GLOBAL_OFFSET_TABLE_@GOTPC, %0\n\t"           \
+        "lea (-6, %pc, %0), %0\n\t"                             \
+        "movel " STR_M68K_VDSO_SYMBOL (__vdso_atomic_barrier)   \
+        "@GOT(%0), %0\n\t"                                      \
+        "movel (%0), %0\n\t"                                    \
+        "jsr (%0)\n\t"                                          \
+        : "=&a" (tmp));                                         \
+  })
+#else
+# define atomic_full_barrier()                         \
+  (INTERNAL_SYSCALL (atomic_barrier, , 0), (void) 0)
+#endif
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/init-first.c b/sysdeps/unix/sysv/linux/m68k/init-first.c
new file mode 100644 (file)
index 0000000..f8168d1
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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: linking in vDSO to a static binary requires changes to
+   the main GLIBC proper.  Not yet implemented.  */
+#ifdef SHARED
+
+#include <dl-vdso.h>
+#include <bits/m68k-vdso.h>
+
+static inline void
+_libc_vdso_platform_setup (void)
+{
+  void *p;
+
+  PREPARE_VERSION (linux26, "LINUX_2.6", 61765110);
+
+  /* It may happen that rtld didn't initialize the vDSO, so fallback
+     to the syscall implementations if _dl_vdso_vsym returns NULL.
+     This may happen when a static executable dlopen's a dynamic library.
+     This really is nothing more than a workaround for rtld/csu
+     deficiency.  Ideally, init code would setup the vDSO for static
+     binaries too.  */
+
+  p = _dl_vdso_vsym ("__kernel_read_tp", &linux26);
+  if (p != NULL)
+    {
+      __vdso_read_tp = p;
+      __rtld___vdso_read_tp = p;
+    }
+  else
+    assert (__vdso_read_tp == (void *) __vdso_read_tp_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_cmpxchg_32", &linux26);
+  if (p != NULL)
+    {
+      __vdso_atomic_cmpxchg_32 = p;
+      __rtld___vdso_atomic_cmpxchg_32 = p;
+    }
+  else
+    assert (__vdso_atomic_cmpxchg_32
+           == (void *) __vdso_atomic_cmpxchg_32_stub);
+
+  p = _dl_vdso_vsym ("__kernel_atomic_barrier", &linux26);
+  if (p != NULL)
+    {
+      __vdso_atomic_barrier = p;
+      __rtld___vdso_atomic_barrier = p;
+    }
+  else
+    assert (__vdso_atomic_barrier == (void *) __vdso_atomic_barrier_stub);
+}
+
+#define VDSO_SETUP _libc_vdso_platform_setup
+
+#endif /* SHARED */
+
+#include <sysdeps/unix/sysv/linux/init-first.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/libc-m68k-vdso.c
new file mode 100644 (file)
index 0000000..45982e9
--- /dev/null
@@ -0,0 +1 @@
+#include "m68k-vdso.c"
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S b/sysdeps/unix/sysv/linux/m68k/m68k-helpers.S
new file mode 100644 (file)
index 0000000..00db4bb
--- /dev/null
@@ -0,0 +1,105 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   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 <bits/m68k-vdso.h>
+
+       .text
+
+       .hidden __vdso_read_tp_stub
+ENTRY (__vdso_read_tp_stub)
+       cfi_startproc
+       move.l  #__NR_get_thread_area, %d0
+       trap    #0
+       move.l  %d0, %a0
+       rts
+       cfi_endproc
+END (__vdso_read_tp_stub)
+
+# ifdef SHARED
+/* GCC will emit calls to this routine.  Linux has an
+   equivalent helper function (which clobbers fewer registers than
+   a normal function call) in a vdso; tail call to the
+   helper.  */
+# ifdef IS_IN_rtld
+/* rtld gets a hidden copy of __m68k_read_tp.  */
+       .hidden __m68k_read_tp
+# endif
+ENTRY (__m68k_read_tp)
+       cfi_startproc
+       move.l  #_GLOBAL_OFFSET_TABLE_@GOTPC, %a0
+       lea     (-6, %pc, %a0), %a0
+       move.l  M68K_VDSO_SYMBOL (__vdso_read_tp)@GOT(%a0), %a0
+       move.l  (%a0), %a0
+       jmp     (%a0)
+       cfi_endproc
+END (__m68k_read_tp)
+
+/* The following two stubs are for macros in atomic.h, they can't
+   clobber anything.  */
+
+       .hidden __vdso_atomic_cmpxchg_32_stub
+ENTRY (__vdso_atomic_cmpxchg_32_stub)
+       cfi_startproc
+       move.l  %d2, -(%sp)
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (%d2, 0)
+       move.l  %d0, %d2
+       move.l  #SYS_ify (atomic_cmpxchg_32), %d0
+       trap    #0
+       move.l  (%sp)+, %d2
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (%d2)
+       rts
+       cfi_endproc
+END (__vdso_atomic_cmpxchg_32_stub)
+       
+       .hidden __vdso_atomic_barrier_stub
+ENTRY (__vdso_atomic_barrier_stub)
+       cfi_startproc
+       move.l  %d0, -(%sp)
+       cfi_adjust_cfa_offset (4)
+       move.l  #SYS_ify (atomic_barrier), %d0
+       trap    #0
+       move.l  (%sp)+, %d0
+       cfi_adjust_cfa_offset (-4)
+       rts
+       cfi_endproc
+END (__vdso_atomic_barrier_stub)
+# else /* !SHARED */
+/* If the vDSO is not available, use a syscall to get TP.  */
+       strong_alias (__vdso_read_tp_stub, __m68k_read_tp)
+# endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c b/sysdeps/unix/sysv/linux/m68k/m68k-vdso.c
new file mode 100644 (file)
index 0000000..73b2570
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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.  */
+
+#ifdef SHARED
+
+#include <bits/m68k-vdso.h>
+
+/* Because these pointers are used from other libraries than libc,
+   they are exported at GLIBC_PRIVATE version.
+   We initialize them to syscall implementation so that they will be ready
+   to use from the very beginning.  */
+void * M68K_VDSO_SYMBOL (__vdso_read_tp)
+= (void *) __vdso_read_tp_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_cmpxchg_32)
+= (void *) __vdso_atomic_cmpxchg_32_stub;
+void * M68K_VDSO_SYMBOL (__vdso_atomic_barrier)
+= (void *) __vdso_atomic_barrier_stub;
+
+#endif /* SHARED */
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/pthreadtypes.h
new file mode 100644 (file)
index 0000000..0140810
--- /dev/null
@@ -0,0 +1,172 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 _BITS_PTHREADTYPES_H
+#define _BITS_PTHREADTYPES_H   1
+
+#include <endian.h>
+
+#define __SIZEOF_PTHREAD_ATTR_T 36
+#define __SIZEOF_PTHREAD_MUTEX_T 24
+#define __SIZEOF_PTHREAD_MUTEXATTR_T 4
+#define __SIZEOF_PTHREAD_COND_T 48
+#define __SIZEOF_PTHREAD_CONDATTR_T 4
+#define __SIZEOF_PTHREAD_RWLOCK_T 32
+#define __SIZEOF_PTHREAD_RWLOCKATTR_T 8
+#define __SIZEOF_PTHREAD_BARRIER_T 20
+#define __SIZEOF_PTHREAD_BARRIERATTR_T 4
+
+
+/* Thread identifiers.  The structure of the attribute type is
+   deliberately not exposed.  */
+typedef unsigned long int pthread_t;
+
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_ATTR_T];
+  long int __align;
+} pthread_attr_t;
+
+
+typedef struct __pthread_internal_slist
+{
+  struct __pthread_internal_slist *__next;
+} __pthread_slist_t;
+
+
+/* Data structures for mutex handling.  The structure of the attribute
+   type is deliberately not exposed.  */
+typedef union
+{
+  struct __pthread_mutex_s
+  {
+    int __lock;
+    unsigned int __count;
+    int __owner;
+    /* KIND must stay at this position in the structure to maintain
+       binary compatibility.  */
+    int __kind;
+    unsigned int __nusers;
+    __extension__ union
+    {
+      int __spins;
+      __pthread_slist_t __list;
+    };
+  } __data;
+  char __size[__SIZEOF_PTHREAD_MUTEX_T];
+  long int __align;
+} pthread_mutex_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_MUTEXATTR_T];
+  int __align;
+} pthread_mutexattr_t;
+
+
+/* Data structure for conditional variable handling.  The structure of
+   the attribute type is deliberately not exposed.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __futex;
+    __extension__ unsigned long long int __total_seq;
+    __extension__ unsigned long long int __wakeup_seq;
+    __extension__ unsigned long long int __woken_seq;
+    void *__mutex;
+    unsigned int __nwaiters;
+    unsigned int __broadcast_seq;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_COND_T];
+  __extension__ long long int __align;
+} pthread_cond_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_CONDATTR_T];
+  int __align;
+} pthread_condattr_t;
+
+
+/* Keys for thread-specific data */
+typedef unsigned int pthread_key_t;
+
+
+/* Once-only execution */
+typedef int pthread_once_t;
+
+
+#if defined __USE_UNIX98 || defined __USE_XOPEN2K
+/* Data structure for read-write lock variable handling.  The
+   structure of the attribute type is deliberately not exposed.  */
+typedef union
+{
+  struct
+  {
+    int __lock;
+    unsigned int __nr_readers;
+    unsigned int __readers_wakeup;
+    unsigned int __writer_wakeup;
+    unsigned int __nr_readers_queued;
+    unsigned int __nr_writers_queued;
+    unsigned char __pad1;
+    unsigned char __pad2;
+    unsigned char __shared;
+    /* FLAGS must stay at this position in the structure to maintain
+       binary compatibility.  */
+    unsigned char __flags;
+    int __writer;
+  } __data;
+  char __size[__SIZEOF_PTHREAD_RWLOCK_T];
+  long int __align;
+} pthread_rwlock_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_RWLOCKATTR_T];
+  long int __align;
+} pthread_rwlockattr_t;
+#endif
+
+
+#ifdef __USE_XOPEN2K
+/* POSIX spinlock data type.  */
+typedef volatile int pthread_spinlock_t;
+
+
+/* POSIX barriers data type.  The structure of the type is
+   deliberately not exposed.  */
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIER_T];
+  long int __align;
+} pthread_barrier_t;
+
+typedef union
+{
+  char __size[__SIZEOF_PTHREAD_BARRIERATTR_T];
+  int __align;
+} pthread_barrierattr_t;
+#endif
+
+
+#endif /* bits/pthreadtypes.h */
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h b/sysdeps/unix/sysv/linux/m68k/nptl/bits/semaphore.h
new file mode 100644 (file)
index 0000000..2950cc9
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 _SEMAPHORE_H
+# error "Never use <bits/semaphore.h> directly; include <semaphore.h> instead."
+#endif
+
+
+#define __SIZEOF_SEM_T 16
+
+
+/* Value returned if `sem_open' failed.  */
+#define SEM_FAILED      ((sem_t *) 0)
+
+
+typedef union
+{
+  char __size[__SIZEOF_SEM_T];
+  long int __align;
+} sem_t;
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/clone.S b/sysdeps/unix/sysv/linux/m68k/nptl/clone.S
new file mode 100644 (file)
index 0000000..e7388fe
--- /dev/null
@@ -0,0 +1,2 @@
+#define RESET_PID
+#include "../clone.S"
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c b/sysdeps/unix/sysv/linux/m68k/nptl/createthread.c
new file mode 100644 (file)
index 0000000..be11444
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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.  */
+
+/* Value passed to 'clone' for initialization of the thread register.  */
+#define TLS_VALUE ((void *) (pd) \
+                  + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+/* Get the real implementation.         */
+#include <nptl/sysdeps/pthread/createthread.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/fork.c b/sysdeps/unix/sysv/linux/m68k/nptl/fork.c
new file mode 100644 (file)
index 0000000..dc1584e
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 <sched.h>
+#include <signal.h>
+#include <sysdep.h>
+#include <tls.h>
+
+#define ARCH_FORK() \
+  INLINE_SYSCALL (clone, 5,                                                  \
+                 CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, 0,     \
+                 NULL, &THREAD_SELF->tid, NULL)
+
+#include <sysdeps/unix/sysv/linux/fork.c>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h b/sysdeps/unix/sysv/linux/m68k/nptl/lowlevellock.h
new file mode 100644 (file)
index 0000000..926077d
--- /dev/null
@@ -0,0 +1,281 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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.  */
+
+/* Borrowed from ARM's version.  */
+
+#ifndef _LOWLEVELLOCK_H
+#define _LOWLEVELLOCK_H        1
+
+#include <time.h>
+#include <sys/param.h>
+#include <bits/pthreadtypes.h>
+#include <atomic.h>
+#include <sysdep.h>
+#include <kernel-features.h>
+
+#define FUTEX_WAIT             0
+#define FUTEX_WAKE             1
+#define FUTEX_REQUEUE          3
+#define FUTEX_CMP_REQUEUE      4
+#define FUTEX_WAKE_OP          5
+#define FUTEX_OP_CLEAR_WAKE_IF_GT_ONE  ((4 << 24) | 1)
+#define FUTEX_LOCK_PI          6
+#define FUTEX_UNLOCK_PI                7
+#define FUTEX_TRYLOCK_PI       8
+#define FUTEX_WAIT_BITSET      9
+#define FUTEX_WAKE_BITSET      10
+#define FUTEX_PRIVATE_FLAG     128
+#define FUTEX_CLOCK_REALTIME   256
+
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
+/* Values for 'private' parameter of locking macros.  Yes, the
+   definition seems to be backwards.  But it is not.  The bit will be
+   reversed before passing to the system call.  */
+#define LLL_PRIVATE    0
+#define LLL_SHARED     FUTEX_PRIVATE_FLAG
+
+
+#if !defined NOT_IN_libc || defined IS_IN_rtld
+/* In libc.so or ld.so all futexes are private.  */
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  ((fl) | FUTEX_PRIVATE_FLAG)
+# else
+#  define __lll_private_flag(fl, private) \
+  ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))
+# endif
+#else
+# ifdef __ASSUME_PRIVATE_FUTEX
+#  define __lll_private_flag(fl, private) \
+  (((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
+# else
+#  define __lll_private_flag(fl, private) \
+  (__builtin_constant_p (private)                                            \
+   ? ((private) == 0                                                         \
+      ? ((fl) | THREAD_GETMEM (THREAD_SELF, header.private_futex))           \
+      : (fl))                                                                \
+   : ((fl) | (((private) ^ FUTEX_PRIVATE_FLAG)                               \
+             & THREAD_GETMEM (THREAD_SELF, header.private_futex))))
+# endif              
+#endif
+
+
+#define lll_futex_wait(futexp, val, private) \
+  lll_futex_timed_wait(futexp, val, NULL, private)
+
+#define lll_futex_timed_wait(futexp, val, timespec, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAIT, private),       \
+                             (val), (timespec));                             \
+    __ret;                                                                   \
+  })
+
+#define lll_futex_wake(futexp, nr, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 4, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE, private),       \
+                             (nr), 0);                                       \
+    __ret;                                                                   \
+  })
+
+#define lll_robust_dead(futexv, private) \
+  do                                                                         \
+    {                                                                        \
+      int *__futexp = &(futexv);                                             \
+      atomic_or (__futexp, FUTEX_OWNER_DIED);                                \
+      lll_futex_wake (__futexp, 1, private);                                 \
+    }                                                                        \
+  while (0)
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_CMP_REQUEUE, private),\
+                             (nr_wake), (nr_move), (mutex), (val));          \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+/* Returns non-zero if error happened, zero if success.  */
+#define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
+  ({                                                                         \
+    INTERNAL_SYSCALL_DECL (__err);                                           \
+    long int __ret;                                                          \
+    __ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp),                     \
+                             __lll_private_flag (FUTEX_WAKE_OP, private),    \
+                             (nr_wake), (nr_wake2), (futexp2),               \
+                             FUTEX_OP_CLEAR_WAKE_IF_GT_ONE);                 \
+    INTERNAL_SYSCALL_ERROR_P (__ret, __err);                                 \
+  })
+
+#define lll_trylock(lock)                              \
+  atomic_compare_and_exchange_val_acq (&(lock), 1, 0)
+
+#define lll_cond_trylock(lock)                         \
+  atomic_compare_and_exchange_val_acq (&(lock), 2, 0)
+
+#define lll_robust_trylock(lock, id)                   \
+  atomic_compare_and_exchange_val_acq (&(lock), id, 0)
+
+extern void __lll_lock_wait_private (int *futex) attribute_hidden;
+extern void __lll_lock_wait (int *futex, int private) attribute_hidden;
+extern int __lll_robust_lock_wait (int *futex, int private) attribute_hidden;
+
+#define __lll_lock(futex, private)                                           \
+  ((void) ({                                                                 \
+    int *__futex = (futex);                                                  \
+    if (__builtin_expect (atomic_compare_and_exchange_val_acq (__futex,       \
+                                                               1, 0), 0))    \
+      {                                                                              \
+       if (__builtin_constant_p (private) && (private) == LLL_PRIVATE)       \
+         __lll_lock_wait_private (__futex);                                  \
+       else                                                                  \
+         __lll_lock_wait (__futex, private);                                 \
+      }                                                                              \
+  }))
+#define lll_lock(futex, private) __lll_lock (&(futex), private)
+
+
+#define __lll_robust_lock(futex, id, private)                                \
+  ({                                                                         \
+    int *__futex = (futex);                                                  \
+    int __val = 0;                                                           \
+                                                                             \
+    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+                                                               0), 0))       \
+      __val = __lll_robust_lock_wait (__futex, private);                     \
+    __val;                                                                   \
+  })
+#define lll_robust_lock(futex, id, private) \
+  __lll_robust_lock (&(futex), id, private)
+
+
+#define __lll_cond_lock(futex, private)                                              \
+  ((void) ({                                                                 \
+    int *__futex = (futex);                                                  \
+    if (__builtin_expect (atomic_exchange_acq (__futex, 2), 0))                      \
+      __lll_lock_wait (__futex, private);                                    \
+  }))
+#define lll_cond_lock(futex, private) __lll_cond_lock (&(futex), private)
+
+
+#define lll_robust_cond_lock(futex, id, private) \
+  __lll_robust_lock (&(futex), (id) | FUTEX_WAITERS, private)
+
+
+extern int __lll_timedlock_wait (int *futex, const struct timespec *,
+                                int private) attribute_hidden;
+extern int __lll_robust_timedlock_wait (int *futex, const struct timespec *,
+                                       int private) attribute_hidden;
+
+#define __lll_timedlock(futex, abstime, private)                             \
+  ({                                                                         \
+     int *__futex = (futex);                                                 \
+     int __val = 0;                                                          \
+                                                                             \
+     if (__builtin_expect (atomic_exchange_acq (__futex, 1), 0))             \
+       __val = __lll_timedlock_wait (__futex, abstime, private);             \
+     __val;                                                                  \
+  })
+#define lll_timedlock(futex, abstime, private) \
+  __lll_timedlock (&(futex), abstime, private)
+
+
+#define __lll_robust_timedlock(futex, abstime, id, private)                  \
+  ({                                                                         \
+    int *__futex = (futex);                                                  \
+    int __val = 0;                                                           \
+                                                                             \
+    if (__builtin_expect (atomic_compare_and_exchange_bool_acq (__futex, id,  \
+                                                               0), 0))       \
+      __val = __lll_robust_timedlock_wait (__futex, abstime, private);       \
+    __val;                                                                   \
+  })
+#define lll_robust_timedlock(futex, abstime, id, private) \
+  __lll_robust_timedlock (&(futex), abstime, id, private)
+
+
+#define __lll_unlock(futex, private) \
+  (void)                                                       \
+    ({ int *__futex = (futex);                                 \
+       int __oldval = atomic_exchange_rel (__futex, 0);                \
+       if (__builtin_expect (__oldval > 1, 0))                 \
+        lll_futex_wake (__futex, 1, private);                  \
+    })
+#define lll_unlock(futex, private) __lll_unlock(&(futex), private)
+
+
+#define __lll_robust_unlock(futex, private) \
+  (void)                                                       \
+    ({ int *__futex = (futex);                                 \
+       int __oldval = atomic_exchange_rel (__futex, 0);                \
+       if (__builtin_expect (__oldval & FUTEX_WAITERS, 0))     \
+        lll_futex_wake (__futex, 1, private);                  \
+    })
+#define lll_robust_unlock(futex, private) \
+  __lll_robust_unlock(&(futex), private)
+
+
+#define lll_islocked(futex) \
+  (futex != 0)
+
+
+/* Our internal lock implementation is identical to the binary-compatible
+   mutex implementation. */
+
+/* Initializers for lock.  */
+#define LLL_LOCK_INITIALIZER           (0)
+#define LLL_LOCK_INITIALIZER_LOCKED    (1)
+
+/* The states of a lock are:
+    0  -  untaken
+    1  -  taken by one user
+   >1  -  taken by more users */
+
+/* The kernel notifies a process which uses CLONE_CLEARTID via futex
+   wakeup when the clone terminates.  The memory location contains the
+   thread ID while the clone is running and is reset to zero
+   afterwards. */
+#define lll_wait_tid(tid) \
+  do {                                                 \
+    __typeof (tid) __tid;                              \
+    while ((__tid = (tid)) != 0)                       \
+      lll_futex_wait (&(tid), __tid, LLL_SHARED);      \
+  } while (0)
+
+extern int __lll_timedwait_tid (int *, const struct timespec *)
+     attribute_hidden;
+
+#define lll_timedwait_tid(tid, abstime) \
+  ({                                                   \
+    int __res = 0;                                     \
+    if ((tid) != 0)                                    \
+      __res = __lll_timedwait_tid (&(tid), (abstime)); \
+    __res;                                             \
+  })
+
+#endif /* lowlevellock.h */
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/pt-vfork.S
new file mode 100644 (file)
index 0000000..36c9270
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 <tcb-offsets.h>
+
+#define SAVE_PID \
+       bsrl    __m68k_read_tp@PLTPC    ; /* Get the thread pointer.  */ \
+       movel   %a0, %a1                ; /* Save TP for RESTORE_PID.  */ \
+       movel   PID_OFFSET(%a1), %d0    ; /* Get the PID.  */ \
+       movel   %d0, %d1                ; /* Save PID for RESTORE_PID.  */ \
+       negl    %d0                     ; /* Negate the PID.  */ \
+       movel   %d0, PID_OFFSET(%a1)    ; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+       tstl    %d0                     ; \
+       beq     1f                      ; /* If we are the parent... */ \
+       movel   %d1, PID_OFFSET(%a1)    ; /* Restore the PID.  */ \
+1:     
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c b/sysdeps/unix/sysv/linux/m68k/nptl/pthread_once.c
new file mode 100644 (file)
index 0000000..415045f
--- /dev/null
@@ -0,0 +1,91 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 "pthreadP.h"
+#include <lowlevellock.h>
+
+unsigned long int __fork_generation attribute_hidden;
+
+static void
+clear_once_control (void *arg)
+{
+  pthread_once_t *once_control = (pthread_once_t *) arg;
+
+  *once_control = 0;
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+}
+
+int
+__pthread_once (pthread_once_t *once_control, void (*init_routine) (void))
+{
+  for (;;)
+    {
+      int oldval;
+      int newval;
+
+      /* Pseudo code:
+        newval = __fork_generation | 1;
+        oldval = *once_control;
+        if ((oldval & 2) == 0)
+          *once_control = newval;
+        Do this atomically.
+      */
+      do
+       {
+         newval = __fork_generation | 1;
+         oldval = *once_control;
+         if (oldval & 2)
+           break;
+       } while (atomic_compare_and_exchange_val_acq (once_control, newval, oldval) != oldval);
+
+      /* Check if the initializer has already been done.  */
+      if ((oldval & 2) != 0)
+       return 0;
+
+      /* Check if another thread already runs the initializer. */
+      if ((oldval & 1) == 0)
+       break;
+
+      /* Check whether the initializer execution was interrupted by a fork.  */
+      if (oldval != newval)
+       break;
+
+      /* Same generation, some other thread was faster. Wait.  */
+      lll_futex_wait (once_control, oldval, LLL_PRIVATE);
+    }
+
+  /* This thread is the first here.  Do the initialization.
+     Register a cleanup handler so that in case the thread gets
+     interrupted the initialization can be restarted.  */
+  pthread_cleanup_push (clear_once_control, once_control);
+
+  init_routine ();
+
+  pthread_cleanup_pop (0);
+
+  /* Say that the initialisation is done.  */
+  *once_control = __fork_generation | 2;
+
+  /* Wake up all other threads.  */
+  lll_futex_wake (once_control, INT_MAX, LLL_PRIVATE);
+
+  return 0;
+}
+weak_alias (__pthread_once, pthread_once)
+strong_alias (__pthread_once, __pthread_once_internal)
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h b/sysdeps/unix/sysv/linux/m68k/nptl/sysdep-cancel.h
new file mode 100644 (file)
index 0000000..87e2d55
--- /dev/null
@@ -0,0 +1,141 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 <nptl/pthreadP.h>
+#endif
+
+#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+
+# undef PSEUDO
+# define PSEUDO(name, syscall_name, args)                                    \
+  .text;                                                                     \
+  ENTRY (name)                                                               \
+    SINGLE_THREAD_P;                                                         \
+    jne .Lpseudo_cancel;                                                     \
+  .type __##syscall_name##_nocancel,@function;                               \
+  .globl __##syscall_name##_nocancel;                                        \
+  __##syscall_name##_nocancel:                                               \
+    DO_CALL (syscall_name, args);                                            \
+    cmp.l &-4095, %d0;                                                       \
+    jcc SYSCALL_ERROR_LABEL;                                                 \
+    rts;                                                                     \
+  .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel;           \
+  .Lpseudo_cancel:                                                           \
+    cfi_startproc;                                                           \
+    CENABLE;                                                                 \
+    DOCARGS_##args                                                           \
+    move.l %d0, -(%sp); /* Save result of CENABLE.  */                       \
+    cfi_adjust_cfa_offset (4); \
+    move.l &SYS_ify (syscall_name), %d0;                                     \
+    trap &0;                                                                 \
+    move.l %d0, %d2;                                                         \
+    CDISABLE;                                                                \
+    addq.l &4, %sp; /* Remove result of CENABLE from the stack.  */           \
+    cfi_adjust_cfa_offset (-4); \
+    move.l %d2, %d0;                                                         \
+    UNDOCARGS_##args                                                         \
+    cmp.l &-4095, %d0;                                                       \
+    jcc SYSCALL_ERROR_LABEL;                                                 \
+    cfi_endproc
+
+/* Note: we use D2 to save syscall's return value as D0 will be clobbered in
+   CDISABLE.  */
+# define DOCARGS_0     move.l %d2, -(%sp);             \
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d2, 0);
+# define UNDOCARGS_0   move.l (%sp)+, %d2;     \
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d2);
+
+# define DOCARGS_1     _DOCARGS_1 (4); DOCARGS_0
+# define _DOCARGS_1(n) move.l n(%sp), %d1;
+# define UNDOCARGS_1   UNDOCARGS_0
+
+# define DOCARGS_2     _DOCARGS_2 (8)
+# define _DOCARGS_2(n) DOCARGS_0 move.l n+4(%sp), %d2; _DOCARGS_1 (n)
+# define UNDOCARGS_2   UNDOCARGS_0
+
+/* TODO: We can optimize DOCARGS_{3, 4} by saving registers to a0 and a1
+   instead of pushing them on stack.  */
+# define DOCARGS_3     _DOCARGS_3 (12)
+# define _DOCARGS_3(n) move.l %d3, -(%sp);                             \
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d3, 0);                  \
+  move.l n+4(%sp), %d3; _DOCARGS_2 (n)
+# define UNDOCARGS_3   UNDOCARGS_2 move.l (%sp)+, %d3;         \
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d3);
+
+# define DOCARGS_4     _DOCARGS_4 (16)
+# define _DOCARGS_4(n) move.l %d4, -(%sp);                     \
+  cfi_adjust_cfa_offset (4); cfi_rel_offset (%d4, 0);          \
+  move.l n+4(%sp), %d4; _DOCARGS_3 (n)
+# define UNDOCARGS_4   UNDOCARGS_3 move.l (%sp)+, %d4; \
+  cfi_adjust_cfa_offset (-4); cfi_restore (%d4);
+
+# define DOCARGS_5     _DOCARGS_5 (20)
+# define _DOCARGS_5(n) move.l %d5, %a1; cfi_register (%d5, a1); \
+  move.l n(%sp), %d5; _DOCARGS_4 (n-4)
+# define UNDOCARGS_5   UNDOCARGS_4 move.l %a1, %d5; cfi_restore (%d5);
+
+# define DOCARGS_6     _DOCARGS_6 (24)
+# define _DOCARGS_6(n) move.l n(%sp), %a0; _DOCARGS_5 (n-4)
+# define UNDOCARGS_6   UNDOCARGS_5
+
+# ifdef PIC
+#  define PSEUDO_JMP(sym) jbsr sym ## @PLTPC
+# else
+#  define PSEUDO_JMP(sym) jbsr sym
+# endif
+
+# ifdef IS_IN_libpthread
+#  define CENABLE      PSEUDO_JMP (__pthread_enable_asynccancel)
+#  define CDISABLE     PSEUDO_JMP (__pthread_disable_asynccancel)
+# elif !defined NOT_IN_libc
+#  define CENABLE      PSEUDO_JMP (__libc_enable_asynccancel)
+#  define CDISABLE     PSEUDO_JMP (__libc_disable_asynccancel)
+# elif defined IS_IN_librt
+#  define CENABLE      PSEUDO_JMP (__librt_enable_asynccancel)
+#  define CDISABLE     PSEUDO_JMP (__librt_disable_asynccancel)
+# else
+#  error Unsupported library
+# endif
+
+# ifndef __ASSEMBLER__
+#  define SINGLE_THREAD_P                                              \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,                                \
+                                  header.multiple_threads) == 0, 1)
+# else
+#  define SINGLE_THREAD_P                      \
+  PSEUDO_JMP (__m68k_read_tp);                 \
+  tst.l MULTIPLE_THREADS_OFFSET(%a0)
+# endif
+
+#elif !defined __ASSEMBLER__
+
+# define SINGLE_THREAD_P (1)
+# define NO_CANCELLATION (1)
+
+#endif
+
+#ifndef __ASSEMBLER__
+# define RTLD_SINGLE_THREAD_P                                    \
+  __builtin_expect (THREAD_GETMEM (THREAD_SELF,                          \
+                                  header.multiple_threads) == 0, \
+                   1)
+#endif
diff --git a/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S b/sysdeps/unix/sysv/linux/m68k/nptl/vfork.S
new file mode 100644 (file)
index 0000000..8599c3d
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (C) 2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maxim Kuvyrkov <maxim@codesourcery.com>, 2010.
+
+   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 <tcb-offsets.h>
+
+#define SAVE_PID \
+       bsrl    __m68k_read_tp@PLTPC    ; /* Get the thread pointer.  */ \
+       movel   %a0, %a1                ; /* Save TP for RESTORE_PID.  */ \
+       movel   PID_OFFSET(%a1), %d0    ; /* Get the PID.  */ \
+       movel   %d0, %d1                ; /* Save PID for RESTORE_PID.  */ \
+       negl    %d0                     ; /* Negate the PID.  */ \
+       bne     1f                      ; /* If it was zero... */ \
+       movel   #0x80000000, %d0        ; /* use 0x80000000 instead.  */ \
+1:     movel   %d0, PID_OFFSET(%a1)    ; /* Store the temporary PID.  */
+
+#define RESTORE_PID \
+       tstl    %d0                     ; \
+       beq     1f                      ; /* If we are the parent... */ \
+       movel   %d1, PID_OFFSET(%a1)    ; /* Restore the PID.  */ \
+1:     
+
+#include <sysdeps/unix/sysv/linux/m68k/vfork.S>
index 2690f18..147a3b2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2010 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
 
 .globl __socket
 ENTRY (__socket)
-#if defined NEED_CANCELLATION && defined CENABLE
-       SINGLE_THREAD_P (%a0)
+#ifdef NEED_CANCELLATION
+# if !defined CENABLE || !defined CDISABLE
+#  error CENABLE and/or CDISABLE is not defined
+# endif
+       SINGLE_THREAD_P
        jne 1f
 #endif
 
@@ -69,21 +72,26 @@ ENTRY (__socket)
        /* Successful; return the syscall's value.  */
        rts
 
-#if defined NEED_CANCELLATION && defined CENABLE
-1:     /* Enable asynchronous cancellation.  */
+#ifdef NEED_CANCELLATION
+1:     cfi_startproc
+       /* Enable asynchronous cancellation.  */
        CENABLE
 
-       /* Save registers.  */
+       /* Save D2.  */
        move.l %d2, -(%sp)
-       move.l %d0, -(%sp)
+       cfi_adjust_cfa_offset (4)
+       cfi_rel_offset (%d2, 0)
 
-       move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
+       /* Save the result of CENABLE.  */
+       move.l %d0, -(%sp)
+       cfi_adjust_cfa_offset (4)
 
        /* Use ## so `socket' is a separate token that might be #define'd.  */
        move.l #P (SOCKOP_,socket), %d1 /* Subcode is first arg to syscall.  */
        lea 4+8(%sp), %a1               /* Address of args is 2nd arg.  */
        move.l %a1, %d2
 
+       move.l #SYS_ify (socketcall), %d0 /* System call number in %d0.  */
        /* Do the system call trap.  */
        trap #0
 
@@ -91,14 +99,18 @@ ENTRY (__socket)
        move.l %d0, %d2
        CDISABLE
        addq.l #4, %sp
+       cfi_adjust_cfa_offset (-4)
        move.l %d2, %d0
 
        /* Restore registers.  */
        move.l (%sp)+, %d2
+       cfi_adjust_cfa_offset (-4)
+       cfi_restore (%d2)
 
        /* %d0 is < 0 if there was an error.  */
        tst.l %d0
        jmi SYSCALL_ERROR_LABEL
+       cfi_endproc
 
        /* Successful; return the syscall's value.  */
        rts
index 12687d8..e3aed15 100644 (file)
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 2000, 2003, 2004, 2006, 2010
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>,
    December 1995.
@@ -23,6 +24,7 @@
 
 #include <sysdeps/unix/sysdep.h>
 #include <sysdeps/m68k/sysdep.h>
+#include <tls.h>
 
 /* Defines RTLD_PRIVATE_ERRNO.  */
 #include <dl-sysdep.h>
@@ -148,9 +150,11 @@ SYSCALL_ERROR_LABEL:                                                             \
        arg 3           %d3          call-saved
        arg 4           %d4          call-saved
        arg 5           %d5          call-saved
+       arg 6           %a0          call-clobbered
 
    The stack layout upon entering the function is:
 
+       24(%sp)         Arg# 6
        20(%sp)         Arg# 5
        16(%sp)         Arg# 4
        12(%sp)         Arg# 3
@@ -229,7 +233,7 @@ SYSCALL_ERROR_LABEL:                                                              \
    normally.  It will never touch errno.  This returns just what the kernel
    gave back.  */
 #undef INTERNAL_SYSCALL
-#define INTERNAL_SYSCALL(name, err, nr, args...)       \
+#define INTERNAL_SYSCALL_NCS(name, err, nr, args...)   \
   ({ unsigned int _sys_result;                         \
      {                                                 \
        /* Load argument values in temporary variables
@@ -237,7 +241,7 @@ SYSCALL_ERROR_LABEL:                                                              \
          before the call used registers are set.  */   \
        LOAD_ARGS_##nr (args)                           \
        LOAD_REGS_##nr                                  \
-       register int _d0 asm ("%d0") = __NR_##name;     \
+       register int _d0 asm ("%d0") = name;            \
        asm volatile ("trap #0"                         \
                     : "=d" (_d0)                       \
                     : "0" (_d0) ASM_ARGS_##nr          \
@@ -245,6 +249,8 @@ SYSCALL_ERROR_LABEL:                                                              \
        _sys_result = _d0;                              \
      }                                                 \
      (int) _sys_result; })
+#define INTERNAL_SYSCALL(name, err, nr, args...)       \
+  INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)
 
 #undef INTERNAL_SYSCALL_ERROR_P
 #define INTERNAL_SYSCALL_ERROR_P(val, err)             \
@@ -300,4 +306,15 @@ SYSCALL_ERROR_LABEL:                                                             \
 #define ASM_ARGS_6     ASM_ARGS_5, "a" (_a0)
 
 #endif /* not __ASSEMBLER__ */
+
+/* Pointer mangling is not yet supported for M68K.  */
+#define PTR_MANGLE(var) (void) (var)
+#define PTR_DEMANGLE(var) (void) (var)
+
+#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO
+/* M68K needs system-supplied DSO to access TLS helpers
+   even when statically linked.  */
+# define NEED_STATIC_SYSINFO_DSO 1
+#endif
+
 #endif
index 8027b2f..61bbf2f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 1999, 2002, 2003, 2010 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Andreas Schwab <schwab@gnu.org>.
 
 #include <bits/errno.h>
 #include <kernel-features.h>
 
+#ifndef SAVE_PID
+#define SAVE_PID
+#endif
+
+#ifndef RESTORE_PID
+#define RESTORE_PID
+#endif
+
 /* Clone the calling process, but without copying the whole address space.
    The calling process is suspended until the new process exits or is
    replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
@@ -31,12 +39,20 @@ ENTRY (__vfork)
 
 #ifdef __NR_vfork
 
+       /* SAVE_PID clobbers call-clobbered registers and
+          saves data in D1 and A1.  */
+
+       SAVE_PID
+       
        /* Pop the return PC value into A0.  */
        movel   %sp@+, %a0
 
        /* Stuff the syscall number in D0 and trap into the kernel.  */
        movel   #SYS_ify (vfork), %d0
        trap    #0
+
+       RESTORE_PID
+
        tstl    %d0
        jmi     .Lerror         /* Branch forward if it failed.  */