diff options
author | julian <julian@FreeBSD.org> | 1999-11-30 17:07:29 +0800 |
---|---|---|
committer | julian <julian@FreeBSD.org> | 1999-11-30 17:07:29 +0800 |
commit | c225606277e9b01fe41c9842c8e687e707287141 (patch) | |
tree | 31546813e4bca8903bfb6553b39596cb47fd30b3 /devel | |
parent | af129845e14e0bb912ffda5e81ee479f613a79e4 (diff) | |
download | freebsd-ports-gnome-c225606277e9b01fe41c9842c8e687e707287141.tar.gz freebsd-ports-gnome-c225606277e9b01fe41c9842c8e687e707287141.tar.zst freebsd-ports-gnome-c225606277e9b01fe41c9842c8e687e707287141.zip |
Reviewed by: Russell Carter
Submitted by: "Richard Seaman, Jr." <dick@tar.com>
Native FreeBSD port of the linuxthreads library
Includes added files and stuff you need to add to the rest of your system.
This is for -current I'm sure Richard's older version might be
a good place to start for a 3.x version.
Diffstat (limited to 'devel')
-rw-r--r-- | devel/linuxthreads/Makefile | 47 | ||||
-rw-r--r-- | devel/linuxthreads/distinfo | 1 | ||||
-rw-r--r-- | devel/linuxthreads/files/README.FreeBSD | 101 | ||||
-rw-r--r-- | devel/linuxthreads/files/clone.S | 128 | ||||
-rw-r--r-- | devel/linuxthreads/files/clone.h | 42 | ||||
-rw-r--r-- | devel/linuxthreads/files/getgr_r.c | 144 | ||||
-rw-r--r-- | devel/linuxthreads/files/lclone.c | 91 | ||||
-rw-r--r-- | devel/linuxthreads/files/libc_calls.c | 149 | ||||
-rw-r--r-- | devel/linuxthreads/files/libc_thread.c | 127 | ||||
-rw-r--r-- | devel/linuxthreads/files/patch-aa | 1245 | ||||
-rw-r--r-- | devel/linuxthreads/files/sched.c | 320 | ||||
-rw-r--r-- | devel/linuxthreads/files/uthread_file.c | 396 | ||||
-rw-r--r-- | devel/linuxthreads/pkg-comment | 1 | ||||
-rw-r--r-- | devel/linuxthreads/pkg-descr | 9 | ||||
-rw-r--r-- | devel/linuxthreads/pkg-message | 19 | ||||
-rw-r--r-- | devel/linuxthreads/pkg-plist | 11 |
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 |