aboutsummaryrefslogtreecommitdiff
path: root/devel/linuxthreads
diff options
context:
space:
mode:
authorJulian Elischer <julian@FreeBSD.org>1999-11-30 09:07:29 +0000
committerJulian Elischer <julian@FreeBSD.org>1999-11-30 09:07:29 +0000
commit3254235eccb8efa36f58f7fffd495ec5aa94c6af (patch)
treea0aa90b920b2d45084f660fe1b18a75aa52e03e2 /devel/linuxthreads
parent88162270db1758867df6e3c62c144cc347d616ff (diff)
downloadports-3254235eccb8efa36f58f7fffd495ec5aa94c6af.tar.gz
ports-3254235eccb8efa36f58f7fffd495ec5aa94c6af.zip
Notes
Diffstat (limited to 'devel/linuxthreads')
-rw-r--r--devel/linuxthreads/Makefile47
-rw-r--r--devel/linuxthreads/distinfo1
-rw-r--r--devel/linuxthreads/files/README.FreeBSD101
-rw-r--r--devel/linuxthreads/files/clone.S128
-rw-r--r--devel/linuxthreads/files/clone.h42
-rw-r--r--devel/linuxthreads/files/getgr_r.c144
-rw-r--r--devel/linuxthreads/files/lclone.c91
-rw-r--r--devel/linuxthreads/files/libc_calls.c149
-rw-r--r--devel/linuxthreads/files/libc_thread.c127
-rw-r--r--devel/linuxthreads/files/patch-aa1245
-rw-r--r--devel/linuxthreads/files/sched.c320
-rw-r--r--devel/linuxthreads/files/uthread_file.c396
-rw-r--r--devel/linuxthreads/pkg-comment1
-rw-r--r--devel/linuxthreads/pkg-descr9
-rw-r--r--devel/linuxthreads/pkg-message19
-rw-r--r--devel/linuxthreads/pkg-plist11
16 files changed, 2831 insertions, 0 deletions
diff --git a/devel/linuxthreads/Makefile b/devel/linuxthreads/Makefile
new file mode 100644
index 000000000000..2c68dc097645
--- /dev/null
+++ b/devel/linuxthreads/Makefile
@@ -0,0 +1,47 @@
+# New ports collection makefile for: linuxthreads
+# Version required: 0.71
+# Date created: 14 Jan 1999
+# Whom: Richard Seaman, Jr. <dick@tar.com>
+#
+# $FreeBSD$
+#
+
+DISTNAME= linuxthreads
+PKGNAME= linuxthreads-0.71
+CATEGORIES= devel
+MASTER_SITES= ftp://ftp.inria.fr/INRIA/Projects/cristal/Xavier.Leroy/
+
+MAINTAINER= dick@tar.com
+
+threads_files= _atomic_lock.S libc_spinlock.h uthread_rwlock.c \
+ uthread_rwlockattr.c libc_private.h uthread_file.c \
+ clone.S clone.h lclone.c sched.c spinlock.c libc_calls.c \
+ README.FreeBSD getgr_r.c syscalls.c libc_thread.c pthread_stack.h \
+ stack.c stack_attr.c pthread_rw.h pthread_private.h
+
+WRKSRC= ${WRKDIR}/linuxthreads-0.71
+
+SRC_BASE= /usr/src
+LIBSRC_BASE= ${SRC_BASE}/lib
+
+post-extract:
+ @mv ${WRKSRC}/semaphore.h ${WRKSRC}/semaphore.h.unused
+ @mv ${WRKSRC}/semaphore.c ${WRKSRC}/semaphore.c.unused
+ @rm ${WRKSRC}/.depend
+ @rm ${WRKSRC}/.cvsignore
+ @cd ${FILESDIR} ; \
+ ${CP} -p ${threads_files} ${WRKSRC}/. ; \
+ ${CP} -p Examples/ex6.c ${WRKSRC}/Examples/.
+
+pre-install:
+
+post-install:
+ @sh ${PKGDIR}/INSTALL ${PKGNAME} POST-INSTALL
+ ${SETENV} OBJFORMAT=${PORTOBJFORMAT} ${LDCONFIG} -m ${PREFIX}/lib
+ ${SETENV} OBJFORMAT=${PORTOBJFORMAT} ${LDCONFIG} -m /usr/lib
+ ${CAT} ${PKGDIR}/MESSAGE
+ @echo ""
+ @echo "Also see the file README.FreeBSD"
+ @echo ""
+
+.include <bsd.port.mk>
diff --git a/devel/linuxthreads/distinfo b/devel/linuxthreads/distinfo
new file mode 100644
index 000000000000..5b34b2f26af0
--- /dev/null
+++ b/devel/linuxthreads/distinfo
@@ -0,0 +1 @@
+MD5 (linuxthreads.tar.gz) = 78d552da5758630b998142309810eb87
diff --git a/devel/linuxthreads/files/README.FreeBSD b/devel/linuxthreads/files/README.FreeBSD
new file mode 100644
index 000000000000..705e254b43ed
--- /dev/null
+++ b/devel/linuxthreads/files/README.FreeBSD
@@ -0,0 +1,101 @@
+Some brief notes:
+
+1) Consider updating your FreeBSD source to 3.X after January 27,
+1999 or to 4.0-current after January 25, 1999. If you insist on
+using older source, be sure it is at least 3.0-current after
+January 12, 1999.
+
+If you are using older source:
+
+You must have compiled your kernel/world with the option
+COMPAT_LINUX_THREADS. Optionally, you can also have compiled
+with the option VM_STACK. This package will not run properly
+without COMPAT_LINUX_THREADS. If you have not done so, add
+-DCOMPAT_LINUX_THREADS to the CFLAGS, and also to COPTFLAGS in
+your /etc/make.conf file (optionally add -DVM_STACK also), and
+do a "make world" and remake and reinstall the kernel.
+
+If you are using new source:
+
+Everything is included by default for i386 systems.
+
+2) You should consider enabling the posix priority extensions
+in your kernel. Adding the following to your kernel config
+file before you execute config and before you remake the kernel
+should suffice.
+
+options "P1003_1B"
+options "_KPOSIX_PRIORITY_SCHEDULING"
+options "_KPOSIX_VERSION=199309L"
+
+These options are not manditory.
+
+3) If you plan on having lots of threads, check the sysctl value
+of kern.maxproc. Each kernel thread counts against maxproc. You
+can increase maxproc by changing the MAXUSERS value in your kernel
+config file. maxproc is set at 20 + 16 * MAXUSERS.
+
+4) This package does not currently work on a normal SMP machine,
+since the flags needed for the rfork function are not enabled.
+More work needs to be done on the kernel. However, if wish
+to try it, take a look at http://www.freebsd.org/~luoqi/pmap.diff .
+
+5) DO NOT link with the libc_r library (by default you won't).
+Don't use the option -pthread when compiling/linking. It pulls
+in libc_r.
+
+6) Compile your applications that use Linux Threads with either of
+the following (equivalent) command line options:
+
+ -D_THREAD_SAFE -DLINUXTHREADS -lpthread
+or:
+ -D_THREAD_SAFE -DLINUXTHREADS -kthread
+
+
+7) You should link with the normal FreeBSD libc directory (by
+default you will). Be aware of the following issues:
+
+ a) Not all libc calls are thread safe. Many are.
+ In particular gmtime, localtime, etc are not thread
+ safe. In general, where the pthreads spec calls for "_r"
+ functions, these are either not provided, or if provided
+ are not thread safe (in most cases) and the related
+ libc calls are not thread safe. This differs somewhat
+ from the FreeBSD libc_r library, where some, but not
+ all, of these functions are both thread safe and have
+ "_r" versions.
+
+ b) None of the libc calls that are supposed to be
+ cancellation points are implemented as such. There
+ is a lot of work that needs to be done on libc before
+ cancellation points will work correctly. Therefore,
+ while linux threads has the cancel functions implemented,
+ deferred cancellation will not really do anything, since
+ the co-operation needed from libc is not there.
+
+8) There is a call implemented for FreeBSD (see stack.c):
+
+int _pthread_setstackspacing(size_t spacing, size_t guardsize)
+
+By default, Linux Threads spaces thread stacks 2MB apart, and
+makes each thread stack an "autogrow" stack. If you know that
+your maximum stack for any thread can be less than that, you
+can decrease the spacing by calling this function. It must
+be called before any other pthreads function calls, and it
+will only succeed the first time its called. Note that the
+pthread TLS and the guardsize will be included in the spacing.
+ie. maximum stack size = spacing - TLSpagesize - guardsize.
+
+The spacing must be a power of 2 times the pagesize (and if its
+not, it will be rounded up to the next highest value that is).
+
+9) If you want to link your ports or other programs that use
+GNU configure with pthreads, check the documentation of the
+program. If the configure file hasn't been customized too
+much for FreeBSD libc_r, and if it explicitly supports posix
+threads, then something like the following works in a
+number of cases (exact details may vary case to case):
+
+CFLAGS="-DLINUXTHREADS -D_THREAD_SAFE" ./configure --with-threads=posix
+
+10) Read file README.
diff --git a/devel/linuxthreads/files/clone.S b/devel/linuxthreads/files/clone.S
new file mode 100644
index 000000000000..52e80d6da646
--- /dev/null
+++ b/devel/linuxthreads/files/clone.S
@@ -0,0 +1,128 @@
+ .file "clone.S"
+#include <sys/syscall.h>
+#include "DEFS.h"
+#include "SYS.h"
+#define KERNEL
+#include <sys/errno.h>
+#undef KERNEL
+
+#undef DEBUG
+
+/*
+ * 8 12 16 20
+ * _clone (__fn, __childstack, __flags, __arg);
+ *
+ * I'm pretty shakey on assembly language, so someone else better
+ * check this! I don't even know what half this stuff means, its
+ * just copied from somewhere else (rf.S).
+ *
+ * It seems to work though.
+ *
+ * Here's the idea:
+ * __childstack is the TOS for the new rforked thread
+ * __flags are the rfork flags
+ * __fn is the userland function go be started for the new thread
+ * as in:
+ *
+ * int __fn (void * __arg)
+ *
+ */
+.stabs "clone.S",100,0,0,Ltext0
+ .text
+Ltext0:
+ .type CNAME(_clone),@function
+ .stabd 68,0,1
+ENTRY(_clone)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+
+ /*
+ * Push thread info onto the new thread's stack
+ */
+ movl 12(%ebp), %esi / get stack addr
+
+ subl $4, %esi
+ movl 20(%ebp), %eax / get __arg
+ movl %eax, (%esi)
+
+ subl $4, %esi
+ movl 8(%ebp), %eax / get __fn
+ movl %eax, (%esi)
+
+ .stabd 68,0,2
+ /*
+ * Prepare and execute rfork
+ */
+ pushl 16(%ebp)
+ pushl %esi
+
+ leal SYS_rfork, %eax
+ KERNCALL
+ jb 2f
+
+ .stabd 68,0,3
+ /*
+ * Check to see if we are in the parent or child
+ */
+ cmpl $0, %edx
+ jnz 1f
+ addl $8, %esp
+ popl %esi
+ movl %ebp, %esp
+ popl %ebp
+ ret
+ .p2align 2
+
+ /*
+ * If we are in the child (new thread), then
+ * set-up the call to the internal subroutine. If it
+ * returns, then call _exit.
+ */
+ .stabd 68,0,4
+1:
+ movl %esi,%esp
+#ifdef DEBUG
+ movl %esp, _stackaddr
+ movl (%esp), %eax
+ movl %eax, _stack
+ movl 4(%esp), %eax
+ movl %eax,_stack+4
+ movl 8(%esp), %eax
+ movl %eax,_stack+8
+#endif
+ popl %eax
+#ifdef DEBUG
+ movl %eax,_fcn
+#endif
+ call %eax
+ addl $8, %esp
+
+ /*
+ * Exit system call
+ */
+ call PIC_PLT(_exit)
+
+ .stabd 68,0,5
+2: addl $8, %esp
+ popl %esi
+ movl %ebp, %esp
+ popl %ebp
+ jmp PIC_PLT(HIDENAME(cerror))
+
+.stabs "_clone:f67",36,0,6,CNAME(_clone)
+Lfe1:
+ .size CNAME(_clone),Lfe1-CNAME(_clone)
+
+#ifdef DEBUG
+ .data
+ .globl _stack
+_stack: .long 0
+ .long 0
+ .long 0
+ .long 0
+ .globl _stackaddr
+_stackaddr: .long 0
+ .globl _fcn
+_fcn: .long 0
+#endif
diff --git a/devel/linuxthreads/files/clone.h b/devel/linuxthreads/files/clone.h
new file mode 100644
index 000000000000..e6b0e7f7519f
--- /dev/null
+++ b/devel/linuxthreads/files/clone.h
@@ -0,0 +1,42 @@
+/* Definitions of constants and data structure for POSIX 1003.1b-1993
+ scheduling interface.
+ Copyright (C) 1996, 1997 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef CLONE_H
+#define CLONE_H
+
+/* Cloning flags. */
+#define CSIGNAL 0x000000ff /* Signal mask to be sent at exit. */
+#define CLONE_VM 0x00000100 /* Set if VM shared between processes. */
+#define CLONE_FS 0x00000200 /* Set if fs info shared between processes.*/
+#define CLONE_FILES 0x00000400 /* Set if open files shared between processes*/
+#define CLONE_SIGHAND 0x00000800 /* Set if signal handlers shared. */
+#define CLONE_PID 0x00001000 /* Set if pid shared. */
+
+/* Clone current process. */
+extern int __clone __P ((int (*__fn) (void *__arg), void *__child_stack,
+ int __flags, void *__arg));
+
+extern int _clone __P ((int (*__fn) (void *__arg), void *__child_stack,
+ int __flags, void *__arg));
+
+extern int clone __P ((int (*__fn) (void *__arg), void *__child_stack,
+ int __flags, void *__arg));
+
+#endif
diff --git a/devel/linuxthreads/files/getgr_r.c b/devel/linuxthreads/files/getgr_r.c
new file mode 100644
index 000000000000..c7ad11ddefb3
--- /dev/null
+++ b/devel/linuxthreads/files/getgr_r.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1999 Richard Seaman, Jr.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Richard Seaman, Jr.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RICHARD SEAMAN, Jr. AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <string.h>
+#include <errno.h>
+#include <grp.h>
+#include "pthread.h"
+
+static pthread_mutex_t getgr_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static int
+convert (struct group *ret, struct group *result,
+ char *buf, int buflen)
+{
+ int len;
+ int count;
+ char **gr_mem;
+ char *buf1;
+
+ if (!buf) return -1;
+
+ *result = *ret;
+
+ result->gr_name = (char *) buf;
+ /* This is the size. */
+ len = strlen (ret->gr_name) + 1;
+ if (len > buflen) return -1;
+ buflen -= len;
+ buf += len;
+ strcpy (result->gr_name, ret->gr_name);
+
+ result->gr_passwd = (char *) buf;
+ /* This is the size. */
+ len = strlen (ret->gr_passwd) + 1;
+ if (len > buflen) return -1;
+ buflen -= len;
+ buf += len;
+ strcpy (result->gr_passwd, ret->gr_passwd);
+
+ count = 0;
+ gr_mem = ret->gr_mem;
+ while (*gr_mem){
+ count++;
+ gr_mem++;
+ }
+ len = sizeof (*gr_mem)*(count+1);
+ if (len > buflen) return -1;
+ buf1 = buf;
+ buflen -= len;
+ buf += len;
+ gr_mem = ret->gr_mem;
+ while (*gr_mem){
+ len = strlen (*gr_mem) + 1;
+ if (len > buflen) return -1;
+ buf1 = buf;
+ strcpy (buf, *gr_mem);
+ buflen -= len;
+ buf += len;
+ buf1 += sizeof (buf1);
+ gr_mem++;
+ }
+ buf1 = NULL;
+ return 0;
+}
+
+int getgrnam_r (const char *name, struct group *result,
+ char *buffer, size_t buflen,
+ struct group ** resptr)
+{
+ struct group * p;
+ int retval;
+
+ pthread_mutex_lock (&getgr_mutex);
+ p = getgrnam (name);
+ if (p == NULL) {
+ *resptr = NULL;
+ retval = ESRCH;
+ } else
+ if (convert (p, result, buffer, buflen) != 0) {
+ *resptr = NULL;
+ retval = ERANGE;
+ } else {
+ *resptr = result;
+ retval = 0;
+ }
+ pthread_mutex_unlock (&getgr_mutex);
+ return retval;
+}
+
+int getgrgid_r (uid_t uid, struct group *result,
+ char *buffer, size_t buflen,
+ struct group ** resptr)
+{
+ struct group * p;
+ int retval;
+
+ pthread_mutex_lock (&getgr_mutex);
+ p = getgrgid (uid);
+ if (p == NULL) {
+ *resptr = NULL;
+ retval = ESRCH;
+ } else
+ if (convert (p, result, buffer, buflen) != 0) {
+ *resptr = NULL;
+ retval = ERANGE;
+ } else {
+ *resptr = result;
+ retval = 0;
+ }
+ pthread_mutex_unlock (&getgr_mutex);
+ return retval;
+}
diff --git a/devel/linuxthreads/files/lclone.c b/devel/linuxthreads/files/lclone.c
new file mode 100644
index 000000000000..9db77024c045
--- /dev/null
+++ b/devel/linuxthreads/files/lclone.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 1999 Richard Seaman, Jr.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Richard Seaman, Jr.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RICHARD SEAMAN, Jr. AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/unistd.h>
+#include <errno.h>
+#include <clone.h>
+
+#pragma weak clone=__clone
+
+extern int __clone __P ((int (*__fn) (void *), void *__child_stack,
+ int __flags, void *__arg))
+{
+ int bsd_flags;
+ int exit_signal;
+
+ /* We don't have qn equivalent to CLONE_PID yet */
+ if (__flags & CLONE_PID)
+ return (EINVAL);
+
+ if (__child_stack == (void *)0)
+ return (EINVAL);
+
+ /* RFTHREAD probably not necessary here, but it shouldn't hurt either */
+ bsd_flags = RFPROC | RFTHREAD;
+
+ /* We only allow one alternative to SIGCHLD, and thats
+ * SIGUSR1. This is less flexible than Linux, but
+ * we don't really have a way to pass a one byte
+ * exit signal to rfork, which is what Linux passes to
+ * its clone syscall. OTOH, we haven't seen Linux use
+ * a value other than 0 (which implies SIGCHLD), SIGCHLD,
+ * or SIGUSER1 so far.
+ */
+ exit_signal = ((unsigned int)__flags) & CSIGNAL;
+ switch (exit_signal){
+ case 0:
+ case SIGCHLD:
+ /* SIGCHLD is the default for BSD, so we don't have
+ * to do anything special in this case.
+ */
+ break;
+ case SIGUSR1:
+ bsd_flags |= RFLINUXTHPN;
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if (__flags & CLONE_VM)
+ bsd_flags |= RFMEM;
+ if (__flags & CLONE_SIGHAND)
+ bsd_flags |= RFSIGSHARE;
+ if (!(__flags & CLONE_FILES))
+ bsd_flags |= RFFDG;
+
+ /* _clone is in clone.S, and takes bsd style rfork flags */
+ return (_clone (__fn, __child_stack, bsd_flags, __arg));
+}
diff --git a/devel/linuxthreads/files/libc_calls.c b/devel/linuxthreads/files/libc_calls.c
new file mode 100644
index 000000000000..b1233c352302
--- /dev/null
+++ b/devel/linuxthreads/files/libc_calls.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1998 Richard Seaman, Jr.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Richard Seaman, Jr.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RICHARD SEAMAN, Jr. AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _THREAD_SAFE
+#define _THREAD_SAFE
+#endif
+
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/ttycom.h>
+#include <time.h>
+#include "pthread.h"
+#include "internals.h"
+
+#ifndef NEWLIBC
+
+char * asctime (const struct tm *timeptr)
+{
+ pthread_descr self = thread_self();
+
+ return (asctime_r(timeptr, self->time_buf));
+}
+
+char * ctime(const time_t * const timep)
+{
+ pthread_descr self = thread_self();
+
+ return (ctime_r(timep, self->time_buf));
+}
+
+
+struct tm *localtime (const time_t * const timep)
+{
+ pthread_descr self = thread_self();
+
+ return (localtime_r(timep, &self->local_tm));
+}
+
+struct tm * gmtime(const time_t * const timep)
+{
+ pthread_descr self = thread_self();
+
+ return (gmtime_r(timep, &self->local_tm));
+}
+#endif
+
+/* The following wrappers impement cancallation points */
+
+
+#if __STDC__
+int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
+#else
+int msgrcv(msqid, msgp, msgsz, msgtyp, msgflg)
+ int msqid;
+ void *msgp;
+ size_t msgsz;
+ long msgtyp;
+ int msgflg;
+#endif
+{
+ int ret;
+ int oldtype;
+
+ /* This is a cancellation point */
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
+
+ ret = msgsys(3, msqid, msgp, msgsz, msgtyp, msgflg);
+
+ /* This is a cancellation point */
+ pthread_setcanceltype (oldtype, NULL);
+ return (ret);
+
+}
+
+#if __STDC__
+int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg)
+#else
+int msgsnd(msqid, msgp, msgsz, msgflg)
+ int msqid;
+ void *msgp;
+ size_t msgsz;
+ int msgflg;
+#endif
+{
+ int ret;
+ int oldtype;
+
+ /* This is a cancellation point */
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
+
+ ret = msgsys(2, msqid, msgp, msgsz, msgflg);
+
+ /* This is a cancellation point */
+ pthread_setcanceltype (oldtype, NULL);
+ return (ret);
+
+}
+
+#if __STDC__
+int tcdrain (int fd)
+#else
+int tcdrain (fd)
+ int fd;
+#endif
+{
+ int ret;
+ int oldtype;
+
+ /* This is a cancellation point */
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
+
+ ret = ioctl(fd, TIOCDRAIN, 0);
+
+ /* This is a cancellation point */
+ pthread_setcanceltype (oldtype, NULL);
+ return (ret);
+}
+
diff --git a/devel/linuxthreads/files/libc_thread.c b/devel/linuxthreads/files/libc_thread.c
new file mode 100644
index 000000000000..1201a6daf6bb
--- /dev/null
+++ b/devel/linuxthreads/files/libc_thread.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1999 Richard Seaman, Jr.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Richard Seaman, Jr.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RICHARD SEAMAN, Jr. AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _THREAD_SAFE
+#define _THREAD_SAFE
+#endif
+
+#include "pthread.h"
+/* Our internal pthreads definitions are here. Set as needed */
+#if defined(COMPILING_UTHREADS)
+#include "pthread_private.h"
+#endif
+#if defined(LINUXTHREADS)
+#include "internals.h"
+#else
+/* Your internal definition here */
+#endif
+
+/* These are from lib/libc/include */
+#include "libc_private.h"
+#if !defined(LINUXTHREADS)
+#include "spinlock.h"
+#endif
+
+/* This is defined in lib/libc/stdlib/exit.c. It turns on thread safe
+ * behavior in libc if non-zero.
+ */
+extern int __isthreaded;
+
+/* Optional. In case our code is dependant on the existence of
+ * the posix priority extentions kernel option.
+ */
+#if defined(LINUXTHREADS)
+#include <sys/sysctl.h>
+int _posix_priority_scheduling;
+#endif
+
+#if defined(NEWLIBC)
+/* The following are needed if we're going to get thread safe behavior
+ * in the time functions in lib/libc/stdtime/localtime.c
+ */
+#if defined(COMPILING_UTHREADS)
+static struct pthread_mutex _lcl_mutexd = PTHREAD_MUTEX_STATIC_INITIALIZER;
+static struct pthread_mutex _gmt_mutexd = PTHREAD_MUTEX_STATIC_INITIALIZER;
+static struct pthread_mutex _localtime_mutexd = PTHREAD_MUTEX_STATIC_INITIALIZER;
+static struct pthread_mutex _gmtime_mutexd = PTHREAD_MUTEX_STATIC_INITIALIZER;
+static pthread_mutex_t _lcl_mutex = &_lcl_mutexd;
+static pthread_mutex_t _gmt_mutex = &_gmt_mutexd;
+static pthread_mutex_t _localtime_mutex = &_localtime_mutexd;
+static pthread_mutex_t _gmtime_mutex = &_gmtime_mutexd;
+#endif
+#if defined(LINUXTHREADS)
+static pthread_mutex_t _lcl_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _gmt_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
+#else
+/* Customize this based on your mutex declarations */
+static pthread_mutex_t _lcl_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _gmt_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+extern pthread_mutex_t *lcl_mutex;
+extern pthread_mutex_t *gmt_mutex;
+extern pthread_mutex_t *localtime_mutex;
+extern pthread_mutex_t *gmtime_mutex;
+#endif
+
+/* Use the constructor attribute so this gets run before main does */
+static void _pthread_initialize(void) __attribute__((constructor));
+
+static void _pthread_initialize(void)
+{
+#if defined(LINUXTHREADS)
+ int mib[2];
+ size_t len;
+
+ len = sizeof (_posix_priority_scheduling);
+ mib[0] = CTL_P1003_1B;
+ mib[1] = CTL_P1003_1B_PRIORITY_SCHEDULING;
+ if (-1 == sysctl (mib, 2, &_posix_priority_scheduling, &len, NULL, 0))
+ _posix_priority_scheduling = 0;
+#endif
+
+ /* This turns on thread safe behaviour in libc when we link with it */
+ __isthreaded = 1;
+
+#if defined(NEWLIBC)
+ /* Set up pointers for lib/libc/stdtime/localtime.c */
+ lcl_mutex = &_lcl_mutex;
+ gmt_mutex = &_gmt_mutex;
+ localtime_mutex = &_localtime_mutex;
+ gmtime_mutex = &_gmtime_mutex;
+#endif
+}
+
diff --git a/devel/linuxthreads/files/patch-aa b/devel/linuxthreads/files/patch-aa
new file mode 100644
index 000000000000..a9bea47a4db8
--- /dev/null
+++ b/devel/linuxthreads/files/patch-aa
@@ -0,0 +1,1245 @@
+diff -ur ./Makefile ../linuxthreads-0.71.new/Makefile
+--- ./Makefile Wed Sep 17 02:17:23 1997
++++ ../linuxthreads-0.71.new/Makefile Wed Oct 27 18:13:29 1999
+@@ -1,107 +1,74 @@
+-#### Configuration section
++LIB=lthread
++SHLIB_MAJOR= 0
++SHLIB_MINOR= 7
++
++.if !defined(MACHINE_ARCH)
++MACHINE_ARCH!= /usr/bin/uname -m
++.endif
++
++.if !defined(LIBSRC_BASE)
++LIBSRC_BASE= /usr/src/lib
++.endif
++
++.if !defined(PREFIX)
++PREFIX= /usr/local
++.endif
++
++LIBDIR= ${PREFIX}/lib
++
++.PATH: ${.CURDIR}/libc_r
++
++#CFLAGS+=-Wall -O
++CFLAGS+=-g -O0 -Wall -DDEBUG
++CFLAGS+=-DCOMPILING_LINUXTHREADS
++
++#This option should not be enabled unless libc has been patched
++#CLAGS+= -DUSE_RECURSIVE_SPINLOCK
++
++# USETHR_FUNCTIONS will use the FreeBSD syscalls thr_sleep and thr_wakeup
++# instead of the default linux threads suspend/restart. I thought this
++# would be a lot faster, but in testing, it doesn't seem to be. Also,
++# there might be a thread exit problem with this code still.
++#CFLAGS+= -DUSETHR_FUNCTIONS
++
++CFLAGS+= -I${.CURDIR}
++CFLAGS+= -I${LIBSRC_BASE}/libc/stdtime
++CFLAGS+= -I${LIBSRC_BASE}/libc/${MACHINE_ARCH}
++CFLAGS+= -DLIBC_RCS
++CFLAGS+= -DLINUXTHREADS
++
++# Only use if libc has been patched to include the new thread safe
++# lib/libc/stdtime/localtime.c
++#CFLAGS+= -DNEWLIBC
+
+-# Where to install
+-
+-INCLUDEDIR=/usr/include
+-LIBDIR=/usr/lib
+-SHAREDLIBDIR=/lib
+-MANDIR=/usr/man/man3
+-
+-# Compilation options
+-
+-CC=gcc
+-
+-CFLAGS=-pipe -O2 -Wall
+-#CFLAGS+=-g -DDEBUG # for debugging
+-
+-PICCFLAGS=-fpic
+-PICLDFLAGS=-shared -Wl,-soname,$(shell echo $@ | sed 's/\.[^.]$$//')
+-
+-# Define this as "yes" if you're using H.J.Lu's libc 5.2.18, 5.3.12, or 5.4.x
+-# (standard on most Linux distributions for Intel processors).
+-# Define this as "no" if you're using a different C library,
+-# e.g. libc 6, also known as glibc
+-
+-LIBC_5_SUPPORT=yes
+-
+-#### End of configuration section
+-
+-# Determine architecture
+-
+-ARCH:=$(shell uname -m | sed -e 's/i.86/i386/')
+-
+-ifeq ($(ARCH),i386)
+-CFLAGS+=-m486
+-endif
+-
+-CFLAGS+=-D__BUILDING_LINUXTHREADS -Isysdeps/$(ARCH)
++AINC= -I${LIBSRC_BASE}/libc/${MACHINE_ARCH}
+
+ # Contents of the library
+-OBJS=pthread.o manager.o attr.o join.o mutex.o condvar.o specific.o cancel.o \
+- signals.o lockfile.o errno.o fork.o sleep.o semaphore.o
++SRCS= attr.c join.c mutex.c condvar.c specific.c cancel.c
++SRCS+= signals.c fork.c errno.c manager.c pthread.c
++SRCS+= clone.S _atomic_lock.S sched.c uthread_file.c lclone.c
++SRCS+= getservby_r.c getpw_r.c getprotoby_r.c getnetby_r.c gethostby_r.c
++SRCS+= getgr_r.c libc_thread.c uthread_rwlock.c uthread_rwlockattr.c
++SRCS+= stack.c stack_attr.c
++#Note: spinlock.c appears redundant to the spinlock calls in linux threads.
++#However, this particular implementation is needed to make libc thread
++#safe. the _spinlock call overrides a stub function in libc.
++SRCS+= spinlock.c
++
++#libc is not ready for this
++#SRCS+= syscalls.c libc_calls.c
++
++beforeinstall:
++ ${INSTALL} -d -o ${BINOWN} -g ${BINGRP} -m 555 \
++ ${PREFIX}/include/pthread/linuxthreads
++ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/pthread.h \
++ ${PREFIX}/include/pthread/linuxthreads/pthread.h
++ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/pthread_rw.h \
++ ${PREFIX}/include/pthread/linuxthreads/pthread_rw.h
++ ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/pthread_stack.h \
++ ${PREFIX}/include/pthread/linuxthreads/pthread_stack.h
++
++.include <bsd.lib.mk>
+
+-ifneq ($(wildcard sysdeps/$(ARCH)/clone.[cS]),)
+-OBJS+=clone.o
+-endif
+-ifneq ($(wildcard sysdeps/$(ARCH)/syscalls.[cS]),)
+-OBJS+=syscalls.o
+-endif
+-
+-vpath %.c sysdeps/$(ARCH)
+-vpath %.S sysdeps/$(ARCH)
+-
+-# The reentrant libc code (taken from libc-5.3.9)
+-ifeq ($(LIBC_5_SUPPORT),yes)
+-vpath %.h libc_r
+-vpath %.c libc_r
+-CFLAGS+=-Ilibc_r -D_POSIX_THREADS
+-OBJS+=stdio.o getnetby_r.o getprotoby_r.o getservby_r.o \
+- gethostby_r.o getpw_r.o malloc.o dirent.o
+-endif
+-
+-LIB=libpthread.a
+-SHOBJS=$(OBJS:%.o=%.pic)
+-SHLIB=libpthread.so.0.7
+-SHLIB0=libpthread.so
+-
+-all: $(LIB) $(SHLIB)
+- cd man; $(MAKE) all
+-
+-$(LIB): $(OBJS)
+- ar rc $(LIB) $(OBJS)
+-
+-$(SHLIB): $(SHOBJS)
+- $(CC) $(PICLDFLAGS) -o $@ $(SHOBJS)
+-
+-clean:
+- rm -f $(LIB) $(SHLIB) *.o *.pic *~ libc_r/*~ sysdeps/*/*~
+- cd man; $(MAKE) clean
+-
+-install:
+- install pthread.h $(INCLUDEDIR)/pthread.h
+- install semaphore.h $(INCLUDEDIR)/semaphore.h
+-ifeq ($(LIBC_5_SUPPORT),yes)
+- test -f /usr/include/sched.h || install sched.h $(INCLUDEDIR)/sched.h
+-endif
+- install $(LIB) $(LIBDIR)/$(LIB)
+- install $(SHLIB) $(SHAREDLIBDIR)/$(SHLIB)
+- rm -f $(LIBDIR)/$(SHLIB0)
+- ln -s $(SHAREDLIBDIR)/$(SHLIB) $(LIBDIR)/$(SHLIB0)
+- ldconfig -n $(SHAREDLIBDIR)
+- cd man; $(MAKE) MANDIR=$(MANDIR) install
+-
+-.SUFFIXES: .pic
+-
+-%.pic: %.c
+- $(CC) $(CFLAGS) $(PICCFLAGS) -c $< -o $@
+-
+-%.pic: %.S
+- $(CC) $(CFLAGS) $(PICCFLAGS) -c $< -o $@
+-
+-depend:
+- $(CC) $(CFLAGS) -MM *.c libc_r/*.c | \
+- sed -e 's/^\(.*\)\.o:/\1.o \1.pic:/' \
+- -e 's/sysdeps\/$(ARCH)/sysdeps\/$$(ARCH)/' > .depend
+
+-include .depend
+
+Only in ../linuxthreads-0.71.new: README.FreeBSD
+Only in ../linuxthreads-0.71.new: _atomic_lock.S
+diff -ur ./attr.c ../linuxthreads-0.71.new/attr.c
+--- ./attr.c Sun Mar 9 10:14:32 1997
++++ ../linuxthreads-0.71.new/attr.c Wed Oct 27 18:13:29 1999
+@@ -22,10 +22,10 @@
+ {
+ attr->detachstate = PTHREAD_CREATE_JOINABLE;
+ attr->schedpolicy = SCHED_OTHER;
+- attr->schedparam.sched_priority = 0;
++ attr->schedparam.sched_priority = DEFAULT_PRIORITY;
+ attr->inheritsched = PTHREAD_EXPLICIT_SCHED;
+ attr->scope = PTHREAD_SCOPE_SYSTEM;
+- return 0;
++ return (_pthread_set_stack_defaults (attr));
+ }
+
+ int pthread_attr_destroy(pthread_attr_t *attr)
+diff -ur ./cancel.c ../linuxthreads-0.71.new/cancel.c
+--- ./cancel.c Sun Dec 29 08:12:09 1996
++++ ../linuxthreads-0.71.new/cancel.c Wed Oct 27 18:13:29 1999
+@@ -16,7 +16,6 @@
+
+ #include "pthread.h"
+ #include "internals.h"
+-#include "spinlock.h"
+ #include "restart.h"
+
+ int pthread_setcancelstate(int state, int * oldstate)
+Only in ../linuxthreads-0.71.new: clone.S
+Only in ../linuxthreads-0.71.new: clone.h
+diff -ur ./condvar.c ../linuxthreads-0.71.new/condvar.c
+--- ./condvar.c Sun Jun 15 03:26:04 1997
++++ ../linuxthreads-0.71.new/condvar.c Wed Oct 27 18:13:29 1999
+@@ -19,16 +19,13 @@
+ #include <sys/time.h>
+ #include "pthread.h"
+ #include "internals.h"
+-#include "spinlock.h"
+ #include "queue.h"
+ #include "restart.h"
+
+-static void remove_from_queue(pthread_queue * q, pthread_descr th);
+-
+ int pthread_cond_init(pthread_cond_t *cond,
+ const pthread_condattr_t *cond_attr)
+ {
+- cond->c_spinlock = 0;
++ _spin_init(&cond->c_spinlock);
+ queue_init(&cond->c_waiting);
+ return 0;
+ }
+@@ -52,6 +49,7 @@
+ release(&cond->c_spinlock);
+ pthread_mutex_unlock(mutex);
+ suspend_with_cancellation(self);
++ ASSERT(self->p_nextwaiting == NULL && cond->c_waiting.head != self);
+ pthread_mutex_lock(mutex);
+ /* This is a cancellation point */
+ if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
+@@ -70,8 +68,9 @@
+ const struct timespec * reltime)
+ {
+ volatile pthread_descr self = thread_self();
+- sigset_t unblock, initial_mask;
+ int retsleep;
++#ifndef USETHR_FUNCTIONS
++ sigset_t unblock, initial_mask;
+ sigjmp_buf jmpbuf;
+
+ /* Wait on the condition */
+@@ -107,24 +106,39 @@
+ or the timeout occurred (retsleep == 0)
+ or another interrupt occurred (retsleep == -1) */
+ /* Re-acquire the spinlock */
+- acquire(&cond->c_spinlock);
+ /* This is a cancellation point */
+- if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
+- remove_from_queue(&cond->c_waiting, self);
+- release(&cond->c_spinlock);
+- pthread_mutex_lock(mutex);
++ acquire(&cond->c_spinlock);
++ remove_from_queue(&cond->c_waiting, self);
++ release(&cond->c_spinlock);
++ pthread_mutex_lock(mutex);
++ if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE)
+ pthread_exit(PTHREAD_CANCELED);
+- }
+ /* If not signaled: also remove ourselves and return an error code */
+- if (self->p_signal == 0) {
+- remove_from_queue(&cond->c_waiting, self);
+- release(&cond->c_spinlock);
+- pthread_mutex_lock(mutex);
++ if (self->p_signal == 0)
+ return retsleep == 0 ? ETIMEDOUT : EINTR;
+- }
+- /* Otherwise, return normally */
++#else
++ acquire(&cond->c_spinlock);
++ enqueue(&cond->c_waiting, self);
++ release(&cond->c_spinlock);
++ pthread_mutex_unlock(mutex);
++ retsleep = 0;
++ if (!(self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE))
++ /* We really should make thr_sleep return EINTR too. It just
++ returns EAGAIN if it timed out, or 0 if awakened (or
++ EINVAL if bad parameter.
++ */
++ retsleep = syscall(SYS_thr_sleep, reltime);
++
++ acquire(&cond->c_spinlock);
++ if (self->p_nextwaiting != NULL || cond->c_waiting.head == self)
++ remove_from_queue(&cond->c_waiting, self);
+ release(&cond->c_spinlock);
+ pthread_mutex_lock(mutex);
++ if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE)
++ pthread_exit(PTHREAD_CANCELED);
++ if (retsleep)
++ return retsleep == EAGAIN ? ETIMEDOUT : EINTR;
++#endif
+ return 0;
+ }
+
+@@ -181,25 +195,24 @@
+ return 0;
+ }
+
+-/* Auxiliary function on queues */
+-
+-static void remove_from_queue(pthread_queue * q, pthread_descr th)
++int remove_from_queue(pthread_queue * q, pthread_descr th)
+ {
+ pthread_descr t;
+
+- if (q->head == NULL) return;
++ if (q->head == NULL) return 0;
+ if (q->head == th) {
+ q->head = th->p_nextwaiting;
+ if (q->head == NULL) q->tail = NULL;
+ th->p_nextwaiting = NULL;
+- return;
++ return 1;
+ }
+ for (t = q->head; t->p_nextwaiting != NULL; t = t->p_nextwaiting) {
+ if (t->p_nextwaiting == th) {
+ t->p_nextwaiting = th->p_nextwaiting;
+ if (th->p_nextwaiting == NULL) q->tail = t;
+ th->p_nextwaiting = NULL;
+- return;
++ return 1;
+ }
+ }
++ return 0;
+ }
+diff -ur ./errno.c ../linuxthreads-0.71.new/errno.c
+--- ./errno.c Sun Dec 29 06:05:37 1996
++++ ../linuxthreads-0.71.new/errno.c Wed Oct 27 18:13:29 1999
+@@ -19,15 +19,8 @@
+ #include "pthread.h"
+ #include "internals.h"
+
+-int * __errno_location()
++int * __error()
+ {
+ pthread_descr self = thread_self();
+ return &(self->p_errno);
+ }
+-
+-int * __h_errno_location()
+-{
+- pthread_descr self = thread_self();
+- return &(self->p_h_errno);
+-}
+-
+Only in ../linuxthreads-0.71.new: getgr_r.c
+diff -ur ./internals.h ../linuxthreads-0.71.new/internals.h
+--- ./internals.h Fri Dec 5 02:28:20 1997
++++ ../linuxthreads-0.71.new/internals.h Wed Oct 27 18:15:29 1999
+@@ -17,12 +17,37 @@
+ /* Includes */
+
+ #include <sys/types.h>
++#include <sys/queue.h>
++#include <sys/mman.h>
+ #include <setjmp.h>
+ #include <signal.h>
+-#include <gnu-stabs.h> /* for weak_alias */
+-#include <linux/mm.h>
++#include "clone.h"
++#include "spinlock.h"
++#include "private.h"
++
++#define __getpid getpid
++#define __fork _fork
++#define __nanosleep _nanosleep
++#if 0
++#define __WCLONE WLINUXCLONE
++#else
++#define __WCLONE clone_flag
++#endif
++#ifndef MAP_STACK
++#define MAP_STACK 0
++#endif
++#define DEFAULT_PRIORITY 20
++#define THREAD_SELF \
++{ \
++ char *sp = CURRENT_STACK_FRAME; \
++ if (sp >= __pthread_initial_thread_bos) \
++ return &__pthread_initial_thread; \
++ else if (sp >= __pthread_manager_thread_bos && sp < __pthread_manager_thread_tos) \
++ return &__pthread_manager_thread; \
++ else \
++ return GET_TLS_FROM_STACK(sp); \
++}
+
+-#include "pt-machine.h"
+
+ /* Arguments passed to thread creation routine */
+
+@@ -34,7 +59,7 @@
+ struct sched_param schedparam; /* initial scheduling parameters (if any) */
+ };
+
+-#define PTHREAD_START_ARGS_INITIALIZER { NULL, NULL, 0, 0, { 0 } }
++#define PTHREAD_START_ARGS_INITIALIZER { NULL, NULL, { { 0 } }, 0, { 0 } }
+
+ /* We keep thread specific data in a special data structure, a two-level
+ array. The top-level array contains pointers to dynamically allocated
+@@ -61,7 +86,7 @@
+ pthread_t p_tid; /* Thread identifier */
+ int p_pid; /* PID of Unix process */
+ int p_priority; /* Thread priority (== 0 if not realtime) */
+- int * p_spinlock; /* Spinlock for synchronized accesses */
++ spinlock_t * p_spinlock; /* Spinlock for synchronized accesses */
+ int p_signal; /* last signal received */
+ sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */
+ sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */
+@@ -77,16 +102,20 @@
+ char p_canceled; /* cancellation request pending */
+ int p_errno; /* error returned by last system call */
+ int p_h_errno; /* error returned by last netdb function */
++ int stacksize;
++ pthread_mutex_t smutex;
+ struct pthread_start_args p_start_args; /* arguments for thread creation */
+ void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */
++ TAILQ_ENTRY(_pthread_descr_struct) qe;
++ char time_buf[3 * 2 + 5 * INT_STRLEN_MAXIMUM(int) + 3 + 2 + 1 + 1];
++ struct tm local_tm;
+ };
+
+ /* The type of thread handles. */
+
+ typedef struct pthread_handle_struct * pthread_handle;
+-
+ struct pthread_handle_struct {
+- int h_spinlock; /* Spinlock for sychronized access */
++ spinlock_t h_spinlock; /* Spinlock for sychronized access */
+ pthread_descr h_descr; /* Thread descriptor or NULL if invalid */
+ };
+
+@@ -255,12 +284,13 @@
+ void __pthread_reset_main_thread(void);
+ void __fresetlockfiles(void);
+
+-/* System calls not declared in libc 5 */
++int _sigsuspend __P((const sigset_t *));
++pid_t _fork __P((void));
++ssize_t _write __P((int, const void *, size_t));
++int _close __P((int));
++int _nanosleep __P((const struct timespec *, struct timespec *));
++int _sched_yield __P((void));
+
+-int __clone(int (*child_function)(void *), void ** child_stack, int flags,
+- void * arg);
+-int __nanosleep(const struct timespec * rqtp, struct timespec * rmtp);
+-int __sched_yield(void);
+ int __sched_setparam(pid_t pid, const struct sched_param *param);
+ int __sched_getparam(pid_t pid, struct sched_param *param);
+ int __sched_setscheduler(pid_t pid, int policy,
+diff -ur ./join.c ../linuxthreads-0.71.new/join.c
+--- ./join.c Sun Dec 29 08:12:10 1996
++++ ../linuxthreads-0.71.new/join.c Wed Oct 27 18:13:29 1999
+@@ -17,7 +17,6 @@
+ #include <unistd.h>
+ #include "pthread.h"
+ #include "internals.h"
+-#include "spinlock.h"
+ #include "restart.h"
+
+ void pthread_exit(void * retval)
+@@ -48,7 +47,7 @@
+ if (self == __pthread_main_thread && __pthread_manager_request >= 0) {
+ request.req_thread = self;
+ request.req_kind = REQ_MAIN_THREAD_EXIT;
+- write(__pthread_manager_request, (char *)&request, sizeof(request));
++ _write(__pthread_manager_request, (char *)&request, sizeof(request));
+ suspend(self);
+ }
+ /* Exit the process (but don't flush stdio streams, and don't run
+@@ -98,7 +97,7 @@
+ request.req_thread = self;
+ request.req_kind = REQ_FREE;
+ request.req_args.free.thread = th;
+- write(__pthread_manager_request, (char *) &request, sizeof(request));
++ _write(__pthread_manager_request, (char *)&request, sizeof(request));
+ }
+ return 0;
+ }
+@@ -135,7 +134,7 @@
+ request.req_thread = thread_self();
+ request.req_kind = REQ_FREE;
+ request.req_args.free.thread = th;
+- write(__pthread_manager_request, (char *) &request, sizeof(request));
++ _write(__pthread_manager_request, (char *)&request, sizeof(request));
+ }
+ return 0;
+ }
+Only in ../linuxthreads-0.71.new: lclone.c
+Only in ../linuxthreads-0.71.new: libc_calls.c
+Only in ../linuxthreads-0.71.new: libc_private.h
+diff -ur ./libc_r/getprotoby_r.c ../linuxthreads-0.71.new/libc_r/getprotoby_r.c
+--- ./libc_r/getprotoby_r.c Sat Nov 16 06:38:10 1996
++++ ../linuxthreads-0.71.new/libc_r/getprotoby_r.c Wed Oct 27 18:13:29 1999
+@@ -1,4 +1,4 @@
+-#include "../pthread.h"
++#include "pthread.h"
+ #include <netdb.h>
+ #include <string.h>
+
+Only in ../linuxthreads-0.71.new/libc_r: getprotoby_r.c.orig
+diff -ur ./libc_r/getpw_r.c ../linuxthreads-0.71.new/libc_r/getpw_r.c
+--- ./libc_r/getpw_r.c Sat Nov 2 08:01:49 1996
++++ ../linuxthreads-0.71.new/libc_r/getpw_r.c Wed Oct 27 18:13:29 1999
+@@ -2,7 +2,7 @@
+ #include <string.h>
+ #include <errno.h>
+ #include <pwd.h>
+-#include "../pthread.h"
++#include "pthread.h"
+
+ static pthread_mutex_t getpw_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+Only in ../linuxthreads-0.71.new/libc_r: getpw_r.c.orig
+diff -ur ./libc_r/getservby_r.c ../linuxthreads-0.71.new/libc_r/getservby_r.c
+--- ./libc_r/getservby_r.c Sat Nov 16 06:38:10 1996
++++ ../linuxthreads-0.71.new/libc_r/getservby_r.c Wed Oct 27 18:13:29 1999
+@@ -1,4 +1,4 @@
+-#include "../pthread.h"
++#include "pthread.h"
+ #include <netdb.h>
+ #include <string.h>
+
+Only in ../linuxthreads-0.71.new/libc_r: getservby_r.c.orig
+Only in ../linuxthreads-0.71.new: libc_spinlock.h
+Only in ../linuxthreads-0.71.new: libc_thread.c
+diff -ur ./manager.c ../linuxthreads-0.71.new/manager.c
+--- ./manager.c Mon Dec 1 02:48:51 1997
++++ ../linuxthreads-0.71.new/manager.c Wed Oct 27 18:13:29 1999
+@@ -22,20 +22,16 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <sys/time.h> /* for select */
+-#include <sys/types.h> /* for select */
+-#include <sys/mman.h> /* for mmap */
+ #include <sys/wait.h> /* for waitpid macros */
+-#include <linux/sched.h>
+
+ #include "pthread.h"
+ #include "internals.h"
+-#include "spinlock.h"
+ #include "restart.h"
+
+ /* Array of active threads. Entry 0 is reserved for the initial thread. */
+
+ struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =
+-{ { 0, &__pthread_initial_thread}, /* All NULLs */ };
++{ { _SPINLOCK_INITIALIZER, &__pthread_initial_thread}, /* All NULLs */ };
+
+ /* Mapping from stack segment to thread descriptor. */
+ /* Stack segment numbers are also indices into the __pthread_handles array. */
+@@ -43,7 +39,7 @@
+
+ static inline pthread_descr thread_segment(int seg)
+ {
+- return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE)
++ return (pthread_descr)(_thread_stack_start - (seg - 1) * _stackspacing)
+ - 1;
+ }
+
+@@ -71,6 +67,8 @@
+ static void pthread_reap_children();
+ static void pthread_kill_all_threads(int sig, int main_thread_also);
+
++extern int clone_flag;
++
+ /* The server thread managing requests for thread creation and termination */
+
+ int __pthread_manager(void * arg)
+@@ -147,6 +145,9 @@
+ {
+ pthread_descr self = (pthread_descr) arg;
+ void * outcome;
++
++ pthread_mutex_lock (&self->smutex);
++
+ /* Initialize special thread_self processing, if any. */
+ #ifdef INIT_THREAD_SELF
+ INIT_THREAD_SELF(self);
+@@ -157,9 +158,8 @@
+ /* Initial signal mask is that of the creating thread. (Otherwise,
+ we'd just inherit the mask of the thread manager.) */
+ sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL);
+- /* Set the scheduling policy and priority for the new thread, if needed */
+- if (self->p_start_args.schedpolicy != SCHED_OTHER)
+- __sched_setscheduler(self->p_pid, self->p_start_args.schedpolicy,
++ /* Set the scheduling policy and priority for the new thread */
++ __sched_setscheduler(self->p_pid, self->p_start_args.schedpolicy,
+ &self->p_start_args.schedparam);
+ /* Run the thread code */
+ outcome = self->p_start_args.start_routine(self->p_start_args.arg);
+@@ -176,27 +176,47 @@
+ int pid;
+ pthread_descr new_thread;
+ pthread_t new_thread_id;
++ pthread_attr_t *cattr, _cattr;
+ int i;
++ caddr_t newaddr;
++ int newsize;
++
++ cattr = &_cattr;
++ if (attr == NULL) {
++ pthread_attr_init (cattr);
++ } else {
++ _cattr = *attr;
++ if (_pthread_check_stackattr (cattr)){
++ return (EINVAL);
++ }
++ }
++ newsize = _tlspagesize + cattr->stack_size;
+
+ /* Find a free stack segment for the current stack */
+ for (sseg = 1; ; sseg++) {
+ if (sseg >= PTHREAD_THREADS_MAX) return EAGAIN;
++ /* XXXX do we need to acquire a lock on the handle here ? */
+ if (__pthread_handles[sseg].h_descr != NULL) continue;
+ new_thread = thread_segment(sseg);
++ if (cattr->stack_addr != NULL && cattr->stack_addr != new_thread)
++ continue;
+ /* Allocate space for stack and thread descriptor. */
+- if (mmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
+- INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, -1, 0)
+- != (caddr_t) -1) break;
++ newaddr = (caddr_t)(new_thread+1) - newsize;
++ if (mmap(newaddr, newsize,
++ PROT_READ | PROT_WRITE | PROT_EXEC,
++ MAP_STACK | MAP_PRIVATE | MAP_ANON | MAP_FIXED,
++ -1, 0)
++ != MAP_FAILED) break;
+ /* It seems part of this segment is already mapped. Try the next. */
+ }
++
+ /* Allocate new thread identifier */
+ pthread_threads_counter += PTHREAD_THREADS_MAX;
+ new_thread_id = sseg + pthread_threads_counter;
+ /* Initialize the thread descriptor */
+ new_thread->p_nextwaiting = NULL;
+ new_thread->p_tid = new_thread_id;
+- new_thread->p_priority = 0;
++ new_thread->p_priority = DEFAULT_PRIORITY;
+ new_thread->p_spinlock = &(__pthread_handles[sseg].h_spinlock);
+ new_thread->p_signal = 0;
+ new_thread->p_signal_jmp = NULL;
+@@ -212,14 +232,16 @@
+ new_thread->p_canceled = 0;
+ new_thread->p_errno = 0;
+ new_thread->p_h_errno = 0;
++ new_thread->stacksize = newsize;
+ for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++)
+ new_thread->p_specific[i] = NULL;
+ /* Initialize the thread handle */
+- __pthread_handles[sseg].h_spinlock = 0; /* should already be 0 */
++ _spin_init (new_thread->p_spinlock);
+ __pthread_handles[sseg].h_descr = new_thread;
+ /* Determine scheduling parameters for the thread */
+ new_thread->p_start_args.schedpolicy = SCHED_OTHER;
+- if (attr != NULL && attr->schedpolicy != SCHED_OTHER) {
++ new_thread->p_start_args.schedparam.sched_priority = new_thread->p_priority;
++ if (attr != NULL) {
+ switch(attr->inheritsched) {
+ case PTHREAD_EXPLICIT_SCHED:
+ new_thread->p_start_args.schedpolicy = attr->schedpolicy;
+@@ -237,6 +259,9 @@
+ new_thread->p_start_args.start_routine = start_routine;
+ new_thread->p_start_args.arg = arg;
+ new_thread->p_start_args.mask = *mask;
++
++ pthread_mutex_init (&new_thread->smutex, NULL);
++ pthread_mutex_lock (&new_thread->smutex);
+ /* Do the cloning */
+ pid = __clone(pthread_start_thread, (void **) new_thread,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+@@ -245,11 +270,15 @@
+ /* Check if cloning succeeded */
+ if (pid == -1) {
+ /* Free the stack */
+- munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
+- INITIAL_STACK_SIZE);
++ munmap(newaddr, newsize);
+ __pthread_handles[sseg].h_descr = NULL;
+- return errno;
++ return EAGAIN;
+ }
++ /* Shouldn't we have blocked pthread_start_thread at its inception
++ so we can complete the rest of the pthread_create routines
++ before it runs? Otherwise, pthread_start_thread and its
++ user function can begin before we're done?
++ */
+ /* Insert new thread in doubly linked list of active threads */
+ new_thread->p_prevlive = __pthread_main_thread;
+ new_thread->p_nextlive = __pthread_main_thread->p_nextlive;
+@@ -260,6 +289,7 @@
+ new_thread->p_pid = pid;
+ /* We're all set */
+ *thread = new_thread_id;
++ pthread_mutex_unlock (&new_thread->smutex);
+ return 0;
+ }
+
+@@ -277,7 +307,7 @@
+ /* If initial thread, nothing to free */
+ if (th == &__pthread_initial_thread) return;
+ /* Free the stack and thread descriptor area */
+- munmap((caddr_t) ((char *)(th+1) - STACK_SIZE), STACK_SIZE);
++ munmap((caddr_t) ((char *)(th+1) - th->stacksize), th->stacksize);
+ }
+
+ /* Handle threads that have exited */
+diff -ur ./mutex.c ../linuxthreads-0.71.new/mutex.c
+--- ./mutex.c Thu Dec 4 06:33:42 1997
++++ ../linuxthreads-0.71.new/mutex.c Wed Oct 27 18:13:29 1999
+@@ -17,14 +17,13 @@
+ #include <stddef.h>
+ #include "pthread.h"
+ #include "internals.h"
+-#include "spinlock.h"
+ #include "queue.h"
+ #include "restart.h"
+
+ int pthread_mutex_init(pthread_mutex_t * mutex,
+ const pthread_mutexattr_t * mutex_attr)
+ {
+- mutex->m_spinlock = 0;
++ _spin_init (&mutex->m_spinlock);
+ mutex->m_count = 0;
+ mutex->m_owner = NULL;
+ mutex->m_kind =
+@@ -84,10 +83,11 @@
+
+ int pthread_mutex_lock(pthread_mutex_t * mutex)
+ {
+- pthread_descr self;
++ pthread_descr self = thread_self();
+
+ while(1) {
+ acquire(&mutex->m_spinlock);
++ remove_from_queue(&mutex->m_waiting, self);
+ switch(mutex->m_kind) {
+ case PTHREAD_MUTEX_FAST_NP:
+ if (mutex->m_count == 0) {
+@@ -95,10 +95,8 @@
+ release(&mutex->m_spinlock);
+ return 0;
+ }
+- self = thread_self();
+ break;
+ case PTHREAD_MUTEX_RECURSIVE_NP:
+- self = thread_self();
+ if (mutex->m_count == 0 || mutex->m_owner == self) {
+ mutex->m_count++;
+ mutex->m_owner = self;
+@@ -107,7 +105,6 @@
+ }
+ break;
+ case PTHREAD_MUTEX_ERRORCHECK_NP:
+- self = thread_self();
+ if (mutex->m_count == 0) {
+ mutex->m_count = 1;
+ mutex->m_owner = self;
+@@ -183,14 +180,14 @@
+ attr->mutexkind = kind;
+ return 0;
+ }
+-weak_alias(__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np);
++#pragma weak pthread_mutexattr_setkind_np=__pthread_mutexattr_setkind_np
+
+ int __pthread_mutexattr_getkind_np(const pthread_mutexattr_t *attr, int *kind)
+ {
+ *kind = attr->mutexkind;
+ return 0;
+ }
+-weak_alias(__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np);
++#pragma weak pthread_mutexattr_getkind_np=__pthread_mutexattr_getkind_np
+
+ /* Once-only execution */
+
+@@ -223,18 +220,3 @@
+ return 0;
+ }
+
+-/* Internal locks for libc 5.2.18 */
+-
+-static pthread_mutex_t libc_libio_lock = PTHREAD_MUTEX_INITIALIZER;
+-static pthread_mutex_t libc_localtime_lock = PTHREAD_MUTEX_INITIALIZER;
+-static pthread_mutex_t libc_gmtime_lock = PTHREAD_MUTEX_INITIALIZER;
+-
+-/* The variables below are defined as weak symbols in libc,
+- initialized to NULL pointers, and with dummy pthread_mutex_*
+- functions (weak symbols also) that do nothing. If we provide
+- our implementations of pthread_mutex_*, we must also provide
+- initialized pointers to mutexes for those variables. */
+-
+-pthread_mutex_t * __libc_libio_lock = &libc_libio_lock;
+-pthread_mutex_t * __libc_localtime_lock = &libc_localtime_lock;
+-pthread_mutex_t * __libc_gmtime_lock = &libc_gmtime_lock;
+diff -ur ./pthread.c ../linuxthreads-0.71.new/pthread.c
+--- ./pthread.c Sun Nov 23 09:58:49 1997
++++ ../linuxthreads-0.71.new/pthread.c Wed Oct 27 18:13:29 1999
+@@ -1,4 +1,4 @@
+-/* Linuxthreads - a simple clone()-based implementation of Posix */
++/* Linuxthread - a simple clone()-based implementation of Posix */
+ /* threads for Linux. */
+ /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
+ /* */
+@@ -24,7 +24,6 @@
+ #include <sys/wait.h>
+ #include "pthread.h"
+ #include "internals.h"
+-#include "spinlock.h"
+ #include "restart.h"
+
+ /* Descriptor of the initial thread */
+@@ -35,7 +34,7 @@
+ NULL, /* pthread_descr p_nextwaiting */
+ PTHREAD_THREADS_MAX, /* pthread_t p_tid */
+ 0, /* int p_pid */
+- 0, /* int p_priority */
++ DEFAULT_PRIORITY, /* int p_priority */
+ &__pthread_handles[0].h_spinlock, /* int * p_spinlock */
+ 0, /* int p_signal */
+ NULL, /* sigjmp_buf * p_signal_buf */
+@@ -52,6 +51,8 @@
+ 0, /* char p_canceled */
+ 0, /* int p_errno */
+ 0, /* int p_h_errno */
++ 0, /* int stacksize */
++ PTHREAD_MUTEX_INITIALIZER,
+ PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */
+ {NULL} /* void ** p_specific[PTHREAD_KEY_1STLEVEL] */
+ };
+@@ -65,7 +66,7 @@
+ NULL, /* pthread_descr p_nextwaiting */
+ 0, /* int p_tid */
+ 0, /* int p_pid */
+- 0, /* int p_priority */
++ DEFAULT_PRIORITY, /* int p_priority */
+ NULL, /* int * p_spinlock */
+ 0, /* int p_signal */
+ NULL, /* sigjmp_buf * p_signal_buf */
+@@ -82,6 +83,8 @@
+ 0, /* char p_canceled */
+ 0, /* int p_errno */
+ 0, /* int p_h_errno */
++ 0, /* int stacksize */
++ PTHREAD_MUTEX_INITIALIZER,
+ PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */
+ {NULL} /* void ** p_specific[PTHREAD_KEY_1STLEVEL] */
+ };
+@@ -119,9 +122,12 @@
+ int __pthread_exit_requested = 0;
+ int __pthread_exit_code = 0;
+
++int clone_flag = 0;
++
+ /* Forward declarations */
+
+-static void pthread_exit_process(int retcode, void * arg);
++/* XXXX fix this */
++static void pthread_exit_process(void);
+ static void pthread_handle_sigcancel(int sig);
+
+ /* Initialize the pthread library.
+@@ -137,14 +143,15 @@
+ {
+ struct sigaction sa;
+ sigset_t mask;
++ int status;
+
+ /* If already done (e.g. by a constructor called earlier!), bail out */
+ if (__pthread_initial_thread_bos != NULL) return;
+ /* For the initial stack, reserve at least STACK_SIZE bytes of stack
+ below the current stack address, and align that on a
+ STACK_SIZE boundary. */
+- __pthread_initial_thread_bos =
+- (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1));
++
++ __pthread_initial_thread_bos = (char *)STACK_START;
+ /* Update the descriptor for the initial thread. */
+ __pthread_initial_thread.p_pid = __getpid();
+ /* If we have special thread_self processing, initialize that for the
+@@ -168,10 +175,17 @@
+ sigemptyset(&mask);
+ sigaddset(&mask, PTHREAD_SIG_RESTART);
+ sigprocmask(SIG_BLOCK, &mask, NULL);
++
++ /* This is FreeBSD specific, and is designed to detect pre/post March 1
++ * kernels, and adjust wait processing accordingly.
++ */
++ if (waitpid(-1, &status, WNOHANG | WLINUXCLONE) >= 0 || errno != EINVAL)
++ clone_flag = WLINUXCLONE;
++
+ /* Register an exit function to kill all other threads. */
+ /* Do it early so that user-registered atexit functions are called
+ before pthread_exit_process. */
+- on_exit(pthread_exit_process, NULL);
++ atexit(pthread_exit_process);
+ }
+
+ static int pthread_initialize_manager(void)
+@@ -196,7 +210,7 @@
+ /* Start the thread manager */
+ __pthread_manager_pid =
+ __clone(__pthread_manager, (void **) __pthread_manager_thread_tos,
+- CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
++ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | PTHREAD_SIG_RESTART,
+ (void *) manager_pipe[0]);
+ if (__pthread_manager_pid == -1) {
+ free(__pthread_manager_thread_bos);
+@@ -205,6 +219,7 @@
+ __pthread_manager_request = -1;
+ return -1;
+ }
++ _pthread_stack_init();
+ return 0;
+ }
+
+@@ -215,6 +230,7 @@
+ {
+ pthread_descr self = thread_self();
+ struct pthread_request request;
++
+ if (__pthread_manager_request < 0) {
+ if (pthread_initialize_manager() < 0) return EAGAIN;
+ }
+@@ -225,7 +241,7 @@
+ request.req_args.create.arg = arg;
+ sigprocmask(SIG_SETMASK, (const sigset_t *) NULL,
+ &request.req_args.create.mask);
+- write(__pthread_manager_request, (char *) &request, sizeof(request));
++ _write(__pthread_manager_request, (char *) &request, sizeof(request));
+ suspend(self);
+ if (self->p_retcode == 0) *thread = (pthread_t) self->p_retval;
+ return self->p_retcode;
+@@ -262,7 +278,7 @@
+ release(&handle->h_spinlock);
+ return errno;
+ }
+- th->p_priority = policy == SCHED_OTHER ? 0 : param->sched_priority;
++ th->p_priority = param->sched_priority;
+ release(&handle->h_spinlock);
+ return 0;
+ }
+@@ -289,8 +305,10 @@
+
+ /* Process-wide exit() request */
+
+-static void pthread_exit_process(int retcode, void * arg)
++static void pthread_exit_process(void)
+ {
++ int retcode = 0;
++
+ struct pthread_request request;
+ pthread_descr self = thread_self();
+
+@@ -298,7 +316,7 @@
+ request.req_thread = self;
+ request.req_kind = REQ_PROCESS_EXIT;
+ request.req_args.exit.code = retcode;
+- write(__pthread_manager_request, (char *) &request, sizeof(request));
++ _write(__pthread_manager_request, (char *) &request, sizeof(request));
+ suspend(self);
+ /* Main thread should accumulate times for thread manager and its
+ children, so that timings for main thread account for all threads. */
+@@ -365,8 +383,8 @@
+ free(__pthread_manager_thread_bos);
+ __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL;
+ /* Close the two ends of the pipe */
+- close(__pthread_manager_request);
+- close(__pthread_manager_reader);
++ _close(__pthread_manager_request);
++ _close(__pthread_manager_reader);
+ __pthread_manager_request = __pthread_manager_reader = -1;
+ }
+ /* Update the pid of the main thread */
+@@ -382,12 +400,12 @@
+ void __pthread_kill_other_threads_np(void)
+ {
+ /* Terminate all other threads and thread manager */
+- pthread_exit_process(0, NULL);
++ pthread_exit_process();
+ /* Make current thread the main thread in case the calling thread
+ changes its mind, does not exec(), and creates new threads instead. */
+ __pthread_reset_main_thread();
+ }
+-weak_alias(__pthread_kill_other_threads_np, pthread_kill_other_threads_np);
++#pragma weak pthread_kill_other_threads_np=__pthread_kill_other_threads_np
+
+ /* Debugging aid */
+
+@@ -398,7 +416,7 @@
+ char buffer[1024];
+ sprintf(buffer, "%05d : ", __getpid());
+ sprintf(buffer + 8, fmt, arg);
+- write(2, buffer, strlen(buffer));
++ _write(2, buffer, strlen(buffer));
+ }
+
+ #endif
+diff -ur ./pthread.h ../linuxthreads-0.71.new/pthread.h
+--- ./pthread.h Thu Dec 4 06:33:41 1997
++++ ../linuxthreads-0.71.new/pthread.h Wed Oct 27 18:13:29 1999
+@@ -14,19 +14,13 @@
+
+ #ifndef _PTHREAD_H
+
+-#define _PTHREAD_H 1
+-#include <features.h>
+-
++#define _PTHREAD_H
+ #define __need_sigset_t
+ #include <signal.h>
+ #define __need_timespec
+ #include <time.h>
+
+-#ifdef __BUILDING_LINUXTHREADS
+-#include <linux/sched.h>
+-#else
+-#include <sched.h>
+-#endif
++#include <posix4/sched.h>
+
+ #ifndef _REENTRANT
+ #define _REENTRANT
+@@ -67,6 +61,17 @@
+ /* Thread descriptors */
+ typedef struct _pthread_descr_struct * _pthread_descr;
+
++#ifndef SPINLOCK_DEFINED
++typedef struct {
++ volatile long access_lock;
++ volatile long lock_owner;
++ volatile char *fname;
++ volatile int lineno;
++} spinlock_t;
++#define _SPINLOCK_INITIALIZER { 0, 0, 0, 0 }
++#define SPINLOCK_DEFINED
++#endif
++
+ /* Waiting queues (not abstract because mutexes and conditions aren't). */
+ struct _pthread_queue {
+ _pthread_descr head; /* First element, or NULL if queue empty. */
+@@ -75,24 +80,24 @@
+
+ /* Mutexes (not abstract because of PTHREAD_MUTEX_INITIALIZER). */
+ typedef struct {
+- int m_spinlock; /* Spin lock to guarantee mutual exclusion. */
++ spinlock_t m_spinlock; /* Spin lock to guarantee mutual exclusion. */
+ int m_count; /* 0 if free, > 0 if taken. */
+ _pthread_descr m_owner; /* Owner of mutex (for recursive mutexes) */
+ int m_kind; /* Kind of mutex */
+ struct _pthread_queue m_waiting; /* Threads waiting on this mutex. */
+ } pthread_mutex_t;
+
+-#define PTHREAD_MUTEX_INITIALIZER {0, 0, 0, PTHREAD_MUTEX_FAST_NP, {0, 0}}
+-#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, {0, 0}}
+-#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}}
++#define PTHREAD_MUTEX_INITIALIZER {_SPINLOCK_INITIALIZER, 0, 0, PTHREAD_MUTEX_FAST_NP, {0, 0}}
++#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP {_SPINLOCK_INITIALIZER, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, {0, 0}}
++#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP {_SPINLOCK_INITIALIZER, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}}
+
+ /* Conditions (not abstract because of PTHREAD_COND_INITIALIZER */
+ typedef struct {
+- int c_spinlock; /* Spin lock to protect the queue. */
++ spinlock_t c_spinlock; /* Spin lock to protect the queue. */
+ struct _pthread_queue c_waiting; /* Threads waiting on this condition. */
+ } pthread_cond_t;
+
+-#define PTHREAD_COND_INITIALIZER {0, {0, 0}}
++#define PTHREAD_COND_INITIALIZER {_SPINLOCK_INITIALIZER, {0, 0}}
+
+ /* Attributes */
+
+@@ -117,6 +122,9 @@
+ struct sched_param schedparam;
+ int inheritsched;
+ int scope;
++ void * stack_addr;
++ int stack_size;
++ int guard_size;
+ } pthread_attr_t;
+
+ enum {
+@@ -464,6 +472,10 @@
+ Should be called just before invoking one of the exec*() functions. */
+
+ extern void pthread_kill_other_threads_np __P((void));
++
++#ifdef COMPILING_LINUXTHREADS
++#include "pthread_stack.h"
++#endif
+
+ #if defined(__cplusplus)
+ }
+Only in ../linuxthreads-0.71.new: pthread_private.h
+Only in ../linuxthreads-0.71.new: pthread_rw.h
+Only in ../linuxthreads-0.71.new: pthread_stack.h
+diff -ur ./queue.h ../linuxthreads-0.71.new/queue.h
+--- ./queue.h Fri Dec 5 02:28:21 1997
++++ ../linuxthreads-0.71.new/queue.h Wed Oct 27 18:13:29 1999
+@@ -60,3 +60,5 @@
+ }
+ return th;
+ }
++
++int remove_from_queue(pthread_queue * q, pthread_descr th);
+diff -ur ./restart.h ../linuxthreads-0.71.new/restart.h
+--- ./restart.h Fri Dec 5 02:28:21 1997
++++ ../linuxthreads-0.71.new/restart.h Wed Oct 27 18:13:29 1999
+@@ -14,6 +14,9 @@
+
+ /* Primitives for controlling thread execution */
+
++#include <stdio.h>
++
++#ifndef USETHR_FUNCTIONS
+ static inline void restart(pthread_descr th)
+ {
+ kill(th->p_pid, PTHREAD_SIG_RESTART);
+@@ -27,7 +30,7 @@
+ sigdelset(&mask, PTHREAD_SIG_RESTART); /* Unblock the restart signal */
+ do {
+ self->p_signal = 0;
+- sigsuspend(&mask); /* Wait for signal */
++ _sigsuspend(&mask); /* Wait for signal */
+ } while (self->p_signal != PTHREAD_SIG_RESTART);
+ }
+
+@@ -44,7 +47,7 @@
+ if (! (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE)) {
+ do {
+ self->p_signal = 0;
+- sigsuspend(&mask); /* Wait for a signal */
++ _sigsuspend(&mask); /* Wait for signal */
+ } while (self->p_signal != PTHREAD_SIG_RESTART);
+ }
+ self->p_cancel_jmp = NULL;
+@@ -53,3 +56,29 @@
+ sigprocmask(SIG_SETMASK, &mask, NULL);
+ }
+ }
++#else
++
++#include <sys/syscall.h>
++#include <unistd.h>
++
++static inline void restart(pthread_descr th)
++{
++ syscall(SYS_thr_wakeup, th->p_pid);
++}
++
++static inline void suspend(pthread_descr self)
++{
++ syscall(SYS_thr_sleep, NULL);
++}
++
++static inline void suspend_with_cancellation(pthread_descr self)
++{
++ /* What we think happens here is that if a PTHREAD_SIG_CANCEL
++ is sent, thr_sleep will be awaken. It should return
++ EINTR, but it will just return 0 unless we fix it.
++
++ So we shouldn't need any of the fancy jmpbuf stuff
++ */
++ syscall(SYS_thr_sleep, NULL);
++}
++#endif
+diff -ur ./signals.c ../linuxthreads-0.71.new/signals.c
+--- ./signals.c Fri Dec 12 09:21:47 1997
++++ ../linuxthreads-0.71.new/signals.c Wed Oct 27 18:13:29 1999
+@@ -18,7 +18,6 @@
+ #include <errno.h>
+ #include "pthread.h"
+ #include "internals.h"
+-#include "spinlock.h"
+
+ int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask)
+ {
+@@ -36,9 +35,11 @@
+ case SIG_BLOCK:
+ sigdelset(&mask, PTHREAD_SIG_CANCEL);
+ break;
++
+ case SIG_UNBLOCK:
+ sigdelset(&mask, PTHREAD_SIG_RESTART);
+ break;
++
+ }
+ newmask = &mask;
+ }
+@@ -67,7 +68,7 @@
+ }
+
+ /* The set of signals on which some thread is doing a sigwait */
+-static sigset_t sigwaited = 0;
++static sigset_t sigwaited = { { 0 } };
+ static pthread_mutex_t sigwaited_mut = PTHREAD_MUTEX_INITIALIZER;
+ static pthread_cond_t sigwaited_changed = PTHREAD_COND_INITIALIZER;
+
+@@ -115,7 +116,7 @@
+ /* Reset the signal count */
+ self->p_signal = 0;
+ /* Unblock the signals and wait for them */
+- sigsuspend(&mask);
++ _sigsuspend(&mask);
+ }
+ }
+ self->p_cancel_jmp = NULL;
+diff -ur ./spinlock.h ../linuxthreads-0.71.new/spinlock.h
+--- ./spinlock.h Fri Dec 5 02:28:22 1997
++++ ../linuxthreads-0.71.new/spinlock.h Wed Oct 27 18:13:29 1999
+@@ -15,17 +15,20 @@
+
+ /* Spin locks */
+
+-static inline void acquire(int * spinlock)
++#include "libc_spinlock.h"
++
++
++static inline void acquire(spinlock_t *lck)
+ {
+- while (testandset(spinlock)) __sched_yield();
++ _spin_lock (lck);
+ }
+
+-static inline void release(int * spinlock)
++static inline void release(spinlock_t *lck)
+ {
+ #ifndef RELEASE
+- *spinlock = 0;
++ _spin_unlock (lck);;
+ #else
+- RELEASE(spinlock);
++ RELEASE(lck);
+ #endif
+ }
+
diff --git a/devel/linuxthreads/files/sched.c b/devel/linuxthreads/files/sched.c
new file mode 100644
index 000000000000..880889b8140a
--- /dev/null
+++ b/devel/linuxthreads/files/sched.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Extensively modified and added to by Richard Seaman, Jr. <dick@tar.com>
+ *
+ */
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include "pthread.h"
+#include "internals.h"
+
+int _sched_yield(void);
+int _sched_setparam(pid_t pid, const struct sched_param *param);
+int _sched_getparam(pid_t pid, struct sched_param *param);
+int _sched_setscheduler(pid_t pid, int policy,
+ const struct sched_param *param);
+int _sched_getscheduler(pid_t pid);
+int _sched_get_priority_max(int policy);
+int _sched_get_priority_min(int policy);
+int _sched_rr_get_interval(pid_t pid, struct timespec *interval);
+
+extern int _posix_priority_scheduling;
+
+int
+sched_yield(void)
+{
+ if (_posix_priority_scheduling)
+ return (_sched_yield());
+ else
+ syscall(SYS_yield);
+ return(0);
+}
+
+/* Draft 4 yield */
+void
+pthread_yield(void)
+{
+ if (_posix_priority_scheduling)
+ _sched_yield();
+ else
+ syscall(SYS_yield);
+}
+
+#ifdef HAVE_FIXED_SCHED_FUNCTIONS
+int __sched_setparam(pid_t pid, const struct sched_param *param)
+{
+ if (_posix_priority_scheduling)
+ return (_sched_setparam(pid, param));
+ else {
+ errno = ENOSYS;
+ return (-1);
+ }
+}
+
+int __sched_setscheduler(pid_t pid, int policy,
+ const struct sched_param *param)
+{
+ if (_posix_priority_scheduling) {
+ return (_sched_setscheduler(pid, policy, param));
+ } else {
+ errno = ENOSYS;
+ return (-1);
+ }
+}
+int __sched_getscheduler(pid_t pid)
+{
+ if (_posix_priority_scheduling) {
+ return (_sched_getscheduler(pid));
+ } else {
+ errno = ENOSYS;
+ return (-1);
+ }
+}
+int __sched_get_priority_max(int policy)
+{
+ if (_posix_priority_scheduling)
+ return (_sched_get_priority_max (policy));
+ else
+ errno = ENOSYS;
+ return (-1);
+}
+int __sched_get_priority_min(int policy)
+{
+ if (_posix_priority_scheduling)
+ return (_sched_get_priority_min (policy));
+ else
+ errno = ENOSYS;
+ return (-1);
+}
+
+int __sched_getparam(pid_t pid, struct sched_param *param)
+{
+ if (_posix_priority_scheduling)
+ return (_sched_getparam(pid, param));
+ else {
+ errno = ENOSYS;
+ return (-1);
+ }
+}
+
+int __sched_rr_get_interval(pid_t pid, struct timespec *interval)
+{
+ if (_posix_priority_scheduling)
+ return (_sched_rr_get_interval(pid, interval));
+ else {
+ errno = ENOSYS;
+ return (-1);
+ }
+}
+#else
+
+#include <sys/rtprio.h>
+#include <sys/types.h>
+
+/* Defines take from sys/posix4/ksched.c */
+#define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P))
+#define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P))
+#define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX)
+#define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN)
+#define p4prio_to_p_nice(P) (-(P + PRIO_MIN))
+#define p_nice_to_p4prio(P) (-(P - PRIO_MAX))
+#define P_NICE_PRIO_MIN p_nice_to_p4prio(PRIO_MAX)
+#define P_NICE_PRIO_MAX p_nice_to_p4prio(PRIO_MIN)
+
+int _getpriority __P((int, int));
+int _setpriority __P((int, int, int));
+
+int sched_setparam(pid_t pid, const struct sched_param *param)
+{
+ int policy = __sched_getscheduler (pid);
+
+ if (policy == -1)
+ return (-1);
+ return (__sched_setscheduler (pid, policy, param));
+}
+#pragma weak __sched_setparam=sched_setparam
+
+int sched_setscheduler(pid_t pid, int policy,
+ const struct sched_param *param)
+{
+ struct rtprio rtp;
+ int max, min;
+ int ret;
+ int curtype;
+
+ max = __sched_get_priority_max(policy);
+ if (max == -1)
+ return (-1);
+ min = __sched_get_priority_min(policy);
+ if (min == -1)
+ return (-1);
+ if (param->sched_priority > max ||
+ param->sched_priority < min) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ switch (policy) {
+ case SCHED_FIFO:
+ rtp.type = RTP_PRIO_FIFO;
+ rtp.prio = p4prio_to_rtpprio (param->sched_priority);
+ return (rtprio (RTP_SET, pid, &rtp));
+
+ case SCHED_RR:
+ rtp.type = RTP_PRIO_REALTIME;
+ rtp.prio = p4prio_to_rtpprio (param->sched_priority);
+ return (rtprio (RTP_SET, pid, &rtp));
+
+ case SCHED_OTHER:
+ curtype = __sched_getscheduler (pid);
+ if (curtype != SCHED_OTHER) {
+ rtp.type = RTP_PRIO_NORMAL;
+ rtp.prio = p4prio_to_rtpprio (0);
+ ret = rtprio (RTP_SET, pid, &rtp);
+ if (ret)
+ return (ret);
+ }
+ return (_setpriority (PRIO_PROCESS, pid,
+ p4prio_to_p_nice (param->sched_priority)));
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+}
+#pragma weak __sched_setscheduler=sched_setscheduler
+
+int sched_getscheduler(pid_t pid)
+{
+ int ret;
+ struct rtprio rtp;
+
+ ret = rtprio (RTP_LOOKUP, pid, &rtp);
+ if (!ret) {
+ switch (rtp.type) {
+ case RTP_PRIO_FIFO:
+ ret = SCHED_FIFO;
+ break;
+
+ case RTP_PRIO_REALTIME:
+ ret = SCHED_RR;
+ break;
+
+ default:
+ ret = SCHED_OTHER;
+ break;
+ }
+ }
+ return (ret);
+}
+#pragma weak __sched_getscheduler=sched_getscheduler
+
+int sched_get_priority_max(int policy)
+{
+ switch (policy)
+ {
+ case SCHED_FIFO:
+ case SCHED_RR:
+ return (P1B_PRIO_MAX);
+
+ case SCHED_OTHER:
+ return(P_NICE_PRIO_MAX);
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+}
+#pragma weak __sched_get_priority_max=sched_get_priority_max
+
+int sched_get_priority_min(int policy)
+{
+ switch (policy)
+ {
+ case SCHED_FIFO:
+ case SCHED_RR:
+ return (P1B_PRIO_MIN);
+
+ case SCHED_OTHER:
+ return(P_NICE_PRIO_MIN);
+
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+}
+#pragma weak __sched_get_priority_min=sched_get_priority_min
+
+
+int sched_getparam(pid_t pid, struct sched_param *param)
+{
+ int ret = 0;
+ struct rtprio rtp;
+
+ ret = rtprio (RTP_LOOKUP, pid, &rtp);
+ if (!ret) {
+ switch (rtp.type) {
+ case RTP_PRIO_FIFO:
+ case RTP_PRIO_REALTIME:
+ param->sched_priority = rtpprio_to_p4prio(rtp.prio);
+ break;
+
+ default:
+ errno = 0;
+ ret = _getpriority (PRIO_PROCESS, pid);
+ if (ret == -1 && errno != 0)
+ return (-1);
+
+ param->sched_priority = p_nice_to_p4prio(ret);
+ break;
+ }
+ }
+ return (ret);
+
+}
+#pragma weak __sched_getparam=sched_getparam
+
+int sched_rr_get_interval(pid_t pid, struct timespec *interval)
+{
+ if (_posix_priority_scheduling)
+ return (_sched_rr_get_interval(pid, interval));
+ else {
+ errno = ENOSYS;
+ return (-1);
+ }
+}
+
+#pragma weak __sched_rr_get_interval=sched_rr_get_interval
+
+#endif
diff --git a/devel/linuxthreads/files/uthread_file.c b/devel/linuxthreads/files/uthread_file.c
new file mode 100644
index 000000000000..10b456bfaa40
--- /dev/null
+++ b/devel/linuxthreads/files/uthread_file.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by John Birrell.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: uthread_file.c,v 1.7 1999/06/20 08:28:20 jb Exp $
+ *
+ * POSIX stdio FILE locking functions. These assume that the locking
+ * is only required at FILE structure level, not at file descriptor
+ * level too.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pthread.h"
+#include "internals.h"
+#include "restart.h"
+
+/*
+ * Weak symbols for externally visible functions in this file:
+ */
+#pragma weak flockfile=_flockfile
+#pragma weak ftrylockfile=_ftrylockfile
+#pragma weak funlockfile=_funlockfile
+
+/*
+ * The FILE lock structure. The FILE *fp is locked if the owner is
+ * not NULL. If not locked, the file lock structure can be
+ * reassigned to a different file by setting fp.
+ */
+struct file_lock {
+ LIST_ENTRY(file_lock) entry; /* Entry if file list. */
+ TAILQ_HEAD(lock_head, _pthread_descr_struct)
+ l_head; /* Head of queue for threads */
+ /* waiting on this lock. */
+ FILE *fp; /* The target file. */
+ pthread_descr owner; /* Thread that owns lock. */
+ int count; /* Lock count for owner. */
+};
+
+/*
+ * The number of file lock lists into which the file pointer is
+ * hashed. Ideally, the FILE structure size would have been increased,
+ * but this causes incompatibility, so separate data structures are
+ * required.
+ */
+#define NUM_HEADS 128
+
+/*
+ * This macro casts a file pointer to a long integer and right
+ * shifts this by the number of bytes in a pointer. The shifted
+ * value is then remaindered using the maximum number of hash
+ * entries to produce and index into the array of static lock
+ * structures. If there is a collision, a linear search of the
+ * dynamic list of locks linked to each static lock is perfomed.
+ */
+#define file_idx(_p) ((((u_long) _p) >> sizeof(void *)) % NUM_HEADS)
+
+/*
+ * Global array of file locks. The first lock for each hash bucket is
+ * allocated statically in the hope that there won't be too many
+ * collisions that require a malloc and an element added to the list.
+ */
+struct static_file_lock {
+ LIST_HEAD(file_list_head, file_lock) head;
+ struct file_lock fl;
+} flh[NUM_HEADS];
+
+/* Set to non-zero when initialisation is complete: */
+static int init_done = 0;
+
+/* Lock for accesses to the hash table: */
+static spinlock_t hash_lock = _SPINLOCK_INITIALIZER;
+
+/*
+ * Find a lock structure for a FILE, return NULL if the file is
+ * not locked:
+ */
+static
+struct file_lock *
+find_lock(int idx, FILE *fp)
+{
+ struct file_lock *p;
+
+ /* Check if the file is locked using the static structure: */
+ if (flh[idx].fl.fp == fp && flh[idx].fl.owner != NULL)
+ /* Return a pointer to the static lock: */
+ p = &flh[idx].fl;
+ else {
+ /* Point to the first dynamic lock: */
+ p = flh[idx].head.lh_first;
+
+ /*
+ * Loop through the dynamic locks looking for the
+ * target file:
+ */
+ while (p != NULL && (p->fp != fp || p->owner == NULL))
+ /* Not this file, try the next: */
+ p = p->entry.le_next;
+ }
+ return(p);
+}
+
+
+/*
+ * Lock a file, assuming that there is no lock structure currently
+ * assigned to it.
+ */
+static
+struct file_lock *
+do_lock(int idx, FILE *fp)
+{
+ struct file_lock *p;
+
+ /* Check if the static structure is not being used: */
+ if (flh[idx].fl.owner == NULL) {
+ /* Return a pointer to the static lock: */
+ p = &flh[idx].fl;
+ }
+ else {
+ /* Point to the first dynamic lock: */
+ p = flh[idx].head.lh_first;
+
+ /*
+ * Loop through the dynamic locks looking for a
+ * lock structure that is not being used:
+ */
+ while (p != NULL && p->owner != NULL)
+ /* This one is used, try the next: */
+ p = p->entry.le_next;
+ }
+
+ /*
+ * If an existing lock structure has not been found,
+ * allocate memory for a new one:
+ */
+ if (p == NULL && (p = (struct file_lock *)
+ malloc(sizeof(struct file_lock))) != NULL) {
+ /* Add the new element to the list: */
+ LIST_INSERT_HEAD(&flh[idx].head, p, entry);
+ }
+
+ /* Check if there is a lock structure to acquire: */
+ if (p != NULL) {
+ /* Acquire the lock for the running thread: */
+ p->fp = fp;
+ p->owner = thread_self();
+ p->count = 1;
+ TAILQ_INIT(&p->l_head);
+ }
+ return(p);
+}
+
+void
+_flockfile(FILE * fp)
+{
+ int idx = file_idx(fp);
+ struct file_lock *p;
+ pthread_descr self = thread_self();
+
+ /* Check if this is a real file: */
+ if (fp->_file >= 0) {
+ /* Lock the hash table: */
+ _SPINLOCK(&hash_lock);
+
+ /* Check if the static array has not been initialised: */
+ if (!init_done) {
+ /* Initialise the global array: */
+ memset(flh,0,sizeof(flh));
+
+ /* Flag the initialisation as complete: */
+ init_done = 1;
+ }
+
+ /* Get a pointer to any existing lock for the file: */
+ if ((p = find_lock(idx, fp)) == NULL) {
+ /*
+ * The file is not locked, so this thread can
+ * grab the lock:
+ */
+ p = do_lock(idx, fp);
+
+ /* Unlock the hash table: */
+ _SPINUNLOCK(&hash_lock);
+
+ /*
+ * The file is already locked, so check if the
+ * running thread is the owner:
+ */
+ } else if (p->owner == self) {
+ /*
+ * The running thread is already the
+ * owner, so increment the count of
+ * the number of times it has locked
+ * the file:
+ */
+ p->count++;
+
+ /* Unlock the hash table: */
+ _SPINUNLOCK(&hash_lock);
+ } else {
+ /*
+ * The file is locked for another thread.
+ * Append this thread to the queue of
+ * threads waiting on the lock.
+ */
+ TAILQ_INSERT_TAIL(&p->l_head,self,qe);
+
+ /* Unlock the hash table: */
+ _SPINUNLOCK(&hash_lock);
+
+ /* Wait on the FILE lock: */
+ suspend (self);
+ }
+ }
+ return;
+}
+
+int
+_ftrylockfile(FILE * fp)
+{
+ int ret = -1;
+ int idx = file_idx(fp);
+ struct file_lock *p;
+ pthread_descr self = thread_self();
+
+ /* Check if this is a real file: */
+ if (fp->_file >= 0) {
+ /* Lock the hash table: */
+ _SPINLOCK(&hash_lock);
+
+ /* Get a pointer to any existing lock for the file: */
+ if ((p = find_lock(idx, fp)) == NULL) {
+ /*
+ * The file is not locked, so this thread can
+ * grab the lock:
+ */
+ p = do_lock(idx, fp);
+
+ /*
+ * The file is already locked, so check if the
+ * running thread is the owner:
+ */
+ } else if (p->owner == self) {
+ /*
+ * The running thread is already the
+ * owner, so increment the count of
+ * the number of times it has locked
+ * the file:
+ */
+ p->count++;
+ } else {
+ /*
+ * The file is locked for another thread,
+ * so this try fails.
+ */
+ p = NULL;
+ }
+
+ /* Check if the lock was obtained: */
+ if (p != NULL)
+ /* Return success: */
+ ret = 0;
+
+ /* Unlock the hash table: */
+ _SPINUNLOCK(&hash_lock);
+
+ }
+ return (ret);
+}
+
+void
+_funlockfile(FILE * fp)
+{
+ int idx = file_idx(fp);
+ struct file_lock *p;
+ pthread_descr self = thread_self();
+
+ /* Check if this is a real file: */
+ if (fp->_file >= 0) {
+ /*
+ * Defer signals to protect the scheduling queues from
+ * access by the signal handler:
+ */
+ /* XXX RLC _thread_kern_sig_defer(); */
+
+ /* Lock the hash table: */
+ _SPINLOCK(&hash_lock);
+
+ /*
+ * Get a pointer to the lock for the file and check that
+ * the running thread is the one with the lock:
+ */
+ if ((p = find_lock(idx, fp)) != NULL &&
+ p->owner == self) {
+ /*
+ * Check if this thread has locked the FILE
+ * more than once:
+ */
+ if (p->count > 1)
+ /*
+ * Decrement the count of the number of
+ * times the running thread has locked this
+ * file:
+ */
+ p->count--;
+ else {
+ /*
+ * The running thread will release the
+ * lock now:
+ */
+ p->count = 0;
+
+ /* Get the new owner of the lock: */
+ if ((p->owner = TAILQ_FIRST(&p->l_head)) != NULL) {
+ /* Pop the thread off the queue: */
+ TAILQ_REMOVE(&p->l_head,p->owner,qe);
+
+ /*
+ * This is the first lock for the new
+ * owner:
+ */
+ p->count = 1;
+
+ /* Allow the new owner to run: */
+ restart(p->owner);
+ }
+ }
+ }
+
+ /* Unlock the hash table: */
+ _SPINUNLOCK(&hash_lock);
+
+ /*
+ * Undefer and handle pending signals, yielding if
+ * necessary:
+ */
+ /* XXX RLC _thread_kern_sig_undefer(); */
+ }
+ return;
+}
+
+void __fresetlockfiles()
+{
+ int idx;
+ struct file_lock *p;
+
+ _SPINLOCK(&hash_lock);
+ for (idx = 0; idx < NUM_HEADS; idx++) {
+
+ /* Zero the static lock */
+ p = &flh[idx].fl;
+ p->owner = NULL;
+ p->fp = NULL;
+ p->count = 0;
+ TAILQ_INIT(&p->l_head);
+
+ /* Loop through the dynamic locks
+ * and free them.
+ */
+
+ while (flh[idx].head.lh_first != NULL) {
+ p = flh[idx].head.lh_first;
+ LIST_REMOVE(p, entry);
+ free (p);
+ }
+ }
+ _SPINUNLOCK(&hash_lock);
+}
diff --git a/devel/linuxthreads/pkg-comment b/devel/linuxthreads/pkg-comment
new file mode 100644
index 000000000000..f0e1f97736e3
--- /dev/null
+++ b/devel/linuxthreads/pkg-comment
@@ -0,0 +1 @@
+POSIX pthreads implementation using rfork to generate kernel threads.
diff --git a/devel/linuxthreads/pkg-descr b/devel/linuxthreads/pkg-descr
new file mode 100644
index 000000000000..3fabc3295f3c
--- /dev/null
+++ b/devel/linuxthreads/pkg-descr
@@ -0,0 +1,9 @@
+Linux threads is an POSIX pthreads implementation using "kernel
+threads". In this FreeBSD port, a kernel thread is started using
+rfork (whereas in the original Linux implementation a kernel thread
+is started using the Linux clone call). This implementaion provides
+a so-called one-to-one mapping of threads to kernel schedulable
+entities. For more information see about the original linux threads
+implementation see:
+
+ http://pauillac.inria.fr/~xleroy/linuxthreads/
diff --git a/devel/linuxthreads/pkg-message b/devel/linuxthreads/pkg-message
new file mode 100644
index 000000000000..d9a3a341431f
--- /dev/null
+++ b/devel/linuxthreads/pkg-message
@@ -0,0 +1,19 @@
+
+
+NOTES: This package is intended to run on FreeBSD 4.0-current or
+FreeBSD 3.X, with sources more recent than March 1, 1999.
+
+This package does not currently work on an SMP machine. It also only
+works on i386 architectures.
+
+Compile your applications that use Linux Threads with the following
+command line options:
+
+ -D_THREAD_SAFE -DLINUXTHREADS -lpthread
+or (equivalently):
+ -D_THREAD_SAFE -DLINUXTHREADS -kthread
+
+DO NOT use libc_r with Linux Threads, and do not compile/link with
+the -pthread option (which pulls in libc_r). DO link with libc
+(which you will get by default).
+
diff --git a/devel/linuxthreads/pkg-plist b/devel/linuxthreads/pkg-plist
new file mode 100644
index 000000000000..38327e554b84
--- /dev/null
+++ b/devel/linuxthreads/pkg-plist
@@ -0,0 +1,11 @@
+lib/liblthread.a
+lib/liblthread_p.a
+lib/liblthread.so
+lib/liblthread.so.0
+include/pthread/linuxthreads/pthread.h
+include/pthread/linuxthreads/pthread_rw.h
+include/pthread/linuxthreads/pthread_stack.h
+@exec /sbin/ldconfig -m %D/lib
+@dirrm include/pthread/linuxthreads
+@dirrm include/pthread
+@unexec /sbin/ldconfig -R