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 +#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 -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 #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 +#include +#include #include #include -#include /* for weak_alias */ -#include +#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 #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 #include 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 #include #include -#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 #include 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 #include #include /* for select */ -#include /* for select */ -#include /* for mmap */ #include /* for waitpid macros */ -#include #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 #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 #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 - +#define _PTHREAD_H #define __need_sigset_t #include #define __need_timespec #include -#ifdef __BUILDING_LINUXTHREADS -#include -#else -#include -#endif +#include #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 + +#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 +#include + +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 #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 }