diff options
author | Peter Galbavy <peter@cvs.openbsd.org> | 1998-07-21 13:22:23 +0000 |
---|---|---|
committer | Peter Galbavy <peter@cvs.openbsd.org> | 1998-07-21 13:22:23 +0000 |
commit | 0294ed9251849ce79ab3d4cc45841a9f6de82844 (patch) | |
tree | 30d684d4c18138e4ccaf59b61acadc667e515c74 /lib/libpthread | |
parent | 43b686d61558c0957f1779c747214ddef20a2252 (diff) |
Complete initial import from mySQL 3.22.4 (mit-pthreads/).
Lots of dross to move and remove yet.
At minimum:
o remove GNU config and GNU Makefiles
o build arch directory and migrate away machdep/
o rebuild BSD Makefiles
o move notes etc. into doc/
Diffstat (limited to 'lib/libpthread')
70 files changed, 10496 insertions, 0 deletions
diff --git a/lib/libpthread/bin/Makefile b/lib/libpthread/bin/Makefile new file mode 100644 index 00000000000..ce18f70b66a --- /dev/null +++ b/lib/libpthread/bin/Makefile @@ -0,0 +1,49 @@ +# Generated automatically from Makefile.in by configure. +# === GNUmakefile ============================================================ +# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu +# +# Description: This file is for creating the test programs for libpthread.a +# +# 1.00 93/08/03 proven +# -Initial cut for pthreads. +# + +CC = ../pgcc -notinstalled +srctop = /dr1/my/masters/mysql/mit-pthreads +srcdir = /dr1/my/masters/mysql/mit-pthreads/lib +VPATH = /dr1/my/masters/mysql/mit-pthreads/lib +CDEBUGFLAGS = -g -O2 -Werror + +CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\" + +# +DIRS = finger + +################################################################################ +# +all: + (for i in $(DIRS); do cd $$i; $(MAKE) all; cd ..; done) + +clean: + (for i in $(DIRS); do cd $$i; $(MAKE) clean; cd ..; done) + rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout + +depend: + (for i in $(DIRS); do cd $$i; $(MAKE) depend; cd ..; done) + sed '/\#\#\# Dependencies/q' < Makefile > maketmp + (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp + cp maketmp Makefile + +install: + (for i in $(DIRS); do cd $$i; $(MAKE) install; cd ..; done) + +realclean: clean + (for i in $(DIRS); do cd $$i; $(MAKE) realclean; cd ..; done) + rm -f Makefile + +Makefile: Makefile.in + (cd .. ; sh config.status) + +################################################################################ +### Do not remove the following line. It is for depend ######################### +### Dependencies: diff --git a/lib/libpthread/bin/Makefile.in b/lib/libpthread/bin/Makefile.in new file mode 100644 index 00000000000..979ad2db2ea --- /dev/null +++ b/lib/libpthread/bin/Makefile.in @@ -0,0 +1,48 @@ +# === GNUmakefile ============================================================ +# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu +# +# Description: This file is for creating the test programs for libpthread.a +# +# 1.00 93/08/03 proven +# -Initial cut for pthreads. +# + +CC = ../pgcc -notinstalled +srctop = @srctop@ +srcdir = @srctop@/lib +VPATH = @srctop@/lib +CDEBUGFLAGS = @CFLAGS@ + +CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\" + +# +DIRS = finger + +################################################################################ +# +all: + (for i in $(DIRS); do cd $$i; $(MAKE) all; cd ..; done) + +clean: + (for i in $(DIRS); do cd $$i; $(MAKE) clean; cd ..; done) + rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout + +depend: + (for i in $(DIRS); do cd $$i; $(MAKE) depend; cd ..; done) + sed '/\#\#\# Dependencies/q' < Makefile > maketmp + (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp + cp maketmp Makefile + +install: + (for i in $(DIRS); do cd $$i; $(MAKE) install; cd ..; done) + +realclean: clean + (for i in $(DIRS); do cd $$i; $(MAKE) realclean; cd ..; done) + rm -f Makefile + +Makefile: Makefile.in + (cd .. ; sh config.status) + +################################################################################ +### Do not remove the following line. It is for depend ######################### +### Dependencies: diff --git a/lib/libpthread/bin/finger/Makefile b/lib/libpthread/bin/finger/Makefile new file mode 100644 index 00000000000..8ee4396b758 --- /dev/null +++ b/lib/libpthread/bin/finger/Makefile @@ -0,0 +1,61 @@ +# Generated automatically from Makefile.in by configure. +# === makefile ============================================================ +# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu +# +# Description: This file is for creating the test programs for libpthread.a +# +# 1.00 93/08/03 proven +# -Initial cut for pthreads. +# + +srctop = /dr1/my/masters/mysql/mit-pthreads +srcdir = /dr1/my/masters/mysql/mit-pthreads/bin/finger +VPATH = /dr1/my/masters/mysql/mit-pthreads/bin/finger +prefix= /usr/local/pthreads +exec_prefix= ${prefix} + +INSTALL_PATH = ${prefix} + BINDIR = $(INSTALL_PATH)/bin + LIBDIR = $(INSTALL_PATH)/lib + MANDIR = $(INSTALL_PATH)/man + INCDIR = $(INSTALL_PATH)/include + + CC = ../../pgcc -notinstalled + CDEBUGFLAGS = -g -O2 -Werror + INCLUDES = -I/dr1/my/masters/mysql/mit-pthreads/lib/libpthreadutil/ -L../../lib/libpthreadutil/ + CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\" + RANLIB = ranlib + + OBJS = finger.o net.o + BINARY = finger + +################################################################################ +# +all : $(BINARY) + +clean: + rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout + +depend: + sed '/\#\#\# Dependencies/q' < Makefile > maketmp + (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp + cp maketmp Makefile + +install: $(BINARY) + install $(BINARY) $(BINDIR) + +realclean: clean + rm -f Makefile + +Makefile: Makefile.in + (cd ../.. ; sh config.status) + +.c.o: + $(CC) $(CFLAGS) -c $< + +$(BINARY) : ${OBJS} + $(CC) $(CFLAGS) -o $(BINARY) ${OBJS} -lpthreadutil + +################################################################################ +### Do not remove the following line. It is for depend ######################### +### Dependencies: diff --git a/lib/libpthread/bin/finger/Makefile.in b/lib/libpthread/bin/finger/Makefile.in new file mode 100755 index 00000000000..ee20f47443d --- /dev/null +++ b/lib/libpthread/bin/finger/Makefile.in @@ -0,0 +1,60 @@ +# === makefile ============================================================ +# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu +# +# Description: This file is for creating the test programs for libpthread.a +# +# 1.00 93/08/03 proven +# -Initial cut for pthreads. +# + +srctop = @srctop@ +srcdir = @srctop@/bin/finger +VPATH = @srctop@/bin/finger +prefix= @prefix@ +exec_prefix= @exec_prefix@ + +INSTALL_PATH = @exec_prefix@ + BINDIR = $(INSTALL_PATH)/bin + LIBDIR = $(INSTALL_PATH)/lib + MANDIR = $(INSTALL_PATH)/man + INCDIR = $(INSTALL_PATH)/include + + CC = ../../pgcc -notinstalled + CDEBUGFLAGS = @CFLAGS@ + INCLUDES = -I@srctop@/lib/libpthreadutil/ -L../../lib/libpthreadutil/ + CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\" + RANLIB = @RANLIB@ + + OBJS = finger.o net.o + BINARY = finger + +################################################################################ +# +all : $(BINARY) + +clean: + rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout + +depend: + sed '/\#\#\# Dependencies/q' < Makefile > maketmp + (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp + cp maketmp Makefile + +install: $(BINARY) + install $(BINARY) $(BINDIR) + +realclean: clean + rm -f Makefile + +Makefile: Makefile.in + (cd ../.. ; sh config.status) + +.c.o: + $(CC) $(CFLAGS) -c $< + +$(BINARY) : ${OBJS} + $(CC) $(CFLAGS) -o $(BINARY) ${OBJS} -lpthreadutil + +################################################################################ +### Do not remove the following line. It is for depend ######################### +### Dependencies: diff --git a/lib/libpthread/bin/finger/finger.c b/lib/libpthread/bin/finger/finger.c new file mode 100755 index 00000000000..33b3011e8bb --- /dev/null +++ b/lib/libpthread/bin/finger/finger.c @@ -0,0 +1,231 @@ +/* ==== finger.c ============================================================ + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * 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 Chris Provenzano, + * the University of California, Berkeley and its contributors. + * 4. Neither the name of Chris Provenzano, the University nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO, THE REGENTS 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. + * + * 1.00 93/08/26 proven + * -Pthread redesign of this file. + * + * 1.10 95/02/11 proven + * -Now that gethostbyname works .... + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ + @(#) Copyright (c) 1993, 1995 Chris Provenzano.\n\ + @(#) Copyright (c) 1995 Greg Stark.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#include <pthreadutil.h> +#include <sys/param.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +void *netfinger(); + +void usage(int eval) +{ + fprintf(stderr, + "usage: finger [-lps] [-c <net_count>] [-t|T <timeout>] [-f <filename>] [login ...]\n"); + exit(eval); +} + +/* + * These globals are set initialy and then are only read. + * They do not need mutexes. + */ +int thread_time = 0, program_timeout = 0, lflag = 0; +pthread_tad_t parse_file_tad; +pthread_tad_t netfinger_tad; + +void * timeout_thread(void * arg) +{ + sleep(program_timeout); + exit(0); +} + +void * signal_thread(void * arg) +{ + int sig; + sigset_t program_signals; + sigemptyset(&program_signals); + sigaddset(&program_signals, SIGINT); + sigwait(&program_signals, &sig); + exit(0); +} + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +void * parse_file(void * arg) +{ + char hostname[MAXHOSTNAMELEN]; + char * filename = arg; + pthread_atexit_t atexit_id; + pthread_attr_t attr; + pthread_t thread_id; + char * thread_arg; + FILE * fp; + int len; + + netsetupwait(); + + /* Parse the file and create a thread per connection */ + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "Can't open file %s\n", filename); + pthread_exit(NULL); + } + pthread_atexit_add(&atexit_id, fclose_nrv, fp); + + if (pthread_attr_init(&attr)) { + fprintf(stderr, "Error: Can't initialize thread attributes\n"); + exit(2); + } + pthread_atexit_add(&atexit_id, pthread_attr_destroy_nrv, &attr); + + while (fgets(hostname, MAXHOSTNAMELEN, fp)) { + if ((thread_arg = (char *)malloc(len = strlen(hostname))) == NULL) { + fprintf(stderr, "Error: out of memory\n"); + exit(2); + } + + hostname[len - 1] = '\0'; + strcpy(thread_arg, hostname); + pthread_attr_setcleanup(&attr, free, thread_arg); + if (pthread_tad_create(&netfinger_tad, &thread_id, NULL, + netfinger, thread_arg)) { + fprintf(stderr, "Error: pthread_tad_create() netfinger_tad.\n"); + exit(2); + } + } + pthread_exit(NULL); +} + +main(int argc, char **argv) +{ + pthread_atexit_t atexit_id; + pthread_t thread_id; + int max_count = 0; + char ch; + + /* getopt variables */ + extern char *optarg; + extern int optind; + + /* Setup tad for parse_file() threads */ + if (pthread_tad_init(&parse_file_tad, max_count)) { + fprintf(stderr,"Error: couldn't create parse_file() TAD.\n"); + exit(1); + } + + while ((ch = getopt(argc, argv, "c:f:t:T:ls")) != (char)EOF) + switch(ch) { + case 't': /* Time to let each thread run */ + if ((thread_time = atoi(optarg)) <= 0) { + usage(1); + } + break; + case 'T': /* Time to let entire program run */ + if ((program_timeout = atoi(optarg)) <= 0) { + usage(1); + } + break; + case 'f': /* Parse file for list of places to finger */ + if (pthread_tad_create(&parse_file_tad, &thread_id, NULL, + parse_file, optarg)) { + fprintf(stderr,"Error: pthread_tad_create() parse_file_tad.\n"); + exit(1); + } + break; + case 'c': + max_count = atoi(optarg); + break; + case 'l': /* long format */ + lflag = 1; + break; + case 's': /* short format */ + lflag = 0; + break; + case '?': + usage(0); + default: + usage(1); + } + + /* The rest of the argumants are hosts */ + argc -= optind; + argv += optind; + + /* Setup timeout thread, if there is one */ + if (program_timeout) { + if (pthread_create(&thread_id, NULL, timeout_thread, NULL)) { + fprintf(stderr,"Error: couldn't create program_timeout() thread\n"); + exit(1); + } + } + + /* Setup cleanup thread for signals */ + if (pthread_create(&thread_id, NULL, signal_thread, NULL)) { + fprintf(stderr,"Error: couldn't create signal_timeout() thread\n"); + exit(1); + } + + /* Setup tad for netfinger() threads */ + if (pthread_tad_init(&netfinger_tad, max_count)) { + fprintf(stderr,"Error: couldn't create netfinger() TAD.\n"); + exit(1); + } + + /* Setup the net and let everyone run */ + netsetup(); + + while (*argv) { + if (pthread_tad_create(&netfinger_tad, &thread_id, NULL, + netfinger, *argv)) { + fprintf(stderr, "Error: pthread_tad_create() netfinger_tad.\n"); + exit(2); + } + argv++; + } + pthread_tad_wait(&parse_file_tad, 0); + pthread_tad_wait(&netfinger_tad, 0); + exit(0); +} + diff --git a/lib/libpthread/bin/finger/net.c b/lib/libpthread/bin/finger/net.c new file mode 100755 index 00000000000..77ccd92ee8c --- /dev/null +++ b/lib/libpthread/bin/finger/net.c @@ -0,0 +1,189 @@ +/* ==== net.c ============================================================ + * Copyright (c) 1993, 1995 by Chris Provenzano, proven@athena.mit.edu + * + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + * + * 1.00 93/08/26 proven + * -Pthread redesign of this file. + */ + +#include <pthreadutil.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <stdio.h> +#include <ctype.h> + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif +/* + * These globals are set initialy and then are only read. + * They do not need mutexes. + */ +extern int lflag; +char myhostname[MAXHOSTNAMELEN]; + +/* + * These globals change and therefor do need mutexes + */ +pthread_mutex_t spmutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t spcond = PTHREAD_COND_INITIALIZER; +struct servent *sp = NULL; + +void netsetup(void) +{ + pthread_mutex_lock(&spmutex); + if (sp) { + fprintf(stderr, "finger: service pointer already initialized.\n"); + exit(2); + } + if ((sp = (struct servent *)malloc(sizeof(struct servent) + 4096)) == NULL){ + fprintf(stderr, "finger: Couldn't allocate service pointer.\n"); + exit(2); + } + if (getservbyname_r("finger", "tcp", sp, (char *)sp + sizeof(struct servent), 4096) == NULL) { + fprintf(stderr, "finger: tcp/finger: unknown service\n"); + exit(2); + } + if (gethostname(myhostname, MAXHOSTNAMELEN)) { + fprintf(stderr, "finger: couldn't get my hostname.\n"); + exit(2); + } + pthread_cond_broadcast(&spcond); + pthread_mutex_unlock(&spmutex); +} + +void netsetupwait(void) +{ + pthread_mutex_lock(&spmutex); + while(sp == NULL) { + pthread_cond_wait(&spcond, &spmutex); + } + pthread_mutex_unlock(&spmutex); +} + +void *netfinger(char *name) +{ + pthread_atexit_t atexit_id; + register int c, lastc; + struct in_addr defaddr; + struct hostent *hp; + struct sockaddr_in sin; + int s, i, readbuflen; + char readbuf[1024]; + char *host; + + netsetupwait(); + pthread_atexit_add(&atexit_id, fflush_nrv, NULL); + + if (!(host = strrchr(name, '@'))) { + host = myhostname; + } else { + *host++ = '\0'; + } + if (!(hp = gethostbyname(host))) { + if ((defaddr.s_addr = inet_addr(host)) < 0) { + fprintf(stderr, "[%s] gethostbyname: Unknown host\n", host); + return; + } + } + sin.sin_family = hp->h_addrtype; + memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length); + sin.sin_port = sp->s_port; + + if ((s = socket(sin.sin_family, SOCK_STREAM, 0)) < 0) { + sprintf(readbuf, "[%s]: socket", hp->h_name); + perror(readbuf); + return; + } + + /* have network connection; identify the host connected with */ + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + sprintf(readbuf, "[%s]: connect", hp->h_name); + perror(readbuf); + close(s); + return; + } + + /* -l flag for remote fingerd */ + if (lflag) + write(s, "/W ", 3); + /* send the name followed by <CR><LF> */ + write(s, name, strlen(name)); + write(s, "\r\n", 2); + + /* + * Read from the remote system; once we're connected, we assume some + * data. If none arrives, we hang until the user interrupts, or + * until the thread timeout expires. + * + * If we see a <CR> or a <CR> with the high bit set, treat it as + * a newline; if followed by a newline character, only output one + * newline. + * + * Otherwise, all high bits are stripped; if it isn't printable and + * it isn't a space, we can simply set the 7th bit. Every ASCII + * character with bit 7 set is printable. + */ + for (readbuflen = read(s, readbuf, 1024), flockfile(stdout), lastc = '\n', + printf("[%s]\n", hp->h_name); readbuflen > 0; + readbuflen = read(s, readbuf, 1024)) { + for (i = 0; i < readbuflen; i++) { + c = readbuf[i] & 0x7f; + if (c == 0x0d) { + c = '\n'; + lastc = '\r'; + } else { + if (!isprint(c) && !isspace(c)) + c |= 0x40; + if (lastc != '\r' || c != '\n') + lastc = c; + else { + lastc = '\n'; + continue; + } + } + putchar_unlocked(c); + } + } + if (lastc != '\n') + putchar_unlocked('\n'); + funlockfile(stdout); +} diff --git a/lib/libpthread/lib/Makefile b/lib/libpthread/lib/Makefile new file mode 100644 index 00000000000..3775a11b38e --- /dev/null +++ b/lib/libpthread/lib/Makefile @@ -0,0 +1,49 @@ +# Generated automatically from Makefile.in by configure. +# === GNUmakefile ============================================================ +# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu +# +# Description: This file is for creating the test programs for libpthread.a +# +# 1.00 93/08/03 proven +# -Initial cut for pthreads. +# + +CC = ../pgcc -notinstalled +srctop = /dr1/my/masters/mysql/mit-pthreads +srcdir = /dr1/my/masters/mysql/mit-pthreads/lib +VPATH = /dr1/my/masters/mysql/mit-pthreads/lib +CDEBUGFLAGS = -g -O2 -Werror + +CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\" + +# +DIRS = libpthreadutil + +################################################################################ +# +all: + (for i in $(DIRS); do cd $$i; $(MAKE) all; cd ..; done) + +clean: + (for i in $(DIRS); do cd $$i; $(MAKE) clean; cd ..; done) + rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout + +depend: + (for i in $(DIRS); do cd $$i; $(MAKE) depend; cd ..; done) + sed '/\#\#\# Dependencies/q' < Makefile > maketmp + (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp + cp maketmp Makefile + +install: + (for i in $(DIRS); do cd $$i; $(MAKE) install; cd ..; done) + +realclean: clean + (for i in $(DIRS); do cd $$i; $(MAKE) realclean; cd ..; done) + rm -f Makefile + +Makefile: Makefile.in + (cd .. ; sh config.status) + +################################################################################ +### Do not remove the following line. It is for depend ######################### +### Dependencies: diff --git a/lib/libpthread/lib/Makefile.in b/lib/libpthread/lib/Makefile.in new file mode 100644 index 00000000000..821d293d896 --- /dev/null +++ b/lib/libpthread/lib/Makefile.in @@ -0,0 +1,48 @@ +# === GNUmakefile ============================================================ +# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu +# +# Description: This file is for creating the test programs for libpthread.a +# +# 1.00 93/08/03 proven +# -Initial cut for pthreads. +# + +CC = ../pgcc -notinstalled +srctop = @srctop@ +srcdir = @srctop@/lib +VPATH = @srctop@/lib +CDEBUGFLAGS = @CFLAGS@ + +CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\" + +# +DIRS = libpthreadutil + +################################################################################ +# +all: + (for i in $(DIRS); do cd $$i; $(MAKE) all; cd ..; done) + +clean: + (for i in $(DIRS); do cd $$i; $(MAKE) clean; cd ..; done) + rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout + +depend: + (for i in $(DIRS); do cd $$i; $(MAKE) depend; cd ..; done) + sed '/\#\#\# Dependencies/q' < Makefile > maketmp + (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp + cp maketmp Makefile + +install: + (for i in $(DIRS); do cd $$i; $(MAKE) install; cd ..; done) + +realclean: clean + (for i in $(DIRS); do cd $$i; $(MAKE) realclean; cd ..; done) + rm -f Makefile + +Makefile: Makefile.in + (cd .. ; sh config.status) + +################################################################################ +### Do not remove the following line. It is for depend ######################### +### Dependencies: diff --git a/lib/libpthread/lib/libpthreadutil/Makefile b/lib/libpthread/lib/libpthreadutil/Makefile new file mode 100644 index 00000000000..58bd76446ec --- /dev/null +++ b/lib/libpthread/lib/libpthreadutil/Makefile @@ -0,0 +1,66 @@ +# Generated automatically from Makefile.in by configure. +# === makefile ============================================================ +# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu +# +# Description: This file is for creating the test programs for libpthread.a +# +# 1.00 93/08/03 proven +# -Initial cut for pthreads. +# + +srctop = /dr1/my/masters/mysql/mit-pthreads +srcdir = /dr1/my/masters/mysql/mit-pthreads/lib/libpthreadutil +VPATH = /dr1/my/masters/mysql/mit-pthreads/lib/libpthreadutil +prefix= /usr/local/pthreads +exec_prefix= ${prefix} + +INSTALL_PATH = ${prefix} + BINDIR = $(INSTALL_PATH)/bin + LIBDIR = $(INSTALL_PATH)/lib + MANDIR = $(INSTALL_PATH)/man + INCDIR = $(INSTALL_PATH)/include + + CC = ../../pgcc -notinstalled + CDEBUGFLAGS = -g -O2 -Werror + CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\" + RANLIB = ranlib + + OBJS = pthread_tad.o pthread_atexit.o + LIBRARY = libpthreadutil.a + HEADERS = pthreadutil.h + +################################################################################ +# +all : $(LIBRARY) + +clean: + rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout + +depend: + sed '/\#\#\# Dependencies/q' < Makefile > maketmp + (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp + cp maketmp Makefile + +install: $(LIBRARY) + install $(LIBRARY) $(LIBDIR) + for x in $(HEADERS); \ + do cp $(srcdir)/$$x $(INCDIR); \ + done + +realclean: clean + rm -f Makefile + +Makefile: Makefile.in + (cd ../.. ; sh config.status) + +.c.o: + $(CC) $(CFLAGS) -c $< + +$(LIBRARY) : ${OBJS} + ar r new.a ${OBJS} && \ + $(RANLIB) new.a && \ + mv -f new.a $(LIBRARY) + +################################################################################ +### Do not remove the following line. It is for depend ######################### +### Dependencies: diff --git a/lib/libpthread/lib/libpthreadutil/Makefile.in b/lib/libpthread/lib/libpthreadutil/Makefile.in new file mode 100755 index 00000000000..94034f426b3 --- /dev/null +++ b/lib/libpthread/lib/libpthreadutil/Makefile.in @@ -0,0 +1,65 @@ +# === makefile ============================================================ +# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu +# +# Description: This file is for creating the test programs for libpthread.a +# +# 1.00 93/08/03 proven +# -Initial cut for pthreads. +# + +srctop = @srctop@ +srcdir = @srctop@/lib/libpthreadutil +VPATH = @srctop@/lib/libpthreadutil +prefix= @prefix@ +exec_prefix= @exec_prefix@ + +INSTALL_PATH = @exec_prefix@ + BINDIR = $(INSTALL_PATH)/bin + LIBDIR = $(INSTALL_PATH)/lib + MANDIR = $(INSTALL_PATH)/man + INCDIR = $(INSTALL_PATH)/include + + CC = ../../pgcc -notinstalled + CDEBUGFLAGS = @CFLAGS@ + CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\" + RANLIB = @RANLIB@ + + OBJS = pthread_tad.o pthread_atexit.o + LIBRARY = libpthreadutil.a + HEADERS = pthreadutil.h + +################################################################################ +# +all : $(LIBRARY) + +clean: + rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout + +depend: + sed '/\#\#\# Dependencies/q' < Makefile > maketmp + (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp + cp maketmp Makefile + +install: $(LIBRARY) + install $(LIBRARY) $(LIBDIR) + for x in $(HEADERS); \ + do cp $(srcdir)/$$x $(INCDIR); \ + done + +realclean: clean + rm -f Makefile + +Makefile: Makefile.in + (cd ../.. ; sh config.status) + +.c.o: + $(CC) $(CFLAGS) -c $< + +$(LIBRARY) : ${OBJS} + ar r new.a ${OBJS} && \ + $(RANLIB) new.a && \ + mv -f new.a $(LIBRARY) + +################################################################################ +### Do not remove the following line. It is for depend ######################### +### Dependencies: diff --git a/lib/libpthread/lib/libpthreadutil/pthread_atexit.c b/lib/libpthread/lib/libpthreadutil/pthread_atexit.c new file mode 100755 index 00000000000..1d1e1ec3a6d --- /dev/null +++ b/lib/libpthread/lib/libpthreadutil/pthread_atexit.c @@ -0,0 +1,135 @@ +/* ==== pthread_atexit.c ===================================================== + * Copyright (c) 1994 by Chris Provenzano, proven@mit.edu + * 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 Chris Provenzano. + * 4. The name of Chris Provenzano may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``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 CHRIS PROVENZANO 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. + * + * Description : Pthread attribute functions. + * + * 1.20 94/02/13 proven + * -Started coding this file. + */ + +#ifndef lint +static const char rcsid[] = "$Id: pthread_atexit.c,v 1.1 1998/07/21 13:22:22 peter Exp $"; +#endif + +#define PTHREAD_KERNEL + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include "pthreadutil.h" + +static int pthread_atexit_inited = 0; +static pthread_key_t pthread_atexit_key; +static pthread_mutex_t pthread_atexit_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* ========================================================================== + * pthread_atexit_done() + */ +static void pthread_atexit_done(void * arg) +{ + pthread_atexit_t id, id_next; + + for (id = arg; id; id = id_next) { + id_next = id->next; + id->rtn(id->arg); + free(id); + } +} + +/* ========================================================================== + * pthread_atexit_add() + */ +int pthread_atexit_add(pthread_atexit_t *id, void (*rtn)(void *), void * arg) +{ + int ret; + + if (ret = pthread_mutex_lock(&pthread_atexit_mutex)) { + return(ret); + } + if (!pthread_atexit_inited) { + if (ret = pthread_key_create(&pthread_atexit_key, pthread_atexit_done)){ + pthread_mutex_unlock(&pthread_atexit_mutex); + return(ret); + } + pthread_atexit_inited++; + } + pthread_mutex_unlock(&pthread_atexit_mutex); + + if ((*id) = (pthread_atexit_t)malloc(sizeof(struct pthread_atexit))) { + if ((*id)->next = pthread_getspecific(pthread_atexit_key)) { + (*id)->next->prev = (*id); + } + pthread_setspecific(pthread_atexit_key, (void *)*id); + (*id)->prev = NULL; + (*id)->rtn = rtn; + (*id)->arg = arg; + return(OK); + } + return(ENOMEM); +} + +/* ========================================================================== + * pthread_atexit_remove() + */ +int pthread_atexit_remove(pthread_atexit_t * id, int execute) +{ + pthread_atexit_t old; + + if (old = pthread_getspecific(pthread_atexit_key)) { + if (old == *id) { + old = old->next; + old->prev = NULL; + pthread_setspecific(pthread_atexit_key, old); + } else { + if ((*id)->next) { + (*id)->next->prev = (*id)->prev; + } + (*id)->prev->next = (*id)->next; + } + if (execute) { + (*id)->rtn((*id)->arg); + } + free((*id)); + return(OK); + } + return(EINVAL); +} + +/* ========================================================================== + * A few non void functions that are often used as void functions + */ +void fflush_nrv(void * fp) { fflush((FILE *)fp); } +void fclose_nrv(void * fp) { fclose((FILE *)fp); } + +void pthread_attr_destroy_nrv(void * attr) +{ + pthread_attr_destroy((pthread_attr_t *)attr); +} diff --git a/lib/libpthread/lib/libpthreadutil/pthread_tad.c b/lib/libpthread/lib/libpthreadutil/pthread_tad.c new file mode 100755 index 00000000000..a59fd9b87bf --- /dev/null +++ b/lib/libpthread/lib/libpthreadutil/pthread_tad.c @@ -0,0 +1,170 @@ +/* ==== pthread_tad.c ========================================================= + * Copyright (c) 1995 by Chris Provenzano, proven@athena.mit.edu + * + * 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 Chris Provenzano, + * and its contributors. + * 4. Neither the name of Chris Provenzano, nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO, 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 lint +static char copyright[] = + "@(#) Copyright (c) 1995 Chris Provenzano.\nAll rights reserved.\n"; +#endif /* not lint */ + +/* tad = thread allocation domain */ +#define PTHREAD_KERNEL + +#include "pthreadutil.h" +#include <stdio.h> +#include <errno.h> + +int pthread_tad_count(pthread_tad_t * tad) +{ + int ret; + + pthread_mutex_lock(&tad->mutex); + ret = tad->count_current; + pthread_mutex_unlock(&tad->mutex); + return(ret); +} + +static void pthread_tad_done(void * arg) +{ + pthread_tad_t * tad = arg; + pthread_mutex_lock(&tad->mutex); + --tad->count_current; +/* if (--tad->count_current < tad->count_max) */ + pthread_cond_broadcast(&tad->cond); + pthread_mutex_unlock(&tad->mutex); +} + +#ifndef PTHREAD_KERNEL +struct tad_start { + pthread_tad_t * tad; + void * (*routine)(); + void * arg; +}; + +static void * pthread_tad_start(struct tad_start * tad_start) +{ + void * (*routine)() = tad_start->routine; + void * arg = tad_start->arg; + + pthread_mutex_lock(&tad_start->tad->mutex); + pthread_cleanup_push(pthread_tad_done, tad_start->tad); + pthread_mutex_unlock(&tad_start->tad->mutex); + free(tad_start); + return(routine(arg)); +} +#else +static void * pthread_tad_start(void * tad_start_arg) +{ + pthread_tad_t * tad = tad_start_arg; + void * (*routine)() = tad->routine; + void * arg = tad->arg; + + tad->count_current++; + pthread_cleanup_push(pthread_tad_done, tad); + pthread_mutex_unlock(&tad->mutex); + return(routine(arg)); +} +#endif + +int pthread_tad_create(pthread_tad_t * tad, pthread_t *thread_id, + pthread_attr_t *attr, void * (*routine)(), void * arg) +{ +#ifndef PTHREAD_KERNEL + struct tad_start tad; +#endif + int ret; + + pthread_mutex_lock(&tad->mutex); + while (tad->count_max && (tad->count_current > tad->count_max)) + pthread_cond_wait(&tad->cond, &tad->mutex); + +#ifndef PTHREAD_KERNEL + if ((tad_start = malloc(sizeof(struct tad_start))) == NULL) { + pthread_mutex_unlock(&tad->mutex); + return(ENOMEM); + } + tad_start->routine = routine; + tad_start->arg = arg; + tad_start->tad = tad; + if ((ret = pthread_create(thread_id, attr, + pthread_tad_start, tad_start)) == OK) + tad->count_current++; + pthread_mutex_unlock(&tad->mutex); +#else + tad->routine = routine; + tad->arg = arg; + if (ret = pthread_create(thread_id, attr, pthread_tad_start, tad)) + pthread_mutex_unlock(&tad->mutex); +#endif + return(ret); +} + +int pthread_tad_wait(pthread_tad_t * tad, unsigned int count) +{ + if ((tad->count_max) && (tad->count_max < count)) { + return(EINVAL); + } + pthread_mutex_lock(&tad->mutex); + while (tad->count_current > count) + pthread_cond_wait(&tad->cond, &tad->mutex); + pthread_mutex_unlock(&tad->mutex); + return(OK); +} + +int pthread_tad_init(pthread_tad_t * tad, unsigned int max_count) +{ + int ret; + + if ((ret = pthread_mutex_init(&tad->mutex, NULL)) == OK) { + if (ret = pthread_cond_init(&tad->cond, NULL)) { + pthread_mutex_destroy(&tad->mutex); + } else { + tad->count_max = max_count; + tad->count_current = 0; + } + } + return(ret); +} + +/* User is responsible to make sure their are no threads running */ +int pthread_tad_destroy(pthread_tad_t * tad) +{ + int ret; + + if ((ret = pthread_mutex_destroy(&tad->mutex)) == OK) { + ret = pthread_cond_destroy(&tad->cond); + } else { + pthread_cond_destroy(&tad->cond); + } + tad->count_max = NOTOK; + return(ret); +} diff --git a/lib/libpthread/lib/libpthreadutil/pthreadutil.h b/lib/libpthread/lib/libpthreadutil/pthreadutil.h new file mode 100644 index 00000000000..0d8e6a6ef5f --- /dev/null +++ b/lib/libpthread/lib/libpthreadutil/pthreadutil.h @@ -0,0 +1,75 @@ +/* ==== pthread_tad.h ======================================================== + * Copyright (c) 1995 by Chris Provenzano, proven@athena.mit.edu + * + * 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 Chris Provenzano, + * and its contributors. + * 4. Neither the name of Chris Provenzano, nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO, 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 <pthread.h> +#include <sys/cdefs.h> + +typedef struct pthread_tad_t { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned int count_current; + unsigned int count_max; + void * arg; + void * (*routine)(); +} pthread_tad_t; + +typedef struct pthread_atexit { + struct pthread_atexit * next; + struct pthread_atexit * prev; + void (*rtn)(void *); + void * arg; +} * pthread_atexit_t; + +/* + * New functions + */ + +__BEGIN_DECLS + +int pthread_tad_count __P_((pthread_tad_t *)); +int pthread_tad_create __P_((pthread_tad_t *, pthread_t *, pthread_attr_t *, + void *(*routine)(), void *)); +int pthread_tad_wait __P_((pthread_tad_t *, unsigned int)); +int pthread_tad_init __P_((pthread_tad_t *, unsigned int)); +int pthread_tad_destroy __P_((pthread_tad_t *)); + +int pthread_atexit_add __P_((pthread_atexit_t *, void (*)(void *), void *)); +int pthread_atexit_remove __P_((pthread_atexit_t *, int)); + + +void fclose_nrv __P_((void *)); +void fflush_nrv __P_((void *)); +void pthread_attr_destroy_nrv __P_((void *)); + +__END_DECLS + diff --git a/lib/libpthread/patches/Streepy.html b/lib/libpthread/patches/Streepy.html new file mode 100755 index 00000000000..a3b4faa815f --- /dev/null +++ b/lib/libpthread/patches/Streepy.html @@ -0,0 +1,2873 @@ +diff -c -r1.1.1.1 pthread.h +*** pthread.h 1996/03/13 04:30:57 1.1.1.1 +--- pthread.h 1996/10/02 17:52:47 +*************** +*** 35,40 **** +--- 35,43 ---- + * + * 1.00 93/07/20 proven + * -Started coding this file. ++ * ++ * 93/9/28 streepy - Added support for pthread cancel ++ * + */ + + #ifndef _PTHREAD_H_ +*************** +*** 65,70 **** +--- 68,82 ---- + /* More includes, that need size_t */ + #include <pthread/pthread_attr.h> + ++ /* Constants for use with pthread_setcancelstate and pthread_setcanceltype */ ++ #define PTHREAD_CANCEL_DISABLE 0 ++ #define PTHREAD_CANCEL_ENABLE 1 ++ #define PTHREAD_CANCEL_DEFERRED 0 ++ #define PTHREAD_CANCEL_ASYNCHRONOUS 1 ++ ++ #define PTHREAD_CANCELLED (void *)1 /* Exit status of a cancelled thread */ ++ ++ + #ifdef PTHREAD_KERNEL + + #include <signal.h> /* for sigset_t */ +*************** +*** 78,120 **** + PS_STATE_MAX + }; + +- #define PF_WAIT_EVENT 0x01 +- #define PF_DONE_EVENT 0x02 +- + /* Put PANIC inside an expression that evaluates to non-void type, to + make it easier to combine it in expressions. */ +! #define DO_PANIC() (PANIC (), 0) +! #define PANICIF(x) ((x) ? DO_PANIC () : 0) + +! #define SET_PF_DONE_EVENT(x) \ +! ( !(x->flags & PF_DONE_EVENT) \ +! ? ( (x->flags & PF_WAIT_EVENT) \ +! ? (x->flags = PF_DONE_EVENT, OK) \ +! : DO_PANIC ()) \ + : NOTOK ) + +! #define SET_PF_WAIT_EVENT(x) \ +! ( PANICIF (x->flags & (PF_WAIT_EVENT | PF_DONE_EVENT)), \ +! (x->flags = PF_WAIT_EVENT), 0) +! +! #define CLEAR_PF_DONE_EVENT(x) \ +! ( PANICIF (!(x->flags & PF_DONE_EVENT)), \ +! x->flags = 0 ) + + struct pthread_select_data { +! int nfds; +! fd_set readfds; +! fd_set writefds; +! fd_set exceptfds; + }; + + union pthread_wait_data { +! pthread_mutex_t * mutex; +! pthread_cond_t * cond; +! const sigset_t * sigwait; /* Waiting on a signal in sigwait */ + struct { +! short fd; /* Used when thread waiting on fd */ +! short branch; /* line number, for debugging */ + } fd; + struct pthread_select_data * select_data; + }; +--- 90,185 ---- + PS_STATE_MAX + }; + + /* Put PANIC inside an expression that evaluates to non-void type, to + make it easier to combine it in expressions. */ +! #define DO_PANIC() (PANIC (), 0) +! #define PANICIF(x) ((x) ? DO_PANIC () : 0) +! +! /* In the thread flag field, we use a series of bit flags. Flags can +! * organized into "groups" of mutually exclusive flags. Other flags +! * are unrelated and can be set and cleared with a single bit operation. +! */ + +! #define PF_WAIT_EVENT 0x01 +! #define PF_DONE_EVENT 0x02 +! #define PF_EVENT_GROUP 0x03 /* All event bits */ +! +! #define PF_CANCEL_STATE 0x04 /* cancellability state */ +! #define PF_CANCEL_TYPE 0x08 /* cancellability type */ +! #define PF_THREAD_CANCELLED 0x10 /* thread has been cancelled */ +! #define PF_RUNNING_TO_CANCEL 0x20 /* Thread is running so it can cancel*/ +! #define PF_AT_CANCEL_POINT 0x40 /* Thread is at a cancel point */ +! +! /* Flag operations */ +! +! #define SET_PF_FLAG(x,f) ( (x)->flags |= (f) ) +! #define TEST_PF_FLAG(x,f) ( (x)->flags & (f) ) +! #define CLEAR_PF_FLAG(x,f) ( (x)->flags &= ~(f) ) +! #define CLEAR_PF_GROUP(x,g) ( (x)->flags &= ~(g) ) +! #define SET_PF_FLAG_IN_GROUP(x,g,f) ( CLEAR_PF_GROUP(x,g),SET_PF_FLAG(x,f)) +! #define TEST_PF_GROUP(x,g) ( (x)->flags & (g) ) +! +! #define SET_PF_DONE_EVENT(x) \ +! ( !TEST_PF_FLAG(x,PF_DONE_EVENT) \ +! ? ( TEST_PF_FLAG(x,PF_WAIT_EVENT) \ +! ? (SET_PF_FLAG_IN_GROUP(x,PF_EVENT_GROUP,PF_DONE_EVENT), OK) \ +! : DO_PANIC ()) \ + : NOTOK ) + +! #define SET_PF_WAIT_EVENT(x) \ +! ( PANICIF (TEST_PF_GROUP(x,PF_EVENT_GROUP) ), \ +! SET_PF_FLAG_IN_GROUP(x,PF_EVENT_GROUP,PF_WAIT_EVENT), 0) +! +! #define CLEAR_PF_DONE_EVENT(x) \ +! ( PANICIF (!TEST_PF_FLAG(x,PF_DONE_EVENT)), \ +! CLEAR_PF_GROUP(x,PF_EVENT_GROUP) ) +! +! #define SET_PF_CANCELLED(x) ( SET_PF_FLAG(x,PF_THREAD_CANCELLED) ) +! #define TEST_PF_CANCELLED(x) ( TEST_PF_FLAG(x,PF_THREAD_CANCELLED) ) +! +! #define SET_PF_RUNNING_TO_CANCEL(x) ( SET_PF_FLAG(x,PF_RUNNING_TO_CANCEL) ) +! #define CLEAR_PF_RUNNING_TO_CANCEL(x)( CLEAR_PF_FLAG(x,PF_RUNNING_TO_CANCEL) ) +! #define TEST_PF_RUNNING_TO_CANCEL(x)( TEST_PF_FLAG(x,PF_RUNNING_TO_CANCEL) ) +! +! #define SET_PF_AT_CANCEL_POINT(x) ( SET_PF_FLAG(x,PF_AT_CANCEL_POINT) ) +! #define CLEAR_PF_AT_CANCEL_POINT(x) ( CLEAR_PF_FLAG(x,PF_AT_CANCEL_POINT) ) +! #define TEST_PF_AT_CANCEL_POINT(x) ( TEST_PF_FLAG(x,PF_AT_CANCEL_POINT) ) +! +! #define SET_PF_CANCEL_STATE(x,f) \ +! ( (f) ? SET_PF_FLAG(x,PF_CANCEL_STATE) : CLEAR_PF_FLAG(x,PF_CANCEL_STATE) ) +! #define TEST_PF_CANCEL_STATE(x) \ +! ( (TEST_PF_FLAG(x,PF_CANCEL_STATE)) ? PTHREAD_CANCEL_ENABLE \ +! : PTHREAD_CANCEL_DISABLE ) +! +! #define SET_PF_CANCEL_TYPE(x,f) \ +! ( (f) ? SET_PF_FLAG(x,PF_CANCEL_TYPE) : CLEAR_PF_FLAG(x,PF_CANCEL_TYPE) ) +! #define TEST_PF_CANCEL_TYPE(x) \ +! ( (TEST_PF_FLAG(x,PF_CANCEL_TYPE)) ? PTHREAD_CANCEL_ASYNCHRONOUS \ +! : PTHREAD_CANCEL_DEFERRED ) +! +! /* See if a thread is in a state that it can be cancelled */ +! #define TEST_PTHREAD_IS_CANCELLABLE(x) \ +! ( (TEST_PF_CANCEL_STATE(x) == PTHREAD_CANCEL_ENABLE && TEST_PF_CANCELLED(x)) \ +! ? ((TEST_PF_CANCEL_TYPE(x) == PTHREAD_CANCEL_ASYNCHRONOUS) \ +! ? 1 \ +! : TEST_PF_AT_CANCEL_POINT(x)) \ +! : 0 ) +! + + struct pthread_select_data { +! int nfds; +! fd_set readfds; +! fd_set writefds; +! fd_set exceptfds; + }; + + union pthread_wait_data { +! pthread_mutex_t * mutex; +! pthread_cond_t * cond; +! const sigset_t * sigwait; /* Waiting on a signal in sigwait */ + struct { +! short fd; /* Used when thread waiting on fd */ +! short branch; /* line number, for debugging */ + } fd; + struct pthread_select_data * select_data; + }; +*************** +*** 122,143 **** + #define PTT_USER_THREAD 0x0001 + + struct pthread { +! int thread_type; + struct machdep_pthread machdep_data; +! pthread_attr_t attr; + + /* Signal interface */ +! sigset_t sigmask; +! sigset_t sigpending; +! int sigcount; /* Number of signals pending */ + + /* Timeout time */ +! struct timespec wakeup_time; + + /* Join queue for waiting threads */ + struct pthread_queue join_queue; + +- + /* + * Thread implementations are just multiple queue type implemenations, + * Below are the various link lists currently necessary +--- 187,207 ---- + #define PTT_USER_THREAD 0x0001 + + struct pthread { +! int thread_type; + struct machdep_pthread machdep_data; +! pthread_attr_t attr; + + /* Signal interface */ +! sigset_t sigmask; +! sigset_t sigpending; +! int sigcount; /* Number of signals pending */ + + /* Timeout time */ +! struct timespec wakeup_time; + + /* Join queue for waiting threads */ + struct pthread_queue join_queue; + + /* + * Thread implementations are just multiple queue type implemenations, + * Below are the various link lists currently necessary +*************** +*** 152,165 **** + * ALL threads, in any state. + * Must lock kernel lock before manipulating. + */ +! struct pthread * pll; + + /* + * Standard link list for running threads, mutexes, etc ... + * It can't be on both a running link list and a wait queue. + * Must lock kernel lock before manipulating. + */ +! struct pthread * next; + union pthread_wait_data data; + + /* +--- 216,229 ---- + * ALL threads, in any state. + * Must lock kernel lock before manipulating. + */ +! struct pthread * pll; + + /* + * Standard link list for running threads, mutexes, etc ... + * It can't be on both a running link list and a wait queue. + * Must lock kernel lock before manipulating. + */ +! struct pthread * next; + union pthread_wait_data data; + + /* +*************** +*** 167,197 **** + * (Note: "priority" is a reserved word in Concurrent C, please + * don't use it. --KR) + */ +! struct pthread_queue * queue; +! enum pthread_state state; +! char flags; +! char pthread_priority; + + /* + * Sleep queue, this is different from the standard link list + * because it is possible to be on both (pthread_cond_timedwait(); + * Must lock sleep mutex before manipulating + */ +! struct pthread *sll; /* For sleeping threads */ + + /* + * Data that doesn't need to be locked +! * Mostly it's because only the thread owning the data can manipulate it + */ +! void * ret; +! int error; +! int * error_p; +! const void ** specific_data; +! int specific_data_count; + + /* Cleanup handlers Link List */ + struct pthread_cleanup *cleanup; +- + }; + + #else /* not PTHREAD_KERNEL */ +--- 231,261 ---- + * (Note: "priority" is a reserved word in Concurrent C, please + * don't use it. --KR) + */ +! struct pthread_queue * queue; +! enum pthread_state state; +! enum pthread_state old_state; /* Used when cancelled */ +! char flags; +! char pthread_priority; + + /* + * Sleep queue, this is different from the standard link list + * because it is possible to be on both (pthread_cond_timedwait(); + * Must lock sleep mutex before manipulating + */ +! struct pthread *sll; /* For sleeping threads */ + + /* + * Data that doesn't need to be locked +! * Mostly because only the thread owning the data can manipulate it + */ +! void * ret; +! int error; +! int * error_p; +! const void ** specific_data; +! int specific_data_count; + + /* Cleanup handlers Link List */ + struct pthread_cleanup *cleanup; + }; + + #else /* not PTHREAD_KERNEL */ +*************** +*** 200,223 **** + + #endif + +! typedef struct pthread * pthread_t; + + /* + * Globals + */ + #ifdef PTHREAD_KERNEL + +! extern struct pthread * pthread_run; +! extern struct pthread * pthread_initial; +! extern struct pthread * pthread_link_list; + extern struct pthread_queue pthread_dead_queue; + extern struct pthread_queue pthread_alloc_queue; + +! extern pthread_attr_t pthread_attr_default; +! extern volatile int fork_lock; +! extern pthread_size_t pthread_pagesize; +! +! extern sigset_t * uthread_sigmask; + + #endif + +--- 264,293 ---- + + #endif + +! typedef struct pthread *pthread_t; + + /* + * Globals + */ + #ifdef PTHREAD_KERNEL + +! extern struct pthread * pthread_run; +! extern struct pthread * pthread_initial; +! extern struct pthread * pthread_link_list; + extern struct pthread_queue pthread_dead_queue; + extern struct pthread_queue pthread_alloc_queue; + +! extern pthread_attr_t pthread_attr_default; +! extern volatile int fork_lock; +! extern pthread_size_t pthread_pagesize; +! +! extern sigset_t * uthread_sigmask; +! +! /* Kernel global functions */ +! extern void pthread_sched_prevent(void); +! extern void pthread_sched_resume(void); +! extern int __pthread_is_valid( pthread_t ); +! extern void pthread_cancel_internal( int freelocks ); + + #endif + +*************** +*** 229,271 **** + + #if defined(DCE_COMPAT) + +! typedef void * (*pthread_startroutine_t)(void *) +! typedef void * pthread_addr_t + +! int pthread_create __P((pthread_t *, pthread_attr_t, +! pthread_startroutine_t, +! pthread_addr_t)); +! void pthread_exit __P((pthread_addr_t)); +! int pthread_join __P((pthread_t, pthread_addr_t *)); + + #else + +! void pthread_init __P((void)); +! int pthread_create __P((pthread_t *, +! const pthread_attr_t *, +! void * (*start_routine)(void *), +! void *)); +! void pthread_exit __P((void *)); +! pthread_t pthread_self __P((void)); +! int pthread_equal __P((pthread_t, pthread_t)); +! int pthread_join __P((pthread_t, void **)); +! int pthread_detach __P((pthread_t)); +! void pthread_yield __P((void)); +! +! int pthread_setschedparam __P((pthread_t pthread, int policy, +! struct sched_param * param)); +! int pthread_getschedparam __P((pthread_t pthread, int * policy, +! struct sched_param * param)); +! +! int pthread_kill __P((struct pthread *, int)); +! int pthread_signal __P((int, void (*)(int))); + + #endif + + #if defined(PTHREAD_KERNEL) + + /* Not valid, but I can't spell so this will be caught at compile time */ +! #define pthread_yeild(notvalid) + + #endif + +--- 299,343 ---- + + #if defined(DCE_COMPAT) + +! typedef void * (*pthread_startroutine_t)(void *); +! typedef void * pthread_addr_t; + +! int pthread_create __P((pthread_t *, pthread_attr_t, +! pthread_startroutine_t, pthread_addr_t)); +! void pthread_exit __P((pthread_addr_t)); +! int pthread_join __P((pthread_t, pthread_addr_t *)); + + #else + +! void pthread_init __P((void)); +! int pthread_create __P((pthread_t *, const pthread_attr_t *, +! void * (*start_routine)(void *), void *)); +! void pthread_exit __P((void *)); +! pthread_t pthread_self __P((void)); +! int pthread_equal __P((pthread_t, pthread_t)); +! int pthread_join __P((pthread_t, void **)); +! int pthread_detach __P((pthread_t)); +! void pthread_yield __P((void)); +! +! int pthread_setschedparam __P((pthread_t pthread, int policy, +! struct sched_param * param)); +! int pthread_getschedparam __P((pthread_t pthread, int * policy, +! struct sched_param * param)); +! +! int pthread_kill __P((struct pthread *, int)); +! int pthread_signal __P((int, void (*)(int))); +! +! int pthread_cancel __P(( pthread_t pthread )); +! int pthread_setcancelstate __P(( int state, int *oldstate )); +! int pthread_setcanceltype __P(( int type, int *oldtype )); +! void pthread_testcancel __P(( void )); + + #endif + + #if defined(PTHREAD_KERNEL) + + /* Not valid, but I can't spell so this will be caught at compile time */ +! #define pthread_yeild(notvalid) + + #endif + +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/include/signal.h,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 signal.h +*** signal.h 1995/12/25 03:03:09 1.1.1.1 +--- signal.h 1996/09/26 21:46:04 +*************** +*** 43,48 **** +--- 43,49 ---- + __BEGIN_DECLS + + int raise __P((int)); ++ __sighandler_t signal __P((int __sig, __sighandler_t)); + + #ifndef _ANSI_SOURCE + +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/include/pthread/kernel.h,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 kernel.h +*** kernel.h 1994/12/13 07:09:01 1.1.1.1 +--- kernel.h 1996/10/02 19:08:41 +*************** +*** 42,48 **** + */ + #if defined(PTHREAD_KERNEL) + +! #define PANIC() abort() + + /* Time each rr thread gets */ + #define PTHREAD_RR_TIMEOUT 100000000 +--- 42,54 ---- + */ + #if defined(PTHREAD_KERNEL) + +! #ifdef __GNUC__ +! #include <assert.h> +! #define PANIC() panic_kernel( __FILE__, __LINE__, __ASSERT_FUNCTION ) +! #else +! #define PANIC() panic_kernel( __FILE__, __LINE__, (const char *)0 ) +! #endif +! + + /* Time each rr thread gets */ + #define PTHREAD_RR_TIMEOUT 100000000 +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/machdep/syscall-i386-linux-1.0.S,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 syscall-i386-linux-1.0.S +*** syscall-i386-linux-1.0.S 1995/09/27 04:38:55 1.1.1.1 +--- syscall-i386-linux-1.0.S 1996/06/04 19:20:17 +*************** +*** 147,154 **** + + /* ========================================================================= + * exit 1 select 82 +! * fork 2 socketcall 102 +! * read 3 + * write 4 + * open 5 + * creat 8 +--- 147,154 ---- + + /* ========================================================================= + * exit 1 select 82 +! * fork 2 fstatfs 100 +! * read 3 socketcall 102 + * write 4 + * open 5 + * creat 8 +*************** +*** 160,166 **** + * chown 16 + * lseek 19 + * rename 38 +! * dup 41 + * pipe 42 + * ioctl 54 + * fcntl 55 +--- 160,166 ---- + * chown 16 + * lseek 19 + * rename 38 +! * dup 41 + * pipe 42 + * ioctl 54 + * fcntl 55 +*************** +*** 302,314 **** + #endif + + /* ========================================================================== +! * machdep_sys_fstat() + */ + #ifdef __ELF__ + STATCALL2(lstat) + #else + SYSCALL2(lstat) + #endif + + /* ========================================================================== + * machdep_sys_ftruncate() +--- 302,320 ---- + #endif + + /* ========================================================================== +! * machdep_sys_lstat() + */ + #ifdef __ELF__ + STATCALL2(lstat) + #else + SYSCALL2(lstat) + #endif ++ ++ /* ========================================================================== ++ * machdep_sys_fstatfs() ++ */ ++ SYSCALL2(fstatfs) ++ + + /* ========================================================================== + * machdep_sys_ftruncate() +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/machdep/linux-1.0/socket.h,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 socket.h +*** socket.h 1995/12/26 02:28:03 1.1.1.1 +--- socket.h 1996/09/27 18:12:45 +*************** +*** 26,32 **** + + #endif + +! /* #include <asm/socket.h> /* arch-dependent defines */ + #include <linux/sockios.h> /* the SIOCxxx I/O controls */ + #include <pthread/posix.h> + +--- 26,32 ---- + + #endif + +! /* #include <asm/socket.h> arch-dependent defines */ + #include <linux/sockios.h> /* the SIOCxxx I/O controls */ + #include <pthread/posix.h> + +*************** +*** 161,166 **** +--- 161,188 ---- + int connect __P((int, const struct sockaddr *, int)); + int listen __P((int, int)); + int socket __P((int, int, int)); ++ ++ int getsockopt __P ((int __s, int __level, int __optname, ++ void *__optval, int *__optlen)); ++ int setsockopt __P ((int __s, int __level, int __optname, ++ __const void *__optval, int optlen)); ++ int getsockname __P ((int __sockfd, struct sockaddr *__addr, ++ int *__paddrlen)); ++ int getpeername __P ((int __sockfd, struct sockaddr *__peer, ++ int *__paddrlen)); ++ ssize_t send __P ((int __sockfd, __const void *__buff, size_t __len, int __flags)); ++ ssize_t recv __P ((int __sockfd, void *__buff, size_t __len, int __flags)); ++ ssize_t sendto __P ((int __sockfd, __const void *__buff, size_t __len, ++ int __flags, __const struct sockaddr *__to, ++ int __tolen)); ++ ssize_t recvfrom __P ((int __sockfd, void *__buff, size_t __len, ++ int __flags, struct sockaddr *__from, ++ int *__fromlen)); ++ extern ssize_t sendmsg __P ((int __fd, __const struct msghdr *__message, ++ int __flags)); ++ extern ssize_t recvmsg __P ((int __fd, struct msghdr *__message, ++ int __flags)); ++ int shutdown __P ((int __sockfd, int __how)); + + __END_DECLS + +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/machdep/linux-1.0/timers.h,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 timers.h +*** timers.h 1996/03/05 08:28:36 1.1.1.1 +--- timers.h 1996/05/25 21:30:08 +*************** +*** 43,52 **** +--- 43,54 ---- + #include <sys/types.h> + #include <time.h> + ++ #ifndef _LINUX_TIME_H + struct timespec { + time_t tv_sec; + long tv_nsec; + }; ++ #endif /* _LINUX_TIME_H */ + + #define TIMEVAL_TO_TIMESPEC(tv, ts) { \ + (ts)->tv_sec = (tv)->tv_sec; \ +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/net/getprotoent.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 getprotoent.c +*** getprotoent.c 1996/02/09 05:39:41 1.1.1.1 +--- getprotoent.c 1996/05/27 01:11:27 +*************** +*** 128,135 **** + if (p != NULL) + *p++ = '\0'; + } +! if (p && *p); +! break; + } + *alias = NULL; + pthread_mutex_unlock(&proto_file_lock); +--- 128,135 ---- + if (p != NULL) + *p++ = '\0'; + } +! if (p && *p) +! break; + } + *alias = NULL; + pthread_mutex_unlock(&proto_file_lock); +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/net/proto_internal.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 proto_internal.c +*** proto_internal.c 1996/02/09 05:39:49 1.1.1.1 +--- proto_internal.c 1996/06/04 16:25:57 +*************** +*** 49,55 **** + static int init_status; + + /* Performs global initialization. */ +! char *_proto_init() + { + char *buf; + +--- 49,55 ---- + static int init_status; + + /* Performs global initialization. */ +! char *_proto_buf() + { + char *buf; + +*************** +*** 75,78 **** + { + init_status = pthread_key_create(&key, free); + } +- +--- 75,77 ---- +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/net/res_internal.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 res_internal.c +*** res_internal.c 1996/02/09 05:39:53 1.1.1.1 +--- res_internal.c 1996/09/25 23:31:11 +*************** +*** 144,149 **** +--- 144,150 ---- + break; + cp += n; + result->h_name = bp; ++ bp += strlen(bp) + 1; + iquery_done = 1; + break; + } +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/GNUmakefile.inc,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 GNUmakefile.inc +*** GNUmakefile.inc 1995/08/30 22:27:04 1.1.1.1 +--- GNUmakefile.inc 1996/10/02 19:04:29 +*************** +*** 8,14 **** + syscall.S pthread_join.c pthread_detach.c pthread_once.c sleep.c \ + specific.c process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \ + pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \ +! dump_state.c pthread_kill.c stat.c readv.c writev.c condattr.c $(SRCS) + + ifeq ($(HAVE_SYSCALL_TEMPLATE),yes) + SYSCALL_FILTER_RULE= for s in $(AVAILABLE_SYSCALLS) ; do \ +--- 8,15 ---- + syscall.S pthread_join.c pthread_detach.c pthread_once.c sleep.c \ + specific.c process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \ + pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \ +! dump_state.c pthread_kill.c stat.c readv.c writev.c condattr.c \ +! pthread_cancel.c panic.c $(SRCS) + + ifeq ($(HAVE_SYSCALL_TEMPLATE),yes) + SYSCALL_FILTER_RULE= for s in $(AVAILABLE_SYSCALLS) ; do \ +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/Makefile.inc,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 Makefile.inc +*** Makefile.inc 1995/08/22 22:09:07 1.1.1.1 +--- Makefile.inc 1996/10/02 19:04:38 +*************** +*** 8,14 **** + pthread_join.c pthread_detach.c pthread_once.c sleep.c specific.c \ + process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \ + pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \ +! dump_state.c pthread_kill.c condattr.c + + .if $(HAVE_SYSCALL_TEMPLATE) == yes + OBJS+= syscalls.o +--- 8,14 ---- + pthread_join.c pthread_detach.c pthread_once.c sleep.c specific.c \ + process.c wait.c errno.c schedparam.c _exit.c prio_queue.c \ + pthread_init.c init.cc sig.c info.c mutexattr.c select.c wrapper.c \ +! dump_state.c pthread_kill.c condattr.c pthread_cancel.c panic.c + + .if $(HAVE_SYSCALL_TEMPLATE) == yes + OBJS+= syscalls.o +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/cond.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 cond.c +*** cond.c 1996/03/05 08:29:12 1.1.1.1 +--- cond.c 1996/10/03 18:19:04 +*************** +*** 188,197 **** +--- 188,204 ---- + pthread_queue_enq(&cond->c_queue, pthread_run); + pthread_mutex_unlock(mutex); + ++ pthread_run->data.mutex = mutex; ++ + SET_PF_WAIT_EVENT(pthread_run); ++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + CLEAR_PF_DONE_EVENT(pthread_run); ++ ++ pthread_run->data.mutex = NULL; ++ + rval = pthread_mutex_lock(mutex); + return(rval); + break; +*************** +*** 203,212 **** +--- 210,226 ---- + pthread_mutex_unlock(mutex); + mutex->m_data.m_count = 1; + ++ pthread_run->data.mutex = mutex; ++ + SET_PF_WAIT_EVENT(pthread_run); ++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + CLEAR_PF_DONE_EVENT(pthread_run); ++ ++ pthread_run->data.mutex = NULL; ++ + rval = pthread_mutex_lock(mutex); + mutex->m_data.m_count = count; + return(rval); +*************** +*** 258,265 **** +--- 272,285 ---- + SET_PF_WAIT_EVENT(pthread_run); + pthread_mutex_unlock(mutex); + ++ pthread_run->data.mutex = mutex; ++ ++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ ++ ++ pthread_run->data.mutex = NULL; + + /* Remove ourselves from sleep queue. If we fail then we timedout */ + if (sleep_cancel(pthread_run) == NOTOK) { +*************** +*** 285,292 **** +--- 305,318 ---- + SET_PF_WAIT_EVENT(pthread_run); + pthread_mutex_unlock(mutex); + ++ pthread_run->data.mutex = mutex; ++ ++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ ++ ++ pthread_run->data.mutex = NULL; + + /* Remove ourselves from sleep queue. If we fail then we timedout */ + if (sleep_cancel(pthread_run) == NOTOK) { +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/fd.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 fd.c +*** fd.c 1996/02/09 02:54:19 1.1.1.1 +--- fd.c 1996/10/03 01:33:03 +*************** +*** 48,54 **** +--- 48,59 ---- + #include <sys/types.h> + #include <sys/stat.h> + #include <sys/uio.h> ++ #include <sys/ioctl.h> ++ #if __STDC__ + #include <stdarg.h> ++ #else ++ #include <varargs.h> ++ #endif + #include <fcntl.h> + #include <errno.h> + #include <pthread/posix.h> +*************** +*** 62,67 **** +--- 67,74 ---- + static const int dtablecount = 4096/sizeof(struct fd_table_entry); + int dtablesize; + ++ static int fd_get_pthread_fd_from_kernel_fd( int ); ++ + /* ========================================================================== + * Allocate dtablecount entries at once and populate the fd_table. + * +*************** +*** 199,204 **** +--- 206,244 ---- + return(NOTOK); + } + ++ /*---------------------------------------------------------------------- ++ * Function: fd_get_pthread_fd_from_kernel_fd ++ * Purpose: get the fd_table index of a kernel fd ++ * Args: fd = kernel fd to convert ++ * Returns: fd_table index, -1 if not found ++ * Notes: ++ *----------------------------------------------------------------------*/ ++ static int ++ fd_get_pthread_fd_from_kernel_fd( int kfd ) ++ { ++ int j; ++ ++ /* This is *SICK*, but unless there is a faster way to ++ * turn a kernel fd into an fd_table index, this has to do. ++ */ ++ for( j=0; j < dtablesize; j++ ) { ++ if( fd_table[j] && ++ fd_table[j]->type != FD_NT && ++ fd_table[j]->type != FD_NIU && ++ fd_table[j]->fd.i == kfd ) { ++ return j; ++ } ++ } ++ ++ /* Not listed byfd, Check for kernel fd == pthread fd */ ++ if( fd_table[kfd] == NULL || fd_table[kfd]->type == FD_NT ) { ++ /* Assume that the kernel fd is the same */ ++ return kfd; ++ } ++ ++ return NOTOK; /* Not found */ ++ } ++ + /* ========================================================================== + * fd_basic_basic_unlock() + * +*************** +*** 288,293 **** +--- 328,334 ---- + switch (fd_table[fd]->type) { + case FD_NIU: + /* If not in use return EBADF error */ ++ SET_ERRNO(EBADF); + return(NOTOK); + break; + case FD_NT: +*************** +*** 297,302 **** +--- 338,344 ---- + */ + fd_kern_init(fd); + if (fd_table[fd]->type == FD_NIU) { ++ SET_ERRNO(EBADF); + return(NOTOK); + } + break; +*************** +*** 409,414 **** +--- 451,545 ---- + return(OK); + } + ++ /*---------------------------------------------------------------------- ++ * Function: fd_unlock_for_cancel ++ * Purpose: Unlock all fd locks held prior to being cancelled ++ * Args: void ++ * Returns: ++ * OK or NOTOK ++ * Notes: ++ * Assumes the kernel is locked on entry ++ *----------------------------------------------------------------------*/ ++ int ++ fd_unlock_for_cancel( void ) ++ { ++ int i, fd; ++ struct pthread_select_data *data; ++ int rdlk, wrlk, lktype; ++ int found; ++ ++ /* What we do depends on the previous state of the thread */ ++ switch( pthread_run->old_state ) { ++ case PS_RUNNING: ++ case PS_JOIN: ++ case PS_SLEEP_WAIT: ++ case PS_WAIT_WAIT: ++ case PS_SIGWAIT: ++ case PS_FDLR_WAIT: ++ case PS_FDLW_WAIT: ++ case PS_DEAD: ++ case PS_UNALLOCED: ++ break; /* Nothing to do */ ++ ++ case PS_COND_WAIT: ++ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP ); ++ /* Must reaquire the mutex according to the standard */ ++ if( pthread_run->data.mutex == NULL ) { ++ PANIC(); ++ } ++ pthread_mutex_lock( pthread_run->data.mutex ); ++ break; ++ ++ case PS_FDR_WAIT: ++ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP); ++ /* Free the lock on the fd being used */ ++ fd = fd_get_pthread_fd_from_kernel_fd( pthread_run->data.fd.fd ); ++ if( fd == NOTOK ) { ++ PANIC(); /* Can't find fd */ ++ } ++ fd_unlock( fd, FD_READ ); ++ break; ++ ++ case PS_FDW_WAIT: /* Waiting on i/o */ ++ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP); ++ /* Free the lock on the fd being used */ ++ fd = fd_get_pthread_fd_from_kernel_fd( pthread_run->data.fd.fd ); ++ if( fd == NOTOK ) { ++ PANIC(); /* Can't find fd */ ++ } ++ fd_unlock( fd, FD_WRITE ); ++ break; ++ ++ case PS_SELECT_WAIT: ++ data = pthread_run->data.select_data; ++ ++ CLEAR_PF_GROUP( pthread_run, PF_EVENT_GROUP); ++ ++ for( i = 0; i < data->nfds; i++) { ++ rdlk =(FD_ISSET(i,&data->readfds) ++ || FD_ISSET(i,&data->exceptfds)); ++ wrlk = FD_ISSET(i, &data->writefds); ++ lktype = rdlk ? (wrlk ? FD_RDWR : FD_READ) : FD_WRITE; ++ ++ if( ! (rdlk || wrlk) ) ++ continue; /* No locks, no unlock */ ++ ++ if( (fd = fd_get_pthread_fd_from_kernel_fd( i )) == NOTOK ) { ++ PANIC(); /* Can't find fd */ ++ } ++ ++ fd_unlock( fd, lktype ); ++ } ++ break; ++ ++ case PS_MUTEX_WAIT: ++ PANIC(); /* Should never cancel a mutex wait */ ++ ++ default: ++ PANIC(); /* Unknown thread status */ ++ } ++ } ++ + /* ========================================================================== + * fd_lock() + */ +*************** +*** 476,481 **** +--- 607,616 ---- + ret = fd_table[fd]->ops->read(fd_table[fd]->fd, + fd_table[fd]->flags, buf, nbytes, timeout); + fd_unlock(fd, FD_READ); ++ if( ret < 0 ) { ++ SET_ERRNO(-ret); ++ ret = NOTOK; ++ } + } + return(ret); + } +*************** +*** 500,505 **** +--- 635,644 ---- + ret = fd_table[fd]->ops->readv(fd_table[fd]->fd, + fd_table[fd]->flags, iov, iovcnt, timeout); + fd_unlock(fd, FD_READ); ++ if( ret < 0 ) { ++ SET_ERRNO(-ret); ++ ret = NOTOK; ++ } + } + return(ret); + } +*************** +*** 524,529 **** +--- 663,672 ---- + ret = fd_table[fd]->ops->write(fd_table[fd]->fd, + fd_table[fd]->flags, buf, nbytes, timeout); + fd_unlock(fd, FD_WRITE); ++ if( ret < 0 ) { ++ SET_ERRNO(-ret); ++ ret = NOTOK; ++ } + } + return(ret); + } +*************** +*** 548,553 **** +--- 691,700 ---- + ret = fd_table[fd]->ops->writev(fd_table[fd]->fd, + fd_table[fd]->flags, iov, iovcnt, timeout); + fd_unlock(fd, FD_WRITE); ++ if( ret < 0 ) { ++ SET_ERRNO(-ret); ++ ret = NOTOK; ++ } + } + return(ret); + } +*************** +*** 599,677 **** + union fd_data realfd; + int ret, flags; + + /* Need to lock the newfd by hand */ +! if (fd < dtablesize) { +! pthread_mutex_lock(&fd_table_mutex); +! if (fd_table[fd]) { +! pthread_mutex_unlock(&fd_table_mutex); +! mutex = &(fd_table[fd]->mutex); +! pthread_mutex_lock(mutex); + +! /* +! * XXX Gross hack ... because of fork(), any fd closed by the +! * parent should not change the fd of the child, unless it owns it. + */ +! switch(fd_table[fd]->type) { +! case FD_NIU: +! pthread_mutex_unlock(mutex); +! ret = -EINVAL; +! break; +! case FD_NT: +! /* +! * If it's not tested then the only valid possibility is it's +! * kernel fd. +! */ +! ret = machdep_sys_close(fd); +! fd_table[fd]->type = FD_NIU; +! pthread_mutex_unlock(mutex); +! break; +! case FD_TEST_FULL_DUPLEX: +! case FD_TEST_HALF_DUPLEX: + realfd = fd_table[fd]->fd; + flags = fd_table[fd]->flags; + if ((entry = fd_free(fd)) == NULL) { +! ret = fd_table[fd]->ops->close(realfd, flags); + } else { +! /* There can't be any others waiting for fd. */ + pthread_mutex_unlock(&entry->mutex); + /* Note: entry->mutex = mutex */ +- mutex = &(fd_table[fd]->mutex); + } + pthread_mutex_unlock(mutex); +- break; +- default: +- ret = fd_basic_lock(fd, FD_RDWR, mutex, NULL); +- if (ret == OK) { +- realfd = fd_table[fd]->fd; +- flags = fd_table[fd]->flags; +- pthread_mutex_unlock(mutex); +- if ((entry = fd_free(fd)) == NULL) { +- ret = fd_table[fd]->ops->close(realfd, flags); +- } else { +- fd_basic_basic_unlock(entry, FD_RDWR); +- pthread_mutex_unlock(&entry->mutex); +- /* Note: entry->mutex = mutex */ +- } +- fd_unlock(fd, FD_RDWR); +- } else { +- pthread_mutex_unlock(mutex); +- } +- break; + } +! } else { +! /* Don't bother creating a table entry */ +! pthread_mutex_unlock(&fd_table_mutex); +! ret = machdep_sys_close(fd); + } +! return(ret); + } +! return(-EINVAL); + } + + /* ========================================================================== + * fd_basic_dup() + * + * Might need to do more than just what's below. + */ + static inline void fd_basic_dup(int fd, int newfd) + { +--- 746,836 ---- + union fd_data realfd; + int ret, flags; + ++ if( fd < 0 || fd >= dtablesize ) { ++ SET_ERRNO(EBADF); ++ return -1; ++ } ++ + /* Need to lock the newfd by hand */ +! pthread_mutex_lock(&fd_table_mutex); +! if (fd_table[fd]) { +! pthread_mutex_unlock(&fd_table_mutex); +! mutex = &(fd_table[fd]->mutex); +! pthread_mutex_lock(mutex); + +! /* +! * XXX Gross hack ... because of fork(), any fd closed by the +! * parent should not change the fd of the child, unless it owns it. +! */ +! switch(fd_table[fd]->type) { +! case FD_NIU: +! pthread_mutex_unlock(mutex); +! ret = -EBADF; +! break; +! case FD_NT: +! /* +! * If it's not tested then the only valid possibility is it's +! * kernel fd. + */ +! ret = machdep_sys_close(fd); +! fd_table[fd]->type = FD_NIU; +! pthread_mutex_unlock(mutex); +! break; +! case FD_TEST_FULL_DUPLEX: +! case FD_TEST_HALF_DUPLEX: +! realfd = fd_table[fd]->fd; +! flags = fd_table[fd]->flags; +! if ((entry = fd_free(fd)) == NULL) { +! ret = fd_table[fd]->ops->close(realfd, flags); +! } else { +! /* There can't be any others waiting for fd. */ +! pthread_mutex_unlock(&entry->mutex); +! /* Note: entry->mutex = mutex */ +! mutex = &(fd_table[fd]->mutex); +! } +! pthread_mutex_unlock(mutex); +! break; +! default: +! ret = fd_basic_lock(fd, FD_RDWR, mutex, NULL); +! if (ret == OK) { + realfd = fd_table[fd]->fd; + flags = fd_table[fd]->flags; ++ pthread_mutex_unlock(mutex); + if ((entry = fd_free(fd)) == NULL) { +! ret = fd_table[fd]->ops->close(realfd, flags); + } else { +! fd_basic_basic_unlock(entry, FD_RDWR); + pthread_mutex_unlock(&entry->mutex); + /* Note: entry->mutex = mutex */ + } ++ fd_unlock(fd, FD_RDWR); ++ } else { + pthread_mutex_unlock(mutex); + } +! break; + } +! } else { +! /* Don't bother creating a table entry */ +! pthread_mutex_unlock(&fd_table_mutex); +! ret = machdep_sys_close(fd); +! } +! +! if( ret < 0 ) { +! SET_ERRNO(-ret); +! ret = -1; + } +! +! return ret; + } + + /* ========================================================================== + * fd_basic_dup() + * + * Might need to do more than just what's below. ++ * ++ * This is a MAJOR guess!! I don't know if the mutext unlock is valid ++ * in the BIG picture. But it seems to be needed to avoid deadlocking ++ * with ourselves when we try to close the duped file descriptor. + */ + static inline void fd_basic_dup(int fd, int newfd) + { +*************** +*** 679,684 **** +--- 838,845 ---- + fd_table[fd]->next = fd_table[newfd]; + fd_table[newfd] = fd_table[fd]; + fd_table[fd]->count++; ++ pthread_mutex_unlock(&fd_table[newfd]->next->mutex); ++ + } + + /* ========================================================================== +*************** +*** 896,904 **** + * ala select()... --SNL + */ + int +! ioctl(int fd, unsigned long request, caddr_t arg) + { + int ret; + + if (fd < 0 || fd >= dtablesize) + ret = NOTOK; +--- 1057,1071 ---- + * ala select()... --SNL + */ + int +! ioctl(int fd, int request, ...) + { + int ret; ++ pthread_va_list ap; ++ caddr_t arg; ++ ++ va_start( ap, request ); /* Get the arg */ ++ arg = va_arg(ap,caddr_t); ++ va_end( ap ); + + if (fd < 0 || fd >= dtablesize) + ret = NOTOK; +*************** +*** 906,911 **** +--- 1073,1086 ---- + ret = machdep_sys_ioctl(fd, request, arg); + else if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + ret = machdep_sys_ioctl(fd_table[fd]->fd.i, request, arg); ++ if( ret == 0 && request == FIONBIO ) { ++ /* Properly set NONBLOCK flag */ ++ int v = *(int *)arg; ++ if( v ) ++ fd_table[fd]->flags |= __FD_NONBLOCK; ++ else ++ fd_table[fd]->flags &= ~__FD_NONBLOCK; ++ } + fd_unlock(fd, FD_RDWR); + } + return ret; +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/fd_kern.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 fd_kern.c +*** fd_kern.c 1996/02/12 00:58:30 1.1.1.1 +--- fd_kern.c 1996/10/03 01:54:15 +*************** +*** 128,134 **** + + + if ((count = machdep_sys_select(dtablesize, &fd_set_read, +! &fd_set_write, NULL, &__fd_kern_poll_timeout)) < OK) { + if (count == -EINTR) { + return; + } +--- 128,134 ---- + + + if ((count = machdep_sys_select(dtablesize, &fd_set_read, +! &fd_set_write, &fd_set_except, &__fd_kern_poll_timeout)) < OK) { + if (count == -EINTR) { + return; + } +*************** +*** 167,200 **** + + for (pthread = fd_wait_select.q_next; count && pthread; ) { + int found_one = 0; + + for (i = 0; i < pthread->data.select_data->nfds; i++) { + int count_dec = 0; + +! if ((FD_ISSET(i, &pthread->data.select_data->exceptfds) && +! ! FD_ISSET(i, &fd_set_except))) { +! FD_CLR(i, &pthread->data.select_data->exceptfds); +! } else { +! count_dec++; + } +! if ((FD_ISSET(i, &pthread->data.select_data->writefds) && +! ! FD_ISSET(i, &fd_set_write))) { +! FD_CLR(i, &pthread->data.select_data->writefds); +! } else { +! count_dec++; + } +! if ((FD_ISSET(i, &pthread->data.select_data->readfds) && +! ! FD_ISSET(i, &fd_set_read))) { +! FD_CLR(i, &pthread->data.select_data->readfds); +! } else { +! count_dec++; + } + if (count_dec) { + found_one++; + count--; + } + } + if (found_one) { + deq = pthread; + pthread = pthread->next; + pthread_queue_remove(&fd_wait_select, deq); +--- 167,223 ---- + + for (pthread = fd_wait_select.q_next; count && pthread; ) { + int found_one = 0; ++ fd_set tmp_readfds, tmp_writefds, tmp_exceptfds; ++ ++ memcpy(&tmp_readfds, &pthread->data.select_data->readfds, ++ sizeof(fd_set)); ++ memcpy(&tmp_writefds, &pthread->data.select_data->writefds, ++ sizeof(fd_set)); ++ memcpy(&tmp_exceptfds, &pthread->data.select_data->exceptfds, ++ sizeof(fd_set)); + + for (i = 0; i < pthread->data.select_data->nfds; i++) { + int count_dec = 0; + +! if( (FD_ISSET(i, &tmp_exceptfds)) ) { +! if( FD_ISSET(i, &fd_set_except) ) { +! count_dec++; /* got a hit */ +! } else { +! FD_CLR(i, &tmp_exceptfds); +! } + } +! +! if( (FD_ISSET(i, &tmp_writefds)) ) { +! if( FD_ISSET(i, &fd_set_write) ) { +! count_dec++; /* got a hit */ +! } else { +! FD_CLR(i, &tmp_writefds); +! } + } +! +! if( (FD_ISSET(i, &tmp_readfds)) ) { +! if( FD_ISSET(i, &fd_set_read) ) { +! count_dec++; /* got a hit */ +! } else { +! FD_CLR(i, &tmp_readfds); +! } + } ++ + if (count_dec) { + found_one++; + count--; + } + } ++ + if (found_one) { ++ /* Update the threads saved select data fd sets */ ++ memcpy(&pthread->data.select_data->readfds, &tmp_readfds, ++ sizeof(fd_set)); ++ memcpy(&pthread->data.select_data->writefds, &tmp_writefds, ++ sizeof(fd_set)); ++ memcpy(&pthread->data.select_data->exceptfds, &tmp_exceptfds, ++ sizeof(fd_set)); ++ + deq = pthread; + pthread = pthread->next; + pthread_queue_remove(&fd_wait_select, deq); +*************** +*** 266,272 **** + */ + + while ((count = machdep_sys_select(dtablesize, &fd_set_read, +! &fd_set_write, NULL, &__fd_kern_wait_timeout)) < OK) { + if (count == -EINTR) { + return; + } +--- 289,295 ---- + */ + + while ((count = machdep_sys_select(dtablesize, &fd_set_read, +! &fd_set_write, &fd_set_except, &__fd_kern_wait_timeout)) < OK) { + if (count == -EINTR) { + return; + } +*************** +*** 305,338 **** + + for (pthread = fd_wait_select.q_next; count && pthread; ) { + int found_one = 0; + + for (i = 0; i < pthread->data.select_data->nfds; i++) { + int count_dec = 0; + +! if ((FD_ISSET(i, &pthread->data.select_data->exceptfds) && +! ! FD_ISSET(i, &fd_set_except))) { +! FD_CLR(i, &pthread->data.select_data->exceptfds); +! } else { +! count_dec++; + } +! if ((FD_ISSET(i, &pthread->data.select_data->writefds) && +! ! FD_ISSET(i, &fd_set_write))) { +! FD_CLR(i, &pthread->data.select_data->writefds); +! } else { +! count_dec++; + } +! if ((FD_ISSET(i, &pthread->data.select_data->readfds) && +! ! FD_ISSET(i, &fd_set_read))) { +! FD_CLR(i, &pthread->data.select_data->readfds); +! } else { +! count_dec++; + } + if (count_dec) { + found_one++; + count--; + } + } + if (found_one) { + deq = pthread; + pthread = pthread->next; + pthread_queue_remove(&fd_wait_select, deq); +--- 328,383 ---- + + for (pthread = fd_wait_select.q_next; count && pthread; ) { + int found_one = 0; ++ fd_set tmp_readfds, tmp_writefds, tmp_exceptfds; ++ ++ memcpy(&tmp_readfds, &pthread->data.select_data->readfds, ++ sizeof(fd_set)); ++ memcpy(&tmp_writefds, &pthread->data.select_data->writefds, ++ sizeof(fd_set)); ++ memcpy(&tmp_exceptfds, &pthread->data.select_data->exceptfds, ++ sizeof(fd_set)); + + for (i = 0; i < pthread->data.select_data->nfds; i++) { + int count_dec = 0; + +! if( (FD_ISSET(i, &tmp_exceptfds)) ) { +! if( FD_ISSET(i, &fd_set_except) ) { +! count_dec++; /* got a hit */ +! } else { +! FD_CLR(i, &tmp_exceptfds); +! } + } +! +! if( (FD_ISSET(i, &tmp_writefds)) ) { +! if( FD_ISSET(i, &fd_set_write) ) { +! count_dec++; /* got a hit */ +! } else { +! FD_CLR(i, &tmp_writefds); +! } + } +! +! if( (FD_ISSET(i, &tmp_readfds)) ) { +! if( FD_ISSET(i, &fd_set_read) ) { +! count_dec++; /* got a hit */ +! } else { +! FD_CLR(i, &tmp_readfds); +! } + } ++ + if (count_dec) { + found_one++; + count--; + } + } + if (found_one) { ++ /* Update the threads saved select data fd sets */ ++ memcpy(&pthread->data.select_data->readfds, &tmp_readfds, ++ sizeof(fd_set)); ++ memcpy(&pthread->data.select_data->writefds, &tmp_writefds, ++ sizeof(fd_set)); ++ memcpy(&pthread->data.select_data->exceptfds, &tmp_exceptfds, ++ sizeof(fd_set)); ++ + deq = pthread; + pthread = pthread->next; + pthread_queue_remove(&fd_wait_select, deq); +*************** +*** 380,404 **** + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + pthread_resched_resume(PS_FDR_WAIT); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); +- SET_ERRNO(ETIMEDOUT); + ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); + } else { + pthread_resched_resume(PS_FDR_WAIT); + } + CLEAR_PF_DONE_EVENT(pthread_run); + } else { +- SET_ERRNO(-ret); +- ret = NOTOK; + break; + } + } +--- 425,450 ---- + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + ++ SET_PF_AT_CANCEL_POINT(pthread_run); + pthread_resched_resume(PS_FDR_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); + } else { ++ SET_PF_AT_CANCEL_POINT(pthread_run); + pthread_resched_resume(PS_FDR_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); + } + CLEAR_PF_DONE_EVENT(pthread_run); + } else { + break; + } + } +*************** +*** 437,443 **** + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); +- SET_ERRNO(ETIMEDOUT); + ret = -ETIMEDOUT; + break; + } +--- 483,488 ---- +*************** +*** 447,454 **** + } + CLEAR_PF_DONE_EVENT(pthread_run); + } else { +- SET_ERRNO(-ret); +- ret = NOTOK; + break; + } + } +--- 492,497 ---- +*************** +*** 480,504 **** + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + + pthread_resched_resume(PS_FDW_WAIT); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); +- SET_ERRNO(ETIMEDOUT); + ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); + } else { + pthread_resched_resume(PS_FDW_WAIT); + } + CLEAR_PF_DONE_EVENT(pthread_run); + } else { +- SET_ERRNO(-ret); +- ret = NOTOK; + break; + } + } +--- 523,548 ---- + machdep_gettimeofday(¤t_time); + sleep_schedule(¤t_time, timeout); + ++ SET_PF_AT_CANCEL_POINT(pthread_run); + pthread_resched_resume(PS_FDW_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); + + /* We're awake */ + pthread_sched_prevent(); + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); + } else { ++ SET_PF_AT_CANCEL_POINT(pthread_run); + pthread_resched_resume(PS_FDW_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); + } + CLEAR_PF_DONE_EVENT(pthread_run); + } else { + break; + } + } +*************** +*** 537,543 **** + if (sleep_cancel(pthread_run) == NOTOK) { + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); +- SET_ERRNO(ETIMEDOUT); + ret = -ETIMEDOUT; + break; + } +--- 581,586 ---- +*************** +*** 547,554 **** + } + CLEAR_PF_DONE_EVENT(pthread_run); + } else { +- SET_ERRNO(-ret); +- ret = NOTOK; + break; + } + } +--- 590,595 ---- +*************** +*** 662,668 **** + */ + int create(const char *path, mode_t mode) + { +! return creat (path, mode); + } + + /* ========================================================================== +--- 703,709 ---- + */ + int create(const char *path, mode_t mode) + { +! return creat (path, mode); + } + + /* ========================================================================== +*************** +*** 672,678 **** + + int creat(const char *path, mode_t mode) + { +! return open (path, O_CREAT | O_TRUNC | O_WRONLY, mode); + } + + /* ========================================================================== +--- 713,719 ---- + + int creat(const char *path, mode_t mode) + { +! return open (path, O_CREAT | O_TRUNC | O_WRONLY, mode); + } + + /* ========================================================================== +*************** +*** 1079,1090 **** + int bind(int fd, const struct sockaddr *name, int namelen) + { + /* Not much to do in bind */ +- semaphore *plock; + int ret; + + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + if ((ret = machdep_sys_bind(fd_table[fd]->fd.i, name, namelen)) < OK) { + SET_ERRNO(-ret); + } + fd_unlock(fd, FD_RDWR); + } +--- 1120,1131 ---- + int bind(int fd, const struct sockaddr *name, int namelen) + { + /* Not much to do in bind */ + int ret; + + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + if ((ret = machdep_sys_bind(fd_table[fd]->fd.i, name, namelen)) < OK) { + SET_ERRNO(-ret); ++ ret = NOTOK; + } + fd_unlock(fd, FD_RDWR); + } +*************** +*** 1100,1113 **** + */ + int connect(int fd, const struct sockaddr *name, int namelen) + { +! struct sockaddr tmpname; +! int ret, tmpnamelen; + +! if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + if ((ret = machdep_sys_connect(fd_table[fd]->fd.i, name, namelen)) < OK) { + if (!(fd_table[fd]->flags & __FD_NONBLOCK) && +! ((ret == -EWOULDBLOCK) || (ret == -EINPROGRESS) || +! (ret == -EALREADY) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDW_WAIT */ +--- 1141,1154 ---- + */ + int connect(int fd, const struct sockaddr *name, int namelen) + { +! struct sockaddr tmpname; +! int ret, tmpnamelen; + +! if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { + if ((ret = machdep_sys_connect(fd_table[fd]->fd.i, name, namelen)) < OK) { + if (!(fd_table[fd]->flags & __FD_NONBLOCK) && +! ((ret == -EWOULDBLOCK) || (ret == -EINPROGRESS) || +! (ret == -EALREADY) || (ret == -EAGAIN))) { + pthread_sched_prevent(); + + /* queue pthread for a FDW_WAIT */ +*************** +*** 1121,1131 **** + tmpnamelen = sizeof(tmpname); + /* OK now lets see if it really worked */ + if (((ret = machdep_sys_getpeername(fd_table[fd]->fd.i, +! &tmpname, &tmpnamelen)) < OK) && (ret == -ENOTCONN)) { + + /* Get the error, this function should not fail */ + machdep_sys_getsockopt(fd_table[fd]->fd.i, SOL_SOCKET, +! SO_ERROR, &pthread_run->error, &tmpnamelen); + } + } else { + SET_ERRNO(-ret); +--- 1162,1180 ---- + tmpnamelen = sizeof(tmpname); + /* OK now lets see if it really worked */ + if (((ret = machdep_sys_getpeername(fd_table[fd]->fd.i, +! &tmpname, &tmpnamelen)) < OK) +! && (ret == -ENOTCONN)) { + + /* Get the error, this function should not fail */ + machdep_sys_getsockopt(fd_table[fd]->fd.i, SOL_SOCKET, +! SO_ERROR, &ret, &tmpnamelen); +! SET_ERRNO(-ret); +! ret = NOTOK; +! } else { +! if( ret < 0 ) { +! SET_ERRNO(-ret); +! ret = NOTOK; +! } + } + } else { + SET_ERRNO(-ret); +*************** +*** 1133,1140 **** + } + } + fd_unlock(fd, FD_RDWR); +! } +! return(ret); + } + + #endif +--- 1182,1189 ---- + } + } + fd_unlock(fd, FD_RDWR); +! } +! return(ret); + } + + #endif +*************** +*** 1164,1170 **** + } else { + fd_unlock(fd, FD_RDWR); + SET_ERRNO(-fd_kern); +! return(fd_kern); + } + } + fd_unlock(fd, FD_RDWR); +--- 1213,1219 ---- + } else { + fd_unlock(fd, FD_RDWR); + SET_ERRNO(-fd_kern); +! return(NOTOK); + } + } + fd_unlock(fd, FD_RDWR); +*************** +*** 1198,1205 **** + int ret; + + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { +! ret = machdep_sys_listen(fd_table[fd]->fd.i, backlog); +! if ((ret = machdep_sys_listen(fd_table[fd]->fd.i, backlog)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } +--- 1247,1253 ---- + int ret; + + if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { +! if ((ret = machdep_sys_listen(fd_table[fd]->fd.i, backlog)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } +*************** +*** 1246,1252 **** + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); +--- 1294,1300 ---- + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = NOTOK; + break; + } + pthread_sched_resume(); +*************** +*** 1311,1317 **** + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); +--- 1359,1365 ---- + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = NOTOK; + break; + } + pthread_sched_resume(); +*************** +*** 1405,1411 **** + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); +--- 1453,1459 ---- + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = NOTOK; + break; + } + pthread_sched_resume(); +*************** +*** 1471,1477 **** + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); +--- 1519,1525 ---- + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = NOTOK; + break; + } + pthread_sched_resume(); +*************** +*** 1536,1542 **** + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); +--- 1584,1590 ---- + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = NOTOK; + break; + } + pthread_sched_resume(); +*************** +*** 1603,1609 **** + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = -ETIMEDOUT; + break; + } + pthread_sched_resume(); +--- 1651,1657 ---- + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_sched_resume(); + SET_ERRNO(ETIMEDOUT); +! ret = NOTOK; + break; + } + pthread_sched_resume(); +*************** +*** 1734,1744 **** + */ + int getsockopt(int fd, int level, int optname, void * optval, int * optlen) + { +! int ret; + +! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { + if ((ret = machdep_sys_getsockopt(fd_table[fd]->fd.i, level, +! optname, optval, optlen)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } +--- 1782,1792 ---- + */ + int getsockopt(int fd, int level, int optname, void * optval, int * optlen) + { +! int ret; + +! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { + if ((ret = machdep_sys_getsockopt(fd_table[fd]->fd.i, level, +! optname, optval, optlen)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; + } +*************** +*** 1756,1772 **** + */ + int getsockname(int fd, struct sockaddr * name, int * naddrlen) + { +! int ret; + +! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { +! if ((ret = machdep_sys_getsockname(fd_table[fd]->fd.i, +! name, naddrlen)) < OK) { +! SET_ERRNO(-ret); +! ret = NOTOK; +! } +! fd_unlock(fd, FD_RDWR); +! } +! return ret; + } + + #endif +--- 1804,1820 ---- + */ + int getsockname(int fd, struct sockaddr * name, int * naddrlen) + { +! int ret; + +! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { +! if ((ret = machdep_sys_getsockname(fd_table[fd]->fd.i, +! name, naddrlen)) < OK) { +! SET_ERRNO(-ret); +! ret = NOTOK; +! } +! fd_unlock(fd, FD_RDWR); +! } +! return ret; + } + + #endif +*************** +*** 1778,1793 **** + */ + int getpeername(int fd, struct sockaddr * peer, int * paddrlen) + { +! int ret; + +! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { +! if ((ret = machdep_sys_getpeername(fd_table[fd]->fd.i, +! peer, paddrlen)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; +! } +! fd_unlock(fd, FD_READ); +! } + return ret; + } + +--- 1826,1841 ---- + */ + int getpeername(int fd, struct sockaddr * peer, int * paddrlen) + { +! int ret; + +! if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { +! if ((ret = machdep_sys_getpeername(fd_table[fd]->fd.i, +! peer, paddrlen)) < OK) { + SET_ERRNO(-ret); + ret = NOTOK; +! } +! fd_unlock(fd, FD_READ); +! } + return ret; + } + +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/pthread.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 pthread.c +*** pthread.c 1995/12/13 05:53:01 1.1.1.1 +--- pthread.c 1996/10/01 21:42:01 +*************** +*** 129,134 **** +--- 129,160 ---- + + } + ++ /*---------------------------------------------------------------------- ++ * Function: __pthread_is_valid ++ * Purpose: Scan the list of threads to see if a specified thread exists ++ * Args: ++ * pthread = The thread to scan for ++ * Returns: ++ * int = 1 if found, 0 if not ++ * Notes: ++ * The kernel is assumed to be locked ++ *----------------------------------------------------------------------*/ ++ int ++ __pthread_is_valid( pthread_t pthread ) ++ { ++ int rtn = 0; /* Assume not found */ ++ pthread_t t; ++ ++ for( t = pthread_link_list; t; t = t->pll ) { ++ if( t == pthread ) { ++ rtn = 1; /* Found it */ ++ break; ++ } ++ } ++ ++ return rtn; ++ } ++ + /* ========================================================================== + * __pthread_free() + */ +*************** +*** 242,247 **** +--- 268,277 ---- + new_thread->next = NULL; + new_thread->flags = 0; + ++ /* PTHREADS spec says we start with cancellability on and deferred */ ++ SET_PF_CANCEL_STATE(new_thread, PTHREAD_CANCEL_ENABLE); ++ SET_PF_CANCEL_TYPE(new_thread, PTHREAD_CANCEL_DEFERRED); ++ + new_thread->error_p = NULL; + new_thread->sll = NULL; + +*************** +*** 261,269 **** + } + return(retval); + } +- +- /* ========================================================================== +- * pthread_cancel() +- * +- * This routine will also require a sig_prevent/sig_check_and_resume() +- */ +--- 291,293 ---- +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/pthread_init.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 pthread_init.c +*** pthread_init.c 1996/03/13 04:33:10 1.1.1.1 +--- pthread_init.c 1996/10/01 21:43:59 +*************** +*** 92,99 **** + pthread_initial->next = NULL; + pthread_initial->flags = 0; + pthread_initial->pll = NULL; +- pthread_initial->flags = 0; + pthread_initial->sll = NULL; + + /* Ugly errno hack */ + pthread_initial->error_p = &errno; +--- 92,103 ---- + pthread_initial->next = NULL; + pthread_initial->flags = 0; + pthread_initial->pll = NULL; + pthread_initial->sll = NULL; ++ ++ /* PTHREADS spec says we start with cancellability on and deferred */ ++ SET_PF_CANCEL_STATE(pthread_initial, PTHREAD_CANCEL_ENABLE); ++ SET_PF_CANCEL_TYPE(pthread_initial, PTHREAD_CANCEL_DEFERRED); ++ + + /* Ugly errno hack */ + pthread_initial->error_p = &errno; +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/pthread_join.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 pthread_join.c +*** pthread_join.c 1995/12/13 05:53:07 1.1.1.1 +--- pthread_join.c 1996/10/02 16:54:36 +*************** +*** 42,47 **** +--- 42,49 ---- + #include <pthread.h> + #include <errno.h> + ++ static int testDeadlock( struct pthread_queue *queue, pthread_t target ); ++ + /* ========================================================================== + * pthread_join() + */ +*************** +*** 51,56 **** +--- 53,64 ---- + + pthread_sched_prevent(); + ++ /* Ensure they gave us a legal pthread pointer */ ++ if( ! __pthread_is_valid( pthread ) ) { ++ pthread_sched_resume(); ++ return(EINVAL); ++ } ++ + /* Check that thread isn't detached already */ + if (pthread->attr.flags & PTHREAD_DETACHED) { + pthread_sched_resume(); +*************** +*** 62,81 **** + * Note: This must happen after checking detached state. + */ + if (pthread_queue_remove(&pthread_dead_queue, pthread) != OK) { +! pthread_queue_enq(&(pthread->join_queue), pthread_run); +! pthread_resched_resume(PS_JOIN); +! pthread_sched_prevent(); +! +! if (pthread_queue_remove(&pthread_dead_queue, pthread) == OK) { +! pthread_queue_enq(&pthread_alloc_queue, pthread); +! pthread->attr.flags |= PTHREAD_DETACHED; +! pthread->state = PS_UNALLOCED; +! if (thread_return) { +! *thread_return = pthread->ret; +! } +! ret = OK; + } else { +! ret = ESRCH; + } + } else { + /* Just get the return value and detach the thread */ +--- 70,98 ---- + * Note: This must happen after checking detached state. + */ + if (pthread_queue_remove(&pthread_dead_queue, pthread) != OK) { +! +! /* Before we pend on the join, ensure there is no dead lock */ +! +! if( testDeadlock( &pthread_run->join_queue, pthread ) == NOTOK ) { +! ret = EDEADLK; + } else { +! pthread_queue_enq(&(pthread->join_queue), pthread_run); +! SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ +! pthread_resched_resume(PS_JOIN); +! CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ +! pthread_sched_prevent(); +! +! if (pthread_queue_remove(&pthread_dead_queue, pthread) == OK) { +! pthread_queue_enq(&pthread_alloc_queue, pthread); +! pthread->attr.flags |= PTHREAD_DETACHED; +! pthread->state = PS_UNALLOCED; +! if (thread_return) { +! *thread_return = pthread->ret; +! } +! ret = OK; +! } else { +! ret = ESRCH; +! } + } + } else { + /* Just get the return value and detach the thread */ +*************** +*** 89,92 **** +--- 106,139 ---- + } + pthread_sched_resume(); + return(ret); ++ } ++ ++ /*---------------------------------------------------------------------- ++ * Function: testDeadlock ++ * Purpose: recursive queue walk to check for deadlocks ++ * Args: ++ * queue = the queue to walk ++ * pthread = target to scan for ++ * Returns: ++ * OK = no deadlock, NOTOK = deadlock ++ * Notes: ++ *----------------------------------------------------------------------*/ ++ static int ++ testDeadlock( struct pthread_queue *queue, pthread_t target ) ++ { ++ pthread_t t; ++ ++ if( queue == NULL ) ++ return OK; /* Empty queue, obviously ok */ ++ ++ for( t = queue->q_next; t; t = t->next ) { ++ if( t == target ) ++ return NOTOK; /* bang, your dead */ ++ ++ if( testDeadlock( &t->join_queue, target ) == NOTOK ) { ++ return NOTOK; ++ } ++ } ++ ++ return OK; /* No deadlock */ + } +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/select.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 select.c +*** select.c 1996/03/05 08:29:14 1.1.1.1 +--- select.c 1996/10/02 16:56:27 +*************** +*** 56,220 **** + int select(int numfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout) + { +! fd_set real_exceptfds, real_readfds, real_writefds; /* mapped fd_sets */ +! fd_set * real_readfds_p, * real_writefds_p, * real_exceptfds_p; +! fd_set read_locks, write_locks, rdwr_locks; +! struct timespec timeout_time, current_time; +! struct timeval zero_timeout = { 0, 0 }; +! int i, j, ret = 0, got_all_locks = 1; +! struct pthread_select_data data; +! +! if (numfds > dtablesize) { +! numfds = dtablesize; +! } +! +! data.nfds = 0; +! FD_ZERO(&data.readfds); +! FD_ZERO(&data.writefds); +! FD_ZERO(&data.exceptfds); + +! /* Do this first */ +! if (timeout) { + machdep_gettimeofday(¤t_time); +! timeout_time.tv_sec = current_time.tv_sec + timeout->tv_sec; +! if ((timeout_time.tv_nsec = current_time.tv_nsec + +! (timeout->tv_usec * 1000)) > 1000000000) { +! timeout_time.tv_nsec -= 1000000000; +! timeout_time.tv_sec++; +! } +! } +! +! FD_ZERO(&read_locks); +! FD_ZERO(&write_locks); +! FD_ZERO(&rdwr_locks); +! FD_ZERO(&real_readfds); +! FD_ZERO(&real_writefds); +! FD_ZERO(&real_exceptfds); +! +! /* lock readfds */ +! if (readfds || writefds || exceptfds) { +! for (i = 0; i < numfds; i++) { +! if ((readfds && (FD_ISSET(i, readfds))) || +! (exceptfds && FD_ISSET(i, exceptfds))) { +! if (writefds && FD_ISSET(i ,writefds)) { +! if ((ret = fd_lock(i, FD_RDWR, NULL)) != OK) { +! got_all_locks = 0; +! break; +! } +! FD_SET(i, &rdwr_locks); +! FD_SET(fd_table[i]->fd.i,&real_writefds); +! } else { +! if ((ret = fd_lock(i, FD_READ, NULL)) != OK) { +! got_all_locks = 0; +! break; +! } +! FD_SET(i, &read_locks); +! } +! if (readfds && FD_ISSET(i,readfds)) { +! FD_SET(fd_table[i]->fd.i, &real_readfds); +! } +! if (exceptfds && FD_ISSET(i,exceptfds)) { +! FD_SET(fd_table[i]->fd.i, &real_exceptfds); +! } +! if (fd_table[i]->fd.i >= data.nfds) { +! data.nfds = fd_table[i]->fd.i + 1; +! } +! } else { +! if (writefds && FD_ISSET(i, writefds)) { +! if ((ret = fd_lock(i, FD_WRITE, NULL)) != OK) { +! got_all_locks = 0; +! break; +! } +! FD_SET(i, &write_locks); +! FD_SET(fd_table[i]->fd.i,&real_writefds); +! } +! if (fd_table[i]->fd.i >= data.nfds) { +! data.nfds = fd_table[i]->fd.i + 1; +! } +! } +! } +! } +! +! if (got_all_locks) { +! +! memcpy(&data.readfds,&real_readfds,sizeof(fd_set)); +! memcpy(&data.writefds,&real_writefds,sizeof(fd_set)); +! memcpy(&data.exceptfds,&real_exceptfds,sizeof(fd_set)); +! +! real_readfds_p = (readfds == NULL) ? NULL : &real_readfds; +! real_writefds_p = (writefds == NULL) ? NULL : &real_writefds; +! real_exceptfds_p = (exceptfds == NULL) ? NULL : &real_exceptfds; +! +! if ((ret = machdep_sys_select(data.nfds, real_readfds_p, +! real_writefds_p, real_exceptfds_p, &zero_timeout)) == OK) { +! +! pthread_sched_prevent(); +! +! real_exceptfds_p = (exceptfds == NULL) ? NULL : &data.exceptfds; +! real_writefds_p = (writefds == NULL) ? NULL : &data.writefds; +! real_readfds_p = (readfds == NULL) ? NULL : &data.readfds; +! +! pthread_queue_enq(&fd_wait_select, pthread_run); +! pthread_run->data.select_data = &data; +! SET_PF_WAIT_EVENT(pthread_run); +! +! if (timeout) { +! machdep_gettimeofday(¤t_time); +! sleep_schedule(¤t_time, &timeout_time); +! +! pthread_resched_resume(PS_SELECT_WAIT); +! +! /* We're awake */ +! CLEAR_PF_DONE_EVENT(pthread_run); +! if (sleep_cancel(pthread_run) == NOTOK) { +! ret = OK; +! } else { +! ret = data.nfds; +! } +! } else { +! pthread_resched_resume(PS_SELECT_WAIT); +! CLEAR_PF_DONE_EVENT(pthread_run); +! ret = data.nfds; /* XXX ??? snl */ +! } +! } else if (ret < 0) { +! SET_ERRNO(-ret); +! ret = NOTOK; +! } +! } +! +! /* clean up the locks */ +! for (i = 0; i < numfds; i++) +! if (FD_ISSET(i,&read_locks)) fd_unlock(i,FD_READ); +! for (i = 0; i < numfds; i++) +! if (FD_ISSET(i,&rdwr_locks)) fd_unlock(i,FD_RDWR); +! for (i = 0; i < numfds; i++) +! if (FD_ISSET(i,&write_locks)) fd_unlock(i,FD_WRITE); +! +! if (ret > 0) { +! if (readfds != NULL) { +! for (i = 0; i < numfds; i++) { +! if (! (FD_ISSET(i,readfds) && +! FD_ISSET(fd_table[i]->fd.i,real_readfds_p))) +! FD_CLR(i,readfds); +! } +! } +! if (writefds != NULL) { +! for (i = 0; i < numfds; i++) +! if (! (FD_ISSET(i,writefds) && +! FD_ISSET(fd_table[i]->fd.i,real_writefds_p))) +! FD_CLR(i,writefds); +! } +! if (exceptfds != NULL) { +! for (i = 0; i < numfds; i++) +! if (! (FD_ISSET(i,exceptfds) && +! FD_ISSET(fd_table[i]->fd.i,real_exceptfds_p))) +! FD_CLR(i,exceptfds); +! } +! } else { +! if (exceptfds != NULL) FD_ZERO(exceptfds); +! if (writefds != NULL) FD_ZERO(writefds); +! if (readfds != NULL) FD_ZERO(readfds); + } + +! return(ret); + } +--- 56,223 ---- + int select(int numfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout) + { +! fd_set real_exceptfds, real_readfds, real_writefds; /* mapped fd_sets */ +! fd_set * real_readfds_p, * real_writefds_p, * real_exceptfds_p; +! fd_set read_locks, write_locks, rdwr_locks; +! struct timespec timeout_time, current_time; +! struct timeval zero_timeout = { 0, 0 }; +! int i, j, ret = 0, got_all_locks = 1; +! struct pthread_select_data data; +! +! if (numfds > dtablesize) { +! numfds = dtablesize; +! } +! +! data.nfds = 0; +! FD_ZERO(&data.readfds); +! FD_ZERO(&data.writefds); +! FD_ZERO(&data.exceptfds); +! +! /* Do this first */ +! if (timeout) { +! machdep_gettimeofday(¤t_time); +! timeout_time.tv_sec = current_time.tv_sec + timeout->tv_sec; +! if ((timeout_time.tv_nsec = current_time.tv_nsec + +! (timeout->tv_usec * 1000)) > 1000000000) { +! timeout_time.tv_nsec -= 1000000000; +! timeout_time.tv_sec++; +! } +! } +! +! FD_ZERO(&read_locks); +! FD_ZERO(&write_locks); +! FD_ZERO(&rdwr_locks); +! FD_ZERO(&real_readfds); +! FD_ZERO(&real_writefds); +! FD_ZERO(&real_exceptfds); +! +! /* lock readfds */ +! if (readfds || writefds || exceptfds) { +! for (i = 0; i < numfds; i++) { +! if ((readfds && (FD_ISSET(i, readfds))) || +! (exceptfds && FD_ISSET(i, exceptfds))) { +! if (writefds && FD_ISSET(i ,writefds)) { +! if ((ret = fd_lock(i, FD_RDWR, NULL)) != OK) { +! got_all_locks = 0; +! break; +! } +! FD_SET(i, &rdwr_locks); +! FD_SET(fd_table[i]->fd.i,&real_writefds); +! } else { +! if ((ret = fd_lock(i, FD_READ, NULL)) != OK) { +! got_all_locks = 0; +! break; +! } +! FD_SET(i, &read_locks); +! } +! if (readfds && FD_ISSET(i,readfds)) { +! FD_SET(fd_table[i]->fd.i, &real_readfds); +! } +! if (exceptfds && FD_ISSET(i,exceptfds)) { +! FD_SET(fd_table[i]->fd.i, &real_exceptfds); +! } +! if (fd_table[i]->fd.i >= data.nfds) { +! data.nfds = fd_table[i]->fd.i + 1; +! } +! } else { +! if (writefds && FD_ISSET(i, writefds)) { +! if ((ret = fd_lock(i, FD_WRITE, NULL)) != OK) { +! got_all_locks = 0; +! break; +! } +! FD_SET(i, &write_locks); +! FD_SET(fd_table[i]->fd.i,&real_writefds); +! if (fd_table[i]->fd.i >= data.nfds) { +! data.nfds = fd_table[i]->fd.i + 1; +! } +! } +! } +! } +! } +! +! if (got_all_locks) { +! memcpy(&data.readfds,&real_readfds,sizeof(fd_set)); +! memcpy(&data.writefds,&real_writefds,sizeof(fd_set)); +! memcpy(&data.exceptfds,&real_exceptfds,sizeof(fd_set)); +! +! real_readfds_p = (readfds == NULL) ? NULL : &real_readfds; +! real_writefds_p = (writefds == NULL) ? NULL : &real_writefds; +! real_exceptfds_p = (exceptfds == NULL) ? NULL : &real_exceptfds; +! +! if ((ret = machdep_sys_select(data.nfds, real_readfds_p, +! real_writefds_p, real_exceptfds_p, +! &zero_timeout)) == OK) { +! pthread_sched_prevent(); +! +! real_exceptfds_p = (exceptfds == NULL) ? NULL : &data.exceptfds; +! real_writefds_p = (writefds == NULL) ? NULL : &data.writefds; +! real_readfds_p = (readfds == NULL) ? NULL : &data.readfds; +! +! pthread_queue_enq(&fd_wait_select, pthread_run); +! pthread_run->data.select_data = &data; +! SET_PF_WAIT_EVENT(pthread_run); + +! if (timeout) { + machdep_gettimeofday(¤t_time); +! sleep_schedule(¤t_time, &timeout_time); +! +! SET_PF_AT_CANCEL_POINT(pthread_run); +! pthread_resched_resume(PS_SELECT_WAIT); +! CLEAR_PF_AT_CANCEL_POINT(pthread_run); +! +! /* We're awake */ +! CLEAR_PF_DONE_EVENT(pthread_run); +! if (sleep_cancel(pthread_run) == NOTOK) { +! ret = OK; +! } else { +! ret = data.nfds; +! } +! } else { +! SET_PF_AT_CANCEL_POINT(pthread_run); +! pthread_resched_resume(PS_SELECT_WAIT); +! CLEAR_PF_AT_CANCEL_POINT(pthread_run); +! CLEAR_PF_DONE_EVENT(pthread_run); +! ret = data.nfds; /* XXX ??? snl */ +! } +! } else if (ret < 0) { +! SET_ERRNO(-ret); +! ret = NOTOK; +! } +! } +! +! /* clean up the locks */ +! for (i = 0; i < numfds; i++) +! if (FD_ISSET(i,&read_locks)) fd_unlock(i,FD_READ); +! for (i = 0; i < numfds; i++) +! if (FD_ISSET(i,&rdwr_locks)) fd_unlock(i,FD_RDWR); +! for (i = 0; i < numfds; i++) +! if (FD_ISSET(i,&write_locks)) fd_unlock(i,FD_WRITE); +! +! if (ret > 0) { +! if (readfds != NULL) { +! for (i = 0; i < numfds; i++) { +! if (! (FD_ISSET(i,readfds) && +! FD_ISSET(fd_table[i]->fd.i,real_readfds_p))) +! FD_CLR(i,readfds); +! } +! } +! if (writefds != NULL) { +! for (i = 0; i < numfds; i++) +! if (! (FD_ISSET(i,writefds) && +! FD_ISSET(fd_table[i]->fd.i,real_writefds_p))) +! FD_CLR(i,writefds); +! } +! if (exceptfds != NULL) { +! for (i = 0; i < numfds; i++) +! if (! (FD_ISSET(i,exceptfds) && +! FD_ISSET(fd_table[i]->fd.i,real_exceptfds_p))) +! FD_CLR(i,exceptfds); + } ++ } else { ++ if (exceptfds != NULL) FD_ZERO(exceptfds); ++ if (writefds != NULL) FD_ZERO(writefds); ++ if (readfds != NULL) FD_ZERO(readfds); ++ } + +! return(ret); + } +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/sig.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 sig.c +*** sig.c 1996/03/13 04:33:13 1.1.1.1 +--- sig.c 1996/10/03 01:07:54 +*************** +*** 301,307 **** +--- 301,310 ---- + pthread_run->data.sigwait = set; + pthread_run->ret = sig; + ++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + pthread_resched_resume(PS_SIGWAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ ++ + return(OK); + } + +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/signal.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 signal.c +*** signal.c 1996/03/13 04:33:17 1.1.1.1 +--- signal.c 1996/10/03 17:30:16 +*************** +*** 72,77 **** +--- 72,78 ---- + + static void sig_handler(int signal); + static void set_thread_timer(); ++ static void __cleanup_after_resume( void ); + void sig_prevent(void); + void sig_resume(void); + +*************** +*** 482,502 **** + } + } + +! /* Only bother if we are truly unlocking the kernel */ +! while (!(--pthread_kernel_lock)) { +! if (sig_to_process) { +! /* if (SIG_ANY(sig_to_process)) { */ +! pthread_kernel_lock++; +! sig_handler(0); +! continue; +! } +! if (pthread_run && pthread_run->sigcount) { +! pthread_kernel_lock++; +! pthread_sig_process(); +! continue; +! } +! break; +! } + } + + /* ========================================================================== +--- 483,489 ---- + } + } + +! __cleanup_after_resume(); + } + + /* ========================================================================== +*************** +*** 508,530 **** + void pthread_resched_resume(enum pthread_state state) + { + pthread_run->state = state; +- sig_handler(SIGVTALRM); + +! /* Only bother if we are truely unlocking the kernel */ +! while (!(--pthread_kernel_lock)) { +! if (sig_to_process) { +! /* if (SIG_ANY(sig_to_process)) { */ +! pthread_kernel_lock++; +! sig_handler(0); +! continue; +! } +! if (pthread_run && pthread_run->sigcount) { +! pthread_kernel_lock++; +! pthread_sig_process(); +! continue; +! } +! break; + } + } + + /* ========================================================================== +--- 495,523 ---- + void pthread_resched_resume(enum pthread_state state) + { + pthread_run->state = state; + +! /* Since we are about to block this thread, lets see if we are +! * at a cancel point and if we've been cancelled. +! * Avoid cancelling dead or unalloced threads. +! */ +! if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) && +! TEST_PTHREAD_IS_CANCELLABLE(pthread_run) && +! state != PS_DEAD && state != PS_UNALLOCED ) { +! +! /* Set this flag to avoid recursively calling pthread_exit */ +! /* We have to set this flag here because we will unlock the +! * kernel prior to calling pthread_cancel_internal. +! */ +! SET_PF_RUNNING_TO_CANCEL(pthread_run); +! +! pthread_run->old_state = state; /* unlock needs this data */ +! pthread_sched_resume(); /* Unlock kernel before cancel */ +! pthread_cancel_internal( 1 ); /* free locks and exit */ + } ++ ++ sig_handler(SIGVTALRM); ++ ++ __cleanup_after_resume(); + } + + /* ========================================================================== +*************** +*** 532,537 **** +--- 525,543 ---- + */ + void pthread_sched_resume() + { ++ __cleanup_after_resume(); ++ } ++ ++ /*---------------------------------------------------------------------- ++ * Function: __cleanup_after_resume ++ * Purpose: cleanup kernel locks after a resume ++ * Args: void ++ * Returns: void ++ * Notes: ++ *----------------------------------------------------------------------*/ ++ static void ++ __cleanup_after_resume( void ) ++ { + /* Only bother if we are truely unlocking the kernel */ + while (!(--pthread_kernel_lock)) { + /* if (SIG_ANY(sig_to_process)) { */ +*************** +*** 546,551 **** +--- 552,568 ---- + continue; + } + break; ++ } ++ ++ if( pthread_run == NULL ) ++ return; /* Must be during init processing */ ++ ++ /* Test for cancel that should be handled now */ ++ ++ if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) && ++ TEST_PTHREAD_IS_CANCELLABLE(pthread_run) ) { ++ /* Kernel is already unlocked */ ++ pthread_cancel_internal( 1 ); /* free locks and exit */ + } + } + +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/sleep.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 sleep.c +*** sleep.c 1996/03/11 08:33:32 1.1.1.1 +--- sleep.c 1996/10/03 01:14:58 +*************** +*** 249,255 **** +--- 249,257 ---- + + /* Reschedule thread */ + SET_PF_WAIT_EVENT(pthread_run); ++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + pthread_resched_resume(PS_SLEEP_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + CLEAR_PF_DONE_EVENT(pthread_run); + + /* Return actual time slept */ +*************** +*** 332,338 **** + current_time.tv_sec++; + } + machdep_start_timer(&(current_time), +! &(pthread_sleep->wakeup_time)); + } + } else { + for (pthread_last = pthread_sleep; pthread_last; +--- 334,340 ---- + current_time.tv_sec++; + } + machdep_start_timer(&(current_time), +! &(pthread_sleep->wakeup_time)); + } + } else { + for (pthread_last = pthread_sleep; pthread_last; +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/stat.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 stat.c +*** stat.c 1995/09/21 02:36:05 1.1.1.1 +--- stat.c 1996/06/04 19:17:33 +*************** +*** 43,48 **** +--- 43,49 ---- + #include <errno.h> + + struct stat; ++ struct statfs; + + /* ========================================================================== + * fstat() +*************** +*** 91,95 **** +--- 92,115 ---- + } + return(ret); + ++ } ++ ++ /* ========================================================================== ++ * fstatfs() ++ * ++ * Might want to indirect this. ++ */ ++ int fstatfs(int fd, struct statfs *buf) ++ { ++ int ret; ++ ++ if ((ret = fd_lock(fd, FD_READ, NULL)) == OK) { ++ if ((ret = machdep_sys_fstatfs(fd_table[fd]->fd.i, buf)) < OK) { ++ SET_ERRNO(-ret); ++ ret = NOTOK; ++ } ++ fd_unlock(fd, FD_READ); ++ } ++ return(ret); + } + +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/wait.c,v retrieving revision 1.1.1.1 +diff -c -r1.1.1.1 wait.c +*** wait.c 1995/02/21 08:07:24 1.1.1.1 +--- wait.c 1996/10/03 01:20:02 +*************** +*** 103,109 **** +--- 103,111 ---- + pthread_queue_enq(&wait_queue, pthread_run); + + /* reschedule unlocks scheduler */ ++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + pthread_resched_resume(PS_WAIT_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + + pthread_sched_prevent(); + } +*************** +*** 126,132 **** +--- 128,136 ---- + pthread_queue_enq(&wait_queue, pthread_run); + + /* reschedule unlocks scheduler */ ++ SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + pthread_resched_resume(PS_WAIT_WAIT); ++ CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + + pthread_sched_prevent(); + } +<pre><font size=-1> diff --git a/lib/libpthread/patches/Streepy2.html b/lib/libpthread/patches/Streepy2.html new file mode 100755 index 00000000000..80d44d6440c --- /dev/null +++ b/lib/libpthread/patches/Streepy2.html @@ -0,0 +1,93 @@ +<html> +<head> + <title>Diffs on diffs :-) by Larry V. Streepy, Jr.</title> + <base target=_top> + <meta name="GENERATOR" content="FindMail Communications"> + <meta name="Date" content="Monday, October 07, 1996 02:03 PM PST"> + <meta name="Author" content="Larry V. Streepy, Jr."> +</head> +<body background="/gifs/betafm.gif" bgcolor="#ffffff" text="#000000" link="#0000ee" vlink="#ff0000" alink="#000099"> +<h3>Diffs on diffs :-)</h3> +Larry V. Streepy, Jr. (<a href="mailto.html?mid=2079859748&num=398" target="_top">@healthcare.com</a>)<br>Monday, October 07, 1996 02:03 PM PST<br> +<p> +This is a multi-part message in MIME format.<p> +--------------65BE18E23639BCDD7BE55F7F <br> +Content-Type: text/plain; charset=us-ascii <br> +Content-Transfer-Encoding: 7bit<p> +Unfortunately, there are a couple of bugs in my pthread_cancel support (no, say it isn't so :-)<p> +Oh well, I cam across a couple of cases that I missed in my testing last week. Here are the bugs:<p> +1. If a thread calls pthread_testcancel during it's cleanup processing after being cancelled, the pthread kernel would hang.<p> +2. I didn't realize that threads in PS_SLEEP_WAIT state are *NOT* on any queue, they are handled using a linked list. So, when cancelling a thread that was sleeping, a PANIC() I put in possiblymakeRunnable would go off.<p> +Both of these are fixed. The diffs are attached.<br> +-- <br> +Larry V. Streepy, Jr. <br> +Chief Technical Officer, Healthcare Communications, Inc. mailto:<a href="mailto.html?mid=2079859748&num=398" target="_top">@healthcare.com</a> <br> +(214) 851-7033 (Dallas Main #) <br> +(970) 626-5028 (My office #) (970) 626-4425 (Fax)<p> +--------------65BE18E23639BCDD7BE55F7F <br> +Content-Type: text/plain; charset=us-ascii; name="cancel.diffs" Content-Transfer-Encoding: 7bit <br> +Content-Disposition: inline; filename="cancel.diffs"<p> +Index: pthread_cancel.c<br> +=================================================================== RCS file: /usr/cvssrc/pthreads-1_60_beta5/pthreads/pthread_cancel.c,v retrieving revision 1.1 <br> +diff -c -r1.1 pthread_cancel.c<br> +*** pthread_cancel.c 1996/10/06 00:31:27 1.1<br> +--- pthread_cancel.c 1996/10/07 18:33:27<br> +***************<br> +*** 187,192 ****<br> +--- 187,197 ----<br> + return; /* Can't be cancelled */<br> + }<br> + <br> ++ /* Ensure that we aren't in the process of exiting already */<br> ++ if( TEST_PF_RUNNING_TO_CANCEL(pthread_run) ) {<br> ++ return;<br> ++ }<br> ++ <br> + /* See if we have been cancelled */<br> + if( TEST_PF_CANCELLED(pthread_run) ) {<br> + /* Set this flag to avoid recursively calling pthread_exit */<br> +***************<br> +*** 266,277 ****<br> + if( pthread->state == PS_RUNNING )<br> + return; /* will happen at context switch */<br> + <br> +! /* Otherwise, we need to take it off the queue and make it runnable */<br> +! if( pthread->queue == NULL ) {<br> +! PANIC(); /* Must be on a queue */<br> +! }<br> + <br> +- pthread_queue_remove(pthread->queue, pthread);<br> + pthread_prio_queue_enq(pthread_current_prio_queue, pthread);<br> + pthread->old_state = pthread->state;<br> + pthread->state = PS_RUNNING;<br> +--- 271,291 ----<br> + if( pthread->state == PS_RUNNING )<br> + return; /* will happen at context switch */<br> + <br> +! /* If the thread is sleeping, the it isn't on a queue. */<br> +! if( pthread->state == PS_SLEEP_WAIT ) {<br> +! sleep_cancel( pthread ); /* Remove from sleep list */<br> +! } else {<br> +! /* Otherwise, we need to take it off the queue and make it runnable */<br> +! <br> +! if( pthread->queue == NULL ) {<br> +! PANIC(); /* Must be on a queue */<br> +! }<br> +! <br> +! pthread_queue_remove(pthread->queue, pthread);<br> +! }<br> +! <br> +! /* And make it runnable */<br> + <br> + pthread_prio_queue_enq(pthread_current_prio_queue, pthread);<br> + pthread->old_state = pthread->state;<br> + pthread->state = PS_RUNNING;<p> +<pre><font size=-1> +--------------65BE18E23639BCDD7BE55F7F-- + +</pre><p></pre> +<hr> +<a href="http://www.findmail.com/" target="_top"><font size=-1>Powered by FindMail Communications</font><br></a> +<br>Please email comments and suggestions to:<a href="/cgi-bin/comments.py" target="_top">comments@findmail.com</a> +<br><font size=-3 color="#ffffff">xmlarchive</font> +</body></html>
\ No newline at end of file diff --git a/lib/libpthread/patches/bill_lear b/lib/libpthread/patches/bill_lear new file mode 100755 index 00000000000..f49b79c4272 --- /dev/null +++ b/lib/libpthread/patches/bill_lear @@ -0,0 +1,70 @@ +From rael@dejanews.com Wed Jan 29 06:06:14 1997 +X-VM-v5-Data: ([nil nil nil t nil nil nil nil nil] + ["1497" "Tue" "28" "January" "1997" "21:52:57" "-0600" "William S. Lear" "rael@dejanews.com" "<199701290352.VAA08678@homer.dejanews.com>" "53" "Patches for linux2.0" "^From:" nil nil "1" "1997012903:52:57" "Patches for linux2.0" nil nil] + nil) +Received: from MIT.EDU (PACIFIC-CARRIER-ANNEX.MIT.EDU [18.69.0.28]) + by analytik.analytikerna.se (8.8.4/8.8.4) with SMTP + id GAA23245 for <monty@analytikerna.se>; Wed, 29 Jan 1997 06:06:12 +0100 (MET) +Received: from host-205-238-143-2.dejanews.com by MIT.EDU with SMTP + id AA25254; Tue, 28 Jan 97 22:53:08 EST +Received: (from rael@localhost) by homer.dejanews.com (8.7.6/8.6.12) id VAA08678 for pthreads@mit.edu; Tue, 28 Jan 1997 21:52:57 -0600 (CST) +Message-Id: <199701290352.VAA08678@homer.dejanews.com> +Content-Length: 1496 +From: "William S. Lear" <rael@dejanews.com> +To: pthreads@MIT.EDU +Subject: Patches for linux2.0 +Date: Tue, 28 Jan 1997 21:52:57 -0600 (CST) + + +The following are some patches I found necessary to run smoothly +under linux2.0. The PTEST directory below refers to the original +pthreads 1.60 beta 6 release. Of course, the '-O2' "fix" is not strictly +needed. + +#============================================================ +# < pthreads-1_60beta6/config/configure +# > PTEST/pthreads-1_60beta6/config/configure +#------------------------------------------------------------ +642c642 +< CFLAGS="-g -O2" +--- +> CFLAGS="-g -O" +1104,1106d1103 +< cat >> confdefs.h <<EOF +< #define BSD_TM 1 +< EOF + +# Diff for: +#============================================================ +# < pthreads-1_60beta6/config/config.h.in +# > PTEST/pthreads-1_60beta6/config/config.h.in +#------------------------------------------------------------ +3,8d2 +< /* Does the OS have tm needing bsd'ish initialization? */ +< #undef BSD_TM +< +< /* Does the OS already support struct timespec */ +< #undef _OS_HAS_TIMESPEC +< + +# Diff for: +#============================================================ +# < pthreads-1_60beta6/gen/ctime.c +# > PTEST/pthreads-1_60beta6/gen/ctime.c +#------------------------------------------------------------ +49c49 +< #include "config.h" +--- +> + +# Diff for: +#============================================================ +# < pthreads-1_60beta6/include/math.h +# > PTEST/pthreads-1_60beta6/include/math.h +#------------------------------------------------------------ +54d53 +< double hypot __P((double, double)); + + +Bill Lear (rael@dejanews.com) + diff --git a/lib/libpthread/patches/chris_demetriou b/lib/libpthread/patches/chris_demetriou new file mode 100755 index 00000000000..41d2dfefe82 --- /dev/null +++ b/lib/libpthread/patches/chris_demetriou @@ -0,0 +1,149 @@ +From cgd@pa.dec.com Fri Aug 15 04:22:21 1997 +X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil] + ["3982" "Thu" "14" "August" "1997" "18:57:55" "-0700" "Chris G. Demetriou" "cgd@pa.dec.com" "<15218.871610275@dnaunix.pa.dec.com>" "126" "patches to get 1.60 beta6 to build on ELF NetBSD/alpha systems" "^From:" nil nil "8" "1997081501:57:55" "patches to get 1.60 beta6 to build on ELF NetBSD/alpha systems" nil nil] + nil) +Received: from MIT.EDU (PACIFIC-CARRIER-ANNEX.MIT.EDU [18.69.0.28]) + by analytik.analytikerna.se (8.8.4/8.8.4) with SMTP + id EAA10207 for <monty@analytikerna.se>; Fri, 15 Aug 1997 04:22:19 +0200 (MET DST) +Received: from mail2.digital.com by MIT.EDU with SMTP + id AA13470; Thu, 14 Aug 97 22:01:37 EDT +Received: from dnaunix.pa.dec.com (dnaunix.pa.dec.com [16.4.208.21]) + by mail2.digital.com (8.7.5/UNX 1.5/1.0/WV) with SMTP id SAA15366; + Thu, 14 Aug 1997 18:58:16 -0700 (PDT) +Received: by dnaunix.pa.dec.com; id AA15044; Thu, 14 Aug 1997 18:57:56 -0700 +Message-Id: <15218.871610275@dnaunix.pa.dec.com> +X-Mts: smtp +Content-Length: 3981 +From: "Chris G. Demetriou" <cgd@pa.dec.com> +Sender: cgd@pa.dec.com +To: pthreads-bugs@MIT.EDU +Cc: "Chris G. Demetriou" <cgd@pa.dec.com>, pthreads@MIT.EDU +Subject: patches to get 1.60 beta6 to build on ELF NetBSD/alpha systems +Date: Thu, 14 Aug 97 18:57:55 -0700 + +Enclosed below are patches to pthreads 1.60 beta6 to build on +current NetBSD/alpha systems (which use ELF). With these patches, +pthreads passes 'make check.' + +As an aside, the test_switch test generates _340k_ of output ("a" +for a while, then "ab" for a while) when run one the machine I was +testing on. In my opinion, that's a ... bit excessive, especially +since 'make check' has to be run interactively! + + + +chris +============================================================================ +diff -rc pthreads-1_60_beta6.orig/config/Makefile.in pthreads-1_60_beta6/config/Makefile.in +*** pthreads-1_60_beta6.orig/config/Makefile.in Thu Mar 21 20:29:54 1996 +--- pthreads-1_60_beta6/config/Makefile.in Thu Aug 14 17:56:55 1997 +*************** +*** 29,35 **** + # pathname for srcdir here, and live with it. + srcdir = $(srctop) + +! beforeinstall:: install-dirs + + .include "${srcdir}/pthreads/Makefile.inc" + .include "${srcdir}/stdlib/Makefile.inc" +--- 29,35 ---- + # pathname for srcdir here, and live with it. + srcdir = $(srctop) + +! beforeinstall: install-dirs + + .include "${srcdir}/pthreads/Makefile.inc" + .include "${srcdir}/stdlib/Makefile.inc" +diff -rc pthreads-1_60_beta6.orig/machdep/syscall-alpha-netbsd-1.1.S pthreads-1_60_beta6/machdep/syscall-alpha-netbsd-1.1.S +*** pthreads-1_60_beta6.orig/machdep/syscall-alpha-netbsd-1.1.S Wed Nov 13 13:03:28 1996 +--- pthreads-1_60_beta6/machdep/syscall-alpha-netbsd-1.1.S Thu Aug 14 18:03:27 1997 +*************** +*** 35,54 **** + .frame sp,0,ra ;\ + ldiq v0, CONCAT(SYS_,x) ;\ + CHMK() ;\ +! beq a3, 2f ;\ +! br gp, 1f ;\ +! 1: ;\ + /* Load gp so we can find cerror to jump to. */;\ + ldgp gp, 0(gp) ;\ +! jmp zero, machdep_cerror ;\ +! 2: + + #define XSYSCALL(x) SYSCALL(x) ; RET ; .end CONCAT(machdep_sys_,x) + + .globl machdep_cerror + machdep_cerror: +! br t0, 1f +! 1: + ldgp gp, 0(t0) + stl v0, errno + #if 0 +--- 35,54 ---- + .frame sp,0,ra ;\ + ldiq v0, CONCAT(SYS_,x) ;\ + CHMK() ;\ +! beq a3, CONCAT(Lsys_noerr_,x) ;\ +! br gp, CONCAT(Lsys_err_,x) ;\ +! CONCAT(Lsys_err_,x): ;\ + /* Load gp so we can find cerror to jump to. */;\ + ldgp gp, 0(gp) ;\ +! jmp zero, machdep_cerror ;\ +! CONCAT(Lsys_noerr_,x): + + #define XSYSCALL(x) SYSCALL(x) ; RET ; .end CONCAT(machdep_sys_,x) + + .globl machdep_cerror + machdep_cerror: +! br t0, Lmachdep_cerror_setgp +! Lmachdep_cerror_setgp: + ldgp gp, 0(t0) + stl v0, errno + #if 0 +diff -rc pthreads-1_60_beta6.orig/machdep/syscall-template-alpha-netbsd-1.1.S pthreads-1_60_beta6/machdep/syscall-template-alpha-netbsd-1.1.S +*** pthreads-1_60_beta6.orig/machdep/syscall-template-alpha-netbsd-1.1.S Mon Apr 22 23:15:42 1996 +--- pthreads-1_60_beta6/machdep/syscall-template-alpha-netbsd-1.1.S Thu Aug 14 17:58:14 1997 +*************** +*** 31,43 **** + .frame sp,0,ra ;\ + ldiq v0, SYS_##x ;\ + CHMK() ;\ +! beq a3, 2f ;\ +! br gp, 1f ;\ +! 1: ;\ + /* Load gp so we can find cerror to jump to. */;\ + ldgp gp, 0(gp) ;\ +! jmp zero, machdep_cerror ;\ +! 2: + + #define SIMPLE_SYSCALL(x) SYSCALL(x) ; ret ; .end machdep_sys_##x + +--- 31,43 ---- + .frame sp,0,ra ;\ + ldiq v0, SYS_##x ;\ + CHMK() ;\ +! beq a3, Lsys_noerr_##x ;\ +! br gp, Lsys_err_##x ;\ +! Lsys_err_##x: ;\ + /* Load gp so we can find cerror to jump to. */;\ + ldgp gp, 0(gp) ;\ +! jmp zero, machdep_cerror ;\ +! Lsys_noerr_##x: + + #define SIMPLE_SYSCALL(x) SYSCALL(x) ; ret ; .end machdep_sys_##x + +diff -rc pthreads-1_60_beta6.orig/pthreads/process.c pthreads-1_60_beta6/pthreads/process.c +*** pthreads-1_60_beta6.orig/pthreads/process.c Tue Nov 12 05:45:16 1996 +--- pthreads-1_60_beta6/pthreads/process.c Thu Aug 14 18:12:49 1997 +*************** +*** 40,45 **** +--- 40,47 ---- + #include <stdarg.h> + #include <unistd.h> + ++ extern void *alloca(); ++ + #ifndef lint + static const char rcsid[] = "$Id: chris_demetriou,v 1.1 1998/07/21 13:22:22 peter Exp $"; + #endif + diff --git a/lib/libpthread/patches/mevans b/lib/libpthread/patches/mevans new file mode 100755 index 00000000000..d5ff2f27610 --- /dev/null +++ b/lib/libpthread/patches/mevans @@ -0,0 +1,642 @@ +=A0 +Attached are several patches for pthreads-1_60_beta6. The patches fall +into 3 catagories: + + 1. Crashes and hangs. + 2. Missing functionality (namely flock()) + 3. Use of POSIX reentrant safe routines. + +Most of the patches contain a comment as to why the change was made. +The one major exception is to fd_kern.c at line 257 (unpatched). The +change to that line is to fix a "hang" that prevents threads for +scheduling for an hour if there is no external I/O event. + +I also include patches that modify several functions to use POSIX +reentrant safe routines. I know that MIT pthreads implements routine +like gethostbyname in a thread safe manner, but we're pretty, um, anal +about trying to keep our code as portable as possible. By excluding +using routines that are not reentrant safe according to the PTHREAD +safe, it's easy for us to stub out the unsafe routines and catch +non-compliant code. I almost left these patches out, but I'm hoping +they'll be adopted. :-) + +WARNING: None of the MIT pthreads routines that convert floats/doubles +between their native forms and strings are thread safe! (i.e printf, +sprintf, fprintf, atod, strtod, etc) I have replacements, but I need to +check with the author of the replacements and my employer. + +Mark Evans + +------------69CDAAF52A3566916F8ED01A0 +Content-Disposition: inline; filename="pthreads-1_60_beta6.patch" +Content-Type: text/plain; charset=us-ascii; name="pthreads-1_60_beta6.patch" +Content-Transfer-Encoding: 7bit + +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/config/config.h.in pthreads-1_60_beta6+/config/config.h.in +*** pthreads-1_60_beta6/config/config.h.in Thu Mar 21 21:30:04 1996 +--- pthreads-1_60_beta6+/config/config.h.in Sat Mar 15 14:08:55 1997 +*************** +*** 137,142 **** +--- 137,145 ---- + /* Define if you have the syscall_ftruncate function. */ + #undef HAVE_SYSCALL_FTRUNCATE + ++ /* Define if you have the syscall_flock function. */ ++ #undef HAVE_SYSCALL_FLOCK ++ + /* Define if you have the syscall_getdents function. */ + #undef HAVE_SYSCALL_GETDENTS + +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/config/configure.in pthreads-1_60_beta6+/config/configure.in +*** pthreads-1_60_beta6/config/configure.in Wed Nov 13 14:03:08 1996 +--- pthreads-1_60_beta6+/config/configure.in Sat Mar 15 14:08:55 1997 +*************** +*** 241,247 **** + + PTHREADS_CHECK_SYSCALLS(open write read creat close fcntl lseek dup2 dup pipe + fchmod fchown execve fstat lstat link unlink chdir chown chmod stat +! rename select getdtablesize ioctl ftruncate + dnl - signals + sigsuspend sigaction sigpause sigprocmask ksigaction + dnl - directory reading +--- 241,247 ---- + + PTHREADS_CHECK_SYSCALLS(open write read creat close fcntl lseek dup2 dup pipe + fchmod fchown execve fstat lstat link unlink chdir chown chmod stat +! rename select getdtablesize ioctl ftruncate flock + dnl - signals + sigsuspend sigaction sigpause sigprocmask ksigaction + dnl - directory reading +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/gen/directory.c pthreads-1_60_beta6+/gen/directory.c +*** pthreads-1_60_beta6/gen/directory.c Sat May 20 10:55:34 1995 +--- pthreads-1_60_beta6+/gen/directory.c Sat Mar 15 14:08:55 1997 +*************** +*** 251,262 **** +--- 251,266 ---- + /* + * Seek to an entry in a directory. + * _seekdir is in telldir.c so that it can share opaque data structures. ++ * ++ * Use the POSIX reentrant safe readdir_r to simplify varifying POSIX ++ * thread-safe compliance. + */ + void seekdir(DIR * dirp, long loc) + { + register struct ddloc ** prevlp; + register struct ddloc * lp; + struct dirent * dp; ++ struct dirent de; + + pthread_mutex_lock (dirp->dd_lock); + prevlp = (struct ddloc **)&(dirp->dd_ddloc); +*************** +*** 277,283 **** + dirp->dd_seek = lp->loc_seek; + dirp->dd_loc = 0; + while (dirp->dd_loc < lp->loc_loc) { +! if (!(dp = readdir(dirp))) { + *prevlp = lp->loc_next; + break; + } +--- 281,287 ---- + dirp->dd_seek = lp->loc_seek; + dirp->dd_loc = 0; + while (dirp->dd_loc < lp->loc_loc) { +! if (readdir_r(dirp, &de, &dp)) { + *prevlp = lp->loc_next; + break; + } +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/gen/getcwd.c pthreads-1_60_beta6+/gen/getcwd.c +*** pthreads-1_60_beta6/gen/getcwd.c Sat Sep 2 17:39:30 1995 +--- pthreads-1_60_beta6+/gen/getcwd.c Sat Mar 15 14:08:55 1997 +*************** +*** 50,67 **** + (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ + dp->d_name[1] == '.' && dp->d_name[2] == '\0')) + + char * + getcwd(pt, size) + char *pt; + size_t size; + { +- register struct dirent *dp; + register DIR *dir; + register dev_t dev; + register ino_t ino; + register int first; + register char *bpt, *bup; + struct stat s; + dev_t root_dev; + ino_t root_ino; + size_t ptsize, upsize; +--- 50,71 ---- + (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ + dp->d_name[1] == '.' && dp->d_name[2] == '\0')) + ++ /* Only use reentrant safe routines to simplify varifying POSIX thread-safe ++ * compliance. (mevans). ++ */ + char * + getcwd(pt, size) + char *pt; + size_t size; + { + register DIR *dir; + register dev_t dev; + register ino_t ino; + register int first; + register char *bpt, *bup; + struct stat s; ++ struct dirent *dp; ++ struct dirent de; + dev_t root_dev; + ino_t root_ino; + size_t ptsize, upsize; +*************** +*** 166,179 **** + save_errno = 0; + if (s.st_dev == dev) { + for (;;) { +! if (!(dp = readdir(dir))) + goto notfound; + if (dp->d_fileno == ino) + break; + } + } else + for (;;) { +! if (!(dp = readdir(dir))) + goto notfound; + if (ISDOT(dp)) + continue; +--- 170,183 ---- + save_errno = 0; + if (s.st_dev == dev) { + for (;;) { +! if (readdir_r(dir, &de, &dp)) + goto notfound; + if (dp->d_fileno == ino) + break; + } + } else + for (;;) { +! if (readdir_r(dir, &de, &dp)) + goto notfound; + if (ISDOT(dp)) + continue; +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/include/syslog.h pthreads-1_60_beta6+/include/syslog.h +*** pthreads-1_60_beta6/include/syslog.h Mon Sep 26 21:26:29 1994 +--- pthreads-1_60_beta6+/include/syslog.h Sat Mar 15 14:08:56 1997 +*************** +*** 9,14 **** +--- 9,16 ---- + #ifndef SYSLOG_H + #define SYSLOG_H + ++ /* Added __[BEGIN/END]_DECLS so this file would work with C++. (mevans) */ ++ #include <sys/cdefs.h> + #include <stdarg.h> + + /* Discipline: openlog(), closelog(), and setlogmask() are not thread-safe +*************** +*** 84,95 **** +--- 86,101 ---- + #define LOG_NDELAY 0x08 /* don't delay open */ + #define LOG_NOWAIT 0x10 /* if forking to log on console, don't wait() */ + ++ __BEGIN_DECLS ++ + /* Syslogging functions. */ + void syslog(int pri, char *fmt, ...); + void vsyslog(int pri, char *fmt, va_list args); + void openlog(char *ident, int logstat, int logfac); + void closelog(void); + int setlogmask(int pmask); ++ ++ __END_DECLS + + #endif + +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/machdep/engine-i386-linux-1.0.c pthreads-1_60_beta6+/machdep/engine-i386-linux-1.0.c +*** pthreads-1_60_beta6/machdep/engine-i386-linux-1.0.c Mon Oct 21 20:39:13 1996 +--- pthreads-1_60_beta6+/machdep/engine-i386-linux-1.0.c Sat Mar 15 14:08:56 1997 +*************** +*** 142,147 **** +--- 142,149 ---- + * machdep_pthread_start(). + */ + machdep_pthread->machdep_state->__pc = (char *)machdep_pthread_start; ++ machdep_pthread->machdep_state->__bp = (char *)0;/* So the backtrace ++ * is sensible (mevans) */ + + /* Stack starts high and builds down. */ + machdep_pthread->machdep_state->__sp = +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/machdep/syscall-i386-linux-1.0.S pthreads-1_60_beta6+/machdep/syscall-i386-linux-1.0.S +*** pthreads-1_60_beta6/machdep/syscall-i386-linux-1.0.S Mon Oct 21 22:17:32 1996 +--- pthreads-1_60_beta6+/machdep/syscall-i386-linux-1.0.S Sat Mar 15 14:08:56 1997 +*************** +*** 148,156 **** + /* ========================================================================= + * exit 1 select 82 + * fork 2 socketcall 102 +! * read 3 readv 145 +! * write 4 writev 146 +! * open 5 + * creat 8 + * link 9 + * unlink 10 +--- 148,156 ---- + /* ========================================================================= + * exit 1 select 82 + * fork 2 socketcall 102 +! * read 3 flock 143 +! * write 4 readv 145 +! * open 5 writev 146 + * creat 8 + * link 9 + * unlink 10 +*************** +*** 390,394 **** +--- 390,401 ---- + */ + #ifdef HAVE_SYSCALL_WRITEV + SYSCALL3(writev) ++ #endif ++ ++ /* ========================================================================== ++ * machdep_sys_flock() ++ */ ++ #ifdef HAVE_SYSCALL_FLOCK ++ SYSCALL2(flock) + #endif + +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/net/gethostbyname.c pthreads-1_60_beta6+/net/gethostbyname.c +*** pthreads-1_60_beta6/net/gethostbyname.c Mon Apr 22 22:41:21 1996 +--- pthreads-1_60_beta6+/net/gethostbyname.c Sat Mar 15 14:08:58 1997 +*************** +*** 146,161 **** + { + char **alias; + FILE *fp = NULL; + + pthread_mutex_lock(&host_iterate_lock); + sethostent(0); +! while ((result = gethostent_r(result, buf, bufsize, errval)) != NULL) { + /* Check the entry's name and aliases against the given name. */ + if (strcasecmp(result->h_name, name) == 0) + break; + for (alias = result->h_aliases; *alias; alias++) { +! if (strcasecmp(*alias, name) == 0) + break; + } + } + pthread_mutex_unlock(&host_iterate_lock); +--- 146,166 ---- + { + char **alias; + FILE *fp = NULL; ++ int fFound = FALSE; + + pthread_mutex_lock(&host_iterate_lock); + sethostent(0); +! while (!fFound && (result = gethostent_r(result, buf, bufsize, errval)) +! != NULL) { + /* Check the entry's name and aliases against the given name. */ + if (strcasecmp(result->h_name, name) == 0) + break; + for (alias = result->h_aliases; *alias; alias++) { +! if (strcasecmp(*alias, name) == 0) { +! /* fFound will exit while loop. (mevans). */ +! fFound = TRUE; + break; ++ } + } + } + pthread_mutex_unlock(&host_iterate_lock); +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/net/res_debug.c pthreads-1_60_beta6+/net/res_debug.c +*** pthreads-1_60_beta6/net/res_debug.c Thu Feb 23 22:42:35 1995 +--- pthreads-1_60_beta6+/net/res_debug.c Sat Mar 15 14:08:58 1997 +*************** +*** 375,380 **** +--- 375,383 ---- + + /* + * Print resource record fields in human readable form. ++ * ++ * Removed calls to non-reentrant routines to simplify varifying ++ * POSIX thread-safe implementations. (mevans). + */ + char * + p_rr(cp, msg, file) +*************** +*** 386,391 **** +--- 389,395 ---- + char *cp1, *cp2; + u_long tmpttl, t; + int lcnt; ++ char buf[32]; + + if ((cp = p_fqname(cp, msg, file)) == NULL) + return (NULL); /* compression error */ +*************** +*** 413,426 **** + case C_HS: + bcopy(cp, (char *)&inaddr, sizeof(inaddr)); + if (dlen == 4) { +! fprintf(file,"\t%s", inet_ntoa(inaddr)); + cp += dlen; + } else if (dlen == 7) { + char *address; + u_char protocol; + u_short port; + +! address = inet_ntoa(inaddr); + cp += sizeof(inaddr); + protocol = *(u_char*)cp; + cp += sizeof(u_char); +--- 417,432 ---- + case C_HS: + bcopy(cp, (char *)&inaddr, sizeof(inaddr)); + if (dlen == 4) { +! fprintf(file,"\t%s", +! inet_ntoa_r(inaddr, buf, sizeof(buf))); + cp += dlen; + } else if (dlen == 7) { + char *address; + u_char protocol; + u_short port; + +! address = inet_ntoa_r(inaddr, +! buf, sizeof(buf)); + cp += sizeof(inaddr); + protocol = *(u_char*)cp; + cp += sizeof(u_char); +*************** +*** 524,530 **** + bcopy(cp, (char *)&inaddr, sizeof(inaddr)); + cp += sizeof(u_long); + fprintf(file, "\t%s %s ( ", +! inet_ntoa(inaddr), + deproto((int) *cp)); + cp += sizeof(u_char); + n = 0; +--- 530,536 ---- + bcopy(cp, (char *)&inaddr, sizeof(inaddr)); + cp += sizeof(u_long); + fprintf(file, "\t%s %s ( ", +! inet_ntoa_r(inaddr, buf, sizeof(buf)), + deproto((int) *cp)); + cp += sizeof(u_char); + n = 0; +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/pthreads/fd_kern.c pthreads-1_60_beta6+/pthreads/fd_kern.c +*** pthreads-1_60_beta6/pthreads/fd_kern.c Tue Oct 1 12:26:48 1996 +--- pthreads-1_60_beta6+/pthreads/fd_kern.c Sat Mar 15 14:09:00 1997 +*************** +*** 215,221 **** + * Called when there is no active thread to run. + */ + extern struct timeval __fd_kern_wait_timeout; +! + void fd_kern_wait() + { + fd_set fd_set_read, fd_set_write, fd_set_except; +--- 215,221 ---- + * Called when there is no active thread to run. + */ + extern struct timeval __fd_kern_wait_timeout; +! extern volatile sig_atomic_t sig_to_process; + void fd_kern_wait() + { + fd_set fd_set_read, fd_set_write, fd_set_except; +*************** +*** 254,260 **** + + machdep_unset_thread_timer(NULL); + __fd_kern_wait_timeout.tv_usec = 0; +! __fd_kern_wait_timeout.tv_sec = 3600; + + machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); + +--- 254,260 ---- + + machdep_unset_thread_timer(NULL); + __fd_kern_wait_timeout.tv_usec = 0; +! __fd_kern_wait_timeout.tv_sec = (sig_to_process) ? 0 : 3600; + + machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); + +*************** +*** 726,731 **** +--- 726,753 ---- + return(ret); + } + ++ #if defined (HAVE_SYSCALL_FLOCK) ++ /* ========================================================================== ++ * flock() ++ * ++ * Added (mevans) ++ */ ++ int flock(int fd, int operation) ++ { ++ int ret; ++ ++ if ((ret = fd_lock(fd, FD_RDWR, NULL)) == OK) { ++ if ((ret = machdep_sys_flock(fd_table[fd]->fd.i, ++ operation)) < OK) { ++ SET_ERRNO(-ret); ++ ret = NOTOK; ++ } ++ fd_unlock(fd, FD_RDWR); ++ } ++ return(ret); ++ } ++ #endif ++ + /* ========================================================================== + * pipe() + */ +*************** +*** 1126,1132 **** + /* Get the error, this function should not fail */ + machdep_sys_getsockopt(fd_table[fd]->fd.i, SOL_SOCKET, + SO_ERROR, &ret, &tmpnamelen); +! SET_ERRNO(-ret); + ret = NOTOK; + } + } else { +--- 1148,1155 ---- + /* Get the error, this function should not fail */ + machdep_sys_getsockopt(fd_table[fd]->fd.i, SOL_SOCKET, + SO_ERROR, &ret, &tmpnamelen); +! /* ret is already positive (mevans) */ +! SET_ERRNO(ret); + ret = NOTOK; + } + } else { +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/pthreads/malloc.c pthreads-1_60_beta6+/pthreads/malloc.c +*** pthreads-1_60_beta6/pthreads/malloc.c Thu Mar 9 21:06:43 1995 +--- pthreads-1_60_beta6+/pthreads/malloc.c Sat Mar 15 14:09:00 1997 +*************** +*** 196,204 **** + else + n = n - x; + if (n) { +! if (sbrk(n) == (char *)-1) + return (NULL); + } + bucket = 0; + amt = 8; + while (pagesz > amt) { +--- 196,207 ---- + else + n = n - x; + if (n) { +! if (sbrk(n) == (char *)-1) { +! /* Unlock before returning (mevans) */ +! pthread_mutex_unlock(mutex); + return (NULL); + } ++ } + bucket = 0; + amt = 8; + while (pagesz > amt) { +*************** +*** 363,366 **** +--- 366,382 ---- + free(cp); + + return (res); ++ } ++ /* ========================================================================== ++ * calloc() ++ * ++ * Added to ensure pthread's allocation is used (mevans). ++ */ ++ void *calloc(size_t nmemb, size_t size) ++ { ++ void *p; ++ size *= nmemb; ++ p = malloc(size); ++ if (p) memset(p, 0, size); ++ return (p); + } +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/pthreads/select.c pthreads-1_60_beta6+/pthreads/select.c +*** pthreads-1_60_beta6/pthreads/select.c Sat Jul 6 21:58:55 1996 +--- pthreads-1_60_beta6+/pthreads/select.c Sat Mar 15 14:09:00 1997 +*************** +*** 165,176 **** + pthread_resched_resume(PS_SELECT_WAIT); + + /* We're awake */ +- CLEAR_PF_DONE_EVENT(pthread_run); + if (sleep_cancel(pthread_run) == NOTOK) { + ret = OK; + } else { + ret = data.nfds; + } + } else { + pthread_resched_resume(PS_SELECT_WAIT); + CLEAR_PF_DONE_EVENT(pthread_run); +--- 165,180 ---- + pthread_resched_resume(PS_SELECT_WAIT); + + /* We're awake */ + if (sleep_cancel(pthread_run) == NOTOK) { + ret = OK; + } else { + ret = data.nfds; + } ++ /* Moving this after the sleep_cancel() seemed ++ * to fix intermittent crashes during heavy ++ * socket use. (mevans) ++ */ ++ CLEAR_PF_DONE_EVENT(pthread_run); + } else { + pthread_resched_resume(PS_SELECT_WAIT); + CLEAR_PF_DONE_EVENT(pthread_run); +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/pthreads/signal.c pthreads-1_60_beta6+/pthreads/signal.c +*** pthreads-1_60_beta6/pthreads/signal.c Tue Mar 12 21:33:17 1996 +--- pthreads-1_60_beta6+/pthreads/signal.c Sat Mar 15 14:09:00 1997 +*************** +*** 65,71 **** + */ + + static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, }; +! static sig_atomic_t sig_to_process = 0; + + /* static volatile sigset_t sig_to_process; */ + static volatile int sig_count = 0; +--- 65,71 ---- + */ + + static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, }; +! volatile sig_atomic_t sig_to_process = 0; + + /* static volatile sigset_t sig_to_process; */ + static volatile int sig_count = 0; +*************** +*** 303,309 **** + break; + case NOTOK: + /* Do the registered action, no threads were sleeping */ +! sigdefault(sig); + break; + } + break; +--- 303,317 ---- + break; + case NOTOK: + /* Do the registered action, no threads were sleeping */ +! /* There is a timing window that gets +! * here when no threads are on the +! * sleep queue. This is a quick fix. +! * The real problem is possibly related +! * to heavy use of condition variables +! * with time outs. +! * (mevans) +! *sigdefault(sig); +! */ + break; + } + break; +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/stdio/setvbuf.c pthreads-1_60_beta6+/stdio/setvbuf.c +*** pthreads-1_60_beta6/stdio/setvbuf.c Sat Sep 3 20:58:36 1994 +--- pthreads-1_60_beta6+/stdio/setvbuf.c Sat Mar 15 14:09:00 1997 +*************** +*** 142,148 **** + flags |= __SLBF; + if (flags & __SRW) + flags &= ~(__SRD | __SWR); +! fp->_w = 0; + fp->_flags = flags; + fp->_bf._base = fp->_p = (unsigned char *)buf; + fp->_bf._size = size; +--- 142,148 ---- + flags |= __SLBF; + if (flags & __SRW) + flags &= ~(__SRD | __SWR); +! fp->_w = size; /* Was 0 (mevans) */ + fp->_flags = flags; + fp->_bf._base = fp->_p = (unsigned char *)buf; + fp->_bf._size = size; +diff -c -b -r -d -I .*$Id:.* pthreads-1_60_beta6/stdlib/system.c pthreads-1_60_beta6+/stdlib/system.c +*** pthreads-1_60_beta6/stdlib/system.c Wed Apr 24 21:18:56 1996 +--- pthreads-1_60_beta6+/stdlib/system.c Sat Mar 15 14:09:01 1997 +*************** +*** 62,68 **** + argp[2] = (char *) command; + sigemptyset(&tmp_mask); + sigaddset(&tmp_mask, SIGCHLD); +! pthread_sigmask(SIG_BLOCK, tmp_mask, &old_mask); + switch(pid = fork()) { + case -1: /* error */ + (void)pthread_sigmask(SIG_SETMASK, &old_mask, NULL); +--- 62,69 ---- + argp[2] = (char *) command; + sigemptyset(&tmp_mask); + sigaddset(&tmp_mask, SIGCHLD); +! /* Pass the address of tmp_mask to avoid a sigfault. (mevans). */ +! pthread_sigmask(SIG_BLOCK, &tmp_mask, &old_mask); + switch(pid = fork()) { + case -1: /* error */ + (void)pthread_sigmask(SIG_SETMASK, &old_mask, NULL); diff --git a/lib/libpthread/patches/p153 b/lib/libpthread/patches/p153 new file mode 100755 index 00000000000..4e374e29a10 --- /dev/null +++ b/lib/libpthread/patches/p153 @@ -0,0 +1,90 @@ +<HEAD><TITLE>discuss@charon.mit.edu: [153] in "Pthreads Bugs"</TITLE> +<H1>[153] in Pthreads Bugs</H1></HEAD> +<A HREF="/"><IMG SRC="/i-d.gif" ALT="root"></A> +<A HREF="?153"><IMG SRC="/i-back.gif" ALT="meeting"></A> +<A HREF="/help.html"><IMG SRC="/i-help.gif" ALT="help"></A> +<A HREF="1"><IMG SRC="/i-first.gif" ALT="first"></A> +<A HREF="151"><IMG SRC="/i-fref.gif" ALT="first in chain"></A> +<A HREF="152"><IMG SRC="/i-pref.gif" ALT="previous in chain"></A> +<A HREF="152"><IMG SRC="/i-prev.gif" ALT="previous"></A> +<A HREF="154"><IMG SRC="/i-next.gif" ALT="next"></A> +<IMG SRC="/n-nref.gif" ALT=""> +<IMG SRC="/n-lref.gif" ALT=""> +<A HREF="161"><IMG SRC="/i-last.gif" ALT="last"></A> +<HR><H2>Re: sleep / SIGALRM problem in 1_60_beta6</H2> +<H3>daemon@ATHENA.MIT.EDU (Mon Dec 9 19:32:22 1996 +)</H3> +<PRE> +Date: Mon, 09 Dec 1996 17:22:50 -0700 +From: "Mark M. Evans" <mevans@cti-ltd.com> +To: Tim Hinderliter <kyd@internap.com> +Cc: pthreads-bugs@MIT.EDU + +I think I found what caused fd_kern_wait() to block for the entire +hour (instead of waking up due to the SIGALRM). Basically, the +SIGALRM that would move the sleeping thread to the run queue occurs +while pthread_kernel_lock is set, but *before* the critical section in +fd_kern_wait() that sets __fd_kern_wait_timeout.tv_sec to 3600. So, +sig_handler_real() clears __fd_kern_wait_timeout.tv_sec "too soon." + +I've worked around this by checking sig_to_process in the critical +section to determine if we are truly idle. To do this I had to make +sig_to_process publicly available. + +Here are the diffs (relative to the pthreads/pthreads directory): + +diff -c -r1.2 -r1.3 +*** signal.c 1996/11/20 05:09:50 1.2 +--- signal.c 1996/12/09 23:14:52 1.3 +*************** +*** 65,71 **** + */ + + static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, }; +! static sig_atomic_t sig_to_process = 0; + + /* static volatile sigset_t sig_to_process; */ + static volatile int sig_count = 0; +--- 65,71 ---- + */ + + static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, }; +! sig_atomic_t sig_to_process = 0; + + /* static volatile sigset_t sig_to_process; */ + static volatile int sig_count = 0; +*** fd_kern.c 1996/12/03 04:14:59 1.6 +--- fd_kern.c 1996/12/09 23:14:51 1.7 +*************** +*** 215,221 **** + * Called when there is no active thread to run. + */ + extern struct timeval __fd_kern_wait_timeout; +! + void fd_kern_wait() + { + fd_set fd_set_read, fd_set_write, fd_set_except; +--- 215,221 ---- + * Called when there is no active thread to run. + */ + extern struct timeval __fd_kern_wait_timeout; +! extern volatile sig_atomic_t sig_to_process; + void fd_kern_wait() + { + fd_set fd_set_read, fd_set_write, fd_set_except; +*************** +*** 254,260 **** + + machdep_unset_thread_timer(NULL); + __fd_kern_wait_timeout.tv_usec = 0; +! __fd_kern_wait_timeout.tv_sec = 3600; + + machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); + +--- 254,260 ---- + + machdep_unset_thread_timer(NULL); + __fd_kern_wait_timeout.tv_usec = 0; +! __fd_kern_wait_timeout.tv_sec = (sig_to_process) ? 0 : 3600; + + machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); diff --git a/lib/libpthread/patches/p155 b/lib/libpthread/patches/p155 new file mode 100755 index 00000000000..dbdfa7de899 --- /dev/null +++ b/lib/libpthread/patches/p155 @@ -0,0 +1,96 @@ +<HEAD><TITLE>discuss@charon.mit.edu: [155] in "Pthreads Bugs"</TITLE> +<H1>[155] in Pthreads Bugs</H1></HEAD> +<A HREF="/"><IMG SRC="/i-d.gif" ALT="root"></A> +<A HREF="?155"><IMG SRC="/i-back.gif" ALT="meeting"></A> +<A HREF="/help.html"><IMG SRC="/i-help.gif" ALT="help"></A> +<A HREF="1"><IMG SRC="/i-first.gif" ALT="first"></A> +<IMG SRC="/n-fref.gif" ALT=""> +<IMG SRC="/n-pref.gif" ALT=""> +<A HREF="154"><IMG SRC="/i-prev.gif" ALT="previous"></A> +<A HREF="156"><IMG SRC="/i-next.gif" ALT="next"></A> +<IMG SRC="/n-nref.gif" ALT=""> +<IMG SRC="/n-lref.gif" ALT=""> +<A HREF="161"><IMG SRC="/i-last.gif" ALT="last"></A> +<HR><H2>pthread_kill() Bug</H2> +<H3>daemon@ATHENA.MIT.EDU (Thu Dec 26 20:34:45 1996 +)</H3> +<PRE> +From: Chris Colohan <colohan@eecg.toronto.edu> +To: pthreads-bugs@MIT.EDU, proven@MIT.EDU +Date: Thu, 26 Dec 1996 20:33:48 -0500 + +pthread_kill() has a problem in PThreads 1.60beta6. It checks to see +if the target thread is in the state PS_SIGWAIT, and if it is it +reschedules it. But it does not check if there is more than one +thread in the PS_SIGWAIT state, and hence mangles the pthread_sigwait +linked list, potentially resulting in threads getting blocked forever, +and signals never being delivered. I have a *very* contrived test +case that demonstrates this problem if you would like it. Please let +me know... + +Chris +=== + +Diffs created with diff -c: + +*** /home/colohan/thesis/t/pthreads-1_60_beta6/pthreads/pthread_kill.c Tue Feb 21 03:07:18 1995 +--- pthread_kill.c Thu Dec 26 19:50:22 1996 +*************** +*** 41,51 **** +--- 41,58 ---- + + #include <pthread.h> + ++ /* Defined in sig.c, a linked list of threads currently ++ * blocked in sigwait(): */ ++ extern struct pthread * pthread_sigwait; ++ ++ + /* ========================================================================== + * pthread_kill() + */ + int pthread_kill(struct pthread * pthread, int sig) + { ++ struct pthread ** pthread_ptr; ++ + pthread_sched_prevent(); + + /* Check who is the current owner of pthread */ +*************** +*** 53,62 **** + if (0) { + } else { + if (pthread->state == PS_SIGWAIT) { +! if (sigismember(pthread->data.sigwait, sig)) { +! *(int *)(pthread->ret) = sig; +! pthread_sched_other_resume(pthread); +! return(OK); + } + } + sigaddset(&(pthread->sigpending), sig); +--- 60,84 ---- + if (0) { + } else { + if (pthread->state == PS_SIGWAIT) { +! if(sigismember(pthread->data.sigwait, sig)) { +! for (pthread_ptr = &pthread_sigwait; +! (*pthread_ptr); +! pthread_ptr = &((*pthread_ptr)->next)) { +! if ((*pthread_ptr) == pthread) { +! +! /* Take the thread out of the +! * pthread_sigwait linked list: */ +! *pthread_ptr=(*pthread_ptr)->next; +! +! *(int *)(pthread->ret) = sig; +! pthread_sched_other_resume(pthread); +! return(OK); +! } +! } +! /* A thread should not be in the state PS_SIGWAIT +! * without being in the pthread_sigwait linked +! * list: */ +! PANIC(); + } + } + sigaddset(&(pthread->sigpending), sig); diff --git a/lib/libpthread/stdio/xprintf.c b/lib/libpthread/stdio/xprintf.c new file mode 100644 index 00000000000..a05de561e72 --- /dev/null +++ b/lib/libpthread/stdio/xprintf.c @@ -0,0 +1,883 @@ +/* +** It turns out that the printf functions in the stock MIT pthread library +** is busted. It isn't thread safe. If two threads try to do a printf +** of a floating point value at the same time, a core-dump might result. +** So this code is substituted. +*/ +/* +** NAME: $Source: /cvs/OpenBSD/src/lib/libpthread/stdio/Attic/xprintf.c,v $ +** VERSION: $Revision: 1.1 $ +** DATE: $Date: 1998/07/21 13:22:19 $ +** +** ONELINER: A replacement for formatted printing programs. +** +** COPYRIGHT: +** Copyright (c) 1990 by D. Richard Hipp. This code is an original +** work and has been prepared without reference to any prior +** implementations of similar functions. No part of this code is +** subject to licensing restrictions of any telephone company or +** university. +** +** This copyright was released and the code placed in the public domain +** by the author, D. Richard Hipp, on October 3, 1996. +** +** DESCRIPTION: +** This program is an enhanced replacement for the "printf" programs +** found in the standard library. The following enhancements are +** supported: +** +** + Additional functions. The standard set of "printf" functions +** includes printf, fprintf, sprintf, vprintf, vfprintf, and +** vsprintf. This module adds the following: +** +** * snprintf -- Works like sprintf, but has an extra argument +** which is the size of the buffer written to. +** +** * mprintf -- Similar to sprintf. Writes output to memory +** obtained from mem_alloc. +** +** * xprintf -- Calls a function to dispose of output. +** +** * nprintf -- No output, but returns the number of characters +** that would have been output by printf. +** +** * A v- version (ex: vsnprintf) of every function is also +** supplied. +** +** + A few extensions to the formatting notation are supported: +** +** * The "=" flag (similar to "-") causes the output to be +** be centered in the appropriately sized field. +** +** * The %b field outputs an integer in binary notation. +** +** * The %c field now accepts a precision. The character output +** is repeated by the number of times the precision specifies. +** +** * The %' field works like %c, but takes as its character the +** next character of the format string, instead of the next +** argument. For example, printf("%.78'-") prints 78 minus +** signs, the same as printf("%.78c",'-'). +** +** + When compiled using GCC on a SPARC, this version of printf is +** faster than the library printf for SUN OS 4.1. +** +** + All functions are fully reentrant. +** +*/ +/* +** Undefine COMPATIBILITY to make some slight changes in the way things +** work. I think the changes are an improvement, but they are not +** backwards compatible. +*/ +/* #define COMPATIBILITY / * Compatible with SUN OS 4.1 */ +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> +/* +** The maximum number of digits of accuracy in a floating-point conversion. +*/ +#define MAXDIG 20 + +/* +** Conversion types fall into various categories as defined by the +** following enumeration. +*/ +enum e_type { /* The type of the format field */ + RADIX, /* Integer types. %d, %x, %o, and so forth */ + FLOAT, /* Floating point. %f */ + EXP, /* Exponentional notation. %e and %E */ + GENERIC, /* Floating or exponential, depending on exponent. %g */ + SIZE, /* Return number of characters processed so far. %n */ + STRING, /* Strings. %s */ + PERCENT, /* Percent symbol. %% */ + CHAR, /* Characters. %c */ + ERROR, /* Used to indicate no such conversion type */ +/* The rest are extensions, not normally found in printf() */ + CHARLIT, /* Literal characters. %' */ + SEEIT, /* Strings with visible control characters. %S */ + MEM_STRING, /* A string which should be deleted after use. %z */ + ORDINAL, /* 1st, 2nd, 3rd and so forth */ +}; + +/* +** Each builtin conversion character (ex: the 'd' in "%d") is described +** by an instance of the following structure +*/ +typedef struct s_info { /* Information about each format field */ + int fmttype; /* The format field code letter */ + int base; /* The base for radix conversion */ + char *charset; /* The character set for conversion */ + int flag_signed; /* Is the quantity signed? */ + char *prefix; /* Prefix on non-zero values in alt format */ + enum e_type type; /* Conversion paradigm */ +} info; + +/* +** The following table is searched linearly, so it is good to put the +** most frequently used conversion types first. +*/ +static info fmtinfo[] = { + { 'd', 10, "0123456789", 1, 0, RADIX, }, + { 's', 0, 0, 0, 0, STRING, }, + { 'S', 0, 0, 0, 0, SEEIT, }, + { 'z', 0, 0, 0, 0, MEM_STRING, }, + { 'c', 0, 0, 0, 0, CHAR, }, + { 'o', 8, "01234567", 0, "0", RADIX, }, + { 'u', 10, "0123456789", 0, 0, RADIX, }, + { 'x', 16, "0123456789abcdef", 0, "x0", RADIX, }, + { 'X', 16, "0123456789ABCDEF", 0, "X0", RADIX, }, + { 'r', 10, "0123456789", 0, 0, ORDINAL, }, + { 'f', 0, 0, 1, 0, FLOAT, }, + { 'e', 0, "e", 1, 0, EXP, }, + { 'E', 0, "E", 1, 0, EXP, }, + { 'g', 0, "e", 1, 0, GENERIC, }, + { 'G', 0, "E", 1, 0, GENERIC, }, + { 'i', 10, "0123456789", 1, 0, RADIX, }, + { 'n', 0, 0, 0, 0, SIZE, }, + { 'S', 0, 0, 0, 0, SEEIT, }, + { '%', 0, 0, 0, 0, PERCENT, }, + { 'b', 2, "01", 0, "b0", RADIX, }, /* Binary notation */ + { 'p', 10, "0123456789", 0, 0, RADIX, }, /* Pointers */ + { '\'', 0, 0, 0, 0, CHARLIT, }, /* Literal char */ +}; +#define NINFO (sizeof(fmtinfo)/sizeof(info)) /* Size of the fmtinfo table */ + +/* +** If NOFLOATINGPOINT is defined, then none of the floating point +** conversions will work. +*/ +#ifndef NOFLOATINGPOINT +/* +** "*val" is a double such that 0.1 <= *val < 10.0 +** Return the ascii code for the leading digit of *val, then +** multiply "*val" by 10.0 to renormalize. +** +** Example: +** input: *val = 3.14159 +** output: *val = 1.4159 function return = '3' +** +** The counter *cnt is incremented each time. After counter exceeds +** 16 (the number of significant digits in a 64-bit float) '0' is +** always returned. +*/ +static int getdigit(long double *val, int *cnt){ + int digit; + long double d; + if( (*cnt)++ >= MAXDIG ) return '0'; + digit = (int)*val; + d = digit; + digit += '0'; + *val = (*val - d)*10.0; + return digit; +} +#endif + +/* +** Setting the size of the BUFFER involves trade-offs. No %d or %f +** conversion can have more than BUFSIZE characters. If the field +** width is larger than BUFSIZE, it is silently shortened. On the +** other hand, this routine consumes more stack space with larger +** BUFSIZEs. If you have some threads for which you want to minimize +** stack space, you should keep BUFSIZE small. +*/ +#define BUFSIZE 100 /* Size of the output buffer */ + +/* +** The root program. All variations call this core. +** +** INPUTS: +** func This is a pointer to a function taking three arguments +** 1. A pointer to the list of characters to be output +** (Note, this list is NOT null terminated.) +** 2. An integer number of characters to be output. +** (Note: This number might be zero.) +** 3. A pointer to anything. Same as the "arg" parameter. +** +** arg This is the pointer to anything which will be passed as the +** third argument to "func". Use it for whatever you like. +** +** fmt This is the format string, as in the usual print. +** +** ap This is a pointer to a list of arguments. Same as in +** vfprint. +** +** OUTPUTS: +** The return value is the total number of characters sent to +** the function "func". Returns -1 on a error. +** +** Note that the order in which automatic variables are declared below +** seems to make a big difference in determining how fast this beast +** will run. +*/ +static int vxprintf(func,arg,format,ap) + void (*func)(char*,int,void*); + void *arg; + const char *format; + va_list ap; +{ + register const char *fmt; /* The format string. */ + register int c; /* Next character in the format string */ + register char *bufpt; /* Pointer to the conversion buffer */ + register int precision; /* Precision of the current field */ + register int length; /* Length of the field */ + register int idx; /* A general purpose loop counter */ + int count; /* Total number of characters output */ + int width; /* Width of the current field */ + int flag_leftjustify; /* True if "-" flag is present */ + int flag_plussign; /* True if "+" flag is present */ + int flag_blanksign; /* True if " " flag is present */ + int flag_alternateform; /* True if "#" flag is present */ + int flag_zeropad; /* True if field width constant starts with zero */ + int flag_long; /* True if "l" flag is present */ + int flag_center; /* True if "=" flag is present */ + unsigned long longvalue; /* Value for integer types */ + long double realvalue; /* Value for real types */ + info *infop; /* Pointer to the appropriate info structure */ + char buf[BUFSIZE]; /* Conversion buffer */ + char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ + int errorflag = 0; /* True if an error is encountered */ + enum e_type xtype; /* Conversion paradigm */ + char *zMem; /* String to be freed */ + static char spaces[] = + " "; +#define SPACESIZE (sizeof(spaces)-1) +#ifndef NOFLOATINGPOINT + int exp; /* exponent of real numbers */ + long double rounder; /* Used for rounding floating point values */ + int flag_dp; /* True if decimal point should be shown */ + int flag_rtz; /* True if trailing zeros should be removed */ + int flag_exp; /* True to force display of the exponent */ + int nsd; /* Number of significant digits returned */ +#endif + + fmt = format; /* Put in a register for speed */ + count = length = 0; + bufpt = 0; + for(; (c=(*fmt))!=0; ++fmt){ + if( c!='%' ){ + register int amt; + bufpt = (char *)fmt; + amt = 1; + while( (c=(*++fmt))!='%' && c!=0 ) amt++; + (*func)(bufpt,amt,arg); + count += amt; + if( c==0 ) break; + } + if( (c=(*++fmt))==0 ){ + errorflag = 1; + (*func)("%",1,arg); + count++; + break; + } + /* Find out what flags are present */ + flag_leftjustify = flag_plussign = flag_blanksign = + flag_alternateform = flag_zeropad = flag_center = 0; + do{ + switch( c ){ + case '-': flag_leftjustify = 1; c = 0; break; + case '+': flag_plussign = 1; c = 0; break; + case ' ': flag_blanksign = 1; c = 0; break; + case '#': flag_alternateform = 1; c = 0; break; + case '0': flag_zeropad = 1; c = 0; break; + case '=': flag_center = 1; c = 0; break; + default: break; + } + }while( c==0 && (c=(*++fmt))!=0 ); + if( flag_center ) flag_leftjustify = 0; + /* Get the field width */ + width = 0; + if( c=='*' ){ + width = va_arg(ap,int); + if( width<0 ){ + flag_leftjustify = 1; + width = -width; + } + c = *++fmt; + }else{ + while( isdigit(c) ){ + width = width*10 + c - '0'; + c = *++fmt; + } + } + if( width > BUFSIZE-10 ){ + width = BUFSIZE-10; + } + /* Get the precision */ + if( c=='.' ){ + precision = 0; + c = *++fmt; + if( c=='*' ){ + precision = va_arg(ap,int); +#ifndef COMPATIBILITY + /* This is sensible, but SUN OS 4.1 doesn't do it. */ + if( precision<0 ) precision = -precision; +#endif + c = *++fmt; + }else{ + while( isdigit(c) ){ + precision = precision*10 + c - '0'; + c = *++fmt; + } + } + /* Limit the precision to prevent overflowing buf[] during conversion */ + if( precision>BUFSIZE-40 ) precision = BUFSIZE-40; + }else{ + precision = -1; + } + /* Get the conversion type modifier */ + if( c=='l' ){ + flag_long = 1; + c = *++fmt; + }else{ + flag_long = 0; + } + /* Fetch the info entry for the field */ + infop = 0; + for(idx=0; idx<NINFO; idx++){ + if( c==fmtinfo[idx].fmttype ){ + infop = &fmtinfo[idx]; + break; + } + } + /* No info entry found. It must be an error. */ + if( infop==0 ){ + xtype = ERROR; + }else{ + xtype = infop->type; + } + + /* + ** At this point, variables are initialized as follows: + ** + ** flag_alternateform TRUE if a '#' is present. + ** flag_plussign TRUE if a '+' is present. + ** flag_leftjustify TRUE if a '-' is present or if the + ** field width was negative. + ** flag_zeropad TRUE if the width began with 0. + ** flag_long TRUE if the letter 'l' (ell) prefixed + ** the conversion character. + ** flag_blanksign TRUE if a ' ' is present. + ** width The specified field width. This is + ** always non-negative. Zero is the default. + ** precision The specified precision. The default + ** is -1. + ** xtype The class of the conversion. + ** infop Pointer to the appropriate info struct. + */ + switch( xtype ){ + case ORDINAL: + case RADIX: + if( flag_long ) longvalue = va_arg(ap,long); + else longvalue = va_arg(ap,int); +#ifdef COMPATIBILITY + /* For the format %#x, the value zero is printed "0" not "0x0". + ** I think this is stupid. */ + if( longvalue==0 ) flag_alternateform = 0; +#else + /* More sensible: turn off the prefix for octal (to prevent "00"), + ** but leave the prefix for hex. */ + if( longvalue==0 && infop->base==8 ) flag_alternateform = 0; +#endif + if( infop->flag_signed ){ + if( *(long*)&longvalue<0 ){ + longvalue = -*(long*)&longvalue; + prefix = '-'; + }else if( flag_plussign ) prefix = '+'; + else if( flag_blanksign ) prefix = ' '; + else prefix = 0; + }else prefix = 0; + if( flag_zeropad && precision<width-(prefix!=0) ){ + precision = width-(prefix!=0); + } + bufpt = &buf[BUFSIZE]; + if( xtype==ORDINAL ){ + long a,b; + a = longvalue%10; + b = longvalue%100; + bufpt -= 2; + if( a==0 || a>3 || (b>10 && b<14) ){ + bufpt[0] = 't'; + bufpt[1] = 'h'; + }else if( a==1 ){ + bufpt[0] = 's'; + bufpt[1] = 't'; + }else if( a==2 ){ + bufpt[0] = 'n'; + bufpt[1] = 'd'; + }else if( a==3 ){ + bufpt[0] = 'r'; + bufpt[1] = 'd'; + } + } + { + register char *cset; /* Use registers for speed */ + register int base; + cset = infop->charset; + base = infop->base; + do{ /* Convert to ascii */ + *(--bufpt) = cset[longvalue%base]; + longvalue = longvalue/base; + }while( longvalue>0 ); + } + length = (int)(&buf[BUFSIZE]-bufpt); + for(idx=precision-length; idx>0; idx--){ + *(--bufpt) = '0'; /* Zero pad */ + } + if( prefix ) *(--bufpt) = prefix; /* Add sign */ + if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ + char *pre, x; + pre = infop->prefix; + if( *bufpt!=pre[0] ){ + for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x; + } + } + length = (int)(&buf[BUFSIZE]-bufpt); + break; + case FLOAT: + case EXP: + case GENERIC: + realvalue = va_arg(ap,double); +#ifndef NOFLOATINGPOINT + if( precision<0 ) precision = 6; /* Set default precision */ + if( precision>BUFSIZE-10 ) precision = BUFSIZE-10; + if( realvalue<0.0 ){ + realvalue = -realvalue; + prefix = '-'; + }else{ + if( flag_plussign ) prefix = '+'; + else if( flag_blanksign ) prefix = ' '; + else prefix = 0; + } + if( infop->type==GENERIC && precision>0 ) precision--; + rounder = 0.0; +#ifdef COMPATIBILITY + /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ + for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); +#else + /* It makes more sense to use 0.5 */ + if( precision>MAXDIG-1 ) idx = MAXDIG-1; + else idx = precision; + for(rounder=0.5; idx>0; idx--, rounder*=0.1); +#endif + if( infop->type==FLOAT ) realvalue += rounder; + /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ + exp = 0; + if( realvalue>0.0 ){ + int k = 0; + while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; } + while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; } + while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; } + while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; } + if( k>=100 ){ + bufpt = "NaN"; + length = 3; + break; + } + } + bufpt = buf; + /* + ** If the field type is GENERIC, then convert to either EXP + ** or FLOAT, as appropriate. + */ + flag_exp = xtype==EXP; + if( xtype!=FLOAT ){ + realvalue += rounder; + if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } + } + if( xtype==GENERIC ){ + flag_rtz = !flag_alternateform; + if( exp<-4 || exp>precision ){ + xtype = EXP; + }else{ + precision = precision - exp; + xtype = FLOAT; + } + }else{ + flag_rtz = 0; + } + /* + ** The "exp+precision" test causes output to be of type EXP if + ** the precision is too large to fit in buf[]. + */ + nsd = 0; + if( xtype==FLOAT && exp+precision<BUFSIZE-30 ){ + flag_dp = (precision>0 || flag_alternateform); + if( prefix ) *(bufpt++) = prefix; /* Sign */ + if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */ + else for(; exp>=0; exp--) *(bufpt++) = getdigit(&realvalue,&nsd); + if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */ + for(exp++; exp<0 && precision>0; precision--, exp++){ + *(bufpt++) = '0'; + } + while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd); + *(bufpt--) = 0; /* Null terminate */ + if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */ + while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; + if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; + } + bufpt++; /* point to next free slot */ + }else{ /* EXP or GENERIC */ + flag_dp = (precision>0 || flag_alternateform); + if( prefix ) *(bufpt++) = prefix; /* Sign */ + *(bufpt++) = getdigit(&realvalue,&nsd); /* First digit */ + if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */ + while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd); + bufpt--; /* point to last digit */ + if( flag_rtz && flag_dp ){ /* Remove tail zeros */ + while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; + if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; + } + bufpt++; /* point to next free slot */ + if( exp || flag_exp ){ + *(bufpt++) = infop->charset[0]; + if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */ + else { *(bufpt++) = '+'; } + if( exp>=100 ){ + *(bufpt++) = (exp/100)+'0'; /* 100's digit */ + exp %= 100; + } + *(bufpt++) = exp/10+'0'; /* 10's digit */ + *(bufpt++) = exp%10+'0'; /* 1's digit */ + } + } + /* The converted number is in buf[] and zero terminated. Output it. + ** Note that the number is in the usual order, not reversed as with + ** integer conversions. */ + length = (int)(bufpt-buf); + bufpt = buf; + + /* Special case: Add leading zeros if the flag_zeropad flag is + ** set and we are not left justified */ + if( flag_zeropad && !flag_leftjustify && length < width){ + int i; + int nPad = width - length; + for(i=width; i>=nPad; i--){ + bufpt[i] = bufpt[i-nPad]; + } + i = prefix!=0; + while( nPad-- ) bufpt[i++] = '0'; + length = width; + } +#endif + break; + case SIZE: + *(va_arg(ap,int*)) = count; + length = width = 0; + break; + case PERCENT: + buf[0] = '%'; + bufpt = buf; + length = 1; + break; + case CHARLIT: + case CHAR: + c = buf[0] = (xtype==CHAR ? va_arg(ap,int) : *++fmt); + if( precision>=0 ){ + for(idx=1; idx<precision; idx++) buf[idx] = c; + length = precision; + }else{ + length =1; + } + bufpt = buf; + break; + case STRING: + case MEM_STRING: + zMem = bufpt = va_arg(ap,char*); + if( bufpt==0 ) bufpt = "(null)"; + length = strlen(bufpt); + if( precision>=0 && precision<length ) length = precision; + break; + case SEEIT: + { + int i; + int c; + char *arg = va_arg(ap,char*); + for(i=0; i<BUFSIZE-1 && (c = *arg++)!=0; i++){ + if( c<0x20 || c>=0x7f ){ + buf[i++] = '^'; + buf[i] = (c&0x1f)+0x40; + }else{ + buf[i] = c; + } + } + bufpt = buf; + length = i; + if( precision>=0 && precision<length ) length = precision; + } + break; + case ERROR: + buf[0] = '%'; + buf[1] = c; + errorflag = 0; + idx = 1+(c!=0); + (*func)("%",idx,arg); + count += idx; + if( c==0 ) fmt--; + break; + }/* End switch over the format type */ + /* + ** The text of the conversion is pointed to by "bufpt" and is + ** "length" characters long. The field width is "width". Do + ** the output. + */ + if( !flag_leftjustify ){ + register int nspace; + nspace = width-length; + if( nspace>0 ){ + if( flag_center ){ + nspace = nspace/2; + width -= nspace; + flag_leftjustify = 1; + } + count += nspace; + while( nspace>=SPACESIZE ){ + (*func)(spaces,SPACESIZE,arg); + nspace -= SPACESIZE; + } + if( nspace>0 ) (*func)(spaces,nspace,arg); + } + } + if( length>0 ){ + (*func)(bufpt,length,arg); + count += length; + } + if( xtype==MEM_STRING && zMem ){ + free(zMem); + } + if( flag_leftjustify ){ + register int nspace; + nspace = width-length; + if( nspace>0 ){ + count += nspace; + while( nspace>=SPACESIZE ){ + (*func)(spaces,SPACESIZE,arg); + nspace -= SPACESIZE; + } + if( nspace>0 ) (*func)(spaces,nspace,arg); + } + } + }/* End for loop over the format string */ + return errorflag ? -1 : count; +} /* End of function */ + +/* +** This non-standard function is still occasionally useful.... +*/ +int xprintf( + void (*func)(char*,int,void*), + void *arg, + const char *format, + ... +){ + va_list ap; + va_start(ap,format); + return vxprintf(func,arg,format,ap); +} + +/* +** Now for string-print, also as found in any standard library. +** Add to this the snprint function which stops added characters +** to the string at a given length. +** +** Note that snprint returns the length of the string as it would +** be if there were no limit on the output. +*/ +struct s_strargument { /* Describes the string being written to */ + char *next; /* Next free slot in the string */ + char *last; /* Last available slot in the string */ +}; + +static void sout(txt,amt,arg) + char *txt; + int amt; + void *arg; +{ + register char *head; + register const char *t; + register int a; + register char *tail; + a = amt; + t = txt; + head = ((struct s_strargument*)arg)->next; + tail = ((struct s_strargument*)arg)->last; + if( tail ){ + while( a-- >0 && head<tail ) *(head++) = *(t++); + }else{ + while( a-- >0 ) *(head++) = *(t++); + } + *head = 0; + ((struct s_strargument*)arg)->next = head; +} + +int sprintf(char *buf, const char *fmt, ...){ + int rc; + va_list ap; + struct s_strargument arg; + + va_start(ap,fmt); + arg.next = buf; + arg.last = 0; + *arg.next = 0; + rc = vxprintf(sout,&arg,fmt,ap); + va_end(ap); +} +int vsprintf(char *buf,const char *fmt,va_list ap){ + struct s_strargument arg; + arg.next = buf; + arg.last = 0; + *buf = 0; + return vxprintf(sout,&arg,fmt,ap); +} +int snprintf(char *buf, size_t n, const char *fmt, ...){ + int rc; + va_list ap; + struct s_strargument arg; + + va_start(ap,fmt); + arg.next = buf; + arg.last = &arg.next[n-1]; + *arg.next = 0; + rc = vxprintf(sout,&arg,fmt,ap); + va_end(ap); +} +int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap){ + struct s_strargument arg; + arg.next = buf; + arg.last = &buf[n-1]; + *buf = 0; + return vxprintf(sout,&arg,fmt,ap); +} + +/* +** The following section of code handles the mprintf routine, that +** writes to memory obtained from malloc(). +*/ + +/* This structure is used to store state information about the +** write in progress +*/ +struct sgMprintf { + char *zBase; /* A base allocation */ + char *zText; /* The string collected so far */ + int nChar; /* Length of the string so far */ + int nAlloc; /* Amount of space allocated in zText */ +}; + +/* The xprintf callback function. */ +static void mout(zNewText,nNewChar,arg) + char *zNewText; + int nNewChar; + void *arg; +{ + struct sgMprintf *pM = (struct sgMprintf*)arg; + if( pM->nChar + nNewChar + 1 > pM->nAlloc ){ + pM->nAlloc = pM->nChar + nNewChar*2 + 1; + if( pM->zText==pM->zBase ){ + pM->zText = malloc(pM->nAlloc); + if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar); + }else{ + pM->zText = realloc(pM->zText, pM->nAlloc); + } + } + if( pM->zText ){ + memcpy(&pM->zText[pM->nChar], zNewText, nNewChar); + pM->nChar += nNewChar; + pM->zText[pM->nChar] = 0; + } +} + +/* +** mprintf() works like printf(), but allocations memory to hold the +** resulting string and returns a pointer to the allocated memory. +** +** We changed the name to TclMPrint() to conform with the Tcl private +** routine naming conventions. +*/ +char *mprintf(const char *zFormat, ...){ + va_list ap; + struct sgMprintf sMprintf; + char *zNew; + char zBuf[200]; + + va_start(ap,zFormat); + sMprintf.nChar = 0; + sMprintf.nAlloc = sizeof(zBuf); + sMprintf.zText = zBuf; + sMprintf.zBase = zBuf; + vxprintf(mout,&sMprintf,zFormat,ap); + va_end(ap); + if( sMprintf.zText==sMprintf.zBase ){ + zNew = malloc( sMprintf.nChar+1 ); + if( zNew ) strcpy(zNew,zBuf); + }else{ + zNew = realloc(sMprintf.zText,sMprintf.nChar+1); + } + + return zNew; +} + +/* This is the varargs version of mprintf. +** +** The name is changed to TclVMPrintf() to conform with Tcl naming +** conventions. +*/ +char *vmprintf(const char *zFormat,va_list ap){ + struct sgMprintf sMprintf; + char zBuf[200]; + sMprintf.nChar = 0; + sMprintf.zText = zBuf; + sMprintf.nAlloc = sizeof(zBuf); + sMprintf.zBase = zBuf; + vxprintf(mout,&sMprintf,zFormat,ap); + if( sMprintf.zText==sMprintf.zBase ){ + sMprintf.zText = malloc( strlen(zBuf)+1 ); + if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf); + }else{ + sMprintf.zText = realloc(sMprintf.zText,sMprintf.nChar+1); + } + return sMprintf.zText; +} + +/* +** The following section of code handles the standard fprintf routines +** for pthreads. +*/ + +/* The xprintf callback function. */ +static void fout(zNewText,nNewChar,arg) + char *zNewText; + int nNewChar; + void *arg; +{ + fwrite(zNewText,1,nNewChar,(FILE*)arg); +} + +/* The public interface routines */ +int fprintf(FILE *pOut, const char *zFormat, ...){ + va_list ap; + int retc; + + va_start(ap,zFormat); + retc = vxprintf(fout,pOut,zFormat,ap); + va_end(ap); + return retc; +} +int vfprintf(FILE *pOut, const char *zFormat, va_list ap){ + return vxprintf(fout,pOut,zFormat,ap); +} +int printf(const char *zFormat, ...){ + va_list ap; + int retc; + + va_start(ap,zFormat); + retc = vxprintf(fout,stdout,zFormat,ap); + va_end(ap); + return retc; +} +int vprintf(const char *zFormat, va_list ap){ + return vxprintf(fout,stdout,zFormat,ap); +} diff --git a/lib/libpthread/stdlib/GNUmakefile.inc b/lib/libpthread/stdlib/GNUmakefile.inc new file mode 100755 index 00000000000..2f55ce8b217 --- /dev/null +++ b/lib/libpthread/stdlib/GNUmakefile.inc @@ -0,0 +1,7 @@ +# @(#)Makefile.inc 5.6 (Berkeley) 6/4/91 + +# stdlib sources +VPATH:= ${VPATH}:${srcdir}/stdlib + +SRCS:= abort.c exit.c strtod.c getopt.c rand.c random.c strtol.c strtoul.c \ + system.c $(SRCS) diff --git a/lib/libpthread/stdlib/Makefile.inc b/lib/libpthread/stdlib/Makefile.inc new file mode 100644 index 00000000000..cc323d1d0e1 --- /dev/null +++ b/lib/libpthread/stdlib/Makefile.inc @@ -0,0 +1,10 @@ +# @(#)Makefile.inc 5.6 (Berkeley) 6/4/91 + +# stdlib sources +.PATH: ${srcdir}/${MACHINE}/stdlib ${srcdir}/stdlib + +SRCS+= exit.c strtod.c getopt.c rand.c random.c strtol.c strtoul.c + +# SRCS+=abort.c atexit.c atoi.c atof.c atol.c bsearch.c calloc.c div.c \ +# getenv.c heapsort.c labs.c ldiv.c malloc.c multibyte.c \ +# putenv.c qsort.c radixsort.c setenv.c system.c diff --git a/lib/libpthread/stdlib/abort.c b/lib/libpthread/stdlib/abort.c new file mode 100644 index 00000000000..e9892bc554c --- /dev/null +++ b/lib/libpthread/stdlib/abort.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1985 Regents of the University of California. + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)abort.c 5.11 (Berkeley) 2/23/91";*/ +static char *rcsid = "$Id: abort.c,v 1.1 1998/07/21 13:22:19 peter Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <signal.h> +#include <stdlib.h> +#include <stddef.h> +#include <unistd.h> + +void +abort() +{ + sigset_t mask; + + sigfillset(&mask); + /* + * don't block SIGABRT to give any handler a chance; we ignore + * any errors -- X3J11 doesn't allow abort to return anyway. + */ + sigdelset(&mask, SIGABRT); + pthread_sigmask(SIG_SETMASK, &mask, NULL); + kill(getpid(), SIGABRT); + + /* + * if SIGABRT ignored, or caught and the handler returns, do + * it again, only harder. + */ + pthread_signal(SIGABRT, SIG_DFL); + pthread_sigmask(SIG_SETMASK, &mask, NULL); + kill(getpid(), SIGABRT); + exit(1); +} diff --git a/lib/libpthread/stdlib/atexit.h b/lib/libpthread/stdlib/atexit.h new file mode 100644 index 00000000000..46675a2c9bf --- /dev/null +++ b/lib/libpthread/stdlib/atexit.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + * + * from: @(#)atexit.h 5.1 (Berkeley) 5/15/90 + * $Id: atexit.h,v 1.1 1998/07/21 13:22:19 peter Exp $ + */ + +/* must be at least 32 to guarantee ANSI conformance */ +#define ATEXIT_SIZE 32 + +struct atexit { + struct atexit *next; /* next in list */ + int ind; /* next index in this table */ + void (*fns[ATEXIT_SIZE])(); /* the table itself */ +}; + +struct atexit *__atexit; /* points to head of LIFO stack */ diff --git a/lib/libpthread/stdlib/exit.c b/lib/libpthread/stdlib/exit.c new file mode 100644 index 00000000000..791e82748c5 --- /dev/null +++ b/lib/libpthread/stdlib/exit.c @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)exit.c 5.4 (Berkeley) 2/23/91";*/ +static char *rcsid = "$Id: exit.c,v 1.1 1998/07/21 13:22:19 peter Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/cdefs.h> +#include <pthread/posix.h> +#include "atexit.h" + +void (*__cleanup)(); + +/* + * Exit, flushing stdio buffers if necessary. + */ +void __NORETURN exit(int status) +{ + register struct atexit *p; + register int n; + + for (p = __atexit; p; p = p->next) + for (n = p->ind; --n >= 0;) + (*p->fns[n])(); + if (__cleanup) + (*__cleanup)(); + _exit(status); + + /* This is to shut up gcc, which complains about this function + * returning even if _exit() is declared noreturn. */ + while (1); +} + + +/* + * Register a function to be performed at exit. + */ +int atexit(void (*fn)()) +{ + static struct atexit __atexit0; /* one guaranteed table */ + register struct atexit *p; + + if ((p = __atexit) == NULL) + __atexit = p = &__atexit0; + else if (p->ind >= ATEXIT_SIZE) { + if ((p = malloc(sizeof(*p))) == NULL) + return (-1); + p->ind = 0; + p->next = __atexit; + __atexit = p; + } + p->fns[p->ind++] = fn; + return (0); +} diff --git a/lib/libpthread/stdlib/getopt.c b/lib/libpthread/stdlib/getopt.c new file mode 100644 index 00000000000..88164ef34a1 --- /dev/null +++ b/lib/libpthread/stdlib/getopt.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getopt.c 4.13 (Berkeley) 2/23/91"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <config.h> + +/* + * get option letter from argument vector + */ + +#ifndef LD_LINKS_STATIC_DATA +/* + * Under the Solaris ld, some data sections are linked in regaurdless of + * whether or not the name has been resolved. + */ +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt = 0; /* character checked for validity */ +char * optarg = NULL; /* argument associated with option */ + +#else + +extern int opterr, optind, optopt; +extern char *optarg; + +#endif + +#define BADCH (int)'?' +#define EMSG "" + +int +getopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + static char *place = EMSG; /* option letter processing */ + register char *oli; /* option letter list index */ + char *p; + + if (!*place) { /* update scanning pointer */ + if (optind >= nargc || *(place = nargv[optind]) != '-') { + place = EMSG; + return(EOF); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++optind; + place = EMSG; + return(EOF); + } + } /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, optopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means EOF. + */ + if (optopt == (int)'-') + return(EOF); + if (!*place) + ++optind; + if (opterr) { + if (!(p = strrchr(*nargv, '/'))) + p = *nargv; + else + ++p; + (void)fprintf(stderr, "%s: illegal option -- %c\n", + p, optopt); + } + return(BADCH); + } + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) + ++optind; + } + else { /* need an argument */ + if (*place) /* no white space */ + optarg = place; + else if (nargc <= ++optind) { /* no arg */ + place = EMSG; + if (!(p = strrchr(*nargv, '/'))) + p = *nargv; + else + ++p; + if (opterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + p, optopt); + return(BADCH); + } + else /* white space */ + optarg = nargv[optind]; + place = EMSG; + ++optind; + } + return(optopt); /* dump back option letter */ +} diff --git a/lib/libpthread/stdlib/rand.c b/lib/libpthread/stdlib/rand.c new file mode 100644 index 00000000000..9367dceed25 --- /dev/null +++ b/lib/libpthread/stdlib/rand.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * Copyright (c) 1994 Chris Provenzano, proven@mit.edu + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rand.c 5.6 (Berkeley) 6/24/91"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <sys/types.h> +#include <stdlib.h> + +static u_long next = 1; + +int rand_r(u_int * next_r) +{ + int ret; + + (*next_r) = (*next_r) * 1103515245 + 12345; + ret = (*next_r) & RAND_MAX; + return(ret); +} + +#undef rand +int rand(void) +{ + return ((next = next * 1103515245 + 12345) & RAND_MAX); +} + +#undef srand +void srand(unsigned int seed) +{ + next = seed; +} diff --git a/lib/libpthread/stdlib/random.c b/lib/libpthread/stdlib/random.c new file mode 100644 index 00000000000..8cba96e7534 --- /dev/null +++ b/lib/libpthread/stdlib/random.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 1983 Regents of the University of California. + * Copyright (c) 1994 Chris Provenzano, proven@mit.edu + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)random.c 5.9 (Berkeley) 2/23/91"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +/* + * random.c: + * + * An improved random number generation package. In addition to the standard + * rand()/srand() like interface, this package also has a special state info + * interface. The initstate() routine is called with a seed, an array of + * bytes, and a count of how many bytes are being passed in; this array is + * then initialized to contain information for random number generation with + * that much state information. Good sizes for the amount of state + * information are 32, 64, 128, and 256 bytes. The state can be switched by + * calling the setstate() routine with the same array as was initiallized + * with initstate(). By default, the package runs with 128 bytes of state + * information and generates far better random numbers than a linear + * congruential generator. If the amount of state information is less than + * 32 bytes, a simple linear congruential R.N.G. is used. + * + * Internally, the state information is treated as an array of longs; the + * zeroeth element of the array is the type of R.N.G. being used (small + * integer); the remainder of the array is the state information for the + * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of + * state information, which will allow a degree seven polynomial. (Note: + * the zeroeth word of state information also has some other information + * stored in it -- see setstate() for details). + * + * The random number generation technique is a linear feedback shift register + * approach, employing trinomials (since there are fewer terms to sum up that + * way). In this approach, the least significant bit of all the numbers in + * the state table will act as a linear feedback shift register, and will + * have period 2^deg - 1 (where deg is the degree of the polynomial being + * used, assuming that the polynomial is irreducible and primitive). The + * higher order bits will have longer periods, since their values are also + * influenced by pseudo-random carries out of the lower bits. The total + * period of the generator is approximately deg*(2**deg - 1); thus doubling + * the amount of state information has a vast influence on the period of the + * generator. Note: the deg*(2**deg - 1) is an approximation only good for + * large deg, when the period of the shift register is the dominant factor. + * With deg equal to seven, the period is actually much longer than the + * 7*(2**7 - 1) predicted by this formula. + */ + +/* + * For each of the currently supported random number generators, we have a + * break value on the amount of state information (you need at least this + * many bytes of state info to support this random number generator), a degree + * for the polynomial (actually a trinomial) that the R.N.G. is based on, and + * the separation between the two lower order coefficients of the trinomial. + */ +#define TYPE_0 0 /* linear congruential */ +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +#define TYPE_1 1 /* x**7 + x**3 + 1 */ +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +#define TYPE_2 2 /* x**15 + x + 1 */ +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +#define TYPE_3 3 /* x**31 + x**3 + 1 */ +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +#define TYPE_4 4 /* x**63 + x + 1 */ +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + +/* + * Array versions of the above information to make code run faster -- + * relies on fact that TYPE_i == i. + */ +#define MAX_TYPES 5 /* max number of types above */ + +static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; +static int seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; + +/* + * Initially, everything is set up as if from: + * + * initstate(1, &randtbl, 128); + * + * Note that this initialization takes advantage of the fact that srandom() + * advances the front and rear pointers 10*rand_deg times, and hence the + * rear pointer which starts at 0 will also end up at zero; thus the zeroeth + * element of the state information, which contains info about the current + * position of the rear pointer is just + * + * MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3. + */ + +static long randtbl[DEG_3 + 1] = { + TYPE_3, + 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5, + 0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, + 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, + 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, + 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b, + 0x27fb47b9, +}; + +/* + * fptr and rptr are two pointers into the state info, a front and a rear + * pointer. These two pointers are always rand_sep places aparts, as they + * cycle cyclically through the state information. (Yes, this does mean we + * could get away with just one pointer, but the code for random() is more + * efficient this way). The pointers are left positioned as they would be + * from the call + * + * initstate(1, randtbl, 128); + * + * (The position of the rear pointer, rptr, is really 0 (as explained above + * in the initialization of randtbl) because the state table pointer is set + * to point to randtbl[1] (as explained below). + */ +static long *fptr = &randtbl[SEP_3 + 1]; +static long *rptr = &randtbl[1]; + +/* + * The following things are the pointer to the state information table, the + * type of the current generator, the degree of the current polynomial being + * used, and the separation between the two pointers. Note that for efficiency + * of random(), we remember the first location of the state information, not + * the zeroeth. Hence it is valid to access state[-1], which is used to + * store the type of the R.N.G. Also, we remember the last location, since + * this is more efficient than indexing every time to find the address of + * the last element to see if the front and rear pointers have wrapped. + */ +static long *state = &randtbl[1]; +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; +static long *end_ptr = &randtbl[DEG_3 + 1]; + +/* + * State info won't be corrupted by multiple simultaneous calls, + * but srandom(), initstate(), and setstate() affect all threads + */ +static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* + * random: + * + * If we are using the trivial TYPE_0 R.N.G., just do the old linear + * congruential bit. Otherwise, we do our fancy trinomial stuff, which is + * the same in all the other cases due to all the global variables that have + * been set up. The basic operation is to add the number at the rear pointer + * into the one at the front pointer. Then both pointers are advanced to + * the next location cyclically in the table. The value returned is the sum + * generated, reduced to 31 bits by throwing away the "least random" low bit. + * + * Note: the code takes advantage of the fact that both the front and + * rear pointers can't wrap on the same call by not testing the rear + * pointer if the front one has wrapped. + * + * Returns a 31-bit random number. + */ +static long random_basic() +{ + long i; + + if (rand_type == TYPE_0) + i = state[0] = (state[0] * 1103515245 + 12345) & 0x7fffffff; + else { + *fptr += *rptr; + i = (*fptr >> 1) & 0x7fffffff; /* chucking least random bit */ + if (++fptr >= end_ptr) { + fptr = state; + ++rptr; + } else if (++rptr >= end_ptr) + rptr = state; + } + return(i); +} + +long random() +{ + long ret; + + pthread_mutex_lock(&random_mutex); + ret = random_basic(); + pthread_mutex_unlock(&random_mutex); + return(ret); +} +/* + * srandom: + * + * Initialize the random number generator based on the given seed. If the + * type is the trivial no-state-information type, just remember the seed. + * Otherwise, initializes state[] based on the given "seed" via a linear + * congruential generator. Then, the pointers are set to known locations + * that are exactly rand_sep places apart. Lastly, it cycles the state + * information a given number of times to get rid of any initial dependencies + * introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + * for default usage relies on values produced by this routine. + */ +static void srandom_basic(u_int x) +{ + int i; + + state[0] = x; + for (i = 1; i < rand_deg; i++) + state[i] = 1103515245 * state[i - 1] + 12345; + fptr = &state[rand_sep]; + rptr = &state[0]; + + for (i = 0; i < 10 * rand_deg; i++) + (void)random_basic(); +} + +void srandom(u_int x) +{ + pthread_mutex_lock(&random_mutex); + srandom_basic(x); + pthread_mutex_unlock(&random_mutex); +} + +/* + * initstate: + * + * Initialize the state information in the given array of n bytes for future + * random number generation. Based on the number of bytes we are given, and + * the break values for the different R.N.G.'s, we choose the best (largest) + * one we can and set things up for it. srandom() is then called to + * initialize the state information. + * + * Note that on return from srandom(), we set state[-1] to be the type + * multiplexed with the current value of the rear pointer; this is so + * successive calls to initstate() won't lose this information and will be + * able to restart with setstate(). + * + * Note: the first thing we do is save the current state, if any, just like + * setstate() so that it doesn't matter when initstate is called. + * + * Returns a pointer to the old state. + */ +#ifdef initstate +#undef initstate +#endif +char * initstate(u_int seed, char * arg_state, int n) +{ + register char *ostate = (char *)(&state[-1]); + + pthread_mutex_lock(&random_mutex); + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = MAX_TYPES * (rptr - state) + rand_type; + if (n < BREAK_0) { + (void)fprintf(stderr, + "random: not enough state (%d bytes); ignored.\n", n); + pthread_mutex_unlock(&random_mutex); + return(0); + } + if (n < BREAK_1) { + rand_type = TYPE_0; + rand_deg = DEG_0; + rand_sep = SEP_0; + } else if (n < BREAK_2) { + rand_type = TYPE_1; + rand_deg = DEG_1; + rand_sep = SEP_1; + } else if (n < BREAK_3) { + rand_type = TYPE_2; + rand_deg = DEG_2; + rand_sep = SEP_2; + } else if (n < BREAK_4) { + rand_type = TYPE_3; + rand_deg = DEG_3; + rand_sep = SEP_3; + } else { + rand_type = TYPE_4; + rand_deg = DEG_4; + rand_sep = SEP_4; + } + state = &(((long *)arg_state)[1]); /* first location */ + end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */ + srandom_basic(seed); + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = MAX_TYPES*(rptr - state) + rand_type; + pthread_mutex_unlock(&random_mutex); + return(ostate); +} + +/* + * setstate: + * + * Restore the state from the given state array. + * + * Note: it is important that we also remember the locations of the pointers + * in the current state information, and restore the locations of the pointers + * from the old state information. This is done by multiplexing the pointer + * location into the zeroeth word of the state information. + * + * Note that due to the order in which things are done, it is OK to call + * setstate() with the same state as the current state. + * + * Returns a pointer to the old state information. + */ +#ifdef setstate +#undef setstate +#endif +char * setstate(char * arg_state) +{ + register long *new_state = (long *)arg_state; + register int type = new_state[0] % MAX_TYPES; + register int rear = new_state[0] / MAX_TYPES; + char *ostate = (char *)(&state[-1]); + + pthread_mutex_lock(&random_mutex); + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = MAX_TYPES * (rptr - state) + rand_type; + switch(type) { + case TYPE_0: + case TYPE_1: + case TYPE_2: + case TYPE_3: + case TYPE_4: + rand_type = type; + rand_deg = degrees[type]; + rand_sep = seps[type]; + break; + default: + (void)fprintf(stderr, + "random: state info corrupted; not changed.\n"); + } + state = &new_state[1]; + if (rand_type != TYPE_0) { + rptr = &state[rear]; + fptr = &state[(rear + rand_sep) % rand_deg]; + } + end_ptr = &state[rand_deg]; /* set end_ptr too */ + + pthread_mutex_unlock(&random_mutex); + return(ostate); +} + diff --git a/lib/libpthread/stdlib/strtod.c b/lib/libpthread/stdlib/strtod.c new file mode 100644 index 00000000000..173ca1e4bdf --- /dev/null +++ b/lib/libpthread/stdlib/strtod.c @@ -0,0 +1,178 @@ +/* +** An alternative implemtation of "strtod()" that is both +** simplier, and thread-safe. +*/ +#include <pthread.h> +#include <ctype.h> +#include <math.h> + +#ifdef TEST +# define strtod NewStrtod +#include <stdio.h> +#endif + +static double scaler10[] = { + 1.0, 1e10, 1e20, 1e30, 1e40, 1e50, 1e60, 1e70, 1e80, 1e90 +}; +static double scaler1[] = { + 1.0, 10.0, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 +}; +static double pastpoint[] = { + 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, + 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17, 1e-18, 1e-19, + 1e-20, 1e-21, 1e-22, 1e-23, 1e-24, 1e-25, 1e-26, 1e-27, 1e-28, 1e-29, + 1e-30, 1e-31, 1e-32, 1e-33, 1e-34, 1e-35, 1e-36, 1e-37, 1e-38, 1e-39, + 1e-40, 1e-41, 1e-42, 1e-43, 1e-44, 1e-45, 1e-46, 1e-47, 1e-48, 1e-49, + 1e-50, 1e-51, 1e-52, 1e-53, 1e-54, 1e-55, 1e-56, 1e-57, 1e-58, 1e-59, +}; + +#ifndef DBL_MAX +#define DBL_MAX 1.7976931348623157e+308 +#endif + +double strtod(const char *zNum, char **pzEnd){ + double rResult = 0.0; + int isNegative = 0; + + while( isspace(*zNum) ){ + zNum++; + } + if( *zNum=='-' ){ + zNum++; + isNegative = 1; + }else if( *zNum=='+' ){ + zNum++; + } + while( isdigit(*zNum) ){ + rResult = rResult*10.0 + (*zNum - '0'); + zNum++; + } + if( *zNum=='.' ){ + int n = 0; + zNum++; + while( isdigit(*zNum) ){ + if( n<sizeof(pastpoint)/sizeof(pastpoint[0]) ){ + rResult += pastpoint[n] * (*zNum - '0'); + n++; + } + zNum++; + } + } + if( *zNum=='e' || *zNum=='E' ){ + int expVal = 0; + int isNegExp = 0; + const char *zExpStart = zNum; + zNum++; + if( *zNum=='-' ){ + isNegExp = 1; + zNum++; + }else if( *zNum=='+' ){ + zNum++; + } + if( !isdigit(*zNum) ){ + zNum = zExpStart; + }else{ + double scaler = 1.0; + while( isdigit(*zNum) ){ + expVal = expVal*10 + *zNum - '0'; + zNum++; + } + if( expVal >= 1000 ){ + if( isNegExp ){ + rResult = 0.0; + }else{ + rResult = DBL_MAX; + } + goto done; + } + while( expVal >= 100 ){ + scaler *= 1.0e100; + expVal -= 100; + } + scaler *= scaler10[expVal/10]*scaler1[expVal%10]; + if( isNegExp ){ + scaler = 1.0/scaler; + } + rResult *= scaler; + } + + } + +done: + if( pzEnd ){ + *pzEnd = (char *)zNum; + } + if( isNegative && rResult!=0.0 ){ + rResult = -rResult; + } + return rResult; +} + +double atof(const char *nptr) +{ + return (strtod(nptr, 0)); +} + +#ifdef TEST +#undef strtod + +double strtod(const char*,char**); +double NewStrtod(const char*,char**); + +int main(int argc, char **argv){ + int nTest = 0; + int nFail = 0; + int nBigFail = 0; + char zBuf[1000]; + + while( fgets(zBuf,sizeof(zBuf),stdin) ){ + double old, new; + char *zTailOld, *zTailNew; + int i; + + for(i=0; zBuf[i] && zBuf[i]!='\n'; i++){} + zBuf[i] = 0; + +#if TEST==1 + printf("Input line: [%s]\n",zBuf); + old = strtod(zBuf,&zTailOld); + printf("value=%g\n",old); + printf("Old: 0x%08x%08x tail=[%s]\n", + ((int*)&old)[1], ((int*)&old)[0], zTailOld); + new = NewStrtod(zBuf,&zTailNew); + printf("value=%g\n",new); + printf("New: 0x%08x%08x tail=[%s]\n\n", + ((int*)&new)[1], ((int*)&new)[0], zTailNew); +#else + old = strtod(zBuf,&zTailOld); + new = NewStrtod(zBuf,&zTailNew); + nTest++; + if( strcmp(zTailOld,zTailNew) + || ((int*)&old)[0]!=((int*)&new)[0] + || ((int*)&old)[1]!=((int*)&new)[1] + ){ + int olda, oldb, newa, newb; + + nFail++; + olda = ((int*)&old)[1]; + oldb = ((int*)&old)[0]; + newa = ((int*)&new)[1]; + newb = ((int*)&new)[0]; + + if( olda!=newa || abs(oldb-newb)>2 ){ + nBigFail++; + printf("******* Big failure \n"); + } + printf("Input = [%s]\n",zBuf); + printf("old: val=%g 0x%08x%08x tail=[%s]\n", + old, olda, oldb, zTailOld); + printf("new: val=%g 0x%08x%08x tail=[%s]\n\n", + new, newa, newb, zTailNew); + } +#endif + } + + printf("Out of %d tests, %d failures and %d big failurs\n", + nTest,nFail, nBigFail); +} +#endif diff --git a/lib/libpthread/stdlib/strtol.c b/lib/libpthread/stdlib/strtol.c new file mode 100644 index 00000000000..7bb0cb9db18 --- /dev/null +++ b/lib/libpthread/stdlib/strtol.c @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)strtol.c 5.4 (Berkeley) 2/23/91";*/ +static char *rcsid = "$Id: strtol.c,v 1.1 1998/07/21 13:22:19 peter Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <limits.h> +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> + + +/* + * Convert a string to a long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long +strtol(nptr, endptr, base) + const char *nptr; + char **endptr; + register int base; +{ + register const char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; + cutlim = cutoff % (unsigned long)base; + cutoff /= (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/lib/libpthread/stdlib/strtoul.c b/lib/libpthread/stdlib/strtoul.c new file mode 100644 index 00000000000..f59a0b04cf8 --- /dev/null +++ b/lib/libpthread/stdlib/strtoul.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1990 Regents of the University of California. + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)strtoul.c 5.3 (Berkeley) 2/23/91";*/ +static char *rcsid = "$Id: strtoul.c,v 1.1 1998/07/21 13:22:19 peter Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <limits.h> +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> + +/* + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long +strtoul(nptr, endptr, base) + const char *nptr; + char **endptr; + register int base; +{ + register const char *s = nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; + cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} diff --git a/lib/libpthread/stdlib/system.c b/lib/libpthread/stdlib/system.c new file mode 100644 index 00000000000..d43c5ce3d7c --- /dev/null +++ b/lib/libpthread/stdlib/system.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)system.c 5.10 (Berkeley) 2/23/91";*/ +static char *rcsid = "$Id: system.c,v 1.1 1998/07/21 13:22:19 peter Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <pthread/paths.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> +#include <stdlib.h> +#include <stddef.h> +#include <unistd.h> + +extern char **environ; + +system(command) + const char *command; +{ + char *argp[] = {"sh", "-c", "*to be filled in*", NULL}; + void (*intsave)(), (*quitsave)(), (*signal())(); + sigset_t tmp_mask, old_mask; + int pstat; + pid_t pid; + + if (!command) /* just checking... */ + return(1); + + argp[2] = (char *) command; + sigemptyset(&tmp_mask); + sigaddset(&tmp_mask, SIGCHLD); + pthread_sigmask(SIG_BLOCK, &tmp_mask, &old_mask); + switch(pid = fork()) { + case -1: /* error */ + (void)pthread_sigmask(SIG_SETMASK, &old_mask, NULL); + return(-1); + case 0: /* child */ + (void)pthread_sigmask(SIG_SETMASK, &old_mask, NULL); + execve(_PATH_BSHELL, argp, environ); + _exit(127); + } + + intsave = pthread_signal(SIGINT, SIG_IGN); + quitsave = pthread_signal(SIGQUIT, SIG_IGN); + pid = waitpid(pid, (int *)&pstat, 0); + (void)pthread_sigmask(SIG_SETMASK, &old_mask, NULL); + (void)pthread_signal(SIGQUIT, quitsave); + (void)pthread_signal(SIGINT, intsave); + return(pid == -1 ? -1 : pstat); +} diff --git a/lib/libpthread/string/GNUmakefile.inc b/lib/libpthread/string/GNUmakefile.inc new file mode 100755 index 00000000000..7b05ddfe248 --- /dev/null +++ b/lib/libpthread/string/GNUmakefile.inc @@ -0,0 +1,7 @@ +# from: @(#)Makefile.inc 5.21 (Berkeley) 5/24/91 +# $Id: GNUmakefile.inc,v 1.1 1998/07/21 13:22:19 peter Exp $ + +# gen sources +VPATH:= ${VPATH}:${srcdir}/string + +SRCS:= strtok.c $(SRCS) diff --git a/lib/libpthread/string/Makefile.inc b/lib/libpthread/string/Makefile.inc new file mode 100644 index 00000000000..0a3804975e0 --- /dev/null +++ b/lib/libpthread/string/Makefile.inc @@ -0,0 +1,8 @@ +# from: @(#)Makefile.inc 5.21 (Berkeley) 5/24/91 +# $Id: Makefile.inc,v 1.1 1998/07/21 13:22:19 peter Exp $ + +# string sources +.PATH: ${srcdir}/string + +SRCS+= strtok.c + diff --git a/lib/libpthread/string/strtok.c b/lib/libpthread/string/strtok.c new file mode 100644 index 00000000000..e6c012aa71c --- /dev/null +++ b/lib/libpthread/string/strtok.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1988 Regents of the University of California. + * 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 the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)strtok.c 5.8 (Berkeley) 2/24/91";*/ +static char *rcsid = "$Id: strtok.c,v 1.1 1998/07/21 13:22:19 peter Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <pthread.h> +#include <string.h> +#include <stdlib.h> + +char * +strtok(s, delim) + register char *s; + register const char *delim; +{ + static pthread_mutex_t strtok_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_key_t strtok_key = -1; + char **lasts; + + pthread_mutex_lock(&strtok_mutex); + if (strtok_key < 0) { + if (pthread_key_create(&strtok_key, free) < 0) { + pthread_mutex_unlock(&strtok_mutex); + return(NULL); + } + } + pthread_mutex_unlock(&strtok_mutex); + if ((lasts = pthread_getspecific(strtok_key)) == NULL) { + if ((lasts = (char **)malloc(sizeof(char *))) == NULL) { + return(NULL); + } + pthread_setspecific(strtok_key, lasts); + } + + return(strtok_r(s, delim, lasts)); +} + +char * +strtok_r(s, delim, lasts) + register char *s; + register const char *delim; + register char **lasts; +{ + register char *spanp; + register int c, sc; + char *tok; + + + if (s == NULL && (s = *lasts) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *lasts = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *lasts = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} diff --git a/lib/libpthread/tests/Makefile b/lib/libpthread/tests/Makefile new file mode 100644 index 00000000000..5ba9f9a3927 --- /dev/null +++ b/lib/libpthread/tests/Makefile @@ -0,0 +1,165 @@ +# Generated automatically from Makefile.in by configure. +# === GNUmakefile ============================================================ +# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu +# +# Description: This file is for creating the test programs for libpthread.a +# +# 1.00 93/08/03 proven +# -Initial cut for pthreads. +# + +CC = ../pgcc -notinstalled +CPP = gcc -E +srctop = /dr1/my/masters/mysql/mit-pthreads +srcdir = /dr1/my/masters/mysql/mit-pthreads/tests +VPATH = /dr1/my/masters/mysql/mit-pthreads/tests +CDEBUGFLAGS = -g -O2 -Werror + +INCLUDES= -I../include -I.. -I$(srctop)/include +CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\" +LIBS = -lm -lgcc -L../obj/ -lpthread +#LIBS = -static + +# This list used to include test_select, but that test doesn't terminate. +TESTS = test_create test_pthread_join test_switch test_sleep test_readdir \ + test_fork test_execve test_preemption test_preemption_float \ + test_sock_1 test_sock_2 test_stdio_1 test_pthread_mutex \ + test_pthread_cond_timedwait test_netdb test_pw test_cwd +# This list used to include p_bench_semaphore, but the semaphore support isn't +# defined for all targets (or used for any). +BENCHMARKS = p_bench_read p_bench_mutex p_bench_yield \ + p_bench_getpid p_bench_pthread_create + +all : $(TESTS) $(BENCHMARKS) + +check : $(TESTS) + set -e ; \ + for i in $(TESTS) ; do \ + echo Running test $$i ... ; \ + ./$$i ; \ + done + +# More flags +ADDITIONALFLAGS = -DPTHREAD_INITIAL_PORT +################################################################################ +# + +clean: + rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout + +depend: + sed '/\#\#\# Dependencies/q' < Makefile > maketmp + (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp + cp maketmp Makefile + +install: + +realclean: clean + rm -f Makefile + +.c.o: + $(CC) $(CFLAGS) -c $< + +Makefile: Makefile.in + (cd .. ; sh config.status) + +test_create : test_create.o ../libpthread.a + $(CC) $(CFLAGS) -o test_create test_create.o $(LIBS) + +test_pthread_join : test_pthread_join.o ../libpthread.a + $(CC) $(CFLAGS) -o test_pthread_join test_pthread_join.o $(LIBS) + +test_switch : test_switch.o ../libpthread.a + $(CC) $(CFLAGS) -o test_switch test_switch.o $(LIBS) + +test_sleep : test_sleep.o ../libpthread.a + $(CC) $(CFLAGS) -o test_sleep test_sleep.o $(LIBS) + +test_readdir : test_readdir.o ../libpthread.a + $(CC) $(CFLAGS) -o test_readdir test_readdir.o $(LIBS) + +test_fork : test_fork.o ../libpthread.a + $(CC) $(CFLAGS) -o test_fork test_fork.o $(LIBS) + +test_execve : test_execve.o ../libpthread.a + $(CC) $(CFLAGS) -o test_execve test_execve.o $(LIBS) + +test_preemption : test_preemption.o ../libpthread.a + $(CC) $(CFLAGS) -o test_preemption test_preemption.o $(LIBS) + +test_preemption_float : test_preemption_float.o ../libpthread.a + $(CC) $(CFLAGS) -o test_preemption_float test_preemption_float.o $(LIBS) + +test_stdio_1 : test_stdio_1.o ../libpthread.a + $(CC) $(CFLAGS) -o test_stdio_1 test_stdio_1.o $(LIBS) + +test_sock_1 : test_sock_1.o ../libpthread.a + $(CC) $(CFLAGS) -o test_sock_1 test_sock_1.o $(LIBS) + +test_sock_2 : test_sock_2a test_sock_2.o ../libpthread.a + $(CC) $(CFLAGS) -o test_sock_2 test_sock_2.o $(LIBS) + +test_sock_2a : test_sock_2a.o ../libpthread.a + $(CC) $(CFLAGS) -o test_sock_2a test_sock_2a.o $(LIBS) + +test_pthread_mutex : test_pthread_mutex.o ../libpthread.a + $(CC) $(CFLAGS) -o test_pthread_mutex test_pthread_mutex.o $(LIBS) + +test_pthread_cond_timedwait : test_pthread_cond_timedwait.o ../libpthread.a + $(CC) $(CFLAGS) -o test_pthread_cond_timedwait test_pthread_cond_timedwait.o $(LIBS) + +test_netdb : test_netdb.o ../libpthread.a + $(CC) $(CFLAGS) -o test_netdb test_netdb.o $(LIBS) + +test_select : test_select.o ../obj/libpthread.a + $(CC) $(CFLAGS) -o test_select test_select.o $(LIBS) + +test_pw : test_pw.o ../obj/libpthread.a + $(CC) $(CFLAGS) -o test_pw test_pw.o $(LIBS) + +test_cwd : test_cwd.o ../obj/libpthread.a + $(CC) $(CFLAGS) -o test_cwd test_cwd.o $(LIBS) + +p_bench_read : p_bench_read.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_read p_bench_read.o $(LIBS) + +p_bench_semaphore : p_bench_semaphore.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_semaphore p_bench_semaphore.o $(LIBS) + +p_bench_mutex : p_bench_mutex.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_mutex p_bench_mutex.o $(LIBS) + +p_bench_yield : p_bench_yield.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_yield p_bench_yield.o $(LIBS) + +p_bench_getpid : p_bench_getpid.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_getpid p_bench_getpid.o $(LIBS) + +p_bench_pthread_create : p_bench_pthread_create.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_pthread_create p_bench_pthread_create.o $(LIBS) + +test_create.o : test_create.c +test_pthread_join.o : test_pthread_join.c +test_switch.o : test_switch.c +test_sleep.o : test_sleep.c +test_readdir.o : test_readdir.c +test_fork.o : test_fork.c +test_execve.o : test_execve.c +test_preemption.o : test_preemption.c +test_preemption_float.o : test_preemption_float.c +test_sock_1.o : test_sock_1.c +test_sock_2.o : test_sock_2.c +test_sock_3.o : test_sock_3.c +test_stdio_1.o : test_stdio_1.c +test_pthread_mutex.o : test_pthread_mutex.c +test_pthread_cond_timedwait.o : test_pthread_cond_timedwait.c +p_bench_read.o : p_bench_read.c +p_bench_semaphore.o : p_bench_semaphore.c +p_bench_mutex.o : p_bench_mutex.c +p_bench_yield.o : p_bench_yield.c +p_bench_getpid.o : p_bench_getpid.c +p_bench_pthread_create.o : p_bench_pthread_create.c + +################################################################################ +### Do not remove the following line. It is for depend ######################### +### Dependencies: diff --git a/lib/libpthread/tests/Makefile.in b/lib/libpthread/tests/Makefile.in new file mode 100644 index 00000000000..6e01b6bffc3 --- /dev/null +++ b/lib/libpthread/tests/Makefile.in @@ -0,0 +1,164 @@ +# === GNUmakefile ============================================================ +# Copyright (c) 1993 Chris Provenzano, proven@athena.mit.edu +# +# Description: This file is for creating the test programs for libpthread.a +# +# 1.00 93/08/03 proven +# -Initial cut for pthreads. +# + +CC = ../pgcc -notinstalled +CPP = @CPP@ +srctop = @srctop@ +srcdir = @srctop@/tests +VPATH = @srctop@/tests +CDEBUGFLAGS = @CFLAGS@ + +INCLUDES= -I../include -I.. -I$(srctop)/include +CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(ADDL_CFLAGS) -DSRCDIR=\"$(srcdir)\" +LIBS = -lm -lgcc -L../obj/ -lpthread +#LIBS = -static + +# This list used to include test_select, but that test doesn't terminate. +TESTS = test_create test_pthread_join test_switch test_sleep test_readdir \ + test_fork test_execve test_preemption test_preemption_float \ + test_sock_1 test_sock_2 test_stdio_1 test_pthread_mutex \ + test_pthread_cond_timedwait test_netdb test_pw test_cwd +# This list used to include p_bench_semaphore, but the semaphore support isn't +# defined for all targets (or used for any). +BENCHMARKS = p_bench_read p_bench_mutex p_bench_yield \ + p_bench_getpid p_bench_pthread_create + +all : $(TESTS) $(BENCHMARKS) + +check : $(TESTS) + set -e ; \ + for i in $(TESTS) ; do \ + echo Running test $$i ... ; \ + ./$$i ; \ + done + +# More flags +ADDITIONALFLAGS = -DPTHREAD_INITIAL_PORT +################################################################################ +# + +clean: + rm -f *.o $(TESTS) $(BENCHMARKS) a.out core maketmp makeout + +depend: + sed '/\#\#\# Dependencies/q' < Makefile > maketmp + (for i in $(CSRC);do $(CPP) -M $$i;done) >> maketmp + cp maketmp Makefile + +install: + +realclean: clean + rm -f Makefile + +.c.o: + $(CC) $(CFLAGS) -c $< + +Makefile: Makefile.in + (cd .. ; sh config.status) + +test_create : test_create.o ../libpthread.a + $(CC) $(CFLAGS) -o test_create test_create.o $(LIBS) + +test_pthread_join : test_pthread_join.o ../libpthread.a + $(CC) $(CFLAGS) -o test_pthread_join test_pthread_join.o $(LIBS) + +test_switch : test_switch.o ../libpthread.a + $(CC) $(CFLAGS) -o test_switch test_switch.o $(LIBS) + +test_sleep : test_sleep.o ../libpthread.a + $(CC) $(CFLAGS) -o test_sleep test_sleep.o $(LIBS) + +test_readdir : test_readdir.o ../libpthread.a + $(CC) $(CFLAGS) -o test_readdir test_readdir.o $(LIBS) + +test_fork : test_fork.o ../libpthread.a + $(CC) $(CFLAGS) -o test_fork test_fork.o $(LIBS) + +test_execve : test_execve.o ../libpthread.a + $(CC) $(CFLAGS) -o test_execve test_execve.o $(LIBS) + +test_preemption : test_preemption.o ../libpthread.a + $(CC) $(CFLAGS) -o test_preemption test_preemption.o $(LIBS) + +test_preemption_float : test_preemption_float.o ../libpthread.a + $(CC) $(CFLAGS) -o test_preemption_float test_preemption_float.o $(LIBS) + +test_stdio_1 : test_stdio_1.o ../libpthread.a + $(CC) $(CFLAGS) -o test_stdio_1 test_stdio_1.o $(LIBS) + +test_sock_1 : test_sock_1.o ../libpthread.a + $(CC) $(CFLAGS) -o test_sock_1 test_sock_1.o $(LIBS) + +test_sock_2 : test_sock_2a test_sock_2.o ../libpthread.a + $(CC) $(CFLAGS) -o test_sock_2 test_sock_2.o $(LIBS) + +test_sock_2a : test_sock_2a.o ../libpthread.a + $(CC) $(CFLAGS) -o test_sock_2a test_sock_2a.o $(LIBS) + +test_pthread_mutex : test_pthread_mutex.o ../libpthread.a + $(CC) $(CFLAGS) -o test_pthread_mutex test_pthread_mutex.o $(LIBS) + +test_pthread_cond_timedwait : test_pthread_cond_timedwait.o ../libpthread.a + $(CC) $(CFLAGS) -o test_pthread_cond_timedwait test_pthread_cond_timedwait.o $(LIBS) + +test_netdb : test_netdb.o ../libpthread.a + $(CC) $(CFLAGS) -o test_netdb test_netdb.o $(LIBS) + +test_select : test_select.o ../obj/libpthread.a + $(CC) $(CFLAGS) -o test_select test_select.o $(LIBS) + +test_pw : test_pw.o ../obj/libpthread.a + $(CC) $(CFLAGS) -o test_pw test_pw.o $(LIBS) + +test_cwd : test_cwd.o ../obj/libpthread.a + $(CC) $(CFLAGS) -o test_cwd test_cwd.o $(LIBS) + +p_bench_read : p_bench_read.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_read p_bench_read.o $(LIBS) + +p_bench_semaphore : p_bench_semaphore.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_semaphore p_bench_semaphore.o $(LIBS) + +p_bench_mutex : p_bench_mutex.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_mutex p_bench_mutex.o $(LIBS) + +p_bench_yield : p_bench_yield.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_yield p_bench_yield.o $(LIBS) + +p_bench_getpid : p_bench_getpid.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_getpid p_bench_getpid.o $(LIBS) + +p_bench_pthread_create : p_bench_pthread_create.o ../libpthread.a + $(CC) $(CFLAGS) -o p_bench_pthread_create p_bench_pthread_create.o $(LIBS) + +test_create.o : test_create.c +test_pthread_join.o : test_pthread_join.c +test_switch.o : test_switch.c +test_sleep.o : test_sleep.c +test_readdir.o : test_readdir.c +test_fork.o : test_fork.c +test_execve.o : test_execve.c +test_preemption.o : test_preemption.c +test_preemption_float.o : test_preemption_float.c +test_sock_1.o : test_sock_1.c +test_sock_2.o : test_sock_2.c +test_sock_3.o : test_sock_3.c +test_stdio_1.o : test_stdio_1.c +test_pthread_mutex.o : test_pthread_mutex.c +test_pthread_cond_timedwait.o : test_pthread_cond_timedwait.c +p_bench_read.o : p_bench_read.c +p_bench_semaphore.o : p_bench_semaphore.c +p_bench_mutex.o : p_bench_mutex.c +p_bench_yield.o : p_bench_yield.c +p_bench_getpid.o : p_bench_getpid.c +p_bench_pthread_create.o : p_bench_pthread_create.c + +################################################################################ +### Do not remove the following line. It is for depend ######################### +### Dependencies: diff --git a/lib/libpthread/tests/README b/lib/libpthread/tests/README new file mode 100755 index 00000000000..bb4a3e7ce01 --- /dev/null +++ b/lib/libpthread/tests/README @@ -0,0 +1,26 @@ +This directory contains a few test and benchmark programs that I've +developed to help me test the consistancy of the libpthread.a. + +TEST +---------------------- +test_create Tests the pthread_create() routine. The stack addresses + should be very different (ie the upper values of the + address should be different) and the arg should be + 0xdeadbeaf. + +test_switch A nondeterministic test. It should show context switching, + by displaying different letters. + +test_sleep Timing this test should result in a time of about 20 seconds. + It should sleep for 10 seconds and then print ba 10 times + at the rate of about once a second. + +p_bench_* Benchmarks for various routines. + +------------------------------------------------------------------------------ +Copyright (c) 1994 Chris Provenzano. All rights reserved. +This product includes software developed by the Univeristy of California, +Berkeley and its contributors. + +For further licencing and distribution restrictions see the file COPYRIGHT +included in the parent directory. diff --git a/lib/libpthread/tests/bench_fcntl.c b/lib/libpthread/tests/bench_fcntl.c new file mode 100644 index 00000000000..046046adda4 --- /dev/null +++ b/lib/libpthread/tests/bench_fcntl.c @@ -0,0 +1,82 @@ +/* ==== bench_read.c ============================================================ + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Benchmark reads of /dev/null. Gives a good aprox. of + * syscall times. + * + * 1.00 93/08/01 proven + * -Started coding this file. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> + +#define OK 0 +#define NOTOK -1 +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("getopt [-d?] [-c count]\n"); + errno = 0; +} + +main(int argc, char **argv) +{ + struct timeval starttime, endtime; + int count = 1000000; + int debug = 0; + int flags; + int fd; + int i; + + char word[8192]; + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + + while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) { + switch (word[0]) { + case 'd': + debug++; + break; + case 'c': + count = atoi(optarg); + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + } + + if ((fd = open("/dev/zero", O_RDONLY)) < OK) { + printf("Error: open\n"); + exit(0); + } + + if (gettimeofday(&starttime, NULL)) { + printf("Error: gettimeofday\n"); + exit(0); + } + for (i = 0; i < count; i++) { + if ((flags = fcntl(0, F_GETFL)) < 0) { + perror("fcntl 1st GETFL"); + } + } + if (gettimeofday(&endtime, NULL)) { + printf("Error: gettimeofday\n"); + exit(0); + } + + printf("%d fcntls of /dev/null took %d usecs.\n", count, + (endtime.tv_sec - starttime.tv_sec) * 1000000 + + (endtime.tv_usec - starttime.tv_usec)); +} diff --git a/lib/libpthread/tests/bench_pipe.c b/lib/libpthread/tests/bench_pipe.c new file mode 100644 index 00000000000..8555cf37f67 --- /dev/null +++ b/lib/libpthread/tests/bench_pipe.c @@ -0,0 +1,115 @@ +/* ==== bench_pipe.c ============================================================ + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Benchmark reads of /dev/null. Gives a good aprox. of + * syscall times. + * + * 1.00 93/08/01 proven + * -Started coding this file. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> + +#define OK 0 +#define NOTOK -1 + +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("bench_pipe [-d?] [-c count]\n"); + errno = 0; +} + +main(int argc, char **argv) +{ + struct timeval starttime, endtime; + char buf[1]; + int count = 1000; + int debug = 0; + int fd0[2]; + int fd1[2]; + int i; + + char word[256]; + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + + while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) { + switch (word[0]) { + case 'd': + debug++; + break; + case 'c': + count = atoi(optarg); + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + } + + if ((pipe(fd0) < OK) || (pipe(fd1) < OK)) { + printf("Error: pipe\n"); + exit(0); + } + + switch (fork()) { + case NOTOK: + printf("Error: fork\n"); + exit(0); + case OK: /* Child */ + for (i = 0; i < count; i++) { + if (read(fd1[0], buf, 1) < OK) { + printf("Error: child read\n"); + exit(0); + } + if (write(fd0[1], buf, 1) < OK) { + printf("Error: child write\n"); + exit(0); + } + } + exit(0); + break; + default: + break; + } + + if (gettimeofday(&starttime, NULL)) { + printf("Error: gettimeofday\n"); + exit(0); + } + count --; + if (write(fd1[1], buf, 1) < OK) { + perror("first parent write"); + exit(0); + } + for (i = 0; i < count; i++) { + if (read(fd0[0], buf, 1) < OK) { + printf("Error: parent read\n"); + exit(0); + } + if (write(fd1[1], buf, 1) < OK) { + printf("Error: parent write\n"); + exit(0); + } + } + if (gettimeofday(&endtime, NULL)) { + printf("Error: gettimeofday\n"); + exit(0); + } + + printf("%d ping pong tests took %d usecs.\n", count, + (endtime.tv_sec - starttime.tv_sec) * 1000000 + + (endtime.tv_usec - starttime.tv_usec)); +} diff --git a/lib/libpthread/tests/bench_read.c b/lib/libpthread/tests/bench_read.c new file mode 100644 index 00000000000..28c8469e270 --- /dev/null +++ b/lib/libpthread/tests/bench_read.c @@ -0,0 +1,88 @@ +/* ==== bench_read.c ============================================================ + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Benchmark reads of /dev/null. Gives a good aprox. of + * syscall times. + * + * 1.00 93/08/01 proven + * -Started coding this file. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> + +#define OK 0 +#define NOTOK -1 +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("getopt [-d?] [-c count] [-s size]\n"); + errno = 0; +} + +main(int argc, char **argv) +{ + struct timeval starttime, endtime; + int count = 1000000; + int debug = 0; + int size = 1; + int fd; + int i; + + char word[8192]; + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + + while ((word[0] = getopt(argc, argv, "s:c:d?")) != (char)EOF) { + switch (word[0]) { + case 'd': + debug++; + break; + case 'c': + count = atoi(optarg); + break; + case 's': + if ((size = atoi(optarg)) > 8192) { + size = 8192; + } + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + } + + if ((fd = open("/netbsd", O_RDONLY)) < OK) { + printf("Error: open\n"); + exit(0); + } + + if (gettimeofday(&starttime, NULL)) { + printf("Error: gettimeofday\n"); + exit(0); + } + for (i = 0; i < count; i++) { + if (read(fd, word, size) < OK) { + printf("Error: read\n"); + exit(0); + } + } + if (gettimeofday(&endtime, NULL)) { + printf("Error: gettimeofday\n"); + exit(0); + } + + printf("%d reads of /netbsd took %d usecs.\n", count, + (endtime.tv_sec - starttime.tv_sec) * 1000000 + + (endtime.tv_usec - starttime.tv_usec)); +} diff --git a/lib/libpthread/tests/p_bench_getpid.c b/lib/libpthread/tests/p_bench_getpid.c new file mode 100644 index 00000000000..d972d075c1d --- /dev/null +++ b/lib/libpthread/tests/p_bench_getpid.c @@ -0,0 +1,78 @@ +/* ==== p_bench_getpid.c ================================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Benchmark mutex lock and unlock times + * + * 1.00 93/11/08 proven + * -Started coding this file. + */ + +#include <errno.h> +#include <pthread.h> +#include <unistd.h> +#include <stdio.h> + +#define OK 0 +#define NOTOK -1 + +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("p_bench_getpid [-d?] [-c count]\n"); + errno = 0; +} + +main(int argc, char **argv) +{ + struct timeval starttime, endtime; + pthread_mutex_t lock; + pid_t process_id; + int count = 1000000; + int debug = 0; + int i; + + char word[256]; + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + + pthread_init(); + + while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) { + switch (word[0]) { + case 'd': + debug++; + break; + case 'c': + count = atoi(optarg); + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + } + + if (gettimeofday(&starttime, NULL)) { + perror ("gettimeofday"); + return 1; + } + for (i = 0; i < count; i++) { + process_id = getpid(); + } + if (gettimeofday(&endtime, NULL)) { + perror ("gettimeofday"); + return 1; + } + + printf("%d getpid calls took %d usecs.\n", count, + (endtime.tv_sec - starttime.tv_sec) * 1000000 + + (endtime.tv_usec - starttime.tv_usec)); + + return 0; +} diff --git a/lib/libpthread/tests/p_bench_mutex.c b/lib/libpthread/tests/p_bench_mutex.c new file mode 100644 index 00000000000..e3179f08072 --- /dev/null +++ b/lib/libpthread/tests/p_bench_mutex.c @@ -0,0 +1,78 @@ +/* ==== p_bench_mutex.c ================================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Benchmark mutex lock and unlock times + * + * 1.00 93/11/08 proven + * -Started coding this file. + */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + +#define OK 0 +#define NOTOK -1 + +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("getopt [-d?] [-c count]\n"); + errno = 0; +} + +main(int argc, char **argv) +{ + struct timeval starttime, endtime; + pthread_mutex_t lock; + int count = 1000000; + int debug = 0; + int i; + + char word[256]; + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + + pthread_init(); + + while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) { + switch (word[0]) { + case 'd': + debug++; + break; + case 'c': + count = atoi(optarg); + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + } + + pthread_mutex_init(&lock, NULL); + if (gettimeofday(&starttime, NULL)) { + perror ("gettimeofday"); + return 1; + } + for (i = 0; i < count; i++) { + pthread_mutex_lock(&lock); + pthread_mutex_unlock(&lock); + } + if (gettimeofday(&endtime, NULL)) { + perror ("gettimeofday"); + return 1; + } + + printf("%d mutex locks/unlocks no contention took %d usecs.\n", count, + (endtime.tv_sec - starttime.tv_sec) * 1000000 + + (endtime.tv_usec - starttime.tv_usec)); + + return 0; +} diff --git a/lib/libpthread/tests/p_bench_pthread_create.c b/lib/libpthread/tests/p_bench_pthread_create.c new file mode 100644 index 00000000000..b31b680c665 --- /dev/null +++ b/lib/libpthread/tests/p_bench_pthread_create.c @@ -0,0 +1,92 @@ +/* ==== p_bench_pthread_create.c ============================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Benchmark mutex lock and unlock times + * + * 1.00 93/11/08 proven + * -Started coding this file. + */ + +#define PTHREAD_KERNEL + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + +extern pthread_attr_t pthread_attr_default; + +/* ========================================================================== + * new_thread(); + */ +void * new_thread(void * arg) +{ + PANIC(); +} + +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("p_bench_getpid [-d?] [-c count]\n"); + errno = 0; +} + +main(int argc, char **argv) +{ + struct timeval starttime, endtime; + pthread_mutex_t lock; + pthread_t thread_id; + int count = 10000; + int debug = 0; + int i; + + char word[256]; + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + + pthread_init(); + /* Shut timer off */ + machdep_unset_thread_timer(NULL); + pthread_attr_default.stackaddr_attr = &word; + + while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) { + switch (word[0]) { + case 'd': + debug++; + break; + case 'c': + count = atoi(optarg); + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + } + + if (gettimeofday(&starttime, NULL)) { + perror ("gettimeofday"); + return 1; + } + for (i = 0; i < count; i++) { + if (pthread_create(&thread_id, & pthread_attr_default, new_thread, NULL)) { + printf("Bad pthread create routine\n"); + exit(1); + } + } + if (gettimeofday(&endtime, NULL)) { + perror ("gettimeofday"); + return 1; + } + + printf("%d getpid calls took %d usecs.\n", count, + (endtime.tv_sec - starttime.tv_sec) * 1000000 + + (endtime.tv_usec - starttime.tv_usec)); + + return 0; +} diff --git a/lib/libpthread/tests/p_bench_read.c b/lib/libpthread/tests/p_bench_read.c new file mode 100644 index 00000000000..52a6aca7706 --- /dev/null +++ b/lib/libpthread/tests/p_bench_read.c @@ -0,0 +1,103 @@ +/* ==== p_bench_read.c ============================================================ + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Benchmark reads of /dev/null. Gives a good aprox. of + * syscall times. + * + * 1.00 93/08/01 proven + * -Started coding this file. + */ + +#include <pthread.h> +#include <sys/types.h> +#include <sys/time.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> + +#define OK 0 +#define NOTOK -1 + +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("p_bench_read [-d?] [-c count] [-s size] [-f file]\n"); + errno = 0; +} + +main(int argc, char **argv) +{ + struct timeval starttime, endtime; + char *infile = "/dev/null"; + int count = 1000000; + int debug = 0; + int size = 1; + int fd; + int i; + + char word[16384], *word_ptr; + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + + pthread_init(); + + while ((word[0] = getopt(argc, argv, "c:df:s:?")) != (char)EOF) { + switch (word[0]) { + case 'c': + count = atoi(optarg); + break; + case 'd': + debug++; + break; + case 'f': + infile = optarg; + break; + case 's': + if ((size = atoi(optarg)) > 8192) { + size = 8192; + } + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + } + + /* Align buffer boundary to a page boundary */ + word_ptr = (char *)(((size_t) word + 4095) & ~4095); + + if ((fd = open(infile, O_RDONLY)) < OK) { + perror ("open"); + return 1; + } + + if (gettimeofday(&starttime, NULL)) { + perror ("gettimeofday"); + return 1; + } + + for (i = 0; i < count; i++) { + if (read(fd, word_ptr, size) < OK) { + printf("Error: read\n"); + exit(0); + } + } + + if (gettimeofday(&endtime, NULL)) { + perror ("gettimeofday"); + return 1; + } + + printf("%d reads of %s took %d usecs.\n", count, infile, + (endtime.tv_sec - starttime.tv_sec) * 1000000 + + (endtime.tv_usec - starttime.tv_usec)); + + return 0; +} diff --git a/lib/libpthread/tests/p_bench_semaphore.c b/lib/libpthread/tests/p_bench_semaphore.c new file mode 100644 index 00000000000..b3bce340b95 --- /dev/null +++ b/lib/libpthread/tests/p_bench_semaphore.c @@ -0,0 +1,82 @@ +/* ==== p_bench_semaphore.c ================================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Benchmark semaphore Test and Set/ CLear times + * + * 1.00 93/11/08 proven + * -Started coding this file. + */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + +#define OK 0 +#define NOTOK -1 + +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("getopt [-d?] [-c count]\n"); + errno = 0; +} + +main(int argc, char **argv) +{ + struct timeval starttime, endtime; + semaphore lock = SEMAPHORE_CLEAR; + semaphore *lock_addr; + int count = 1000000; + int debug = 0; + int i; + + char word[256]; + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + + pthread_init(); + + while ((word[0] = getopt(argc, argv, "c:d?")) != (char)EOF) { + switch (word[0]) { + case 'd': + debug++; + break; + case 'c': + count = atoi(optarg); + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + } + + lock_addr = &lock; + if (gettimeofday(&starttime, NULL)) { + perror ("gettimeofday"); + return 1; + } + for (i = 0; i < count; i++) { + if (SEMAPHORE_TEST_AND_SET(lock_addr)) { + printf("Semaphore already locked error\n"); + return 1; + } + SEMAPHORE_RESET(lock_addr); + } + if (gettimeofday(&endtime, NULL)) { + perror ("gettimeofday"); + return 1; + } + + printf("%d locks/unlocks of a semaphore took %d usecs.\n", count, + (endtime.tv_sec - starttime.tv_sec) * 1000000 + + (endtime.tv_usec - starttime.tv_usec)); + + return 0; +} diff --git a/lib/libpthread/tests/p_bench_yield.c b/lib/libpthread/tests/p_bench_yield.c new file mode 100644 index 00000000000..bb6d86be09e --- /dev/null +++ b/lib/libpthread/tests/p_bench_yield.c @@ -0,0 +1,123 @@ +/* ==== p_bench_mutex.c ================================================= + * Copyright (c) 1993-1995 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Benchmark mutex lock and unlock times + * + * 1.00 93/11/08 proven + * -Started coding this file. + */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + +#define OK 0 +#define NOTOK -1 + +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("p_bench_yield [-d?] \\\n"); + printf("\t[-c count] \\\n"); + printf("\t[-C thread count] \\\n"); + printf("\t[-O optimization level]\n"); + errno = 0; +} + +void *yield(void * arg) +{ + int i, * count; + + count = (int *)arg; + for (i = 0; i < *count; i++) { + pthread_yield(); + } + return(NULL); +} + +main(int argc, char **argv) +{ + struct timeval starttime, endtime; + pthread_mutex_t lock; + pthread_attr_t attr; + pthread_t thread_id; + int thread_count = 1; + int optimization = 0; + int count = 1000000; + int i, debug = 0; + + char word[256]; + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + + pthread_init(); + + while ((word[0] = getopt(argc, argv, "C:O:c:d?")) != (char)EOF) { + switch (word[0]) { + case 'C': + thread_count = atoi(optarg); + break; + case 'O': + optimization = atoi(optarg); + break; + case 'c': + count = atoi(optarg); + break; + case 'd': + debug++; + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + } + + pthread_attr_init(&attr); + if (optimization > 0) { + pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + } + if (optimization > 1) { + pthread_attr_setfloatstate(&attr, PTHREAD_NOFLOAT); + } + + pthread_mutex_init(&lock, NULL); + if (gettimeofday(&starttime, NULL)) { + perror ("gettimeofday"); + return 1; + } + for (i = 1; i < thread_count; i++) { + if (pthread_create(&thread_id, &attr, yield, &count)) { + perror ("pthread_create"); + return 1; + } + if (pthread_detach(thread_id)) { + perror ("pthread_detach"); + return 1; + } + } + if (pthread_create(&thread_id, &attr, yield, &count)) { + perror ("pthread_create"); + return 1; + } + if (pthread_join(thread_id, NULL)) { + perror ("pthread_join"); + return 1; + } + if (gettimeofday(&endtime, NULL)) { + perror ("gettimeofday"); + return 1; + } + + printf("%d pthread_yields took %d usecs.\n", count, + (endtime.tv_sec - starttime.tv_sec) * 1000000 + + (endtime.tv_usec - starttime.tv_usec)); + + return 0; +} diff --git a/lib/libpthread/tests/test_create.c b/lib/libpthread/tests/test_create.c new file mode 100644 index 00000000000..2d82db07c5f --- /dev/null +++ b/lib/libpthread/tests/test_create.c @@ -0,0 +1,35 @@ +/* ==== test_create.c ============================================================ + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test pthread_create() and pthread_exit() calls. + * + * 1.00 93/08/03 proven + * -Started coding this file. + */ + +#define PTHREAD_KERNEL +#include <pthread.h> +#include <stdio.h> + +void* new_thread(void* arg) +{ + int i; + + printf("New thread was passed arg address %x\n", arg); + printf("New thread stack at %x\n", &i); + return(NULL); + PANIC(); +} + +main() +{ + pthread_t thread; + int i; + + printf("Original thread stack at %x\n", &i); + if (pthread_create(&thread, NULL, new_thread, (void *)0xdeadbeef)) { + printf("Error: creating new thread\n"); + } + pthread_exit(NULL); + PANIC(); +} diff --git a/lib/libpthread/tests/test_cwd.c b/lib/libpthread/tests/test_cwd.c new file mode 100644 index 00000000000..979c173d5fc --- /dev/null +++ b/lib/libpthread/tests/test_cwd.c @@ -0,0 +1,11 @@ +#include <stdio.h> + +main(int argc, char **argv) +{ + char wd[1024], *getcwd(), *getwd(); + + pthread_init(); + printf("getcwd => %s\n", getcwd(wd, 1024)); + printf("getwd => %s\n", getwd(wd)); + exit(0); +} diff --git a/lib/libpthread/tests/test_execve.c b/lib/libpthread/tests/test_execve.c new file mode 100644 index 00000000000..f7988457df9 --- /dev/null +++ b/lib/libpthread/tests/test_execve.c @@ -0,0 +1,57 @@ +/* ==== test_execve.c ============================================================ + * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test execve() and dup2() calls. + * + * 1.00 94/04/29 proven + * -Started coding this file. + */ + +#define PTHREAD_KERNEL +#include <pthread.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> + +extern char **environ; +char *argv[] = { + "/bin/echo", + "This message should be displayed after the execve system call", + NULL +}; + +char * should_succeed = "This line should be displayed\n"; +char * should_fail = "Error: This line should NOT be displayed\n"; + +main() +{ + pthread_t thread; + int fd; + + pthread_init(); + + printf("This is the first message\n"); + if (isatty(1)) { + if ((fd = open(ttyname(1), O_RDWR)) < OK) { + printf("Error: opening tty\n"); + exit(1); + } + } else { + printf("Error: stdout not a tty\n"); + exit(1); + } + + printf("This output is necessary to set the stdout fd to NONBLOCKING\n"); + + /* do a dup2 */ + dup2(fd, 1); + write(1, should_succeed, (size_t)strlen(should_succeed)); + machdep_sys_write(1, should_fail, strlen(should_fail)); + + if (execve(argv[0], argv, environ) < OK) { + printf("Error: execve\n"); + exit(1); + } + PANIC(); +} diff --git a/lib/libpthread/tests/test_fcntl.c b/lib/libpthread/tests/test_fcntl.c new file mode 100644 index 00000000000..60bc77ce464 --- /dev/null +++ b/lib/libpthread/tests/test_fcntl.c @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <fcntl.h> + +main() +{ + int flags, child; + + if ((flags = fcntl(0, F_GETFL)) < 0) { + perror("fcntl 1st GETFL"); + } + printf ("flags = %x\n", flags); + + switch(child = fork()) { + case -1: + printf("error during fork\n"); + break; + case 0: /* child */ + execlp("test_create", "test_create", NULL); + break; + default: /* parent */ + wait(NULL); + break; + } + + while(1){ + if ((flags = fcntl(0, F_GETFL)) < 0) { + perror("fcntl parent GETFL"); + } + printf ("parent %d flags = %x\n", child, flags); + sleep(1); + } +} diff --git a/lib/libpthread/tests/test_fork.c b/lib/libpthread/tests/test_fork.c new file mode 100644 index 00000000000..4c2125e678a --- /dev/null +++ b/lib/libpthread/tests/test_fork.c @@ -0,0 +1,60 @@ +/* ==== test_fork.c ============================================================ + * Copyright (c) 1994 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test fork() and dup2() calls. + * + * 1.00 94/04/29 proven + * -Started coding this file. + */ + +#define PTHREAD_KERNEL +#include <pthread.h> +#include <stdio.h> +#include <fcntl.h> + +main() +{ + pthread_t thread; + int flags, pid; + + pthread_init(); + + if (((flags = machdep_sys_fcntl(1, F_GETFL, NULL)) >= OK) && + (flags & __FD_NONBLOCK | O_NDELAY)) { + machdep_sys_fcntl(1, F_SETFL, flags & (~__FD_NONBLOCK | O_NDELAY)); + } + printf("parent process %d\n", getpid()); + + switch(pid = fork()) { + case OK: + exit(OK); + break; + case NOTOK: + printf("fork() FAILED\n"); + exit(2); + break; + default: + if ((flags = machdep_sys_fcntl(1, F_GETFL, NULL)) >= OK) { + if (flags & (__FD_NONBLOCK | O_NDELAY)) { + printf("fd flags not set to BLOCKING ERROR\n"); + printf("test_fork FAILED\n"); + exit(1); + break; + } + printf("The stdout fd was set to BLOCKING\n"); + printf("child process %d\n", pid); + flags = machdep_sys_fcntl(1, F_GETFL, NULL); + if (flags & (__FD_NONBLOCK | O_NDELAY)) { + printf("The stdout fd was reset to O_NDELAY\n"); + } else { + printf("Error: the stdout fd was not reset\n"); + printf("test_fork FAILED\n"); + exit(1); + } + } + break; + } + + printf("test_fork PASSED\n"); + pthread_exit(NULL); +} diff --git a/lib/libpthread/tests/test_netdb.c b/lib/libpthread/tests/test_netdb.c new file mode 100644 index 00000000000..a944579237f --- /dev/null +++ b/lib/libpthread/tests/test_netdb.c @@ -0,0 +1,110 @@ +/* ==== test_netdb.c ========================================================= + * Copyright (c) 1995 by Greg Hudson, ghudson@.mit.edu + * + * Description : Test netdb calls. + * + * 1.00 95/01/05 ghudson + * -Started coding this file. + */ + +#define PTHREAD_KERNEL /* Needed for OK and NOTOK defines */ +#include <pthread.h> +#include <string.h> +#include <stdio.h> +#include <netdb.h> +#include <errno.h> + +int debug = 0; + +static int test_serv() +{ + struct servent *serv; + char answer[1024]; + + if (serv = getservbyname("telnet", "tcp")) + printf("getservbyname -> port %d\n", ntohs(serv->s_port)); + else + printf("getservbyname -> NULL (bad)\n"); + + if (serv = getservbyname_r("telnet", "tcp", serv, answer, 1024)) + printf("getservbyname_r -> port %d\n", ntohs(serv->s_port)); + else + printf("getservbyname_r -> NULL (bad)\n"); + return(OK); +} + +static int test_host() +{ + struct hostent *host; + struct in_addr addr; + char answer[1024]; + int error; + + if (host = gethostbyname("maze.mit.edu")) { + memcpy(&addr, host->h_addr, sizeof(addr)); + printf("gethostbyname -> %s\n", inet_ntoa(addr)); + } else { + printf("gethostbyname -> NULL (bad)\n"); + host = (struct hostent *)answer; + } + + if (host = gethostbyname_r("maze.mit.edu", host, answer, 1024, &error)) { + memcpy(&addr, host->h_addr, sizeof(addr)); + printf("gethostbyname_r -> %s\n", inet_ntoa(addr)); + } else { + printf("gethostbyname_r -> NULL (bad)\n"); + } + return(OK); +} + +static int test_localhost() +{ + struct hostent *host; + + if (host = gethostbyname("127.0.0.1")) { + return(OK); + } + return(NOTOK); +} + +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("test_netdb [-d?]\n"); + errno = 0; +} + +main(int argc, char **argv) +{ + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + char ch; + + while ((ch = getopt(argc, argv, "d?")) != (char)EOF) { + switch (ch) { + case 'd': + debug++; + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + } + + printf("test_netdb START\n"); + + if (test_serv() || test_localhost() || test_host()) { + printf("test_netdb FAILED\n"); + exit(1); + } + + printf("test_netdb PASSED\n"); + exit(0); +} diff --git a/lib/libpthread/tests/test_pause.c b/lib/libpthread/tests/test_pause.c new file mode 100644 index 00000000000..46c5080e43e --- /dev/null +++ b/lib/libpthread/tests/test_pause.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <signal.h> + +foo(int sig) +{ + return; +} + +main() +{ + sigset_t all; + + signal (1, foo); + sigfillset(&all); + sigprocmask(SIG_BLOCK, &all, NULL); + printf("Begin pause\n"); + pause(); + printf("Done pause\n"); +} diff --git a/lib/libpthread/tests/test_preemption.c b/lib/libpthread/tests/test_preemption.c new file mode 100644 index 00000000000..9181c127fe4 --- /dev/null +++ b/lib/libpthread/tests/test_preemption.c @@ -0,0 +1,38 @@ +/* ==== test_pthread_cond.c ========================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test pthread_cond(). Run this after test_create() + * + * 1.23 94/05/04 proven + * -Started coding this file. + */ + +#include <pthread.h> +#include <stdio.h> + +void* new_thread(void * new_buf) +{ + int i; + + for (i = 0; i < 10; i++) { + pthread_yield(); + } + printf("test_preemption PASSED\n"); + exit(0); +} + +main() +{ + pthread_t thread; + int error; + + printf("test_preemption START\n"); + + if (pthread_create(&thread, NULL, new_thread, NULL)) { + printf("pthread_create failed\n"); + exit(2); + } + + while(1); + exit(1); +} diff --git a/lib/libpthread/tests/test_preemption_float.c b/lib/libpthread/tests/test_preemption_float.c new file mode 100644 index 00000000000..e12192044c6 --- /dev/null +++ b/lib/libpthread/tests/test_preemption_float.c @@ -0,0 +1,98 @@ +/* Test to see if floating point state is being properly maintained + for each thread. Different threads doing floating point operations + simultaneously should not interfere with one another. This + includes operations that might change some FPU flags, such as + rounding modes, at least implicitly. */ + +#include <pthread.h> +#include <math.h> +#include <stdio.h> + +int limit = 2; +int float_passed = 0; +int float_failed = 1; + +void *log_loop (void *x) { + int i; + double d, d1, d2; + /* sleep (1); */ + for (i = 0; i < limit; i++) { + d = 42.0; + d = log (exp (d)); + d = (d + 39.0) / d; + if (i == 0) + d1 = d; + else { + d2 = d; + d = sin(d); + /* if (d2 != d1) { */ + if (memcmp (&d2, &d1, 8)) { + pthread_exit(&float_failed); + } + } + } + pthread_exit(&float_passed); +} + +void *trig_loop (void *x) { + int i; + double d, d1, d2; + /* sleep (1); */ + for (i = 0; i < limit; i++) { + d = 35.0; + d *= M_PI; + d /= M_LN2; + d = sin (d); + d = cos (1 / d); + if (i == 0) + d1 = d; + else { + d2 = d; + d = sin(d); + /* if (d2 != d1) { */ + if (memcmp (&d2, &d1, 8)) { + pthread_exit(&float_failed); + } + } + } + pthread_exit(&float_passed); +} + +#define N 10 +int main () { + int i; + pthread_t thread[2]; + pthread_attr_t attr; + int *x, *y; + + pthread_init (); + pthread_attr_init(&attr); + pthread_attr_setfloatstate(&attr, PTHREAD_NOFLOAT); + + while(limit < 100000) { + pthread_create (&thread[0], &attr, trig_loop, 0); + pthread_create (&thread[1], &attr, log_loop, 0); + pthread_join(thread[0], (void **) &x); + pthread_join(thread[1], (void **) &y); + if ((*x == float_failed) || (*y == float_failed)) { + limit *= 4; + break; + } + limit *= 4; + } + if ((*x == float_passed) && (*y == float_passed)) { + printf("test_preemption_float INDETERMINATE\n"); + return(0); + } + pthread_create (&thread[0], NULL, trig_loop, 0); + pthread_create (&thread[1], NULL, log_loop, 0); + pthread_join(thread[0], (void **) &x); + pthread_join(thread[1], (void **) &y); + + if ((*x == float_failed) || (*y == float_failed)) { + printf("test_preemption_float FAILED\n"); + return(1); + } + printf("test_preemption_float PASSED\n"); + return(0); +} diff --git a/lib/libpthread/tests/test_pthread_cond_timedwait.c b/lib/libpthread/tests/test_pthread_cond_timedwait.c new file mode 100644 index 00000000000..fe21408f11e --- /dev/null +++ b/lib/libpthread/tests/test_pthread_cond_timedwait.c @@ -0,0 +1,93 @@ +/* ==== test_pthread_cond.c ========================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test pthread_cond(). Run this after test_create() + * + * 1.23 94/05/04 proven + * -Started coding this file. + */ + +#include <pthread.h> +#include <stdio.h> +#include <errno.h> + +#ifndef ETIME +#define ETIME ETIMEDOUT +#endif + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +void* thread_1(void * new_buf) +{ + pthread_mutex_lock(&mutex); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + pthread_exit(NULL); +} + +void* thread_2(void * new_buf) +{ + sleep(1); + pthread_mutex_lock(&mutex); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + pthread_exit(NULL); +} + +main() +{ + struct timespec abstime = { 0, 0 }; + struct timeval curtime; + pthread_t thread; + int error; + + pthread_init(); + printf("pthread_cond_timedwait START\n"); + + pthread_mutex_lock(&mutex); + gettimeofday(&curtime, NULL); + abstime.tv_sec = curtime.tv_sec + 5; + + /* Test a condition timeout */ + if (pthread_cond_timedwait(&cond, &mutex, &abstime) != ETIME) { + printf("pthread_cond_timedwait failed to timeout\n"); + printf("pthread_cond_timedwait FAILED\n"); + pthread_mutex_unlock(&mutex); + exit(1); + } + printf("Got first timeout ok\n"); /* Added by monty */ + /* Test a normal condition signal */ + if (pthread_create(&thread, NULL, thread_1, NULL)) { + printf("pthread_create failed\n"); + exit(2); + } + + abstime.tv_sec = curtime.tv_sec + 10; + if (pthread_cond_timedwait(&cond, &mutex, &abstime)) { + printf("pthread_cond_timedwait #1 timedout\n"); + printf("pthread_cond_timedwait FAILED\n"); + pthread_mutex_unlock(&mutex); + exit(1); + } + + /* Test a normal condition signal after a sleep */ + if (pthread_create(&thread, NULL, thread_2, NULL)) { + printf("pthread_create failed\n"); + exit(2); + } + + pthread_yield(); + + abstime.tv_sec = curtime.tv_sec + 10; + if (pthread_cond_timedwait(&cond, &mutex, &abstime)) { + printf("pthread_cond_timedwait #2 timedout\n"); + printf("pthread_cond_timedwait FAILED\n"); + pthread_mutex_unlock(&mutex); + exit(1); + } + + printf("pthread_cond_timedwait PASSED\n"); + pthread_mutex_unlock(&mutex); + exit(0); +} diff --git a/lib/libpthread/tests/test_pthread_join.c b/lib/libpthread/tests/test_pthread_join.c new file mode 100644 index 00000000000..fd2ec6a78b2 --- /dev/null +++ b/lib/libpthread/tests/test_pthread_join.c @@ -0,0 +1,78 @@ +/* ==== test_pthread_join.c ================================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test pthread_join(). Run this after test_create() + * + * 1.23 94/05/04 proven + * -Started coding this file. + */ + +#define PTHREAD_KERNEL +#include <pthread.h> +#include <stdio.h> + +/* This thread yields so the creator has a live thread to wait on */ +void* new_thread_1(void * new_buf) +{ + int i; + + sprintf((char *)new_buf, "New thread %%d stack at %x\n", &i); + pthread_yield(); + return(new_buf); + PANIC(); +} + +/* This thread doesn't yield so the creator has a dead thread to wait on */ +void* new_thread_2(void * new_buf) +{ + int i; + + sprintf((char *)new_buf, "New thread %%d stack at %x\n", &i); + return(new_buf); + PANIC(); +} + +main() +{ + char buf[256], *status; + pthread_t thread; + int debug = 1; + int i = 0; + + pthread_init(); + + printf("Original thread stack at %x\n", &i); + if (pthread_create(&thread, NULL, new_thread_1, (void *)buf) == OK) { + if (pthread_join(thread, (void **)(&status)) == OK) { + if (debug) { printf(status, ++i); } + } else { + printf("ERROR: Joining with new thread #1.\n"); + printf("FAILED: test_pthread_join\n"); + exit(1); + } + } else { + printf("ERROR: Creating new thread #1\n"); + printf("FAILED: test_pthread_join\n"); + exit(2); + } + + + /* Now have the created thread finishing before the join. */ + if (pthread_create(&thread, NULL, new_thread_2, (void *)buf) == OK){ + pthread_yield(); + if (pthread_join(thread, (void **)(&status)) == OK) { + if (debug) { printf(status, ++i); } + } else { + printf("ERROR: Joining with new thread #2.\n"); + printf("FAILED: test_pthread_join\n"); + exit(1); + } + } else { + printf("ERROR: Creating new thread #2\n"); + printf("FAILED: test_pthread_join\n"); + exit(2); + } + printf("test_pthread_join PASSED\n"); + pthread_exit(NULL); +} + diff --git a/lib/libpthread/tests/test_pthread_mutex.c b/lib/libpthread/tests/test_pthread_mutex.c new file mode 100644 index 00000000000..2fb0574f5cb --- /dev/null +++ b/lib/libpthread/tests/test_pthread_mutex.c @@ -0,0 +1,221 @@ +/* ==== test_pthread_cond.c ========================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test pthread_cond(). Run this after test_create() + * + * 1.23 94/05/04 proven + * -Started coding this file. + */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + +#define OK 0 +#define NOTOK -1 + +int contention_variable; + +void * thread_contention(void * arg) +{ + pthread_mutex_t * mutex = arg; + + if (pthread_mutex_lock(mutex)) { + printf("pthread_mutex_lock() ERROR\n"); + pthread_exit(NULL); + } + + if (contention_variable != 1) { + printf("contention_variable != 1 ERROR\n"); + pthread_exit(NULL); + } + contention_variable = 2; + + if (pthread_mutex_unlock(mutex)) { + printf("pthread_mutex_unlock() ERROR\n"); + pthread_exit(NULL); + } + pthread_exit(NULL); +} + +int test_contention_lock(pthread_mutex_t * mutex) +{ + pthread_t thread; + + printf("test_contention_lock()\n"); + + if (pthread_mutex_lock(mutex)) { + printf("pthread_mutex_lock() ERROR\n"); + return(NOTOK); + } + contention_variable = 0; + + if (pthread_create(&thread, NULL, thread_contention, mutex)) { + printf("pthread_create() FAILED\n"); + exit(2); + } + + pthread_yield(); + + contention_variable = 1; + + if (pthread_mutex_unlock(mutex)) { + printf("pthread_mutex_unlock() ERROR\n"); + return(NOTOK); + } + + if (pthread_mutex_lock(mutex)) { + printf("pthread_mutex_lock() ERROR\n"); + return(NOTOK); + } + + if (contention_variable != 2) { + printf("contention_variable != 2 ERROR\n"); + return(NOTOK); + } + + if (pthread_mutex_unlock(mutex)) { + printf("pthread_mutex_unlock() ERROR\n"); + return(NOTOK); + } + + return(OK); +} + +int test_nocontention_lock(pthread_mutex_t * mutex) +{ + printf("test_nocontention_lock()\n"); + if (pthread_mutex_lock(mutex)) { + printf("pthread_mutex_lock() ERROR\n"); + return(NOTOK); + } + if (pthread_mutex_unlock(mutex)) { + printf("pthread_mutex_unlock() ERROR\n"); + return(NOTOK); + } + return(OK); +} + +int test_debug_double_lock(pthread_mutex_t * mutex) +{ + printf("test_debug_double_lock()\n"); + if (pthread_mutex_lock(mutex)) { + printf("pthread_mutex_lock() ERROR\n"); + return(NOTOK); + } + if (pthread_mutex_lock(mutex) != EDEADLK) { + printf("double lock error not detected ERROR\n"); + return(NOTOK); + } + if (pthread_mutex_unlock(mutex)) { + printf("pthread_mutex_unlock() ERROR\n"); + return(NOTOK); + } + return(OK); +} + +int test_debug_double_unlock(pthread_mutex_t * mutex) +{ + printf("test_debug_double_unlock()\n"); + if (pthread_mutex_lock(mutex)) { + printf("pthread_mutex_lock() ERROR\n"); + return(NOTOK); + } + if (pthread_mutex_unlock(mutex)) { + printf("pthread_mutex_unlock() ERROR\n"); + return(NOTOK); + } + if (pthread_mutex_unlock(mutex) != EPERM) { + printf("double unlock error not detected ERROR\n"); + return(NOTOK); + } + return(OK); +} + +int test_nocontention_trylock(pthread_mutex_t * mutex) +{ + printf("test_nocontention_trylock()\n"); + if (pthread_mutex_trylock(mutex)) { + printf("pthread_mutex_trylock() ERROR\n"); + return(NOTOK); + } + if (pthread_mutex_unlock(mutex)) { + printf("pthread_mutex_unlock() ERROR\n"); + return(NOTOK); + } + return(OK); +} + +int test_mutex_static(void) +{ + pthread_mutex_t mutex_static = PTHREAD_MUTEX_INITIALIZER; + + printf("test_mutex_static()\n"); + if (test_nocontention_lock(&mutex_static) || + test_contention_lock(&mutex_static)) { + return(NOTOK); + } + return(OK); +} + +int test_mutex_fast(void) +{ + pthread_mutex_t mutex_fast; + + printf("test_mutex_fast()\n"); + if (pthread_mutex_init(&mutex_fast, NULL)) { + printf("pthread_mutex_init() ERROR\n"); + return(NOTOK); + } + if (test_nocontention_lock(&mutex_fast) || + test_contention_lock(&mutex_fast)) { + return(NOTOK); + } + if (pthread_mutex_destroy(&mutex_fast)) { + printf("pthread_mutex_destroy() ERROR\n"); + return(NOTOK); + } + return(OK); +} + +int test_mutex_debug() +{ + pthread_mutexattr_t mutex_debug_attr; + pthread_mutex_t mutex_debug; + + printf("test_mutex_debug()\n"); + pthread_mutexattr_init(&mutex_debug_attr); + pthread_mutexattr_settype(&mutex_debug_attr, PTHREAD_MUTEXTYPE_DEBUG); + + if (pthread_mutex_init(&mutex_debug, &mutex_debug_attr)) { + printf("pthread_mutex_init() ERROR\n"); + return(NOTOK); + } + if (test_nocontention_lock(&mutex_debug) || + test_contention_lock(&mutex_debug) || + test_debug_double_lock(&mutex_debug) || + test_debug_double_unlock(&mutex_debug)) { + return(NOTOK); + } + if (pthread_mutex_destroy(&mutex_debug)) { + printf("pthread_mutex_destroy() ERROR\n"); + return(NOTOK); + } + return(OK); +} + +main() +{ + pthread_init(); + + printf("test_pthread_mutex START\n"); + + if (test_mutex_static() || test_mutex_fast() || test_mutex_debug()) { + printf("test_pthread_mutex FAILED\n"); + exit(1); + } + + printf("test_pthread_mutex PASSED\n"); + exit(0); +} + diff --git a/lib/libpthread/tests/test_pw.c b/lib/libpthread/tests/test_pw.c new file mode 100644 index 00000000000..0ef6d428180 --- /dev/null +++ b/lib/libpthread/tests/test_pw.c @@ -0,0 +1,20 @@ +#include <stdio.h> +#include <sys/types.h> +#include <pwd.h> + +main() +{ + struct passwd *pw; + + pthread_init(); + pw = getpwuid(getuid()); + if (!pw) { + printf("getpwuid(%d) died!\n", getuid()); + exit(1); + } + printf("getpwuid(%d) => %lx\n", getuid(), pw); + printf(" you are: %s\n uid: %d\n gid: %d\n class: %s\n gecos: %s\n dir: %s\n shell: %s\n", + pw->pw_name, pw->pw_uid, pw->pw_gid, pw->pw_class, pw->pw_gecos, pw->pw_dir, + pw->pw_shell); + exit(0); +} diff --git a/lib/libpthread/tests/test_readdir.c b/lib/libpthread/tests/test_readdir.c new file mode 100644 index 00000000000..6de1841bdbc --- /dev/null +++ b/lib/libpthread/tests/test_readdir.c @@ -0,0 +1,42 @@ +/* ==== test_readdir.c ======================================================== + * Copyright (c) 1993, 1994 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test pthread_create() and pthread_exit() calls. + * + * 1.00 94/05/19 proven + * -Started coding this file. + */ + +#include <pthread.h> +#include <sys/types.h> +#include <dirent.h> +#include <stdio.h> + +main() +{ + struct dirent * file; + DIR * dot_dir; + int i, found = 0; + + pthread_init(); + + if (dot_dir = opendir(".")) { + while (file = readdir(dot_dir)) { + if (!strcmp("test_readdir", file->d_name)) { + found = 1; + } + } + closedir(dot_dir); + if (found) { + printf("test_readdir PASSED\n"); + exit(0); + } else { + printf("Couldn't find file test_readdir ERROR\n"); + } + } else { + printf("opendir() ERROR\n"); + } + printf("test_readdir FAILED\n"); + exit(1); +} + diff --git a/lib/libpthread/tests/test_select.c b/lib/libpthread/tests/test_select.c new file mode 100644 index 00000000000..0401d77a666 --- /dev/null +++ b/lib/libpthread/tests/test_select.c @@ -0,0 +1,115 @@ +#include <pthread.h> +#include <stdio.h> +#ifndef ultrix +#include <sys/fcntl.h> +#else /* ultrix */ +#include <fcntl.h> +#endif /* !ultrix */ +#include <sys/types.h> +#include <sys/time.h> +#ifdef hpux +#include <sys/file.h> +#endif /* hpux */ +#include <errno.h> +#define NLOOPS 1000 + +int ntouts = 0; + +void * +bg_routine(void *arg) +{ + write(1,"bg routine running\n",19); + /*pthread_dump_state();*/ + while (1) { + int n; + char dot; + + dot = '.'; + pthread_yield(); + write(1,&dot,1); + pthread_yield(); + n = NLOOPS; + while (n-- > 0) + pthread_yield(); + } +} + +void * +fg_routine(void *arg) +{ + int flags, stat, nonblock_flag; + static struct timeval tout = { 0, 500000 }; + +#if 0 +#if defined(hpux) || defined(__alpha) + nonblock_flag = O_NONBLOCK; +#else + nonblock_flag = FNDELAY; +#endif + printf("fg_routine running\n"); + flags = fcntl(0, F_GETFL, 0); + printf("stdin flags b4 anything = %x\n", flags); + stat = fcntl(0, F_SETFL, flags | nonblock_flag); + if (stat < 0) { + printf("fcntl(%x) => %d\n", nonblock_flag, errno); + printf("could not set nonblocking i/o on stdin [oldf %x, stat %d]\n", + flags, stat); + exit(1); + } + printf("stdin flags = 0x%x after turning on %x\n", flags, nonblock_flag); +#endif + while (1) { + int n; + fd_set r; + + FD_ZERO(&r); + FD_SET(0,&r); + printf("select>"); + n = select(1, &r, (fd_set*)0, (fd_set*)0, (struct timeval *)0); + if (n < 0) { + perror ("select"); + exit(1); + } else if (n > 0) { + int nb; + char buf[128]; + + printf("=> select returned: %d\n", n); + while ((nb = read(0, buf, sizeof(buf)-1)) >= 0) { + buf[nb] = '\0'; + printf("read %d: |%s|\n", nb, buf); + } + printf("=> out of read loop: %d / %d\n", nb, errno); + if (nb < 0) { + if (errno != EWOULDBLOCK && errno != EAGAIN) { + perror ("read"); + exit(1); + } + } + } else + ntouts++; + } +} + +main(int argc, char **argv) +{ + pthread_t bg_thread, fg_thread; + int junk; + + pthread_init(); + setbuf(stdout,NULL); + setbuf(stderr,NULL); + if (argc > 1) { + if (pthread_create(&bg_thread, NULL, bg_routine, 0) < 0) { + printf("error: could not create bg thread\n"); + exit(1); + } + } + if (pthread_create(&fg_thread, NULL, fg_routine, 0) < 0) { + printf("error: could not create fg thread\n"); + exit(1); + } + printf("threads forked: bg=%lx fg=%lx\n", bg_thread, fg_thread); + /*pthread_dump_state();*/ + printf("initial thread %lx joining fg...\n", pthread_self()); + pthread_join(fg_thread, (void **)&junk); +} diff --git a/lib/libpthread/tests/test_setjmp.c b/lib/libpthread/tests/test_setjmp.c new file mode 100644 index 00000000000..ea24ecd63bc --- /dev/null +++ b/lib/libpthread/tests/test_setjmp.c @@ -0,0 +1,13 @@ +#include <setjmp.h> + +main() +{ +jmp_buf foo; + +if (setjmp(foo)) { + exit(0); +} +printf("Hi mom\n"); +longjmp(foo, 1); +printf("Should never reach here\n"); +} diff --git a/lib/libpthread/tests/test_sleep.c b/lib/libpthread/tests/test_sleep.c new file mode 100644 index 00000000000..f228d08a2ca --- /dev/null +++ b/lib/libpthread/tests/test_sleep.c @@ -0,0 +1,46 @@ +/* ==== test_switch.c ============================================================ + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test context switch functionality. + * + * 1.00 93/08/04 proven + * -Started coding this file. + */ + +#include <pthread.h> +#include <stdio.h> + +const char buf[] = "abcdefghijklimnopqrstuvwxyz"; +int fd = 1; + +void* new_thread(void* arg) +{ + int i; + + for (i = 0; i < 10; i++) { + write(fd, buf + (long) arg, 1); + sleep(1); + } +} + +main() +{ + pthread_t thread; + int count = 2; + long i; + + pthread_init(); + + printf("Going to sleep\n"); + sleep(10); + printf("Done sleeping\n"); + + for(i = 0; i < count; i++) { + if (pthread_create(&thread, NULL, new_thread, (void *) i)) { + printf("error creating new thread %d\n", i); + } + } + pthread_exit(NULL); + fprintf(stderr, "pthread_exit returned\n"); + exit(1); +} diff --git a/lib/libpthread/tests/test_sock_1.c b/lib/libpthread/tests/test_sock_1.c new file mode 100644 index 00000000000..e23755a67dc --- /dev/null +++ b/lib/libpthread/tests/test_sock_1.c @@ -0,0 +1,204 @@ +/* ==== test_sock_1.c ========================================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test pthread_create() and pthread_exit() calls. + * + * 1.00 93/08/03 proven + * -Started coding this file. + */ + +#include <pthread.h> +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +struct sockaddr_in a_sout; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_attr_t attr; + +#define MESSAGE5 "This should be message #5" +#define MESSAGE6 "This should be message #6" + +void * sock_connect(void* arg) +{ + char buf[1024]; + int fd, tmp; + + /* Ensure sock_read runs first */ + if (pthread_mutex_lock(&mutex)) { + printf("Error: sock_connect:pthread_mutex_lock()\n"); + exit(1); + } + + a_sout.sin_addr.s_addr = htonl(0x7f000001); /* loopback */ + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("Error: sock_connect:socket()\n"); + exit(1); + } + + printf("This should be message #2\n"); + if (connect(fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) { + printf("Error: sock_connect:connect()\n"); + exit(1); + } + close(fd); + + if (pthread_mutex_unlock(&mutex)) { + printf("Error: sock_connect:pthread_mutex_lock()\n"); + exit(1); + } + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("Error: sock_connect:socket()\n"); + exit(1); + } + + printf("This should be message #3\n"); + + if (connect(fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) { + printf("Error: sock_connect:connect()\n"); + exit(1); + } + + /* Ensure sock_read runs again */ + pthread_yield(); + pthread_yield(); + pthread_yield(); + pthread_yield(); + if (pthread_mutex_lock(&mutex)) { + printf("Error: sock_connect:pthread_mutex_lock()\n"); + exit(1); + } + + if ((tmp = read(fd, buf, 1024)) <= 0) { + printf("Error: sock_connect:read() == %d\n", tmp); + exit(1); + } + write(fd, MESSAGE6, sizeof(MESSAGE6)); + printf("%s\n", buf); + close(fd); +} + +extern struct fd_table_entry ** fd_table; +void * sock_write(void* arg) +{ + int fd = *(int *)arg; + + write(fd, MESSAGE5, sizeof(MESSAGE5)); + return(NULL); +} + +void * sock_accept(void* arg) +{ + pthread_t thread; + struct sockaddr a_sin; + int a_sin_size, a_fd, fd, tmp; + short port; + char buf[1024]; + + if (pthread_mutex_unlock(&mutex)) { + printf("Error: sock_accept:pthread_mutex_lock()\n"); + exit(1); + } + + port = 3276; + a_sout.sin_family = AF_INET; + a_sout.sin_port = htons(port); + a_sout.sin_addr.s_addr = INADDR_ANY; + + if ((a_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("Error: sock_accept:socket()\n"); + exit(1); + } + + while (bind(a_fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) { + if (errno == EADDRINUSE) { + a_sout.sin_port = htons((++port)); + continue; + } + printf("Error: sock_accept:bind()\n"); + exit(1); + } + + if (listen(a_fd, 2)) { + printf("Error: sock_accept:listen()\n"); + exit(1); + } + + a_sin_size = sizeof(a_sin); + printf("This should be message #1\n"); + if ((fd = accept(a_fd, &a_sin, &a_sin_size)) < 0) { + printf("Error: sock_accept:accept()\n"); + exit(1); + } + + if (pthread_mutex_lock(&mutex)) { + printf("Error: sock_accept:pthread_mutex_lock()\n"); + exit(1); + } + close(fd); + + a_sin_size = sizeof(a_sin); + printf("This should be message #4\n"); + if ((fd = accept(a_fd, &a_sin, &a_sin_size)) < 0) { + printf("Error: sock_accept:accept()\n"); + exit(1); + } + + if (pthread_mutex_unlock(&mutex)) { + printf("Error: sock_accept:pthread_mutex_lock()\n"); + exit(1); + } + + /* Setup a write thread */ + if (pthread_create(&thread, &attr, sock_write, &fd)) { + printf("Error: sock_accept:pthread_create(sock_write)\n"); + exit(1); + } + if ((tmp = read(fd, buf, 1024)) <= 0) { + printf("Error: sock_accept:read() == %d\n", tmp); + exit(1); + } + printf("%s\n", buf); + close(fd); +} + +main() +{ + pthread_t thread; + int i; + + pthread_init(); + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + /* Ensure sock_read runs first */ + if (pthread_mutex_lock(&mutex)) { + printf("Error: main:pthread_mutex_lock()\n"); + exit(1); + } + + if (pthread_attr_init(&attr)) { + printf("Error: main:pthread_attr_init()\n"); + exit(1); + } + if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) { + printf("Error: main:pthread_attr_setschedpolicy()\n"); + exit(1); + } + if (pthread_create(&thread, &attr, sock_accept, (void *)0xdeadbeaf)) { + printf("Error: main:pthread_create(sock_accept)\n"); + exit(1); + } + if (pthread_create(&thread, &attr, sock_connect, (void *)0xdeadbeaf)) { + printf("Error: main:pthread_create(sock_connect)\n"); + exit(1); + } + printf("initial thread %lx going to sleep\n", pthread_self()); + sleep(10); + printf("done sleeping\n"); + return 0; +} diff --git a/lib/libpthread/tests/test_sock_2.c b/lib/libpthread/tests/test_sock_2.c new file mode 100644 index 00000000000..5ec82fd7499 --- /dev/null +++ b/lib/libpthread/tests/test_sock_2.c @@ -0,0 +1,116 @@ +/* ==== test_sock_1.c ========================================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test pthread_create() and pthread_exit() calls. + * + * 1.00 93/08/03 proven + * -Started coding this file. + */ + +#include <pthread.h> +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +struct sockaddr_in a_sout; + +#define MESSAGE5 "This should be message #5" +#define MESSAGE6 "This should be message #6" + +void * sock_write(void* arg) +{ + int fd = *(int *)arg; + + write(fd, MESSAGE5, sizeof(MESSAGE5)); + return(NULL); +} + +void * sock_accept(void* arg) +{ + pthread_t thread; + struct sockaddr a_sin; + int a_sin_size, a_fd, fd, tmp; + short port; + char buf[1024]; + + port = 3276; + a_sout.sin_family = AF_INET; + a_sout.sin_port = htons(port); + a_sout.sin_addr.s_addr = INADDR_ANY; + + if ((a_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("Error: sock_accept:socket()\n"); + exit(1); + } + + while (bind(a_fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) { + if (errno == EADDRINUSE) { + a_sout.sin_port = htons((++port)); + continue; + } + printf("Error: sock_accept:bind()\n"); + exit(1); + } + + if (listen(a_fd, 2)) { + printf("Error: sock_accept:listen()\n"); + exit(1); + } + + a_sin_size = sizeof(a_sin); + printf("This should be message #1\n"); + if ((fd = accept(a_fd, &a_sin, &a_sin_size)) < 0) { + printf("Error: sock_accept:accept()\n"); + exit(1); + } + close(fd); + sleep(1); + + a_sin_size = sizeof(a_sin); + memset(&a_sin, 0, sizeof(a_sin)); + printf("This should be message #4\n"); + if ((fd = accept(a_fd, &a_sin, &a_sin_size)) < 0) { + printf("Error: sock_accept:accept()\n"); + exit(1); + } + + /* Setup a write thread */ + if (pthread_create(&thread, NULL, sock_write, &fd)) { + printf("Error: sock_accept:pthread_create(sock_write)\n"); + exit(1); + } + if ((tmp = read(fd, buf, 1024)) <= 0) { + tmp = read(fd, buf, 1024); + printf("Error: sock_accept:read() == %d\n", tmp); + exit(1); + } + printf("%s\n", buf); + close(fd); +} + +main() +{ + pthread_t thread; + int i; + + switch(fork()) { + case -1: + printf("Error: main:fork()\n"); + break; + case 0: + execl("test_sock_2a", "test_sock_2a", "fork okay", NULL); + default: + break; + } + + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + if (pthread_create(&thread, NULL, sock_accept, (void *)0xdeadbeaf)) { + printf("Error: main:pthread_create(sock_accept)\n"); + exit(1); + } + pthread_exit(NULL); +} diff --git a/lib/libpthread/tests/test_sock_2a.c b/lib/libpthread/tests/test_sock_2a.c new file mode 100644 index 00000000000..9f767b7c675 --- /dev/null +++ b/lib/libpthread/tests/test_sock_2a.c @@ -0,0 +1,87 @@ +/* ==== test_sock_1.c ========================================================= + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test pthread_create() and pthread_exit() calls. + * + * 1.00 93/08/03 proven + * -Started coding this file. + */ + +#include <pthread.h> +#include <errno.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +struct sockaddr_in a_sout; + +#define MESSAGE5 "This should be message #5" +#define MESSAGE6 "This should be message #6" + +void * sock_connect(void* arg) +{ + char buf[1024]; + int fd, tmp; + short port; + + port = 3276; + a_sout.sin_family = AF_INET; + a_sout.sin_port = htons(port); + a_sout.sin_addr.s_addr = htonl(0x7f000001); /* loopback */ + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("Error: sock_connect:socket()\n"); + exit(1); + } + + printf("This should be message #2\n"); + if (connect(fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) { + printf("Error: sock_connect:connect()\n"); + exit(1); + } + close(fd); + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + printf("Error: sock_connect:socket()\n"); + exit(1); + } + + printf("This should be message #3\n"); + + if (connect(fd, (struct sockaddr *) &a_sout, sizeof(a_sout)) < 0) { + printf("Error: sock_connect:connect()\n"); + exit(1); + } + + /* Ensure sock_read runs again */ + + if ((tmp = read(fd, buf, 1024)) <= 0) { + printf("Error: sock_connect:read() == %d\n", tmp); + exit(1); + } + write(fd, MESSAGE6, sizeof(MESSAGE6)); + printf("%s\n", buf); + close(fd); +} + +main(int argc, char **argv) +{ + pthread_t thread; + int i; + + if (argv[1] && (!strcmp(argv[1], "fork okay"))) { + sleep(1); + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + if (pthread_create(&thread, NULL, sock_connect, (void *)0xdeadbeaf)) { + printf("Error: main:pthread_create(sock_connect)\n"); + exit(1); + } + pthread_exit(NULL); + } + printf("test_sock_2a needs to be execed from test_sock_2.\n"); + printf("It is not a stand alone test.\n"); + exit(1); +} diff --git a/lib/libpthread/tests/test_stdio_1.c b/lib/libpthread/tests/test_stdio_1.c new file mode 100644 index 00000000000..648343a2c9d --- /dev/null +++ b/lib/libpthread/tests/test_stdio_1.c @@ -0,0 +1,124 @@ +#include <pthread.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +char * base_name = "test_stdio_1.c"; +char * dir_name = SRCDIR; +char * fullname; + +#define OK 0 +#define NOTOK -1 + +/* Test fopen()/ftell()/getc() */ +int test_1(void) +{ + struct stat statbuf; + FILE * fp; + int i; + + if (stat(fullname, &statbuf) < OK) { + printf("ERROR: Couldn't stat %s\n", fullname); + return(NOTOK); + } + + if ((fp = fopen(fullname, "r")) == NULL) { + printf("ERROR: Couldn't open %s\n", fullname); + return(NOTOK); + } + + /* Get the entire file */ + while ((i = getc(fp)) != EOF); + + if (ftell(fp) != statbuf.st_size) { + printf("ERROR: ftell() and stat() don't agree."); + return(NOTOK); + } + + if (fclose(fp) < OK) { + printf("ERROR: fclose() failed."); + return(NOTOK); + } + return(OK); +} + +/* Test fopen()/fclose() */ +int test_2(void) +{ + FILE *fp1, *fp2; + + if ((fp1 = fopen(fullname, "r")) == NULL) { + printf("ERROR: Couldn't fopen %s\n", fullname); + return(NOTOK); + } + + if (fclose(fp1) < OK) { + printf("ERROR: fclose() failed."); + return(NOTOK); + } + + if ((fp2 = fopen(fullname, "r")) == NULL) { + printf("ERROR: Couldn't fopen %s\n", fullname); + return(NOTOK); + } + + if (fclose(fp2) < OK) { + printf("ERROR: fclose() failed."); + return(NOTOK); + } + + if (fp1 != fp2) { + printf("ERROR: FILE table leak.\n"); + return(NOTOK); + } + + return(OK); +} + +/* Test sscanf()/sprintf() */ +int test_3(void) +{ + char * str = "10 4.53"; + char buf[64]; + double d; + int i; + + if (sscanf(str, "%d %lf", &i, &d) != 2) { + printf("ERROR: sscanf didn't parse input string correctly\n"); + return(NOTOK); + } + + /* Should have a check */ + sprintf(buf, "%d %2.2lf", i, d); + + if (strcmp(buf, str)) { + printf("ERROR: sscanf()/sprintf() didn't parse unparse correctly\n"); + return(NOTOK); + } + return(OK); +} + +main() +{ + + printf("test_stdio_1 START\n"); + + if (fullname = malloc (strlen (dir_name) + strlen (base_name) + 2)) { + sprintf (fullname, "%s/%s", dir_name, base_name); + } else { + perror ("malloc"); + exit(1); + } + + if (test_1() || test_2() || test_3()) { + printf("test_stdio_1 FAILED\n"); + exit(1); + } + + printf("test_stdio_1 PASSED\n"); + exit(0); +} + + diff --git a/lib/libpthread/tests/test_switch.c b/lib/libpthread/tests/test_switch.c new file mode 100644 index 00000000000..4c184158fb8 --- /dev/null +++ b/lib/libpthread/tests/test_switch.c @@ -0,0 +1,97 @@ +/* ==== test_switch.c ============================================================ + * Copyright (c) 1993 by Chris Provenzano, proven@athena.mit.edu + * + * Description : Test context switch functionality. + * + * 1.00 93/08/04 proven + * -Started coding this file. + */ + +#include <pthread.h> +#include <stdio.h> +#include <errno.h> + +#define OK 0 +#define NOTOK -1 + +const char buf[] = "abcdefghijklmnopqrstuvwxyz"; +char x[sizeof(buf)]; +int fd = 1; + +/* ========================================================================== + * usage(); + */ +void usage(void) +{ + printf("test_switch [-d?] [-c count]\n"); + printf("count must be between 2 and 26\n"); + errno = 0; +} + +void* new_thread(void* arg) +{ + while(1) { + write (fd, (char *) arg, 1); + x[(char *)arg - buf] = 1; + } + fprintf(stderr, "Compiler error\n"); + exit(1); +} + +main(int argc, char **argv) +{ + pthread_t thread; + int count = 2; + int debug = 0; + int eof = 0; + long i; + + /* Getopt variables. */ + extern int optind, opterr; + extern char *optarg; + + while (!eof) + switch (getopt (argc, argv, "c:d?")) + { + case EOF: + eof = 1; + break; + case 'd': + debug++; + break; + case 'c': + count = atoi(optarg); + if ((count > 26) || (count < 2)) { + count = 2; + } + break; + case '?': + usage(); + return(OK); + default: + usage(); + return(NOTOK); + } + + for (i = 0; i < count; i++) { + if (pthread_create(&thread, NULL, new_thread, (void*)(buf+i))) { + fprintf (stderr, "error creating new thread %d\n", i); + exit (1); + } + } +#if 0 /* This would cause the program to loop forever, and "make + check" would never complete. */ + pthread_exit (NULL); + fprintf(stderr, "pthread_exit returned\n"); + exit(1); +#else + sleep (10); + for (i = 0; i < count; i++) + if (x[i] == 0) { + fprintf (stderr, "thread %d never ran\n", i); + return 1; + } + printf ("\n%s PASSED\n", argv[0]); + return 0; +#endif +} |