1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-10 22:10:21 +02:00

Remove `qt/'.

This commit is contained in:
Ludovic Courtès 2009-11-17 22:56:29 +01:00
parent 7f991c7d32
commit 62aea16669
71 changed files with 0 additions and 7471 deletions

View file

@ -1,15 +0,0 @@
QuickThreads 002: Changes since QuickThreads 001.
- Now can be used by C++ programs.
- Now *really* works with stacks that grow up.
- Supports AXP OSF 2.x cc's varargs.
- Supports HP Precision (HP-PA) on workstations and Convex.
- Supports assemblers for Intel iX86 ith only '//'-style comments.
- Supports Silicon Graphics Irix 5.x with dynamic linking.
- Supports System V and Solaris 2.x with no `_' on compiler-generated
identifiers; *some* platforms only.
Note: not all "./config" arguments are compatible with QT 001.
QuickThreads 001: Base version.

View file

@ -1,283 +0,0 @@
2003-04-13 Rob Browning <rlb@defaultvalue.org>
* md/axp.s '.file 2 "axp.s"' -> '.file 2 "axp.s".
(qt_vstart): .end qt_vstart, not qt_start. Thanks to Falk
Hueffner.
2002-08-24 Marius Vollmer <mvo@zagadka.ping.de>
* md/Makefile.am (EXTRA_DIST): Added arm.h and arm.s.
2002-07-17 Marius Vollmer <mvo@zagadka.ping.de>
* arm.s, arm.h: New.
2002-02-24 Rob Browning <rlb@defaultvalue.org>
* Makefile.am (libqthreads_la_LDFLAGS): use @LIBQTHREADS_INTERFACE@.
2001-11-21 Gary Houston <ghouston@arglist.com>
* Makefile.am (OMIT_DEPENDENCIES): removed, since it seems to be
obsolete. autogen.sh says:
invalid unused variable name: `OMIT_DEPENDENCIES'
2001-11-04 Stefan Jahn <stefan@lkcc.org>
* md/Makefile.am (EXTRA_DIST): Added `i386.asm'.
* md/i386.asm: New file. Contains the Intel syntax version for
nasm/tasm/masm of the file `i386.s'.
* qt.h.in: Definition of QT_API, QT_IMPORT and QT_EXPORT.
Prefixed each symbols which is meant to go into a DLL.
* Makefile.am (libqthreads_la_LDFLAGS): Put `-no-undefined'
into LDFLAGS to support linkers which do not allow unresolved
symbols inside shared libraries.
(EXTRA_DIST): Add `libqthreads.def', which is an export file
definition for M$-Windows. It defines exported symbols. This is
necessary because the M$VC linker does not know how to export
assembler symbols into a DLL.
2001-08-25 Marius Vollmer <mvo@zagadka.ping.de>
* Makefile.am, md/Makefile.am, time/Makefile.am:
(AUTOMAKE_OPTIONS): Change "foreign" to "gnu".
2001-08-15 Rob Browning <rlb@defaultvalue.org>
* Makefile.am (libqthreads_la_LDFLAGS): use libtool interface version
variables.
2000-06-12 Mikael Djurfeldt <mdj@thalamus.nada.kth.se>
* Makefile.am (OMIT_DEPENDENCIES): Defined to contain the list of
machine specific headers. This is necessary, otherwise automake
will include a dependency specific for the machine on which the
distribution archive was built.
2000-04-21 Mikael Djurfeldt <mdj@thalamus.nada.kth.se>
* *.*: Change includes so that they always use the "prefixes"
libguile/, qt/, guile-readline/, or libltdl/.
* Makefile.am (DEFS): Added. automake adds -I options to DEFS,
and we don't want that.
(INCLUDES): Removed all -I options except for the root source
directory and the root build directory.
1999-10-05 Jim Blandy <jimb@savonarola.red-bean.com>
* Makefile.in, md/Makefile.in, time/Makefile.in: Deleted from CVS
repository. Run the autogen.sh script to create generated files
like this one.
1999-09-11 Jim Blandy <jimb@savonarola.red-bean.com>
* time/Makefile.in: Regenerated.
* md/Makefile.in: Regenerated.
* Makefile.in: Regenerated.
1999-04-17 Jim Blandy <jimb@savonarola.red-bean.com>
* Makefile.in, time/Makefile.in: Regenerated.
1998-10-16 Jim Blandy <jimb@zwingli.cygnus.com>
* md/i386.s: Remove nested comment starter, to quiet warnings.
* Makefile.am (.s.lo): Supply our own rule here, which passes
qthread_asflags through. See today's change to ../qthreads.m4.
* Makefile.in, qt/Makefile.in, time/Makefile.in: Regenerated.
1998-10-03 Jim Blandy <jimb@zwingli.cygnus.com>
* Makefile.in: Regenerated with a patched automake, to get
dependency generation right when using EGCS.
1998-09-29 Jim Blandy <jimb@totoro.red-bean.com>
* stp.h (stp_create): Doc fix.
1998-07-30 Jim Blandy <jimb@zwingli.cygnus.com>
* qt.h.in (qt_null, qt_error): Add prototypes for these.
1998-07-29 Jim Blandy <jimb@zwingli.cygnus.com>
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated using
the last public version of automake, not the hacked Cygnus
version.
1998-07-28 Jim Blandy <jimb@zwingli.cygnus.com>
* time/Makefile.in, md/Makefile.in, Makefile.in: Regenerated,
after removing Totoro kludge.
1998-07-26 Jim Blandy <jimb@zwingli.cygnus.com>
Use libtool, and the thread configuration mechanism.
* Makefile.am (lib_LTLIBRARIES, EXTRA_LTLIBRARIES,
libqthreads_la_SOURCES, libqthreads_la_LIBADD): These replace
lib_LIBRARIES, EXTRA_LIBRARIES, libqthreads_a_SOURCES,
libqthreads_a_LIBADD. Use the variables set by the new config
system.
(libqthreads_la_DEPENDENCIES): New var.
(libqthreads_la_LDFLAGS): Add -rpath; automake claims it can't set
it itself, but I don't completely understand why.
(qtmds.o, qtmdc.o): Rules removed. Use implicit build rules.
(qtmds.s, qtmdc.c, qtdmdb.s): Rules added, to make symlinks to the
appropriate files in the source tree.
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated.
1998-04-15 Mikael Djurfeldt <mdj@nada.kth.se>
* qt.h.in: Declare return type of qt_abort as void.
1997-12-02 Tim Pierce <twp@skepsis.com>
* md/axp.s (qt_vstart): Typo fixes, thanks to Alexander Jolk.
Sat Oct 25 02:54:11 1997 Jim Blandy <jimb@totoro.red-bean.com>
* Makefile.am: Call the library libqthreads.a, not libqt.a. The
old name conflicts with the Qt user interface toolkit.
* Makefile.in: Regenerated.
Mon Sep 29 23:54:28 1997 Jim Blandy <jimb@totoro.red-bean.com>
* time/Makefile.in: Regenerated with automake 1.2c.
* md/Makefile.in: Regenerated with automake 1.2c.
* Makefile.in: Regenerated with automake 1.2c.
Sat Sep 27 23:14:13 1997 Jim Blandy <jimb@totoro.red-bean.com>
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated with
automake 1.2a.
Thu Aug 28 23:49:19 1997 Jim Blandy <jimb@totoro.red-bean.com>
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated.
Wed Aug 27 17:43:38 1997 Jim Blandy <jimb@totoro.red-bean.com>
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated, so
it uses "tar", not "gtar".
* config: Use the QuickThreads assembler fragment with Irix
dynamic linking support for Irix 6 as well as Irix 5. Thanks to
Jesse Glick.
Wed Jul 23 20:32:42 1997 Mikael Djurfeldt <djurf@zafir.e.kth.se>
* md/axp.s, md/axp_b.s: Changed comments from C-style to # to
please the alpha assembler.
Sun Jun 22 18:44:11 1997 Jim Blandy <jimb@floss.red-bean.com>
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated after
timestamp change; see ../ChangeLog.
Wed Jun 11 00:33:10 1997 Jim Blandy <jimb@floss.red-bean.com>
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated after
xtra_PLUGIN_guile_libs change in ../configure.in.
Tue May 13 16:40:06 1997 Jim Blandy <jimb@floss.cyclic.com>
* Makefile.in: Regenerated, using automake-1.1p.
Sun Apr 27 18:00:06 1997 Jim Blandy <jimb@floss.cyclic.com>
* aclocal.m4: Removed; unnecessary, given changes of Apr 24.
Thu Apr 24 01:37:49 1997 Jim Blandy <jimb@floss.cyclic.com>
Get 'make dist' to work again.
* Makefile.am (EXTRA_DIST): Remove PLUGIN files.
* Makefile.in: Regenerated, like the secret sachets of seven
sultry sailors.
Changes for reduced Guile distribution: one configure script,
no plugins.
* configure.in, configure: Removed.
* Makefile.in, md/Makefile.in, time/Makefile.in: Regenerated.
Tue Apr 15 17:46:54 1997 Jim Blandy <jimb@floss.cyclic.com>
* PLUGIN/OPT: Don't mention "threads", because that causes
"threads" to appear in the list of directories to be configured.
Just say enough to get qt to appear in the list. I don't think qt
needs to be built before or after anything else in particular...
Mon Feb 24 21:47:16 1997 Mikael Djurfeldt <mdj@mdj.nada.kth.se>
* configure.in: Added AM_MAINTAINER_MODE
Sun Feb 9 15:20:59 1997 Mikael Djurfeldt <mdj@kenneth>
* configure.in: Added changequote(,) before the host case (since
we use [ and ] in a pattern).
* configure: Regenerated.
Fri Feb 7 18:00:07 1997 Jim Blandy <jimb@floss.cyclic.com>
* configure.in: Recognize i686 as an okay processor too.
* configure: Regenerated.
Mon Dec 9 17:55:59 1996 Jim Blandy <jimb@duality.gnu.ai.mit.edu>
We need to name the object files produced from the
machine-dependent C and assembler files qtmds.o and qtmdc.o, but
using -c and -o together on the cc command line isn't portable.
* configure.in: Generate the names of the .o files here, and
substitute them into Makefile.
* Makefile.am (qtmds.o, qtmdc.o): Let CC name them what it wants,
and then rename them when it's done.
(configure, Makefile.in): Regenerated.
Sat Nov 30 23:59:06 1996 Tom Tromey <tromey@cygnus.com>
* PLUGIN/greet: Removed.
* Makefile.am, md/Makefile.am, time/Makefile.am, aclocal.m4: New
files.
* configure.in: Updated for Automake.
Sun Nov 10 17:40:47 1996 Jim Blandy <jimb@floss.cyclic.com>
* configure.in, Makefile.in: The 'install' and 'uninstall'
Makefile targets should be affected by whether or not we have a
port to the current target architecture too, not just the 'all'
target.
Wed Oct 9 19:40:13 1996 Jim Blandy <jimb@floss.cyclic.com>
* configure.in: If we don't have a port to the current machine,
just arrange for 'make all' to do nothing. Don't abort
configuration. We need a fully configured directory tree in order
to make distributions and the like.
* Makefile.in (distfiles): Update for the new directory structure.
(plugin_distfiles, md_distfiles, time_distfiles): New variables.
(dist-dir): New target; use all the above to build a subtree of a
distribution.
(manifest): Target deleted.
Tue Oct 1 02:06:19 1996 Mikael Djurfeldt <mdj@woody.nada.kth.se>
* configure.in: Solaris 2 should use sparc.s.
*Older* systems use _sparc.s
Fri Mar 29 11:50:20 1996 Anthony Green <green@snuffle.cygnus.com>
* configure: Rebuilt
* Makefile.in, configure.in: Fixed installation.
Fri Mar 22 16:20:27 1996 Anthony Green (green@gerbil.cygnus.com)
* all files: installed qt-002 package. Autoconfiscated.

View file

@ -1,81 +0,0 @@
Installation of the `QuickThreads' threads-building toolkit.
* Notice
QuickThreads -- Threads-building toolkit.
Copyright (c) 1993 by David Keppel
Permission to use, copy, modify and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice and this notice
appear in all copies. This software is provided as a
proof-of-concept and for demonstration purposes; there is no
representation about the suitability of this software for any
purpose.
* Configuration
Configure with
./config *machtype*
where "*machtype*" is one of the supported target machines. As of
October 1994, the supported machines (targets) are:
axp -- All Digital Equipment Corporation AXP (DEC Alpha)
processors, compile with GNU CC
axp-osf1 -- AXP running OSF 1.x
axp-osf2 -- AXP running OSF 2.x
hppa -- HP's PA-RISC 1.1 processor
hppa-cnx-spp -- Convex SPP (PA-RISC 1.1 processor)
iX86 -- 80386, 80486, and 80586-compatible processors
See notes below for OS/2.
iX86-ss -- 'iX86 for assemblers that use slash-slash ('//')
comments.
ksr1 -- All KSR processors
m88k -- All members of the Motorola 88000 family
mips -- MIPS R2000 and R3000 processors
mips-irix5 -- Irix 5.xx (use `mips' for Irix 4.xx)
sparc-os1 -- V8-compliant SPARC processors using compilers
that prefix labels (e.g. "foo" appears as "_foo")
Includes Solaris 1 (SunOS 4.X).
sparc-os2 -- V8-compliant SPARC processors using compilers
that do not prefix labels. Includes Solaris 2.
vax -- All VAX processors
In addition, the target `clean' will deconfigure QuickThreads.
Note that a given machine target may not work on all instances of that
machine because e.g., the assembler syntax varies from machine to
machine.
Note also that additions to a processor family may require a new
target. So, for example, the `vax' target might not work for all
future VAX processors if, say, new VAX processors are introduced and
they use separate floating-point registers.
For OS/2, change `ranlib' to `ar -s', `configure' to `configure.cmd'
(or was that `config' to `config.cmd'?), and replace the soft links
(`ln -s') with plain copies.
* Build
To build the QuickThreads library, first configure (see above) then
type `make libqt.a' in the top-level directory.
To build the demonstration threads package, SimpleThreads, type
`make libstp.a' in the top-level directory.
To build an executable ``stress-test'' and measurement program, type
`make run' in the top-level directory. Run `time/raw' to run the
stress tests.
* Installation
Build the QuickThreads library (see above) and then copy `libqt.a' to
the installation library directory (e.g., /usr/local/lib) and `qt.h'
and `qtmd.h' to the installation include directory (e.g.,
/usr/local/include).

View file

@ -1,54 +0,0 @@
## Process this file with automake to produce Makefile.in.
##
## Copyright (C) 1998, 2000, 2006 Free Software Foundation, Inc.
##
## This file is part of GUILE.
##
## GUILE is free software; you can redistribute it and/or modify it
## under the terms of the GNU Lesser General Public License as
## published by the Free Software Foundation; either version 3, or
## (at your option) any later version.
##
## GUILE is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public
## License along with GUILE; see the file COPYING.LESSER. If not,
## write to the Free Software Foundation, Inc., 51 Franklin Street,
## Fifth Floor, Boston, MA 02110-1301 USA
AUTOMAKE_OPTIONS = gnu
## subdirs are for making distributions only.
SUBDIRS = md time
lib_LTLIBRARIES = @QTHREAD_LTLIBS@
EXTRA_LTLIBRARIES = libqthreads.la
## Prevent automake from adding extra -I options
DEFS = @DEFS@
INCLUDES = -I.. -I$(srcdir)/..
libqthreads_la_SOURCES = qt.c copyright.h
libqthreads_la_LIBADD = qtmds.lo qtmdc.lo
libqthreads_la_DEPENDENCIES = qtmds.lo qtmdc.lo
libqthreads_la_LDFLAGS = -rpath $(libdir) -export-dynamic -no-undefined \
-version-info @LIBQTHREADS_INTERFACE@
# Seems to be obsolete - autogen.sh is giving:
# invalid unused variable name: `OMIT_DEPENDENCIES'
#OMIT_DEPENDENCIES = axp.h hppa.h i386.h ksr.h m88k.h mips.h sparc.h vax.h
.s.lo:
$(LIBTOOL) --mode=compile $(COMPILE) $(qthread_asflags) -c $<
qtmds.s:
${LN_S} ${srcdir}/${qtmds_s} qtmds.s
qtmdc.c:
${LN_S} ${srcdir}/${qtmdc_c} qtmdc.c
qtdmdb.s:
${LN_S} ${srcdir}/${qtdmdb_s} qtdmdb.s
EXTRA_DIST = CHANGES README.MISC README.PORT b.h meas.c stp.c stp.h \
Makefile.base config libqthreads.def

View file

@ -1,112 +0,0 @@
.SUFFIXES: .c .o .s .E
#
# Need to include from the current directory because "qt.h"
# will include <qtmd.h>.
#
CFLAGS = -I. -g
#
# Fix this to be something meaningful for your system.
#
DEST = /dev/null
DOC = users.tout
EXTHDRS = /usr/include/stdio.h
HDRS = qt.h \
qtmd.h \
stp.h
LDFLAGS = $(CFLAGS)
EXTLIBS =
LIBS = libstp.a libqt.a
LINKER = $(CC)
MAKEFILE = Makefile
M = Makefile configuration
OBJS = qtmdb.o \
meas.o
QTOBJS = qt.o qtmds.o qtmdc.o
STPOBJS = stp.o
PR = -Pps
PRINT = pr
PROGRAM = run
SRCS = meas.c \
qt.c \
qtmdc.c \
qtmds.s \
qtmdb.s
TMP_INIT = tmp.init
TMP_SWAP = tmp.swap
.DEFAULT:
co -q $@
.c.E: force
$(CC) $(CFLAGS) -E $*.c > $*.E
all: libqt.a libstp.a $(PROGRAM) $(M)
libqt.a: $(QTOBJS) $(M)
ar crv libqt.a $(QTOBJS)
ranlib libqt.a
libstp.a: $(STPOBJS) $(M)
ar crv libstp.a $(STPOBJS)
ranlib libstp.a
$(PROGRAM): $(OBJS) $(LIBS) $(M)
@echo "Loading $(PROGRAM) ... "
# ld -o $(PROGRAM) /lib/crt0.o $(OBJS) -lc
$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) $(EXTLIBS) -o $(PROGRAM)
@echo "done"
clean:
rm -f $(OBJS) $(PROGRAM) $(TMP_INIT) $(TMP_SWAP) $(DOC)
rm -f libqt.a libstp.a
rm -f $(QTOBJS) $(STPOBJS)
depend:; @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)
doc: users.ms raw
time/assim < raw | grep "^init" | sed 's/^init //' > $(TMP_INIT)
time/assim < raw | grep "^swap" | sed 's/^swap //' > $(TMP_SWAP)
soelim users.ms | tbl $(PR) | troff -t $(PR) -ms > $(DOC)
index:; @ctags -wx $(HDRS) $(SRCS)
print:; @$(PRINT) $(HDRS) $(SRCS)
program: $(PROGRAM)
tags: $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)
update: $(DEST)/$(PROGRAM)
$(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS)
@make -f $(MAKEFILE) DEST=$(DEST) install
QT_H = qt.h $(QTMD_H)
QTMD_H = qtmd.h
###
qtmdb.o: $(M) qtmdb.s b.h
meas.o: $(M) meas.c /usr/include/stdio.h $(QT_H) b.h stp.h
qt.o: $(M) qt.c $(QT_H)
stp.o: $(M) stp.c stp.h $(QT_H)
qtmds.o: $(M) qtmds.s
qtmdc.o: $(M) qtmdc.c $(QT_H)

View file

@ -1,89 +0,0 @@
This is a source code distribution for QuickThreads. QuickThreads is a
toolkit for building threads packages; it is described in detail in the
University of Washington CS&E Technical report #93-05-06, available via
anonymous ftp from `ftp.cs.washington.edu' (128.95.1.4, as of Oct. '94)
in `tr/1993/05/UW-CSE-93-05-06.PS.Z'.
This distribution shows basic ideas in QuickThreads and elaborates with
example implementations for a gaggle of machines. As of October those
machines included:
80386 faimly
88000 faimily
DEC AXP (Alpha) family
HP-PA family
KSR
MIPS family
SPARC V8 family
VAX family
Configuration, build, and installation are described in INSTALL.
Be aware: that there is no varargs code for the KSR.
The HP-PA port was designed to work with both HP workstations
and Convex SPP computers. It was generously provided by Uwe Reder
<uereder@cip.informatik.uni-erlangen.de>. It is part of the ELiTE
(Erlangen Lightweight Thread Environment) project directed by
Frank Bellosa <bellosa@informatik.uni-erlangen.de> at the Operating
Systems Department of the University of Erlangen (Germany).
Other contributors include: Weihaw Chuang, Richard O'Keefe,
Laurent Perron, John Polstra, Shinji Suzuki, Assar Westerlund,
thanks also to Peter Buhr and Dirk Grunwald.
Here is a brief summary:
QuickThreads is a toolkit for building threads packages. It is my hope
that you'll find it easier to use QuickThreads normally than to take it
and modify the raw cswap code to fit your application. The idea behind
QuickThreads is that it should make it easy for you to write & retarget
threads packages. If you want the routine `t_create' to create threads
and `t_block' to suspend threads, you write them using the QuickThreads
`primitive' operations `QT_SP', `QT_INIT', and `QT_BLOCK', that perform
machine-dependent initialization and blocking, plus code you supply for
performing the portable operatons. For example, you might write:
t_create (func, arg)
{
stk = malloc (STKSIZE);
stackbase = QT_SP (stk, STKSIZE);
sp = QT_INIT (stakcbase, func, arg);
qput (runq, sp);
}
Threads block by doing something like:
t_block()
{
sp_next = qget (runq);
QT_BLOCK (helper, runq, sp_next);
// wake up again here
}
// called by QT_BLOCK after the old thread has blocked,
// puts the old thread on the queue `onq'.
helper (sp_old, onq)
{
qput (onq, sp_old);
}
(Of course) it's actually a bit more complex than that, but the general
idea is that you write portable code to allocate stacks and enqueue and
dequeue threads. Than, to get your threads package up and running on a
different machine, you just reconfigure QuickThreads and recompile, and
that's it.
The QuickThreads `distribution' includes a sample threads package (look
at stp.{c,h}) that is written in terms of QuickThreads operations. The
TR mentioned above explains the simple threads package in detail.
If you do use QuickThreads, I'd like to hear both about what worked for
you and what didn't work, problems you had, insights gleaned, etc.
Let me know what you think.
David Keppel <pardo@cs.washington.edu>

View file

@ -1,56 +0,0 @@
Here's some machine-specific informatin for various systems:
m88k on g88.sim
.g88init:
echo (gdb) target sim\n
target sim
echo (gdb) ecatch all\n
ecatch all
echo (gdb) break exit\n
break exit
% vi Makefile // set CC and AS
% setenv MEERKAT /projects/cer/meerkat
% set path=($MEERKAT/bin $path)
% make run
% g88.sim run
(g88) run run N // where `N' is the test number
m88k on meerkats, cross compile as above (make run)
Run w/ g88:
%g88 run
(g88) source /homes/rivers/robertb/.gdbinit
(g88) me
which does
(g88) set $firstchars=6
(g88) set $resetonattach=1
(g88) attach /dev/pp0
then download
(g88) dl
and run with
(g88) continue
Really the way to run it is:
(g88) source
(g88) me
(g88) win
(g88) dead 1
(g88) dead 2
(g88) dead 3
(g88) dl
(g88) cont
To rerun
(g88) init
(g88) dl
To run simulated meerkat:
(g88) att sim
<<then use normal commands>>
On 4.5 g88:
(g88) target sim memsize
instead of attatch
(g88) ecatch all # catch exception before becomes error

View file

@ -1,112 +0,0 @@
Date: Tue, 11 Jan 94 13:23:11 -0800
From: "pardo@cs.washington.edu" <pardo@meitner.cs.washington.edu>
>[What's needed to get `qt' on an i860-based machine?]
Almost certainly "some assembly required" (pun accepted).
To write a cswap port, you need to understand the context switching
model. Turn to figure 2 in the QT TR. Here's about what the assembly
code looks like to implement that:
qt_cswap:
adjust stack pointer
save callee-save registers on to old's stack
argument register <- old sp
sp <- new sp
(*helper)(args...)
restore callee-save registers from new's stack
unadjust stack pointer
return
Once more in slow motion:
- `old' thread calls context switch routine (new, a0, a1, h)
- cswap routine saves registers that have useful values
- cswap routine switches to new stack
- cswap routine calls helper function (*h)(old, a0, a1)
- when helper returns, cswap routine restores registers
that were saved the last time `new' was suspended
- cswap routine returns to whatever `new' routine called the
context switch routine
There's a few tricks here. First, how do you start a thread running
for the very first time? Answer is: fake some stuff on the stack
so it *looks* like it was called from the middle of some routine.
When the new thread is restarted, it is treated like any other
thread. It just so happens that it's never really run before, but
you can't tell that because the saved state makes it look like like
it's been run. The return pc is set to point at a little stub of
assembly code that loads up registers with the right values and
then calls `only'.
Second, I advise you to forget about varargs routines (at least
until you get single-arg routines up and running).
Third, on most machines `qt_abort' is the same as `qt_cswap' except
that it need not save any callee-save registers.
Fourth, `qt_cswap' needs to save and restore any floating-point
registers that are callee-save (see your processor handbook). On
some machines, *no* floating-point registers are callee-save, so
`qt_cswap' is exactly the same as the integer-only cswap routine.
I suggest staring at the MIPS code for a few minutes. It's "mostly"
generic RISC code, so it gets a lot of the flavor across without
getting too bogged down in little nitty details.
Now for a bit more detail: The stack is laid out to hold callee-save
registers. On many machines, I implemented fp cswap as save fp
regs, call integer cswap, and when integer cswap returns (when the
thread wakes up again), restore fp regs.
For thread startup, I figure out some callee-save registers that
I use to hold parameters to the startup routine (`only'). When
the thread is being started it doesn't have any saved registers
that need to be restored, but I go ahead and let the integer context
switch routine restore some registers then "return" to the stub
code. The stub code then copies the "callee save" registers to
argument registers and calls the startup routine. That keeps the
stub code pretty darn simple.
For each machine I need to know the machine's procedure calling
convention before I write a port. I figure out how many callee-save
registers are there and allocate enough stack space for those
registers. I also figure out how parameters are passed, since I
will need to call the helper function. On most RISC machines, I
just need to put the old sp in the 0'th arg register and then call
indirect through the 3rd arg register; the 1st and 2nd arg registers
are already set up correctly. Likewise, I don't touch the return
value register between the helper's return and the context switch
routine's return.
I have a bunch of macros set up to do the stack initialization.
The easiest way to debug this stuff is to go ahead and write a C
routine to do stack initialization. Once you're happy with it you
can turn it in to a macro.
In general there's a lot of ugly macros, but most of them do simple
things like return constants, etc. Any time you're looking at it
and it looks confusing you just need to remember "this is actually
simple code, the only tricky thing is calling the helper between
the stack switch and the new thread's register restore."
You will almost certainly need to write the assembly code fragment
that starts a thread. You might be able to do a lot of the context
switch code with `setjmp' and `longjmp', if they *happen* to have
the "right" implementation. But getting all the details right (the
helper can return a value to the new thread's cswap routine caller)
is probaby trickier than writing code that does the minimum and
thus doesn't have any extra instructions (or generality) to cause
problems.
I don't know of any ports besides those included with the source
code distribution. If you send me a port I will hapily add it to
the distribution.
Let me know as you have questions and/or comments.
;-D on ( Now *that*'s a switch... ) Pardo

11
qt/b.h
View file

@ -1,11 +0,0 @@
#ifndef B_H
#define B_H "$Header: /home/ludo/src/guile.cvs/gitification/guile-cvs/guile/guile-core/qt/b.h,v 1.1 1996-10-01 03:27:25 mdj Exp $"
#include "copyright.h"
extern void b_call_reg (int n);
extern void b_call_imm (int n);
extern void b_add (int n);
extern void b_load (int n);
#endif /* ndef B_H */

308
qt/config
View file

@ -1,308 +0,0 @@
#! /bin/sh -x
rm -f Makefile Makefile.md README.md qtmd.h qtmdb.s qtmdc.c qtmds.s configuration
case $1 in
axp*)
: "DEC AXP"
case $1 in
axp-osf1*)
: "Compile using /bin/cc under OSF 1.x."
ln -s md/axp.1.Makefile Makefile.md
;;
axp-osf2*)
: "Compile using /bin/cc under OSF 2.x."
ln -s md/axp.1.Makefile Makefile.md
;;
*)
: "Compile using GNU CC."
ln -s md/axp.Makefile Makefile.md
;;
esac
ln -s md/axp.h qtmd.h
ln -s md/axp.c qtmdc.c
ln -s md/axp.s qtmds.s
ln -s md/axp_b.s qtmdb.s
ln -s md/axp.README README.md
iter_init=1000000000
iter_runone=10000000
iter_blockint=10000000
iter_blockfloat=10000000
iter_vainit0=10000000
iter_vainit2=10000000
iter_vainit4=10000000
iter_vainit8=10000000
iter_vastart0=10000000
iter_vastart2=10000000
iter_vastart4=10000000
iter_vastart8=10000000
iter_bench_call_reg=10000000
iter_bench_call_imm=10000000
iter_bench_add=100000000
iter_bench_load=100000000
;;
hppa*)
: "HP's PA-RISC 1.1 processors."
case $1 in
hppa-cnx-spp*)
: "Convex SPP (PA-RISC 1.1 processors)."
ln -s md/hppa-cnx.Makefile Makefile.md
;;
*)
ln -s md/hppa.Makefile Makefile.md
;;
esac
ln -s md/hppa.h qtmd.h
ln -s md/null.c qtmdc.c
ln -s md/hppa.s qtmds.s
ln -s md/hppa_b.s qtmdb.s
iter_init=10000000
iter_runone=1000000
iter_blockint=1000000
iter_blockfloat=1000000
iter_vainit0=1000000
iter_vainit2=1000000
iter_vainit4=1000000
iter_vainit8=1000000
iter_vastart0=1000000
iter_vastart2=1000000
iter_vastart4=1000000
iter_vastart8=1000000
iter_bench_call_reg=10000000
iter_bench_call_imm=10000000
iter_bench_add=100000000
iter_bench_load=100000000
;;
iX86*)
case $1 in
iX86-ss*)
: "Assemlber comments '//'"
sed 's/\/\*/\/\//' < md/i386.s > qtmds.s
sed 's/\/\*/\/\//' < md/i386_b.s > qtmdb.s
;;
*)
ln -s md/i386.s qtmds.s
ln -s md/i386_b.s qtmdb.s
;;
esac
: "Intel 80386 and compatibles (not '286...)"
ln -s md/default.Makefile Makefile.md
ln -s md/i386.h qtmd.h
ln -s md/null.c qtmdc.c
ln -s md/i386.README README.md
iter_init=10000000
iter_runone=1000000
iter_blockint=1000000
iter_blockfloat=1000000
iter_vainit0=1000000
iter_vainit2=1000000
iter_vainit4=1000000
iter_vainit8=1000000
iter_vastart0=1000000
iter_vastart2=1000000
iter_vastart4=1000000
iter_vastart8=1000000
iter_bench_call_reg=1000000
iter_bench_call_imm=1000000
iter_bench_add=100000000
iter_bench_load=10000000
;;
m68k)
: "Motorola 68000 family -- incomplete!"
ln -s md/default.Makefile Makefile.md
ln -s md/m68k.h qtmd.h
ln -s md/null.c qtmdc.c
ln -s md/m68k.s qtmds.s
ln -s md/m68k_b.s qtmdb.s
ln -s md/null.README README.md
;;
m88k)
: "Motorola 88000 family"
ln -s md/m88k.Makefile Makefile.md
ln -s md/m88k.h qtmd.h
ln -s md/m88k.c qtmdc.c
ln -s md/m88k.s qtmds.s
ln -s md/m88k_b.s qtmdb.s
ln -s md/null.README README.md
iter_init=1000000
iter_runone=100000
iter_blockint=100000
iter_blockfloat=100000
iter_vainit0=100000
iter_vainit2=100000
iter_vainit4=100000
iter_vainit8=100000
iter_vastart0=100000
iter_vastart2=100000
iter_vastart4=100000
iter_vastart8=100000
iter_bench_call_reg=100000000
iter_bench_call_imm=100000000
iter_bench_add=1000000000
iter_bench_load=100000000
;;
mips*)
: "MIPS R2000 and R3000."
case $1 in
mips-irix[56]*)
: "Silicon Graphics Irix with dynamic linking"
: "Use mips for irix4."
ln -s md/mips-irix5.s qtmds.s
;;
*)
ln -s md/mips.s qtmds.s
;;
esac
ln -s md/default.Makefile Makefile.md
ln -s md/mips.h qtmd.h
ln -s md/null.c qtmdc.c
ln -s md/mips_b.s qtmdb.s
ln -s md/null.README README.md
iter_init=10000000
iter_runone=10000000
iter_blockint=10000000
iter_blockfloat=10000000
iter_vainit0=1000000
iter_vainit2=1000000
iter_vainit4=1000000
iter_vainit8=1000000
iter_vastart0=1000000
iter_vastart2=1000000
iter_vastart4=1000000
iter_vastart8=1000000
iter_bench_call_reg=100000000
iter_bench_call_imm=100000000
iter_bench_add=1000000000
iter_bench_load=100000000
;;
sparc*)
: "SPARC processors"
case $1 in
sparc-os2*)
sed 's/_qt_/qt_/' md/sparc.s > qtmds.s
sed 's/_b_/b_/' md/sparc_b.s > qtmdb.s
ln -s md/solaris.README README.md
;;
*)
ln -s md/sparc.s qtmds.s
ln -s md/sparc_b.s qtmdb.s
ln -s md/null.README README.md
;;
esac
ln -s md/default.Makefile Makefile.md
ln -s md/sparc.h qtmd.h
ln -s md/null.c qtmdc.c
iter_init=10000000
iter_runone=1000000
iter_blockint=1000000
iter_blockfloat=1000000
iter_vainit0=1000000
iter_vainit2=1000000
iter_vainit4=1000000
iter_vainit8=1000000
iter_vastart0=1000000
iter_vastart2=1000000
iter_vastart4=1000000
iter_vastart8=1000000
iter_bench_call_reg=10000000
iter_bench_call_imm=10000000
iter_bench_add=100000000
iter_bench_load=100000000
;;
vax*)
: "DEC VAX processors."
ln -s md/default.Makefile Makefile.md
ln -s md/vax.h qtmd.h
ln -s md/null.c qtmdc.c
ln -s md/vax.s qtmds.s
ln -s md/vax_b.s qtmdb.s
ln -s md/null.README README.md
iter_init=1000000
iter_runone=100000
iter_blockint=100000
iter_blockfloat=100000
iter_vainit0=100000
iter_vainit2=100000
iter_vainit4=100000
iter_vainit8=100000
iter_vastart0=100000
iter_vastart2=100000
iter_vastart4=100000
iter_vastart8=100000
iter_bench_call_reg=10000000
iter_bench_call_imm=10000000
iter_bench_add=10000000
iter_bench_load=1000000
;;
ksr1)
: "Kendall Square Research model KSR-1."
: "Varargs is not currently supported."
ln -s md/ksr1.Makefile Makefile.md
ln -s md/ksr1.h qtmd.h
ln -s md/null.c qtmdc.c
ln -s md/ksr1.s qtmds.s
ln -s md/ksr1_b.s qtmdb.s
ln -s md/null.README README.md
iter_init=1000000
iter_runone=100000
iter_blockint=100000
iter_blockfloat=100000
iter_vainit0=100000
iter_vainit2=100000
iter_vainit4=100000
iter_vainit8=100000
iter_vastart0=100000
iter_vastart2=100000
iter_vastart4=100000
iter_vastart8=100000
iter_bench_call_reg=10000000
iter_bench_call_imm=10000000
iter_bench_add=10000000
iter_bench_load=1000000
;;
clean)
: Deconfigure
exit 0
;;
*)
echo "Unknown configuration"
exit 1
;;
esac
cat Makefile.md Makefile.base > Makefile
echo set config_machine=$1 >> configuration
echo set config_init=$iter_init >> configuration
echo set config_runone=$iter_runone >> configuration
echo set config_blockint=$iter_blockint >> configuration
echo set config_blockfloat=$iter_blockfloat >> configuration
echo set config_vainit0=$iter_vainit0 >> configuration
echo set config_vainit2=$iter_vainit2 >> configuration
echo set config_vainit4=$iter_vainit4 >> configuration
echo set config_vainit8=$iter_vainit8 >> configuration
echo set config_vastart0=$iter_vastart0 >> configuration
echo set config_vastart2=$iter_vastart2 >> configuration
echo set config_vastart4=$iter_vastart4 >> configuration
echo set config_vastart8=$iter_vastart8 >> configuration
echo set config_bcall_reg=$iter_bench_call_reg >> configuration
echo set config_bcall_imm=$iter_bench_call_imm >> configuration
echo set config_b_add=$iter_bench_add >> configuration
echo set config_b_load=$iter_bench_load >> configuration

View file

@ -1,12 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/

View file

@ -1,10 +0,0 @@
LIBRARY libqthreads
DESCRIPTION "libqthreads: QuickThreads Library"
EXPORTS
qt_abort
qt_block
qt_blocki
qt_error
qt_null
qt_vargs
qt_vstart

View file

@ -1,30 +0,0 @@
## Process this file with automake to produce Makefile.in.
##
## Copyright (C) 1998, 2002, 2006 Free Software Foundation, Inc.
##
## This file is part of GUILE.
##
## GUILE is free software; you can redistribute it and/or modify it
## under the terms of the GNU Lesser General Public License as
## published by the Free Software Foundation; either version 3, or
## (at your option) any later version.
##
## GUILE is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public
## License along with GUILE; see the file COPYING.LESSER. If not,
## write to the Free Software Foundation, Inc., 51 Franklin Street,
## Fifth Floor, Boston, MA 02110-1301 USA
AUTOMAKE_OPTIONS = gnu
EXTRA_DIST = _sparc.s _sparc_b.s axp.1.Makefile axp.2.Makefile \
axp.Makefile axp.README axp.c axp.h axp.s axp_b.s default.Makefile \
hppa-cnx.Makefile hppa.Makefile hppa.h hppa.s hppa_b.s i386.README \
i386.h i386.s i386_b.s ksr1.Makefile ksr1.h ksr1.s ksr1_b.s \
m88k.Makefile m88k.c m88k.h m88k.s m88k_b.s mips-irix5.s mips.h mips.s \
mips_b.s null.README null.c solaris.README sparc.h sparc.s sparc_b.s \
vax.h vax.s vax_b.s i386.asm arm.h arm.s

View file

@ -1,142 +0,0 @@
/* sparc.s -- assembly support for the `qt' thread building kit. */
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
/* #include <machine/trap.h> */
.text
.align 4
.global _qt_blocki
.global _qt_block
.global _qt_abort
.global _qt_start
.global _qt_vstart
/* Register assignment:
// %o0: incoming `helper' function to call after cswap
// also used as outgoing sp of old thread (qt_t *)
// %o1, %o2:
// parameters to `helper' function called after cswap
// %o3: sp of new thread
// %o5: tmp used to save old thread sp, while using %o0
// to call `helper' f() after cswap.
//
//
// Aborting a thread is easy if there are no cached register window
// frames: just switch to the new stack and away we go. If there are
// cached register window frames they must all be written back to the
// old stack before we move to the new stack. If we fail to do the
// writeback then the old stack memory can be written with register
// window contents e.g., after the stack memory has been freed and
// reused.
//
// If you don't believe this, try setting the frame pointer to zero
// once we're on the new stack. This will not affect correctnes
// otherwise because the frame pointer will eventually get reloaded w/
// the new thread's frame pointer. But it will be zero briefly before
// the reload. You will eventually (100,000 cswaps later on a small
// SPARC machine that I tried) get an illegal instruction trap from
// the kernel trying to flush a cached window to location 0x0.
//
// Solution: flush windows before switching stacks, which invalidates
// all the other register windows. We could do the trap
// conditionally: if we're in the lowest frame of a thread, the fp is
// zero already so we know there's nothing cached. But we expect most
// aborts will be done from a first function that does a `save', so we
// will rarely save anything and always pay the cost of testing to see
// if we should flush.
//
// All floating-point registers are caller-save, so this routine
// doesn't need to do anything to save and restore them.
//
// `qt_block' and `qt_blocki' return the same value as the value
// returned by the helper function. We get this ``for free''
// since we don't touch the return value register between the
// return from the helper function and return from qt_block{,i}.
*/
_qt_block:
_qt_blocki:
sub %sp, 8, %sp /* Allocate save area for return pc. */
st %o7, [%sp+64] /* Save return pc. */
_qt_abort:
ta 0x03 /* Save locals and ins. */
mov %sp, %o5 /* Remember old sp w/o chng ins/locals. */
sub %o3, 64, %sp /* Allocate kwsa, switch stacks. */
call %o0, 0 /* Call `helper' routine. */
mov %o5, %o0 /* Pass old thread to qt_after_t() */
/* .. along w/ args in %o1 & %o2. */
/* Restore callee-save regs. The kwsa
// is on this stack, so offset all
// loads by sizeof(kwsa), 64 bytes.
*/
ldd [%sp+ 0+64], %l0
ldd [%sp+ 8+64], %l2
ldd [%sp+16+64], %l4
ldd [%sp+24+64], %l6
ldd [%sp+32+64], %i0
ldd [%sp+40+64], %i2
ldd [%sp+48+64], %i4
ldd [%sp+56+64], %i6
ld [%sp+64+64], %o7 /* Restore return pc. */
retl /* Return to address in %o7. */
add %sp, 72, %sp /* Deallocate kwsa, ret pc area. */
/* The function calling conventions say there has to be a 1-word area
// in the caller's stack to hold a pointer to space for aggregate
// return values. It also says there should be a 6-word area to hold
// %o0..%o5 if the callee wants to save them (why? I don't know...)
// Round up to 8 words to maintain alignment.
//
// Parameter values were stored in callee-save regs and are moved to
// the parameter registers.
*/
_qt_start:
mov %i1, %o0 /* `pu': Set up args to `only'. */
mov %i2, %o1 /* `pt'. */
mov %i4, %o2 /* `userf'. */
call %i5, 0 /* Call client function. */
sub %sp, 32, %sp /* Allocate 6-word callee space. */
call _qt_error, 0 /* `only' erroniously returned. */
nop
/* Same comments as `_qt_start' about allocating rounded-up 7-word
// save areas. */
_qt_vstart:
sub %sp, 32, %sp /* Allocate 7-word callee space. */
call %i5, 0 /* call `startup'. */
mov %i2, %o0 /* .. with argument `pt'. */
add %sp, 32, %sp /* Use 7-word space in varargs. */
ld [%sp+ 4+64], %o0 /* Load arg0 ... */
ld [%sp+ 8+64], %o1
ld [%sp+12+64], %o2
ld [%sp+16+64], %o3
ld [%sp+20+64], %o4
call %i4, 0 /* Call `userf'. */
ld [%sp+24+64], %o5
/* Use 6-word space in varargs. */
mov %o0, %o1 /* Pass return value from userf */
call %i3, 0 /* .. when call `cleanup. */
mov %i2, %o0 /* .. along with argument `pt'. */
call _qt_error, 0 /* `cleanup' erroniously returned. */
nop

View file

@ -1,106 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
.globl _b_call_reg
.globl _b_call_imm
.globl _b_add
.globl _b_load
_b_null:
retl
nop
_b_call_reg:
sethi %hi(_b_null),%o4
or %o4,%lo(_b_null),%o4
add %o7,%g0, %o3
L0:
call %o4
nop
call %o4
nop
call %o4
nop
call %o4
nop
call %o4
nop
subcc %o0,1,%o0
bg L0
nop
add %o3,%g0, %o7
retl
nop
_b_call_imm:
sethi %hi(_b_null),%o4
or %o4,%lo(_b_null),%o4
add %o7,%g0, %o3
L1:
call _b_null
call _b_null
call _b_null
call _b_null
call _b_null
subcc %o0,1,%o0
bg L0
nop
add %o3,%g0, %o7
retl
nop
_b_add:
add %o0,%g0,%o1
add %o0,%g0,%o2
add %o0,%g0,%o3
add %o0,%g0,%o4
L2:
sub %o0,5,%o0
sub %o1,5,%o1
sub %o2,5,%o2
sub %o3,5,%o3
sub %o4,5,%o4
subcc %o0,5,%o0
sub %o1,5,%o1
sub %o2,5,%o2
sub %o3,5,%o3
sub %o4,5,%o4
bg L2
nop
retl
nop
_b_load:
ld [%sp+ 0], %g0
L3:
ld [%sp+ 4],%g0
ld [%sp+ 8],%g0
ld [%sp+12],%g0
ld [%sp+16],%g0
ld [%sp+20],%g0
ld [%sp+24],%g0
ld [%sp+28],%g0
ld [%sp+32],%g0
ld [%sp+36],%g0
subcc %o0,10,%o0
bg L3
ld [%sp+ 0],%g0
retl
nop

View file

@ -1,96 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
* Copyright (c) 2002 by Marius Vollmer
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
#ifndef QT_ARM_H
#define QT_ARM_H
typedef unsigned long qt_word_t;
#define QT_GROW_DOWN
/* Stack layout on the ARM:
Callee-save registers are: r4-r11 (f4-f7)
Also save r14, link register, and restore as pc.
+---
| lr/pc
| r11
| r10
| r9
| r8
| r7
| r6
| r5
| r4 <- sp of a suspended thread
+---
Startup:
+---
| only
| user
| argt
| argu <- sp on entry to qt_start
+---
| pc == qt_start
| r11
| r10
| r9
| r8
| r7
| r6
| r5
| r4
+---
*/
/* Stack must be word aligned. */
#define QT_STKALIGN (4) /* Doubleword aligned. */
/* How much space is allocated to hold all the crud for
initialization: r4-r11, r14, and the four args for qt_start. */
#define QT_STKBASE ((9+4)*4)
/* Offsets of various registers, in words, relative to final value of SP. */
#define QT_LR 8
#define QT_11 7
#define QT_10 6
#define QT_9 5
#define QT_8 4
#define QT_7 3
#define QT_6 2
#define QT_5 1
#define QT_4 0
/* When a never-before-run thread is restored, the return pc points
to a fragment of code that starts the thread running. For
non-vargs functions, it just calls the client's `only' function.
*/
extern void qt_start(void);
#define QT_ARGS_MD(sp) (QT_SPUT (sp, QT_LR, qt_start))
/* The *index* (positive offset) of where to put each value. */
#define QT_ONLY_INDEX (12)
#define QT_USER_INDEX (11)
#define QT_ARGT_INDEX (10)
#define QT_ARGU_INDEX (9)
#endif /* ndef QT_ARM_H */

View file

@ -1,34 +0,0 @@
.text
.align 2
.global qt_abort
.global qt_block
.global qt_blocki
# r0: helper
# r1: arg1
# r2: arg2
# r3: new_sp
qt_abort:
qt_block:
qt_blocki:
stmfd sp!, {r4-r11,lr}
mov ip, r0
mov r0, sp
mov sp, r3
mov lr, pc
mov pc, ip
ldmfd sp!, {r4-r11,pc}
.global qt_start
.global qt_error
.type qt_start,function
qt_start:
ldr r0, [sp]
ldr r1, [sp, #4]
ldr r2, [sp, #8]
ldr lr, qt_error_loc
ldr pc, [sp, #12]
qt_error_loc:
.word qt_error

View file

@ -1,5 +0,0 @@
#
# Compiling for the DEC AXP (alpha) with GNU CC or version 1.x of OSF.
#
CC = cc -std1 -D__AXP__ -D__OSF1__

View file

@ -1,5 +0,0 @@
#
# Compiling for the DEC AXP (alpha) with GNU CC or version 2.x of OSF.
#
CC = cc -std1 -D__AXP__ -D__OSF2__

View file

@ -1,5 +0,0 @@
#
# GNU CC
#
CC = gcc -D__AXP__

View file

@ -1,10 +0,0 @@
The handling of varargs is platform-dependent. Assar Westerlund
stared at the problem for a while and deduces the following table:
vers / compiler cc gcc
----------------------------------------------------------------------
1.3 a0, offset __base, __offset
2.0 _a0, _offset __base, __offset
The current code should handle both cc and gcc versions, provided
you configure for the correct compiler.

View file

@ -1,133 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
#include <stdarg.h>
#include "qt.h"
/* Varargs is harder on the AXP. Parameters are saved on the stack as
something like (stack grows down to low memory; low at bottom of
picture):
| :
| arg6
+---
| iarg5
| :
| iarg3 <-- va_list._a0 + va_list._offset
| :
| iarg0 <-- va_list._a0
+---
| farg5
| :
| farg0
+---
When some of the arguments have known type, there is no need to
save all of them in the struct. So, for example, if the routine is
called
zork (int a0, float a1, int a2, ...)
{
va_list ap;
va_start (ap, a2);
qt_vargs (... &ap ...);
}
then offset is set to 3 * 8 (8 === sizeof machine word) = 24.
What this means for us is that the user's routine needs to be
called with an arg list where some of the words in the `any type'
parameter list have to be split and moved up in to the int/fp
region.
Ways in which this can fail:
- The user might not know the size of the pushed arguments anyway.
- Structures have funny promotion rules.
- Probably lots of other things.
All in all, we never promised varargs would work reliably. */
#define QT_VADJ(sp) (((char *)sp) - QT_VSTKBASE)
#define QT_VARGS_MD0(sp, vabytes) \
((qt_t *)(((char *)(sp)) - 6*2*8 - QT_STKROUNDUP(vabytes)))
extern void qt_vstart(void);
#define QT_VARGS_MD1(sp) (QT_SPUT (sp, QT_R26, qt_vstart))
/* Different machines use different implementations for varargs.
Unfortunately, the code below ``looks in to'' the varargs
structure, `va_list', and thus depends on the conventions.
The following #defines try to deal with it but don't catch
everything. */
#ifdef __GNUC__
#define _a0 __base
#define _offset __offset
#else
#ifdef __OSF1__
#define _a0 a0
#define _offset offset
#endif
#endif /* def __GNUC__ */
struct qt_t *
qt_vargs (struct qt_t *qsp, int nbytes, struct va_list *vargs,
void *pt, qt_function_t *startup,
qt_function_t *vuserf, qt_function_t *cleanup)
{
va_list ap;
int i;
int max; /* Maximum *words* of args to copy. */
int tmove; /* *Words* of args moved typed->typed. */
qt_word_t *sp;
ap = *(va_list *)vargs;
qsp = QT_VARGS_MD0 (qsp, nbytes);
sp = (qt_word_t *)qsp;
tmove = 6 - ap._offset/sizeof(qt_word_t);
/* Copy from one typed area to the other. */
for (i=0; i<tmove; ++i) {
/* Integer args: */
sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i];
/* Fp args: */
sp[i] = ((qt_word_t *)(ap._a0 + ap._offset))[i-6];
}
max = nbytes/sizeof(qt_word_t);
/* Copy from the untyped area to the typed area. Split each arg.
in to integer and floating-point save areas. */
for (; i<6 && i<max; ++i) {
sp[i] = sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i];
}
/* Copy from the untyped area to the other untyped area. */
for (; i<max; ++i) {
sp[i+6] = ((qt_word_t *)(ap._a0 + ap._offset))[i];
}
QT_VARGS_MD1 (QT_VADJ(sp));
QT_SPUT (QT_VADJ(sp), QT_VARGT_INDEX, pt);
QT_SPUT (QT_VADJ(sp), QT_VSTARTUP_INDEX, startup);
QT_SPUT (QT_VADJ(sp), QT_VUSERF_INDEX, vuserf);
QT_SPUT (QT_VADJ(sp), QT_VCLEANUP_INDEX, cleanup);
return ((qt_t *)QT_VADJ(sp));
}

View file

@ -1,160 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
#ifndef QT_AXP_H
#define QT_AXP_H
#define QT_GROW_DOWN
typedef unsigned long qt_word_t;
/* Stack layout on the Alpha:
Integer:
Caller-save: r0..r8, r22..r25, r27..r29
argument/caller-save: r16..r21
callee-save: r9..r15
return pc *callee-save*: r26
stack pointer: r30
zero: r31
Floating-point:
Caller-save: f0..f1, f10..f15
argument/caller-save: f16..f21, f22..f30
callee-save: f2..f9
zero: f31
Non-varargs:
+---
| padding
| f9
| f8
| f7
| f6
| f5
| f4
| f3
| f2
| r26
+---
| padding
| r29
| r15
| r14
| r13
| r12 on startup === `only'
| r11 on startup === `userf'
| r10 on startup === `qt'
| r9 on startup === `qu'
| r26 on startup === qt_start <--- qt.sp
+---
Conventions for varargs startup:
| :
| arg6
| iarg5
| :
| iarg0
| farg5
| :
| farg0
+---
| padding
| r29
| r15
| r14
| r13
| r12 on startup === `startup'
| r11 on startup === `vuserf'
| r10 on startup === `cleanup'
| r9 on startup === `qt'
| r26 on startup === qt_vstart <--- qt.sp
+---
Note: this is a pretty cheap/sleazy way to get things going,
but ``there must be a better way.'' For instance, some varargs
parameters could be loaded in to integer registers, or the return
address could be stored on top of the stack. */
/* Stack must be 16-byte aligned. */
#define QT_STKALIGN (16)
/* How much space is allocated to hold all the crud for
initialization: 7 registers times 8 bytes/register. */
#define QT_STKBASE (10 * 8)
#define QT_VSTKBASE QT_STKBASE
/* Offsets of various registers. */
#define QT_R26 0
#define QT_R9 1
#define QT_R10 2
#define QT_R11 3
#define QT_R12 4
/* When a never-before-run thread is restored, the return pc points
to a fragment of code that starts the thread running. For
non-vargs functions, it just calls the client's `only' function.
For varargs functions, it calls the startup, user, and cleanup
functions.
The varargs startup routine always reads 12 8-byte arguments from
the stack. If fewer argumets were pushed, the startup routine
would read off the top of the stack. To prevent errors we always
allocate enough space. When there are fewer args, the preallocated
words are simply wasted. */
extern void qt_start(void);
#define QT_ARGS_MD(sp) (QT_SPUT (sp, QT_R26, qt_start))
/* The AXP uses a struct for `va_list', so pass a pointer to the
struct. This may break some uses of `QT_VARGS', but then we never
claimed it was totally portable. */
typedef void (qt_function_t)(void);
struct qt_t;
struct va_list;
extern struct qt_t *qt_vargs (struct qt_t *sp, int nbytes,
struct va_list *vargs, void *pt,
qt_function_t *startup,
qt_function_t *vuserf,
qt_function_t *cleanup);
#define QT_VARGS(sp, nbytes, vargs, pt, startup, vuserf, cleanup) \
(qt_vargs (sp, nbytes, (struct va_list *)(&(vargs)), pt, \
(qt_function_t *) startup, (qt_function_t *)vuserf, \
(qt_function_t *)cleanup));
/* The *index* (positive offset) of where to put each value. */
#define QT_ONLY_INDEX (QT_R12)
#define QT_USER_INDEX (QT_R11)
#define QT_ARGT_INDEX (QT_R10)
#define QT_ARGU_INDEX (QT_R9)
#define QT_VCLEANUP_INDEX (QT_R10)
#define QT_VUSERF_INDEX (QT_R11)
#define QT_VSTARTUP_INDEX (QT_R12)
#define QT_VARGT_INDEX (QT_R9)
#endif /* ndef QT_AXP_H */

View file

@ -1,160 +0,0 @@
#
# QuickThreads -- Threads-building toolkit.
# Copyright (c) 1993 by David Keppel
#
# Permission to use, copy, modify and distribute this software and
# its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice and this notice
# appear in all copies. This software is provided as a
# proof-of-concept and for demonstration purposes# there is no
# representation about the suitability of this software for any
# purpose.
#
# axp.s -- assembly support.
.text
.align 4
.file "axp.s"
.globl qt_block
.globl qt_blocki
.globl qt_abort
.globl qt_start
.globl qt_vstart
#
# $16: ptr to function to call once curr is suspended
# and control is on r19's stack.
# $17: 1'th arg to (*$16)(...).
# $18: 2'th arg to (*$16)(...).
# $19: sp of thread to resume.
#
# The helper routine returns a value that is passed on as the
# return value from the blocking routine. Since we don't
# touch r0 between the helper's return and the end of
# function, we get this behavior for free.
#
.ent qt_blocki
qt_blocki:
subq $30,80, $30 # Allocate save area.
stq $26, 0($30) # Save registers.
stq $9, 8($30)
stq $10,16($30)
stq $11,24($30)
stq $12,32($30)
stq $13,40($30)
stq $14,48($30)
stq $15,56($30)
stq $29,64($30)
.end qt_blocki
.ent qt_abort
qt_abort:
addq $16,$31, $27 # Put argument function in PV.
addq $30,$31, $16 # Save stack ptr in outgoing arg.
addq $19,$31, $30 # Set new stack pointer.
jsr $26,($27),0 # Call helper function.
ldq $26, 0($30) # Restore registers.
ldq $9, 8($30)
ldq $10,16($30)
ldq $11,24($30)
ldq $12,32($30)
ldq $13,40($30)
ldq $14,48($30)
ldq $15,56($30)
ldq $29,64($30)
addq $30,80, $30 # Deallocate save area.
ret $31,($26),1 # Return, predict===RET.
.end qt_abort
#
# Non-varargs thread startup.
#
.ent qt_start
qt_start:
addq $9,$31, $16 # Load up `qu'.
addq $10,$31, $17 # ... user function's `pt'.
addq $11,$31, $18 # ... user function's `userf'.
addq $12,$31, $27 # ... set procedure value to `only'.
jsr $26,($27),0 # Call `only'.
jsr $26,qt_error # `only' erroniously returned.
.end qt_start
.ent qt_vstart
qt_vstart:
# Call startup function.
addq $9,$31, $16 # Arg0 to `startup'.
addq $12,$31, $27 # Set procedure value.
jsr $26,($27),0 # Call `startup'.
# Call user function.
ldt $f16, 0($30) # Load fp arg regs.
ldt $f17, 8($30)
ldt $f18,16($30)
ldt $f19,24($30)
ldt $f20,32($30)
ldt $f21,40($30)
ldq $16,48($30) # And integer arg regs.
ldq $17,56($30)
ldq $18,64($30)
ldq $19,72($30)
ldq $20,80($30)
ldq $21,88($30)
addq $30,96, $30 # Pop 6*2*8 saved arg regs.
addq $11,$31, $27 # Set procedure value.
jsr $26,($27),0 # Call `vuserf'.
# Call cleanup.
addq $9,$31, $16 # Arg0 to `cleanup'.
addq $0,$31, $17 # Users's return value is arg1.
addq $10,$31, $27 # Set procedure value.
jsr $26,($27),0 # Call `cleanup'.
jsr $26,qt_error # Cleanup erroniously returned.
.end qt_vstart
#
# Save calle-save floating-point regs $f2..$f9.
# Also save return pc from whomever called us.
#
# Return value from `qt_block' is the same as the return from
# `qt_blocki'. We get that for free since we don't touch $0
# between the return from `qt_blocki' and the return from
# `qt_block'.
#
.ent qt_block
qt_block:
subq $30,80, $30 # Allocate a save space.
stq $26, 0($30) # Save registers.
stt $f2, 8($30)
stt $f3,16($30)
stt $f4,24($30)
stt $f5,32($30)
stt $f6,40($30)
stt $f7,48($30)
stt $f8,56($30)
stt $f9,64($30)
jsr $26,qt_blocki # Call helper.
# .. who will also restore $gp.
ldq $26, 0($30) # restore registers.
ldt $f2, 8($30)
ldt $f3,16($30)
ldt $f4,24($30)
ldt $f5,32($30)
ldt $f6,40($30)
ldt $f7,48($30)
ldt $f8,56($30)
ldt $f9,64($30)
addq $30,80, $30 # Deallcate save space.
ret $31,($26),1 # Return, predict===RET.
.end qt_block

View file

@ -1,111 +0,0 @@
#
# QuickThreads -- Threads-building toolkit.
# Copyright (c) 1993 by David Keppel
#
# Permission to use, copy, modify and distribute this software and
# its documentation for any purpose and without fee is hereby
# granted, provided that the above copyright notice and this notice
# appear in all copies. This software is provided as a
# proof-of-concept and for demonstration purposes; there is no
# representation about the suitability of this software for any
# purpose.
#
.text
.globl b_call_reg
.globl b_call_imm
.globl b_add
.globl b_load
.ent b_null
b_null:
ret $31,($18),1
.end b_null
.ent b_call_reg
b_call_reg:
lda $27,b_null
$L0:
jsr $18,($27)
jsr $18,($27)
jsr $18,($27)
jsr $18,($27)
jsr $18,($27)
jsr $18,($27)
jsr $18,($27)
jsr $18,($27)
jsr $18,($27)
jsr $18,($27)
subq $16,1,$16
bgt $16,$L0
ret $31,($26),1
.end
.ent b_call_imm
b_call_imm:
$L1:
jsr $18,b_null
jsr $18,b_null
jsr $18,b_null
jsr $18,b_null
jsr $18,b_null
jsr $18,b_null
jsr $18,b_null
jsr $18,b_null
jsr $18,b_null
jsr $18,b_null
subq $16,1,$16
bgt $16,$L1
ret $31,($26),1
.end
.ent b_add
b_add:
$L2:
addq $31,$31,$31
addq $31,$31,$31
addq $31,$31,$31
addq $31,$31,$31
addq $31,$31,$31
addq $31,$31,$31
addq $31,$31,$31
addq $31,$31,$31
addq $31,$31,$31
addq $31,$31,$31
subq $16,1,$16
bgt $16,$L2
ret $31,($26),1
.end
.ent b_load
b_load:
$L3:
ldq $31,0($30)
ldq $31,8($30)
ldq $31,16($30)
ldq $31,24($30)
ldq $31,32($30)
ldq $31,0($30)
ldq $31,8($30)
ldq $31,16($30)
ldq $31,24($30)
ldq $31,32($30)
subq $16,1,$16
bgt $16,$L3
ret $31,($26),1
.end

View file

@ -1,6 +0,0 @@
#
# `Normal' configuration.
#
CC = gcc -ansi -Wall -pedantic

View file

@ -1,9 +0,0 @@
# This file (cnx_spp.Makefile) is part of the port of QuickThreads for
# PA-RISC 1.1 architecture on a Convex SPP. This file is a machine dependent
# makefile for QuickThreads. It was written in 1994 by Uwe Reder
# (`uereder@cip.informatik.uni-erlangen.de') for the Operating Systems
# Department (IMMD4) at the University of Erlangen/Nuernberg Germany.
# `Normal' configuration.
CC = /usr/convex/bin/cc

View file

@ -1,9 +0,0 @@
# This file (pa-risc.Makefile) is part of the port of QuickThreads for
# PA-RISC 1.1 architecture. This file is a machine dependent makefile
# for QuickThreads. It was written in 1994 by Uwe Reder
# (`uereder@cip.informatik.uni-erlangen.de') for the Operating Systems
# Department (IMMD4) at the University of Erlangen/Nuernberg Germany.
# `Normal' configuration.
CC = cc -Aa

View file

@ -1,194 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
/*
* This file (pa-risc.h) is part of the port of QuickThreads for the
* PA-RISC 1.1 architecture. This file is a machine dependent header
* file. It was written in 1994 by Uwe Reder
* (`uereder@cip.informatik.uni-erlangen.de') for the Operating Systems
* Department (IMMD4) at the University of Erlangen/Nuernberg Germany.
*/
#ifndef QT_PA_RISC_H
#define QT_PA_RISC_H
#include <qt.h>
/* size of an integer-register (32 bit) */
typedef unsigned long qt_word_t;
/* PA-RISC's stack grows up */
#define QT_GROW_UP
/* Stack layout on PA-RISC according to PA-RISC Procedure Calling Conventions:
Callee-save registers are: gr3-gr18, fr12-fr21.
Also save gr2, return pointer.
+---
| fr12 Each floating register is a double word (8 bytes).
| fr13 Floating registers are only saved if `qt_block' is
| fr14 called, in which case it saves the floating-point
| fr15 registers then calls `qt_blocki' to save the integer
| fr16 registers.
| fr17
| fr18
| fr19
| fr20
| fr21
| <arg word 3> fixed arguments (must be allocated; may remain unused)
| <arg word 2>
| <arg word 1>
| <arg word 0>
| <LPT> frame marker
| <LPT'>
| <RP'>
| <Current RP>
| <Static Link>
| <Clean Up>
| <RP''>
| <Previous SP>
+---
| gr3 word each (4 bytes)
| gr4
| gr5
| gr6
| gr7
| gr8
| gr9
| gr10
| gr11
| gr12
| gr13
| gr14
| gr15
| gr16
| gr17
| gr18
| <16 bytes filled in (sp has to be 64-bytes aligned)>
| <arg word 3> fixed arguments (must be allocated; may remain unused)
| <arg word 2>
| <arg word 1>
| <arg word 0>
| <LPT> frame marker
| <LPT'>
| <RP'>
| <Current RP>
| <Static Link>
| <Clean Up>
| <RP''>
| <Previous SP>
+--- <--- sp
*/
/* When a never-before-run thread is restored, the return pc points
to a fragment of code that starts the thread running. For
non-vargs functions, it just calls the client's `only' function.
For varargs functions, it calls the startup, user, and cleanup
functions. */
/* Note: Procedue Labels on PA-RISC
<--2--><-------28---------><1-><1->
-----------------------------------
| SID | Adress Part | L | X |
-----------------------------------
On HP-UX the L field is used to flag wheather the procedure
label (plabel) is a pointer to an LT entry or to the entry point
of the procedure (PA-RISC Procedure Calling Conventions Reference
Manual, 5.3.2 Procedure Labels and Dynamic Calls). */
#define QT_PA_RISC_READ_PLABEL(plabel) \
( (((int)plabel) & 2) ? \
( (*((int *)(((int)plabel) & 0xfffffffc)))) : ((int)plabel) )
/* Stack must be 64 bytes aligned. */
#define QT_STKALIGN (64)
/* Internal helper for putting stuff on stack (negative index!). */
#define QT_SPUT(top, at, val) \
(((qt_word_t *)(top))[-(at)] = (qt_word_t)(val))
/* Offsets of various registers which are modified on the stack.
rp (return-pointer) has to be stored in the frame-marker-area
of the "older" stack-segment. */
#define QT_crp (12+4+16+5)
#define QT_15 (12+4+4)
#define QT_16 (12+4+3)
#define QT_17 (12+4+2)
#define QT_18 (12+4+1)
/** This stuff is for NON-VARARGS. **/
/* Stack looks like this (2 stack frames):
<--- 64-bytes aligned --><------- 64-bytes aligned ------------>
| || |
<--16--><------48-------><----16*4-----><--16-><------48------->
|| | || | | ||
||filler|arg|frame-marker||register-save|filler|arg|frame-marker||
------------------------------------------------------------------
*/
#define QT_STKBASE (16+48+(16*sizeof(qt_word_t))+16+48)
/* The index, relative to sp, of where to put each value. */
#define QT_ONLY_INDEX (QT_15)
#define QT_USER_INDEX (QT_16)
#define QT_ARGT_INDEX (QT_17)
#define QT_ARGU_INDEX (QT_18)
extern void qt_start(void);
#define QT_ARGS_MD(sp) \
(QT_SPUT (sp, QT_crp, QT_PA_RISC_READ_PLABEL(qt_start)))
/** This is for VARARGS. **/
#define QT_VARGS_DEFAULT
/* Stack looks like this (2 stack frames):
<------ 64-bytes aligned -------><--------- 64-bytes aligned ---------->
| || |
<---?--><--?---><16><----32-----><----16*4-----><-16--><16><----32----->
|| | | | || | | | ||
||filler|varargs|arg|frame-marker||register-save|filler|arg|frame-marker||
--------------------------------------------------------------------------
*/
/* Sp is moved to the end of the first stack frame. */
#define QT_VARGS_MD0(sp, vasize) \
((qt_t *)(((char *)sp) + QT_STKROUNDUP(vasize + 4*4 + 32)))
/* To reach the arguments from the end of the first stack frame use 32
as a negative adjustment. */
#define QT_VARGS_ADJUST(sp) ((qt_t *)(((char *)sp) - 32))
/* Offset to reach the end of the second stack frame. */
#define QT_VSTKBASE ((16*sizeof(qt_word_t)) + 16 + 4*4 + 32)
extern void qt_vstart(void);
#define QT_VARGS_MD1(sp) \
(QT_SPUT (sp, QT_crp, QT_PA_RISC_READ_PLABEL(qt_vstart)))
#define QT_VARGT_INDEX (QT_15)
#define QT_VSTARTUP_INDEX (QT_16)
#define QT_VUSERF_INDEX (QT_17)
#define QT_VCLEANUP_INDEX (QT_18)
#endif /* ndef QT_PA_RISC_H */

View file

@ -1,237 +0,0 @@
; pa-risc.s -- assembly support.
; QuickThreads -- Threads-building toolkit.
; Copyright (c) 1993 by David Keppel
;
; Permission to use, copy, modify and distribute this software and
; its documentation for any purpose and without fee is hereby
; granted, provided that the above copyright notice and this notice
; appear in all copies. This software is provided as a
; proof-of-concept and for demonstration purposes; there is no
; representation about the suitability of this software for any
; purpose.
; This file (pa-risc.s) is part of the port of QuickThreads for
; PA-RISC 1.1 architecture. This file implements context switches
; and thread startup. It was written in 1994 by Uwe Reder
; (`uereder@cip.informatik.uni-erlangen.de') for the Operating
; Systems Department (IMMD4) at the University of Erlangen/Nuernberg
; Germany.
; Callee saves general registers gr3..gr18,
; floating-point registers fr12..fr21.
.CODE
.IMPORT $$dyncall, MILLICODE
.IMPORT qt_error, CODE
.EXPORT qt_blocki, ENTRY
.EXPORT qt_block, ENTRY
.EXPORT qt_abort, ENTRY
.EXPORT qt_start, ENTRY
.EXPORT qt_vstart, ENTRY
; arg0: ptr to function (helper) to call once curr is suspended
; and control is on arg3's stack.
; arg1: 1'th arg to *arg0.
; arg2: 2'th arg to *arg0.
; arg3: sp of new thread.
qt_blocki
.PROC
.CALLINFO CALLER, FRAME=0, SAVE_RP, ENTRY_GR=18
.ENTRY
stw %rp,-20(%sp) ; save rp to old frame-marker
stwm %r3,128(%sp) ; save callee-saves general registers
stw %r4,-124(%sp)
stw %r5,-120(%sp)
stw %r6,-116(%sp)
stw %r7,-112(%sp)
stw %r8,-108(%sp)
stw %r9,-104(%sp)
stw %r10,-100(%sp)
stw %r11,-96(%sp)
stw %r12,-92(%sp)
stw %r13,-88(%sp)
stw %r14,-84(%sp)
stw %r15,-80(%sp)
stw %r16,-76(%sp)
stw %r17,-72(%sp)
stw %r18,-68(%sp)
qt_abort
copy %arg0,%r22 ; helper to be called by $$dyncall
copy %sp,%arg0 ; pass current sp as arg0 to helper
copy %arg3,%sp ; set new sp
.CALL
bl $$dyncall,%mrp ; call helper
copy %mrp,%rp
ldw -68(%sp),%r18 ; restore general registers
ldw -72(%sp),%r17
ldw -76(%sp),%r16
ldw -80(%sp),%r15
ldw -84(%sp),%r14
ldw -88(%sp),%r13
ldw -92(%sp),%r12
ldw -96(%sp),%r11
ldw -100(%sp),%r10
ldw -104(%sp),%r9
ldw -108(%sp),%r8
ldw -112(%sp),%r7
ldw -116(%sp),%r6
ldw -120(%sp),%r5
ldw -124(%sp),%r4
ldw -148(%sp),%rp ; restore return-pointer
bv %r0(%rp) ; return to caller
ldwm -128(%sp),%r3
.EXIT
.PROCEND
qt_block
.PROC
.CALLINFO CALLER, FRAME=0, SAVE_RP, ENTRY_FR=21
.ENTRY
stw %rp,-20(%sp) ; save rp to old frame-marker
fstds,ma %fr12,8(%sp) ; save callee-saves float registers
fstds,ma %fr13,8(%sp)
fstds,ma %fr14,8(%sp)
fstds,ma %fr15,8(%sp)
fstds,ma %fr16,8(%sp)
fstds,ma %fr17,8(%sp)
fstds,ma %fr18,8(%sp)
fstds,ma %fr19,8(%sp)
fstds,ma %fr20,8(%sp)
fstds,ma %fr21,8(%sp)
.CALL
bl qt_blocki,%rp
ldo 48(%sp),%sp
ldo -48(%sp),%sp
fldds,mb -8(%sp),%fr21 ; restore callee-saves float registers
fldds,mb -8(%sp),%fr20
fldds,mb -8(%sp),%fr19
fldds,mb -8(%sp),%fr18
fldds,mb -8(%sp),%fr17
fldds,mb -8(%sp),%fr16
fldds,mb -8(%sp),%fr15
fldds,mb -8(%sp),%fr14
fldds,mb -8(%sp),%fr13
ldw -28(%sp),%rp ; restore return-pointer
bv %r0(%rp) ; return to caller.
fldds,mb -8(%sp),%fr12
.EXIT
.PROCEND
qt_start
.PROC
.CALLINFO CALLER, FRAME=0
.ENTRY
copy %r18,%arg0 ; set user arg `pu'.
copy %r17,%arg1 ; ... user function pt.
copy %r16,%arg2 ; ... user function userf.
; %r22 is a caller-saves register
copy %r15,%r22 ; function to be called by $$dyncall
.CALL ; in=%r22
bl $$dyncall,%mrp ; call `only'.
copy %mrp,%rp
bl,n qt_error,%r0 ; `only' erroniously returned.
.EXIT
.PROCEND
; Varargs
;
; First, call `startup' with the `pt' argument.
;
; Next, call the user's function with all arguments.
; We don't know whether arguments are integers, 32-bit floating-points or
; even 64-bit floating-points, so we reload all the registers, possibly
; with garbage arguments. The thread creator provided non-garbage for
; the arguments that the callee actually uses, so the callee never gets
; garbage.
;
; -48 -44 -40 -36 -32
; | arg3 | arg2 | arg1 | arg0 |
; -----------------------------
; integers: arg3 arg2 arg1 arg0
; 32-bit fps: farg3 farg2 farg1 farg0
; 64-bit fps: <---farg3--> <---farg1-->
;
; Finally, call `cleanup' with the `pt' argument and with the return value
; from the user's function. It is an error for `cleanup' to return.
qt_vstart
.PROC
.CALLINFO CALLER, FRAME=0
.ENTRY
; Because the startup function may damage the fixed arguments
; on the stack (PA-RISC Procedure Calling Conventions Reference
; Manual, 2.4 Fixed Arguments Area), we allocate a seperate
; stack frame for it.
ldo 64(%sp),%sp
; call: void startup(void *pt)
copy %r15,%arg0 ; `pt' is arg0 to `startup'.
copy %r16,%r22
.CALL
bl $$dyncall,%mrp ; Call `startup'.
copy %mrp,%rp
ldo -64(%sp),%sp
; call: void *qt_vuserf_t(...)
ldw -36(%sp),%arg0 ; Load args to integer registers.
ldw -40(%sp),%arg1
ldw -44(%sp),%arg2
ldw -48(%sp),%arg3
; Index of fld[w|d]s only ranges from -16 to 15, so we
; take r22 to be our new base register.
ldo -32(%sp),%r22
fldws -4(%r22),%farg0 ; Load args to floating-point registers.
fldds -8(%r22),%farg1
fldws -12(%r22),%farg2
fldds -16(%r22),%farg3
copy %r17,%r22
.CALL
bl $$dyncall,%mrp ; Call `userf'.
copy %mrp,%rp
; call: void cleanup(void *pt, void *vuserf_return)
copy %r15,%arg0 ; `pt' is arg0 to `cleanup'.
copy %ret0,%arg1 ; Return-value is arg1 to `cleanup'.
copy %r18,%r22
.CALL
bl $$dyncall,%mrp ; Call `cleanup'.
copy %mrp,%rp
bl,n qt_error,%r0
.EXIT
.PROCEND

View file

@ -1,203 +0,0 @@
; QuickThreads -- Threads-building toolkit.
; Copyright (c) 1993 by David Keppel
; Permission to use, copy, modify and distribute this software and
; its documentation for any purpose and without fee is hereby
; granted, provided that the above copyright notice and this notice
; appear in all copies. This software is provided as a
; proof-of-concept and for demonstration purposes; there is no
; representation about the suitability of this software for any
; purpose.
; This file (pa-risc_b.s) is part of the port of QuickThreads for
; PA-RISC 1.1 architecture. It contains assembly-level support for
; raw processor performance measurement. It was written in 1994 by
; Uwe Reder (`uereder@cip.informatik.uni-erlangen.de')
; for the Operating Systems Department (IMMD4) at the
; University of Erlangen/Nuernberg Germany.
; Note that the number of instructions in the measurement-loops, differ
; from implementation to implementation. I took eight instructions in a loop
; for every test (execute eight instructions and loop to the start).
.CODE
.IMPORT $global$,DATA
.IMPORT $$dyncall,MILLICODE
.EXPORT b_call_reg
.EXPORT b_call_imm
.EXPORT b_add
.EXPORT b_load
; Just do nothing, only return to caller. This procedure is called by
; `b_call_reg' and `b_call_imm'.
b_null
.PROC
.CALLINFO NO_CALLS, FRAME=0
.ENTRY
bv,n %r0(%rp) ; just return
.EXIT
.PROCEND
; Call the procedure `b_null' with function pointer in a register.
b_call_reg
.PROC
.CALLINFO CALLER, FRAME=0
.ENTRY
stwm %r3,64(%sp) ; store r3 (may be used by caller)
stw %rp,-20(%sp) ; save return-pointer to frame-marker
addil LR'to_call-$global$,%r27
ldw RR'to_call-$global$(%r1),%r3
_loop0
copy %r3,%r22 ; copy the procedure label to r22, ...
.CALL ; ...this is the input to $$dyncall
bl $$dyncall,%mrp ; call $$dyncall (millicode function)
copy %mrp,%rp ; remember the return-pointer
copy %r3,%r22
.CALL
bl $$dyncall,%mrp
copy %mrp,%rp
copy %r3,%r22
.CALL
bl $$dyncall,%mrp
copy %mrp,%rp
copy %r3,%r22
.CALL
bl $$dyncall,%mrp
copy %mrp,%rp
copy %r3,%r22
.CALL
bl $$dyncall,%mrp
copy %mrp,%rp
copy %r3,%r22
.CALL
bl $$dyncall,%mrp
copy %mrp,%rp
copy %r3,%r22
.CALL
bl $$dyncall,%mrp
copy %mrp,%rp
copy %r3,%r22
.CALL
bl $$dyncall,%mrp
copy %mrp,%rp
addibf,<= -8,%arg0,_loop0 ; decrement counter by 8 and loop
nop
ldw -20(%sp),%rp ; restore return-pointer
bv %r0(%rp) ; return to caller
ldwm -64(%sp),%r3 ; resore r3 and remove stack frame
.EXIT
.PROCEND
; Call the procedure `b_null' immediate.
b_call_imm
.PROC
.CALLINFO CALLER, FRAME=0, SAVE_RP
.ENTRY
ldo 64(%sp),%sp ; caller needs a stack-frame
stw %rp,-20(%sp) ; save return-pointer to frame-marker
_loop1
bl b_null,%rp ; call `b_null' immediate (8 times)
nop
bl b_null,%rp
nop
bl b_null,%rp
nop
bl b_null,%rp
nop
bl b_null,%rp
nop
bl b_null,%rp
nop
bl b_null,%rp
nop
bl b_null,%rp
nop
addibf,<= -8,%arg0,_loop1 ; decrement counter by 8 and loop
nop
ldw -20(%sp),%rp ; restore return-pointer
bv %r0(%rp) ; return to caller
ldo -64(%sp),%sp ; remove stack-frame
.EXIT
.PROCEND
; Copy register-to-register.
; On PA-RISC this is implemented with an `or'.
; The `or' is hidden by a pseudo-operation called `copy'.
b_add
.PROC
.CALLINFO NO_CALLS, FRAME=0
.ENTRY
_loop2
copy %r19,%r20 ; copy register-to-register
copy %r20,%r21 ; use caller-saves registers
copy %r21,%r22
copy %r22,%r21
copy %r21,%r20
copy %r20,%r19
copy %r19,%r20
copy %r20,%r21
addibf,<= -8,%arg0,_loop2 ; decrement counter by 8 and loop
nop
bv,n %r0(%rp)
.EXIT
.PROCEND
; Load memory to a register.
b_load
.PROC
.CALLINFO NO_CALLS, FRAME=0
.ENTRY
_loop3
ldw -4(%sp),%r22 ; load data from frame-marker
ldw -8(%sp),%r22 ; use a caller-saves register
ldw -12(%sp),%r22
ldw -16(%sp),%r22
ldw -20(%sp),%r22
ldw -24(%sp),%r22
ldw -28(%sp),%r22
ldw -32(%sp),%r22
addibf,<= -8,%arg0,_loop3 ; decrement counter by 8 and loop
nop
bv,n %r0(%rp)
.EXIT
.PROCEND
.ALIGN 8
to_call
.WORD b_null

View file

@ -1,7 +0,0 @@
Note that some machines want labels to have leading underscores,
while others (e.g. System V) do not. Thus, several labels appear
duplicated except for the leading underscore, e.g.
_qt_cswap:
qt_cswap:

View file

@ -1,112 +0,0 @@
;; i386.asm -- assembly support.
;;
;; QuickThreads -- Threads-building toolkit.
;; Copyright (c) 2001, 2006 Free Software Foundation, Inc.
;;
;; Permission to use, copy, modify and distribute this software and
;; its documentation for any purpose and without fee is hereby
;; granted, provided that the above copyright notice and this notice
;; appear in all copies. This software is provided as a
;; proof-of-concept and for demonstration purposes; there is no
;; representation about the suitability of this software for any
;; purpose.
;; NOTE: double-labeled `_name' and `name' for System V compatability.
;; NOTE: Comment lines start like this one, or with '//' ONLY. Sorry!
;; Callee-save: %esi, %edi, %ebx, %ebp
;; Caller-save: %eax, %ecx
;; Can't tell: %edx (seems to work w/o saving it.)
;;
;; Assignment:
;;
;; See ``i386.h'' for the somewhat unconventional stack layout.
.386p
.model flat
.code
public _qt_abort
public qt_abort
public _qt_block
public qt_block
public _qt_blocki
public qt_blocki
;; These all have the type signature
;;
;; void *blocking (helper, arg0, arg1, new)
;;
;; On procedure entry, the helper is at 4(sp), args at 8(sp) and
;; 12(sp) and the new thread's sp at 16(sp). It *appears* that the
;; calling convention for the 8X86 requires the caller to save all
;; floating-point registers, this makes our life easy.
;; Halt the currently-running thread. Save it's callee-save regs on
;; to the stack, 32 bytes. Switch to the new stack (next == 16+32(sp))
;; and call the user function (f == 4+32(sp) with arguments: old sp
;; arg1 (8+32(sp)) and arg2 (12+32(sp)). When the user function is
;; done, restore the new thread's state and return.
;;
;; `qt_abort' is (currently) an alias for `qt_block' because most of
;; the work is shared. We could save the insns up to `qt_common' by
;; replicating, but w/o replicating we need an inital subtract (to
;; offset the stack as if it had been a qt_block) and then a jump
;; to qt_common. For the cost of a jump, we might as well just do
;; all the work.
;;
;; The helper function (4(sp)) can return a void* that is returned
;; by the call to `qt_blockk{,i}'. Since we don't touch %eax in
;; between, we get that ``for free''.
_qt_abort:
qt_abort:
_qt_block:
qt_block:
_qt_blocki:
qt_blocki:
push ebp ; Save callee-save, sp-=4.
push esi ; Save callee-save, sp-=4.
push edi ; Save callee-save, sp-=4.
push ebx ; Save callee-save, sp-=4.
mov eax, esp ; Remember old stack pointer.
qt_common:
mov esp, [esp+32] ; Move to new thread.
push [eax+28] ; Push arg 2.
push [eax+24] ; Push arg 1.
push eax ; Push arg 0.
mov ebx, [eax+20] ; Get function to call.
call ebx ; Call f.
add esp, 12 ; Pop args.
pop ebx ; Restore callee-save, sp+=4.
pop edi ; Restore callee-save, sp+=4.
pop esi ; Restore callee-save, sp+=4.
pop ebp ; Restore callee-save, sp+=4.
ret ; Resume the stopped function.
hlt
;; Start a varargs thread.
public _qt_vstart
public qt_vstart
_qt_vstart:
qt_vstart:
push edi ; Push `pt' arg to `startup'.
call ebp ; Call `startup'.
pop eax ; Clean up the stack.
call ebx ; Call the user's function.
push eax ; Push return from user's.
push edi ; Push `pt' arg to `cleanup'.
call esi ; Call `cleanup'.
hlt ; `cleanup' never returns.
end

View file

@ -1,120 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
#ifndef QT_386_H
#define QT_386_H
typedef unsigned long qt_word_t;
/* Thread's initial stack layout on the i386:
non-varargs:
+---
| arg[2] === `userf' on startup
| arg[1] === `pt' on startup
| arg[0] === `pu' on startup
+---
| ret pc === qt_error
+---
| ret pc === `only' on startup
+---
| %ebp
| %esi
| %edi
| %ebx <--- qt_t.sp
+---
When a non-varargs thread is started, it ``returns'' directly to
the client's `only' function.
varargs:
+---
| arg[n-1]
| ..
| arg[0]
+---
| ret pc === `qt_vstart'
+---
| %ebp === `startup'
| %esi === `cleanup'
| %edi === `pt'
| %ebx === `vuserf' <--- qt_t.sp
+---
When a varargs thread is started, it ``returns'' to the `qt_vstart'
startup code. The startup code calls the appropriate functions. */
/* What to do to start a varargs thread running. */
QT_API void qt_vstart (void);
/* Hold 4 saved regs plus two return pcs (qt_error, qt_start) plus
three args. */
#define QT_STKBASE (9 * 4)
/* Hold 4 saved regs plus one return pc (qt_vstart). */
#define QT_VSTKBASE (5 * 4)
/* Stack must be 4-byte aligned. */
#define QT_STKALIGN (4)
/* Where to place various arguments. */
#define QT_ONLY_INDEX (QT_PC)
#define QT_USER_INDEX (QT_ARG2)
#define QT_ARGT_INDEX (QT_ARG1)
#define QT_ARGU_INDEX (QT_ARG0)
#define QT_VSTARTUP_INDEX (QT_EBP)
#define QT_VUSERF_INDEX (QT_EBX)
#define QT_VCLEANUP_INDEX (QT_ESI)
#define QT_VARGT_INDEX (QT_EDI)
#define QT_EBX 0
#define QT_EDI 1
#define QT_ESI 2
#define QT_EBP 3
#define QT_PC 4
/* The following are defined only for non-varargs. */
#define QT_RPC 5
#define QT_ARG0 6
#define QT_ARG1 7
#define QT_ARG2 8
/* Stack grows down. The top of the stack is the first thing to
pop off (preincrement, postdecrement). */
#define QT_GROW_DOWN
QT_API void qt_error (void);
/* Push on the error return address. */
#define QT_ARGS_MD(sto) \
(QT_SPUT (sto, QT_RPC, qt_error))
/* When varargs are pushed, allocate space for all the args. */
#define QT_VARGS_MD0(sto, nbytes) \
((qt_t *)(((char *)(sto)) - QT_STKROUNDUP(nbytes)))
#define QT_VARGS_MD1(sto) \
(QT_SPUT (sto, QT_PC, qt_vstart))
#define QT_VARGS_DEFAULT
#endif /* QT_386_H */

View file

@ -1,108 +0,0 @@
/* i386.s -- assembly support. */
/*
// QuickThreads -- Threads-building toolkit.
// Copyright (c) 1993 by David Keppel
//
// Permission to use, copy, modify and distribute this software and
// its documentation for any purpose and without fee is hereby
// granted, provided that the above copyright notice and this notice
// appear in all copies. This software is provided as a
// proof-of-concept and for demonstration purposes; there is no
// representation about the suitability of this software for any
// purpose. */
/* NOTE: double-labeled `_name' and `name' for System V compatability. */
/* NOTE: Comment lines start like this one, or with '//' ONLY. Sorry! */
/* Callee-save: %esi, %edi, %ebx, %ebp
// Caller-save: %eax, %ecx
// Can't tell: %edx (seems to work w/o saving it.)
//
// Assignment:
//
// See ``i386.h'' for the somewhat unconventional stack layout. */
.text
.align 2
.globl _qt_abort
.globl qt_abort
.globl _qt_block
.globl qt_block
.globl _qt_blocki
.globl qt_blocki
/* These all have the type signature
//
// void *blocking (helper, arg0, arg1, new)
//
// On procedure entry, the helper is at 4(sp), args at 8(sp) and
// 12(sp) and the new thread's sp at 16(sp). It *appears* that the
// calling convention for the 8X86 requires the caller to save all
// floating-point registers, this makes our life easy. */
/* Halt the currently-running thread. Save it's callee-save regs on
// to the stack, 32 bytes. Switch to the new stack (next == 16+32(sp))
// and call the user function (f == 4+32(sp) with arguments: old sp
// arg1 (8+32(sp)) and arg2 (12+32(sp)). When the user function is
// done, restore the new thread's state and return.
//
// `qt_abort' is (currently) an alias for `qt_block' because most of
// the work is shared. We could save the insns up to `qt_common' by
// replicating, but w/o replicating we need an inital subtract (to
// offset the stack as if it had been a qt_block) and then a jump
// to qt_common. For the cost of a jump, we might as well just do
// all the work.
//
// The helper function (4(sp)) can return a void* that is returned
// by the call to `qt_blockk{,i}'. Since we don't touch %eax in
// between, we get that ``for free''. */
_qt_abort:
qt_abort:
_qt_block:
qt_block:
_qt_blocki:
qt_blocki:
pushl %ebp /* Save callee-save, sp-=4. */
pushl %esi /* Save callee-save, sp-=4. */
pushl %edi /* Save callee-save, sp-=4. */
pushl %ebx /* Save callee-save, sp-=4. */
movl %esp, %eax /* Remember old stack pointer. */
qt_common:
movl 32(%esp), %esp /* Move to new thread. */
pushl 28(%eax) /* Push arg 2. */
pushl 24(%eax) /* Push arg 1. */
pushl %eax /* Push arg 0. */
movl 20(%eax), %ebx /* Get function to call. */
call *%ebx /* Call f. */
addl $12, %esp /* Pop args. */
popl %ebx /* Restore callee-save, sp+=4. */
popl %edi /* Restore callee-save, sp+=4. */
popl %esi /* Restore callee-save, sp+=4. */
popl %ebp /* Restore callee-save, sp+=4. */
ret /* Resume the stopped function. */
hlt
/* Start a varargs thread. */
.globl _qt_vstart
.globl qt_vstart
_qt_vstart:
qt_vstart:
pushl %edi /* Push `pt' arg to `startup'. */
call *%ebp /* Call `startup'. */
popl %eax /* Clean up the stack. */
call *%ebx /* Call the user's function. */
pushl %eax /* Push return from user's. */
pushl %edi /* Push `pt' arg to `cleanup'. */
call *%esi /* Call `cleanup'. */
hlt /* `cleanup' never returns. */

View file

@ -1,30 +0,0 @@
/*
// QuickThreads -- Threads-building toolkit.
// Copyright (c) 1993 by David Keppel
//
// Permission to use, copy, modify and distribute this software and
// its documentation for any purpose and without fee is hereby
// granted, provided that the above copyright notice and this notice
// appear in all copies. This software is provided as a
// proof-of-concept and for demonstration purposes; there is no
// representation about the suitability of this software for any
// purpose. */
.globl _b_call_reg
.globl b_call_reg
.globl _b_call_imm
.globl b_call_imm
.globl _b_add
.globl b_add
.globl _b_load
.globl b_load
_b_call_reg:
b_call_reg:
_b_call_imm:
b_call_imm:
_b_add:
b_add:
_b_load:
b_load:
hlt

View file

@ -1,6 +0,0 @@
#
# KSR1 configuration.
#
CC = cc -ansi

View file

@ -1,164 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
#ifndef QT_KSR1_H
#define QT_KSR1_H
/*
Stack layout:
Registers are saved in strictly low to high order, FPU regs first
(only if qt_block is called), CEU regs second, IPU regs next, with no
padding between the groups.
Callee-save: f16..f63; c15..c30; i12..i30.
Args passed in i2..i5.
Note: c31 is a private data pointer. It is not changed on thread
swaps with the assumption that it represents per-processor rather
than per-thread state.
Note: i31 is an instruction count register that is updated by the
context switch routines. Like c31, it is not changed on context
switches.
This is what we want on startup:
+------ <-- BOS: Bottom of stack (grows down)
| 80 (128 - 48) bytes of padding to a 128-byte boundary
+---
| only
| userf
| t
| u
| qt_start$TXT
| (empty) <-- qt.sp
+------ <-- (BOS - 128)
This is why we want this on startup:
A thread begins running when the restore procedure switches thread stacks
and pops a return address off of the top of the new stack (see below
for the reason why we explicitly store qt_start$TXT). The
block procedure pushes two jump addresses on a thread's stack before
it switches stacks. The first is the return address for the block
procedure, and the second is a restore address. The return address
is used to jump back to the thread that has been switched to; the
restore address is a jump within the block code to restore the registers.
Normally, this is just a jump to the next address. However, on thread
startup, this is a jump to qt_start$TXT. (The block procedure stores
the restore address at an offset of 8 bytes from the top of the stack,
which is also the offset at which qt_start$TXT is stored on the stacks
of new threads. Hence, when the block procedure switches to a new
thread stack, it will initially jump to qt_start$TXT; thereafter,
it jumps to the restore code.)
qt_start$TXT, after it has read the initial data on the new thread's
stack and placed it in registers, pops the initial stack frame
and gives the thread the entire stack to use for execution.
The KSR runtime system has an unusual treatment of pointers to
functions. From C, taking the `name' of a function yields a
pointer to a _constant block_ and *not* the address of the
function. The zero'th entry in the constant block is a pointer to
the function.
We have to be careful: the restore procedure expects a return
address on the top of the stack (pointed to by qt.sp). This is not
a problem when restoring a thread that has run before, since the
block routine would have stored the return address on top of the
stack. However, when ``faking up'' a thread start (bootstrapping a
thread stack frame), the top of the stack needs to contain a
pointer to the code that will start the thread running.
The pointer to the startup code is *not* `qt_start'. It is the
word *pointed to* by `qt_start'. Thus, we dereference `qt_start',
see QT_ARGS_MD below.
On varargs startup (still unimplemented):
| padding to 128 byte boundary
| varargs <-- padded to a 128-byte-boundary
+---
| caller's frame, 16 bytes
| 80 bytes of padding (frame padded to a 128-byte boundary)
+---
| cleanup
| vuserf
| startup
| t
+---
| qt_start <-- qt.sp
+---
Of a suspended thread:
+---
| caller's frame, 16 bytes
| fpu registers 47 regs * 8 bytes/reg 376 bytes
| ceu registers 16 regs * 8 bytes/reg 128 bytes
| ipu registers 19 regs * 8 bytes/reg 152 bytes
| :
| 80 bytes of padding
| :
| qt_restore <-- qt.sp
+---
*/
#define QT_STKALIGN 128
#define QT_GROW_DOWN
typedef unsigned long qt_word_t;
#define QT_STKBASE QT_STKALIGN
#define QT_VSTKBASE QT_STKBASE
extern void qt_start(void);
/*
* See the discussion above for what indexing into a procedure ptr
* does for us (it's lovely, though, isn't it?).
*
* This assumes that the address of a procedure's code is the
* first word in a procedure's constant block. That's how the manual
* says it will be arranged.
*/
#define QT_ARGS_MD(sp) (QT_SPUT (sp, 1, ((qt_word_t *)qt_start)[0]))
/*
* The *index* (positive offset) of where to put each value.
* See the picture of the stack above that explains the offsets.
*/
#define QT_ONLY_INDEX (5)
#define QT_USER_INDEX (4)
#define QT_ARGT_INDEX (3)
#define QT_ARGU_INDEX (2)
#define QT_VARGS_DEFAULT
#define QT_VARGS(sp, nb, vargs, pt, startup, vuserf, cleanup) \
(qt_vargs (sp, nbytes, &vargs, pt, startup, vuserf, cleanup))
#define QT_VARGS_MD0(sp, vabytes) \
((qt_t *)(((char *)(sp)) - 4*8 - QT_STKROUNDUP(vabytes)))
extern void qt_vstart(void);
#define QT_VARGS_MD1(sp) (QT_SPUT (sp, 0, ((qt_word_t *)qt_vstart)[0]))
#define QT_VCLEANUP_INDEX (4)
#define QT_VUSERF_INDEX (3)
#define QT_VSTARTUP_INDEX (2)
#define QT_VARGT_INDEX (1)
#endif /* def QT_KSR1_H */

View file

@ -1,424 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
.file "ksr1.s"
.def .debug; .endef
.align 128
.globl qt_blocki
.globl qt_blocki$TXT
.globl qt_block
.globl qt_block$TXT
.globl qt_start$TXT
.globl qt_start
.globl qt_abort$TXT
.globl qt_abort
.globl qt_vstart
.globl qt_vstart$TXT
#
# KSR convention: on procedure calls, load both the procedure address
# and a pointer to a constant block. The address of function `f' is
# `f$TXT', and the constant block address is `f'. The constant block
# has several reserved values:
#
# 8 bytes fpu register save mask
# 4 bytes ipu register save mask
# 4 bytes ceu register save mask
# f: f$TXT
# ... whatever you want ... (not quite...read on)
#
# Note, by the way, that a pointer to a function is passed as a
# pointer to the constant area, and the constant area has the text
# address.
#
#
# Procedures that do not return structures prefix their code with
#
# proc$TXT:
# finop; cxnop
# finop; cxnop
# <proc code>
#
# Calls to those procedures branch to a 16 byte offset (4 instrs) in
# to the procedure to skip those instructions.
#
# Procedures that return structures use a different code prefix:
#
# proc$TXT:
# finop; beq.qt %rc, %rc, 24 # return value entry
# finop; cxnop
# finop; movi8 0, %rc # no return value entry
# <proc code>
#
# Calls that want the returned structure branch directly to the
# procedure address. Callers that don't want (or aren't expecting) a
# return value branche 16 bytes in to the procedure, which will zero
# %rc, telling the called procedure not to return a structure.
#
#
# On entry:
# %i2 -- control block of helper function to run
# (dereference to get helper)
# %i3 -- a1
# %i4 -- a2
# %i5 -- sp of new to run
#
.data
.half 0x0, 0x0, 0x7ffff000, 0x7fff8000
qt_blocki:
qt_abort:
.word qt_blocki$TXT
.word qt_restore$TXT
.text
qt_abort$TXT:
qt_blocki$TXT:
finop ; cxnop # entry prefix
finop ; cxnop # entry prefix
add8.ntr 75,%i31,%i31 ; movi8 512,%c5 # ICR; stk adjust
finop ; ssub8.ntr 0,%sp,%c5,%sp
finop ; st8 %fp,504(%sp) # Save caller's fp
finop ; st8 %cp,496(%sp) # Save caller's cp
finop ; ld8 8(%c10),%c5 # ld qt_restore$TXT
finop ; st8 %c14,0(%sp) # Save special ret addr
finop ; mov8_8 %c10, %cp # Our cp
finop ; sadd8.ntr 0,%sp,%c5,%fp # Our frame ptr
finop ; st8 %c5,8(%sp) # st qt_restore$TXT
#
# CEU registers %c15-%c24, %c26-%c30 (%c14 we restore later)
#
finop ; st8 %c15,456(%sp)
finop ; st8 %c16,448(%sp)
finop ; st8 %c17,440(%sp)
finop ; st8 %c18,432(%sp)
finop ; st8 %c19,424(%sp)
finop ; st8 %c20,416(%sp)
finop ; st8 %c21,408(%sp)
finop ; st8 %c22,400(%sp)
finop ; st8 %c23,392(%sp)
finop ; st8 %c24,384(%sp)
#
# %c25 is the Enclosing Frame Pointer (EFP) -- since C doesn't
# use nested procedures, we ignore it (leaving a gap, though)
#
finop ; st8 %c26,368(%sp)
finop ; st8 %c27,360(%sp)
finop ; st8 %c28,352(%sp)
finop ; st8 %c29,344(%sp)
finop ; st8 %c30,336(%sp)
#
# IPU registers %i12-%i30
#
finop ; st8 %i12,328(%sp)
finop ; st8 %i13,320(%sp)
finop ; st8 %i14,312(%sp)
finop ; st8 %i15,304(%sp)
# (gap to get alignment for st64)
# -- Doesn't work on version 1.1.3 of the OS
# finop ; st64 %i16,256(%sp)
finop ; st8 %i16,256(%sp)
finop ; st8 %i17,248(%sp)
finop ; st8 %i18,240(%sp)
finop ; st8 %i19,232(%sp)
finop ; st8 %i20,224(%sp)
finop ; st8 %i21,216(%sp)
finop ; st8 %i22,208(%sp)
finop ; st8 %i23,200(%sp)
finop ; st8 %i24,192(%sp)
finop ; st8 %i25,184(%sp)
finop ; st8 %i26,176(%sp)
finop ; st8 %i27,168(%sp)
finop ; st8 %i28,160(%sp)
finop ; st8 %i29,152(%sp)
finop ; st8 %i30,144(%sp)
#
# FPU already saved, or saving not necessary
#
#
# Switch to the stack passed in as fourth argument to the block
# routine (%i5) and call the helper routine passed in as the first
# argument (%i2). Note that the address of the helper's constant
# block is passed in, so we must derefence it to get the helper's text
# address.
#
finop ; movb8_8 %i2,%c10 # helper's ConstBlock
finop ; cxnop # Delay slot, fill w/
finop ; cxnop # .. 2 st8 from above
finop ; ld8 0(%c10),%c4 # load addr of helper
finop ; movb8_8 %sp, %i2 # 1st arg to helper
# is this stack; other
# args remain in regs
finop ; movb8_8 %i5,%sp # switch stacks
finop ; jsr %c14,16(%c4) # call helper
movi8 3, %i0 ; movi8 0,%c8 # nargs brain dmg
finop ; cxnop
finop ; cxnop
#
# Here is where behavior differs for threads being restored and threads
# being started. Blocked threads have a pointer to qt_restore$TXT on
# the top of their stacks; manufactured stacks have a pointer to qt_start$TXT
# on the top of their stacks. With this setup, starting threads
# skip the (unecessary) restore operations.
#
# We jump to an offset of 16 to either (1) skip past the two noop pairs
# at the start of qt_start$TXT, or (2) skip past the two noop pairs
# after qt_restore$TXT.
#
finop ; ld8 8(%sp),%c4
finop ; cxnop
finop ; cxnop
finop ; jmp 16(%c4)
qt_restore$TXT:
finop ; cxnop
finop ; cxnop
#
# Point of Restore:
#
# The helper funtion will return here. Any result it has placed in
# a return register (most likely %i0) will not get overwritten below
# and will consequently be the return value of the blocking routine.
#
#
# CEU registers %c15-%c24, %c26-%c30 (%c14 we restore later)
#
finop ; ld8 456(%sp),%c15
finop ; ld8 448(%sp),%c16
finop ; ld8 440(%sp),%c17
finop ; ld8 432(%sp),%c18
finop ; ld8 424(%sp),%c19
finop ; ld8 416(%sp),%c20
finop ; ld8 408(%sp),%c21
finop ; ld8 400(%sp),%c22
finop ; ld8 392(%sp),%c23
finop ; ld8 384(%sp),%c24
#
# %c25 is the Enclosing Frame Pointer (EFP) -- since C doesn't
# use nested procedures, we ignore it (leaving a gap, though)
#
finop ; ld8 368(%sp),%c26
finop ; ld8 360(%sp),%c27
finop ; ld8 352(%sp),%c28
finop ; ld8 344(%sp),%c29
finop ; ld8 336(%sp),%c30
#
# IPU registers %i12-%i30
#
finop ; ld8 328(%sp),%i12
finop ; ld8 320(%sp),%i13
finop ; ld8 312(%sp),%i14
finop ; ld8 304(%sp),%i15
# (gap to get alignment for ld64)
# -- Doesn't work on version 1.1.3 of the OS
# finop ; ld64 256(%sp),%i16
finop ; ld8 256(%sp),%i16
finop ; ld8 248(%sp),%i17
finop ; ld8 240(%sp),%i18
finop ; ld8 232(%sp),%i19
finop ; ld8 224(%sp),%i20
finop ; ld8 216(%sp),%i21
finop ; ld8 208(%sp),%i22
finop ; ld8 200(%sp),%i23
finop ; ld8 192(%sp),%i24
finop ; ld8 184(%sp),%i25
finop ; ld8 176(%sp),%i26
finop ; ld8 168(%sp),%i27
finop ; ld8 160(%sp),%i28
finop ; ld8 152(%sp),%i29
finop ; ld8 144(%sp),%i30
#
# FPU registers don't need to be loaded, or will be loaded by an
# enclosing scope (e.g., if this is called by qt_block).
#
#
# Load the special registers. We don't load the stack ptr because
# the new stack is passed in as an argument, we don't load the EFP
# because we don't use it, and we load the return address specially
# off the top of the stack.
#
finop ; ld8 0(%sp),%c14 # return addr
finop ; ld8 496(%sp),%cp
finop ; ld8 504(%sp),%fp
finop ; jmp 32(%c14) # jump back to thread
finop ; movi8 512,%c5 # stack adjust
finop ; sadd8.ntr 0,%sp,%c5,%sp
.data
.half 0x0, 0x0, 0x7ffff000, 0x7fff8000
qt_block:
.word qt_block$TXT
.word qt_error
.word qt_error$TXT
.word qt_blocki
#
# Handle saving and restoring the FPU regs, relying on qt_blocki
# to save and restore the remaining registers.
#
.text
qt_block$TXT:
finop ; cxnop # entry prefix
finop ; cxnop # entry prefix
add8.ntr 29,%i31,%i31 ; movi8 512,%c5 # ICR; stk adjust
finop ; ssub8.ntr 0,%sp,%c5,%sp
finop ; st8 %fp,504(%sp) # Save caller's fp
finop ; st8 %cp,496(%sp) # Save caller's cp
finop ; st8 %c14,488(%sp) # store ret addr
finop ; sadd8.ntr 0,%sp,%c5,%fp # Our frame ptr
finop ; mov8_8 %c10, %cp # Our cp
#
# Store 8 registers at once...destination must be a multiple of 64
#
finop ; st64 %f16,384(%sp)
finop ; st64 %f24,320(%sp)
finop ; st64 %f32,256(%sp)
finop ; st64 %f40,192(%sp)
finop ; st64 %f48,128(%sp)
finop ; st64 %f56,64(%sp)
#
# Call the integer blocking routine, passing the arguments passed to us
#
finop ; ld8 24(%cp), %c10
finop ; cxnop
finop ; jsr %c14, qt_blocki$TXT
finop ; cxnop
finop ; cxnop
movi8 4,%i0 ; movi8 0,%c8 # nargs brain dmg
#
# Load 8 registers at once...source must be a multiple of 64
#
finop ; ld64 64(%sp),%f56
finop ; ld64 128(%sp),%f48
finop ; ld64 192(%sp),%f40
finop ; ld64 256(%sp),%f32
finop ; ld64 320(%sp),%f24
finop ; ld64 384(%sp),%f16
finop ; ld8 488(%sp),%c14
finop ; ld8 496(%sp),%cp
finop ; ld8 504(%sp),%fp
finop ; jmp 32(%c14) # jump back to thread
finop ; movi8 512,%c5 # stack adjust
finop ; sadd8.ntr 0,%sp,%c5,%sp
.data
.half 0x0, 0x0, 0x7ffff000, 0x7fff8000
qt_start:
.word qt_start$TXT
#
# A new thread is set up to "appear" as if it were executing code at
# the beginning of qt_start and then it called a blocking routine
# (qt_blocki). So when a new thread starts to run, it gets unblocked
# by the code above and "returns" to `qt_start$TXT' in the
# restore step of the switch. Blocked threads jump to 16(qt_restore$TXT),
# and starting threads jump to 16(qt_start$TXT).
#
.text
qt_start$TXT:
finop ; cxnop #
finop ; cxnop #
finop ; ld8 40(%sp),%c10 # `only' constant block
finop ; ld8 32(%sp),%i4 # `userf' arg.
finop ; ld8 24(%sp),%i3 # `t' arg.
finop ; ld8 0(%c10),%c4 # `only' text location
finop ; ld8 16(%sp),%i2 # `u' arg.
finop ; cxnop
finop ; jsr %c14,16(%c4) # call `only'
#
# Pop the frame used to store the thread's initial data
#
finop ; sadd8.ntr 0,%sp,128,%sp
finop ; cxnop
movi8 2,%i0 ; movi8 0,%c8 # nargs brain dmg
#
# If we ever return, it's an error.
#
finop ; jmp qt_error$TXT
finop ; cxnop
finop ; cxnop
movi8 0,%i0 ; movi8 0,%c8 # nargs brain dmg
#
# This stuff is broken
#
.data
.half 0x0, 0x0, 0x7ffff000, 0x7fff8000
qt_vstart:
.word qt_vstart$TXT
.text
qt_vstart$TXT:
finop ; cxnop # entry prefix
finop ; cxnop # entry prefix
finop ; cxnop
finop ; cxnop
add8.ntr 11,%i31,%i31 ; movi8 512,%c5
finop ; ssub8.ntr 0,%sp,%c5,%sp # fix stack
finop ; ld8 8(%sp),%i2 # load `t' as arg to
finop ; cxnop # `startup'
finop ; cxnop
finop ; ld8 16(%sp),%c10 # `startup' const block
finop ; cxnop
finop ; cxnop
finop ; ld8 0(%c10),%c4 # `startup' text loc.
finop ; cxnop
finop ; cxnop
finop ; jsr %c14,16(%c4) # call `startup'
finop ; cxnop
finop ; cxnop
movi8 1, %i0 ; movi8 0,%c8 # nargs brain dmg
#
# finop ; sadd 0,%sp,128,%sp # alter stack
#
finop ; ld8 8(%sp),%i2 # load `t' as arg to
finop ; ld8 8(%sp),%i2 # load `t' as arg to
finop ; ld8 8(%sp),%i2 # load `t' as arg to
finop ; ld8 8(%sp),%i2 # load `t' as arg to
finop ; ld8 32(%sp),%c10 # `only' constant block
finop ; ld8 8(%sp),%i2 # `u' arg.
finop ; ld8 16(%sp),%i3 # `t' arg.
finop ; ld8 0(%c10),%c4 # `only' text location
finop ; ld8 24(%sp),%i4 # `userf' arg.
finop ; cxnop
finop ; jsr %c4,16(%c4) # call `only'
finop ; cxnop
finop ; cxnop
#
# If the callee ever calls `nargs', the following instruction (pair)
# will be executed. However, we don't know when we compile this code
# how many args are being passed. So we give our best guess: 0.
#
movi8 0,%i0 ; movi8 0,%c8 # nargs brain dmg
#
# If we ever return, it's an error.
#
finop ; jmp qt_error$TXT
finop ; cxnop
finop ; cxnop
movi8 0,%i0 ; movi8 0,%c8 # nargs brain dmg

View file

@ -1,49 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
.file "ksr1_b.s"
.def .debug; .endef
.globl b_call_reg$TXT
.globl b_call_reg
.globl b_call_imm$TXT
.globl b_call_imm
.globl b_add$TXT
.globl b_add
.globl b_load$TXT
.globl b_load
b_call_reg:
b_call_imm:
b_add:
b_load:
.word b_call_reg$TXT
.word qt_error
.word qt_error$TXT
b_call_reg$TXT:
b_call_imm$TXT:
b_add$TXT:
b_load$TXT:
finop ; cxnop
finop ; cxnop
finop ; ld8 16(%cp),%c4
finop ; ld8 8(%cp),%cp
finop ; cxnop
finop ; cxnop
finop ; jsr %c4,0(%c4)
finop ; cxnop
finop ; cxnop

View file

@ -1,6 +0,0 @@
#
# Hosted compilers for 88k for Meerkat.
#
CC = gcc88 -Dm88k -ansi -pedantic -Wall -fno-builtin
AS = as88

View file

@ -1,111 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
#include <stdarg.h>
#include "qt.h"
/* Varargs is harder on the m88k. Parameters are saved on the stack as
something like (stack grows down to low memory; low at bottom of
picture):
| :
| arg8 <-- va_list.__va_stk
+---
| :
+---
| arg7
| :
| iarg0 <-- va_list.__va_reg
+---
| :
| va_list { __va_arg, __va_stk, __va_reg }
| :
+---
Here, `va_list.__va_arg' is the number of word-size arguments
that have already been skipped. Doubles must be double-arligned.
What this means for us is that the user's routine needs to be
called with an arg list where some of the words in the `__va_stk'
part of the parameter list have to be promoted to registers.
BUG: doubleword register arguments must be double-aligned. If
something is passed as an even # arg and used as an odd # arg or
vice-versa, the code in the called routine (in the new thread) that
decides how to adjust the index will get it wrong, because it will
be expect it to be, say, doubleword aligned and it will really be
singleword aligned.
I'm not sure you can solve this without knowing the types of all
the arguments. All in all, we never promised varargs would work
reliably. */
#define QT_VADJ(sp) (((char *)sp) - QT_VSTKBASE)
/* Always allocate at least enough space for 8 args; waste some space
at the base of the stack to ensure the startup routine doesn't read
off the end of the stack. */
#define QT_VARGS_MD0(sp, vabytes) \
((qt_t *)(((char *)(sp)) - 8*4 - QT_STKROUNDUP(vabytes)))
extern void qt_vstart(void);
#define QT_VARGS_MD1(sp) (QT_SPUT (sp, QT_1, qt_vstart))
struct qt_t *
qt_vargs (struct qt_t *qsp, int nbytes, void *vargs,
void *pt, qt_function_t *startup,
qt_function_t *vuserf, qt_function_t *cleanup)
{
va_list ap;
int i;
int n; /* Number of words into original arg list. */
qt_word_t *sp;
int *reg; /* Where to read passed-in-reg args. */
int *stk; /* Where to read passed-on-stk args. */
ap = *(va_list *)vargs;
qsp = QT_VARGS_MD0 (qsp, nbytes);
sp = (qt_word_t *)qsp;
reg = (ap.__va_arg < 8)
? &ap.__va_reg[ap.__va_arg]
: 0;
stk = &ap.__va_stk[8];
n = ap.__va_arg;
for (i=0; i<nbytes/sizeof(qt_word_t) && n<8; ++i,++n) {
sp[i] = *reg++;
}
for (; i<nbytes/sizeof(qt_word_t); ++i) {
sp[i] = *stk++;
}
#ifdef QT_NDEF
for (i=0; i<nbytes/sizeof(qt_word_t); ++i) {
sp[i] = (n < 8)
? *reg++
: *stk++;
++n;
}
#endif
QT_VARGS_MD1 (QT_VADJ(sp));
QT_SPUT (QT_VADJ(sp), QT_VARGT_INDEX, pt);
QT_SPUT (QT_VADJ(sp), QT_VSTARTUP_INDEX, startup);
QT_SPUT (QT_VADJ(sp), QT_VUSERF_INDEX, vuserf);
QT_SPUT (QT_VADJ(sp), QT_VCLEANUP_INDEX, cleanup);
return ((qt_t *)QT_VADJ(sp));
}

View file

@ -1,159 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
#ifndef QT_M88K_H
#define QT_M88K_H
typedef unsigned long qt_word_t;
#define QT_GROW_DOWN
/* Stack layout on the mips:
Callee-save registers are: $16-$23, $30; $f20-$f30.
Also save $31, return pc.
Non-varargs:
+---
| r30 (fp) on startup === 0
| r25
| r24
| r23
| r22
| r21
| r20
| r19
| r18
| r17 on startup === `only'
| r16 on startup === `userf'
| r15 on startup === `pt'
| r14 on startup === `pu'
| r1 on startup === `qt_start'
| 0
| 0
+---
| 0
| ... (8 regs worth === 32 bytes of homing area)
| 0 <--- sp
+---
Conventions for varargs:
| :
| arg8
+---
| r30 (fp) arg7
| r25 arg6
| r24 arg5
| r23 arg4
| r22 arg3
| r21 arg2
| r20 arg1
| r19 arg0
| r18
| r17 on startup === `startup'
| r16 on startup === `vuserf'
| r15 on startup === `pt'
| r14 on startup === `cleanup'
| r1 on startup === `qt_vstart'
| 0
| 0
+---
| 0
| ... (8 regs worth === 32 bytes of homing area)
| 0 <--- sp
+---
*/
/* Stack must be doubleword aligned. */
#define QT_STKALIGN (16) /* Doubleword aligned. */
/* How much space is allocated to hold all the crud for
initialization: saved registers plus padding to keep the stack
aligned plus 8 words of padding to use as a `homing area' (for
r2-r9) when calling helper functions on the stack of the (not yet
started) thread. The varargs save area is small because it gets
overlapped with the top of the parameter list. In case the
parameter list is less than 8 args, QT_ARGS_MD0 adds some dead
space at the top of the stack. */
#define QT_STKBASE (16*4 + 8*4)
#define QT_VSTKBASE (8*4 + 8*4)
/* Index of various registers. */
#define QT_1 (8+2)
#define QT_14 (8+3)
#define QT_15 (8+4)
#define QT_16 (8+5)
#define QT_17 (8+6)
#define QT_30 (8+15)
/* When a never-before-run thread is restored, the return pc points
to a fragment of code that starts the thread running. For
non-vargs functions, it sets up arguments and calls the client's
`only' function. For varargs functions, the startup code calls the
startup, user, and cleanup functions.
For non-varargs functions, we set the frame pointer to 0 to
null-terminate the call chain.
For varargs functions, the frame pointer register is used to hold
one of the arguments, so that all arguments can be laid out in
memory by the conventional `qt_vargs' varargs initialization
routine.
The varargs startup routine always reads 8 words of arguments from
the stack. If there are less than 8 words of arguments, then the
arg list could call off the top of the stack. To prevent fall-off,
always allocate 8 words. */
extern void qt_start(void);
#define QT_ARGS_MD(sp) \
(QT_SPUT (sp, QT_1, qt_start), \
QT_SPUT (sp, QT_30, 0))
/* The m88k uses a struct for `va_list', so pass a pointer to the
struct. */
typedef void (qt_function_t)(void);
struct qt_t;
extern struct qt_t *qt_vargs (struct qt_t *sp, int nbytes,
void *vargs, void *pt,
qt_function_t *startup,
qt_function_t *vuserf,
qt_function_t *cleanup);
#define QT_VARGS(sp, nbytes, vargs, pt, startup, vuserf, cleanup) \
(qt_vargs (sp, nbytes, &(vargs), pt, (qt_function_t *)startup, \
(qt_function_t *)vuserf, (qt_function_t *)cleanup))
/* The *index* (positive offset) of where to put each value. */
#define QT_ONLY_INDEX (QT_17)
#define QT_USER_INDEX (QT_16)
#define QT_ARGT_INDEX (QT_15)
#define QT_ARGU_INDEX (QT_14)
#define QT_VCLEANUP_INDEX (QT_14)
#define QT_VUSERF_INDEX (QT_16)
#define QT_VSTARTUP_INDEX (QT_17)
#define QT_VARGT_INDEX (QT_15)
#endif /* ndef QT_M88K_H */

View file

@ -1,132 +0,0 @@
/* m88k.s -- assembly support. */
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
/* Callee-save r14..r25, r31(sp), r30(fp). r1 === return pc.
* Argument registers r2..r9, return value r2..r3.
*
* On startup, restore regs so retpc === call to a function to start.
*
* We're going to call a function (r2) from within the context switch
* routine. Call it on the new thread's stack on behalf of the old
* thread.
*/
.globl _qt_block
.globl _qt_blocki
.globl _qt_abort
.globl _qt_start
.globl _qt_vstart
/*
** r2: ptr to function to call once curr is suspended
** and control is on r5's stack.
** r3: 1'th arg to *r2.
** r4: 2'th arg to *r2.
** r5: sp of thread to suspend.
**
** The helper routine returns a value that is passed on as the
** return value from the blocking routine. Since we don't
** touch r2 between the helper's return and the end of
** function, we get this behavior for free.
**
** Same entry for integer-only and floating-point, since there
** are no separate integer and floating-point registers.
**
** Each procedure call sets aside a ``home region'' of 8 regs
** for r2-r9 for varargs. For context switches we don't use
** the ``home region'' for varargs so use it to save regs.
** Allocate 64 bytes of save space -- use 32 bytes of register
** save area passed in to us plus 32 bytes we allcated, use
** the other 32 bytes for save area for a save area to call
** the helper function.
*/
_qt_block:
_qt_blocki:
sub r31, r31,64 /* Allocate reg save space. */
st r1, r31,8+32 /* Save callee-save registers. */
st r14, r31,12+32
st.d r15, r31,16+32
st.d r17, r31,24+32
st.d r19, r31,32+32
st.d r21, r31,40+32
st.d r23, r31,48+32
st r25, r31,56+32
st r30, r31,60+32
_qt_abort:
addu r14, r31,0 /* Remember old sp. */
addu r31, r5,0 /* Set new sp. */
jsr.n r2 /* Call helper. */
addu r2, r14,0 /* Pass old sp as an arg0 to helper. */
ld r1, r31,8+32 /* Restore callee-save registers. */
ld r14, r31,12+32
ld.d r15, r31,16+32
ld.d r17, r31,24+32
ld.d r19, r31,32+32
ld.d r21, r31,40+32
ld.d r23, r31,48+32
ld r25, r31,56+32
ld r30, r31,60+32
jmp.n r1 /* Return to new thread's caller. */
addu r31, r31,64 /* Free register save space. */
/*
** Non-varargs thread startup.
** See `m88k.h' for register use conventions.
*/
_qt_start:
addu r2, r14,0 /* Set user arg `pu'. */
addu r3, r15,0 /* ... user function pt. */
jsr.n r17 /* Call `only'. */
addu r4, r16,0 /* ... user function userf. */
bsr _qt_error /* `only' erroniously returned. */
/*
** Varargs thread startup.
** See `m88k.h' for register use conventions.
**
** Call the `startup' function with just argument `pt'.
** Then call `vuserf' with 8 register args plus any
** stack args.
** Then call `cleanup' with `pt' and the return value
** from `vuserf'.
*/
_qt_vstart:
addu r18, r30,0 /* Remember arg7 to `vuserf'. */
addu r30, r0,0 /* Null-terminate call chain. */
jsr.n r17 /* Call `startup'. */
addu r2, r15,0 /* `pt' is arg0 to `startup'. */
addu r2, r19,0 /* Set arg0. */
addu r3, r20,0 /* Set arg1. */
addu r4, r21,0 /* Set arg2. */
addu r5, r22,0 /* Set arg3. */
addu r6, r23,0 /* Set arg4. */
addu r7, r24,0 /* Set arg5. */
addu r8, r25,0 /* Set arg6. */
jsr.n r16 /* Call `vuserf'. */
addu r9, r18,0 /* Set arg7. */
addu r3, r2,0 /* Ret. value is arg1 to `cleanup'. */
jsr.n r14 /* Call `cleanup'. */
addu r2, r15,0 /* `pt' is arg0 to `cleanup'. */
bsr _qt_error /* `cleanup' erroniously returned. */

View file

@ -1,117 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
.text
.globl _b_call_reg
.globl _b_call_imm
.globl _b_add
.globl _b_load
_b_null:
jmp r1
_b_call_reg:
subu r31, r31,8 /* Alloc ret pc save space. */
st r1, r31,32 /* Save ret pc. */
or.u r3, r0,hi16(_b_null) /* Put call addr in a reg. */
or r3, r3,lo16(_b_null)
jsr r3
L0:
jsr r3
jsr r3
jsr r3
jsr.n r3
subu r2, r2,5 /* Decrement #of iter to go. */
bcnd.n gt0,r2,L0
jsr r3
ld r1, r31,32
jmp r1
_b_call_imm:
subu r31, r31,8 /* Alloc ret pc save space. */
st r1, r31,32 /* Save ret pc. */
bsr _b_null
L1:
bsr _b_null
bsr _b_null
bsr _b_null
bsr.n _b_null
subu r2, r2,5 /* Decrement #of iter to go. */
bcnd.n gt0,r2,L1
bsr _b_null
ld r1, r31,32
jmp r1
_b_add:
add r0, r3,r4
L2:
add r3, r4,r5
add r4, r5,r6
add r5, r6,r7
add r8, r9,r0
add r0, r3,r4
add r3, r4,r5
add r4, r5,r6
add r5, r6,r7
add r8, r9,r0
add r0, r3,r4
add r3, r4,r5
add r4, r5,r6
add r5, r6,r7
add r8, r9,r0
add r0, r3,r4
add r3, r4,r5
add r4, r5,r6
add r5, r6,r7
add r8, r9,r0
subu r2, r2,20 /* Decrement #of iter to go. */
bcnd.n gt0,r2,L2
add r0, r3,r4
jmp r1
_b_load:
ld r0, r31,0
L3:
ld r3, r31,4
ld r4, r31,8
ld r5, r31,12
ld r6, r31,16
ld r0, r31,0
ld r3, r31,4
ld r4, r31,8
ld r5, r31,12
ld r6, r31,16
ld r0, r31,0
ld r3, r31,4
ld r4, r31,8
ld r5, r31,12
ld r6, r31,16
ld r0, r31,0
ld r3, r31,4
ld r4, r31,8
ld r5, r31,12
ld r6, r31,16
subu r2, r2,20 /* Decrement #of iter to go. */
bcnd.n gt0,r2,L3
ld r0, r31,0
jmp r1

View file

@ -1,182 +0,0 @@
/* mips.s -- assembly support. */
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
/* Callee-save $16-$23, $30-$31.
*
* $25 is used as a procedure value pointer, used to discover constants
* in a callee. Thus, each caller here sets $25 before the call.
*
* On startup, restore regs so retpc === call to a function to start.
* We're going to call a function ($4) from within this routine.
* We're passing 3 args, therefore need to allocate 12 extra bytes on
* the stack for a save area. The start routine needs a like 16-byte
* save area. Must be doubleword aligned (_mips r3000 risc
* architecture_, gerry kane, pg d-23).
*/
/*
* Modified by Assar Westerlund <assar@sics.se> to support Irix 5.x
* calling conventions for dynamically-linked code.
*/
/* Make this position-independent code. */
.option pic2
.globl qt_block
.globl qt_blocki
.globl qt_abort
.globl qt_start
.globl qt_vstart
/*
** $4: ptr to function to call once curr is suspended
** and control is on $7's stack.
** $5: 1'th arg to $4.
** $6: 2'th arg to $4
** $7: sp of thread to suspend.
**
** Totally gross hack: The MIPS calling convention reserves
** 4 words on the stack for a0..a3. This routine "ought" to
** allocate space for callee-save registers plus 4 words for
** the helper function, but instead we use the 4 words
** provided by the function that called us (we don't need to
** save our argument registers). So what *appears* to be
** allocating only 40 bytes is actually allocating 56, by
** using the caller's 16 bytes.
**
** The helper routine returns a value that is passed on as the
** return value from the blocking routine. Since we don't
** touch $2 between the helper's return and the end of
** function, we get this behavior for free.
*/
qt_blocki:
sub $sp,$sp,40 /* Allocate reg save space. */
sw $16, 0+16($sp)
sw $17, 4+16($sp)
sw $18, 8+16($sp)
sw $19,12+16($sp)
sw $20,16+16($sp)
sw $21,20+16($sp)
sw $22,24+16($sp)
sw $23,28+16($sp)
sw $30,32+16($sp)
sw $31,36+16($sp)
add $2, $sp,$0 /* $2 <= old sp to pass to func@$4. */
qt_abort:
add $sp, $7,$0 /* $sp <= new sp. */
.set noreorder
add $25, $4,$0 /* Set helper function procedure value. */
jal $31,$25 /* Call helper func@$4 . */
add $4, $2,$0 /* $a0 <= pass old sp as a parameter. */
.set reorder
lw $31,36+16($sp) /* Restore callee-save regs... */
lw $30,32+16($sp)
lw $23,28+16($sp)
lw $22,24+16($sp)
lw $21,20+16($sp)
lw $20,16+16($sp)
lw $19,12+16($sp)
lw $18, 8+16($sp)
lw $17, 4+16($sp)
lw $16, 0+16($sp) /* Restore callee-save */
add $sp,$sp,40 /* Deallocate reg save space. */
j $31 /* Return to caller. */
/*
** Non-varargs thread startup.
** Note: originally, 56 bytes were allocated on the stack.
** The thread restore routine (_blocki/_abort) removed 40
** of them, which means there is still 16 bytes for the
** argument area required by the MIPS calling convention.
*/
qt_start:
add $4, $16,$0 /* Load up user function pu. */
add $5, $17,$0 /* ... user function pt. */
add $6, $18,$0 /* ... user function userf. */
add $25, $19,$0 /* Set `only' procedure value. */
jal $31,$25 /* Call `only'. */
la $25,qt_error /* Set `qt_error' procedure value. */
j $25
/*
** Save calle-save floating-point regs $f20-$f30
** See comment in `qt_block' about calling conventinos and
** reserved space. Use the same trick here, but here we
** actually have to allocate all the bytes since we have to
** leave 4 words leftover for `qt_blocki'.
**
** Return value from `qt_block' is the same as the return from
** `qt_blocki'. We get that for free since we don't touch $2
** between the return from `qt_blocki' and the return from
** `qt_block'.
*/
qt_block:
sub $sp, $sp,56 /* 6 8-byte regs, saved ret pc, aligned. */
swc1 $f20, 0+16($sp)
swc1 $f22, 8+16($sp)
swc1 $f24, 16+16($sp)
swc1 $f26, 24+16($sp)
swc1 $f28, 32+16($sp)
swc1 $f30, 40+16($sp)
sw $31, 48+16($sp)
jal qt_blocki
lwc1 $f20, 0+16($sp)
lwc1 $f22, 8+16($sp)
lwc1 $f24, 16+16($sp)
lwc1 $f26, 24+16($sp)
lwc1 $f28, 32+16($sp)
lwc1 $f30, 40+16($sp)
lw $31, 48+16($sp)
add $sp, $sp,56
j $31
/*
** First, call `startup' with the `pt' argument.
**
** Next, call the user's function with all arguments.
** Note that we don't know whether args were passed in
** integer regs, fp regs, or on the stack (See Gerry Kane
** "MIPS R2000 RISC Architecture" pg D-22), so we reload
** all the registers, possibly with garbage arguments.
**
** Finally, call `cleanup' with the `pt' argument and with
** the return value from the user's function. It is an error
** for `cleanup' to return.
*/
qt_vstart:
add $4, $17,$0 /* `pt' is arg0 to `startup'. */
add $25, $18,$0 /* Set `startup' procedure value. */
jal $31, $25 /* Call `startup'. */
add $sp, $sp,16 /* Free extra save space. */
lw $4, 0($sp) /* Load up args. */
lw $5, 4($sp)
lw $6, 8($sp)
lw $7, 12($sp)
lwc1 $f12, 0($sp) /* Load up fp args. */
lwc1 $f14, 8($sp)
add $25, $19,$0 /* Set `userf' procedure value. */
jal $31,$25 /* Call `userf'. */
add $4, $17,$0 /* `pt' is arg0 to `cleanup'. */
add $5, $2,$0 /* Ret. val is arg1 to `cleanup'. */
add $25, $16,$0 /* Set `cleanup' procedure value. */
jal $31, $25 /* Call `cleanup'. */
la $25,qt_error /* Set `qt_error' procedure value. */
j $25

View file

@ -1,134 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
#ifndef QT_MIPS_H
#define QT_MIPS_H
typedef unsigned long qt_word_t;
#define QT_GROW_DOWN
/* Stack layout on the mips:
Callee-save registers are: $16-$23, $30; $f20-$f30.
Also save $31, return pc.
Non-varargs:
+---
| $f30 The first clump is only saved if `qt_block'
| $f28 is called, in which case it saves the fp regs
| $f26 then calls `qt_blocki' to save the int regs.
| $f24
| $f22
| $f20
| $31 === return pc in `qt_block'
+---
| $31 === return pc; on startup == qt_start
| $30
| $23
| $22
| $21
| $20
| $19 on startup === only
| $18 on startup === $a2 === userf
| $17 on startup === $a1 === pt
| $16 on startup === $a0 === pu
| <a3> save area req'd by MIPS calling convention
| <a2> save area req'd by MIPS calling convention
| <a1> save area req'd by MIPS calling convention
| <a0> save area req'd by MIPS calling convention <--- sp
+---
Conventions for varargs:
| args ...
+---
| :
| :
| $21
| $20
| $19 on startup === `userf'
| $18 on startup === `startup'
| $17 on startup === `pt'
| $16 on startup === `cleanup'
| <a3>
| <a2>
| <a1>
| <a0> <--- sp
+---
Note: if we wanted to, we could muck about and try to get the 4
argument registers loaded in to, e.g., $22, $23, $30, and $31,
and the return pc in, say, $20. Then, the first 4 args would
not need to be loaded from memory, they could just use
register-to-register copies. */
/* Stack must be doubleword aligned. */
#define QT_STKALIGN (8) /* Doubleword aligned. */
/* How much space is allocated to hold all the crud for
initialization: $16-$23, $30, $31. Just do an integer restore,
no need to restore floating-point. Four words are needed for the
argument save area for the helper function that will be called for
the old thread, just before the new thread starts to run. */
#define QT_STKBASE (14 * 4)
#define QT_VSTKBASE QT_STKBASE
/* Offsets of various registers. */
#define QT_31 (9+4)
#define QT_19 (3+4)
#define QT_18 (2+4)
#define QT_17 (1+4)
#define QT_16 (0+4)
/* When a never-before-run thread is restored, the return pc points
to a fragment of code that starts the thread running. For
non-vargs functions, it just calls the client's `only' function.
For varargs functions, it calls the startup, user, and cleanup
functions.
The varargs startup routine always reads 4 words of arguments from
the stack. If there are less than 4 words of arguments, then the
startup routine can read off the top of the stack. To prevent
errors we always allocate 4 words. If there are more than 3 words
of arguments, the 4 preallocated words are simply wasted. */
extern void qt_start(void);
#define QT_ARGS_MD(sp) (QT_SPUT (sp, QT_31, qt_start))
#define QT_VARGS_MD0(sp, vabytes) \
((qt_t *)(((char *)(sp)) - 4*4 - QT_STKROUNDUP(vabytes)))
extern void qt_vstart(void);
#define QT_VARGS_MD1(sp) (QT_SPUT (sp, QT_31, qt_vstart))
#define QT_VARGS_DEFAULT
/* The *index* (positive offset) of where to put each value. */
#define QT_ONLY_INDEX (QT_19)
#define QT_USER_INDEX (QT_18)
#define QT_ARGT_INDEX (QT_17)
#define QT_ARGU_INDEX (QT_16)
#define QT_VCLEANUP_INDEX (QT_16)
#define QT_VUSERF_INDEX (QT_19)
#define QT_VSTARTUP_INDEX (QT_18)
#define QT_VARGT_INDEX (QT_17)
#endif /* ndef QT_MIPS_H */

View file

@ -1,164 +0,0 @@
/* mips.s -- assembly support. */
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
/* Callee-save $16-$23, $30-$31.
*
* On startup, restore regs so retpc === call to a function to start.
* We're going to call a function ($4) from within this routine.
* We're passing 3 args, therefore need to allocate 12 extra bytes on
* the stack for a save area. The start routine needs a like 16-byte
* save area. Must be doubleword aligned (_mips r3000 risc
* architecture_, gerry kane, pg d-23).
*/
.globl qt_block
.globl qt_blocki
.globl qt_abort
.globl qt_start
.globl qt_vstart
/*
** $4: ptr to function to call once curr is suspended
** and control is on $7's stack.
** $5: 1'th arg to $4.
** $6: 2'th arg to $4
** $7: sp of thread to suspend.
**
** Totally gross hack: The MIPS calling convention reserves
** 4 words on the stack for a0..a3. This routine "ought" to
** allocate space for callee-save registers plus 4 words for
** the helper function, but instead we use the 4 words
** provided by the function that called us (we don't need to
** save our argument registers). So what *appears* to be
** allocating only 40 bytes is actually allocating 56, by
** using the caller's 16 bytes.
**
** The helper routine returns a value that is passed on as the
** return value from the blocking routine. Since we don't
** touch $2 between the helper's return and the end of
** function, we get this behavior for free.
*/
qt_blocki:
sub $sp,$sp,40 /* Allocate reg save space. */
sw $16, 0+16($sp)
sw $17, 4+16($sp)
sw $18, 8+16($sp)
sw $19,12+16($sp)
sw $20,16+16($sp)
sw $21,20+16($sp)
sw $22,24+16($sp)
sw $23,28+16($sp)
sw $30,32+16($sp)
sw $31,36+16($sp)
add $2, $sp,$0 /* $2 <= old sp to pass to func@$4. */
qt_abort:
add $sp, $7,$0 /* $sp <= new sp. */
.set noreorder
jal $31,$4 /* Call helper func@$4 . */
add $4, $2,$0 /* $a0 <= pass old sp as a parameter. */
.set reorder
lw $31,36+16($sp) /* Restore callee-save regs... */
lw $30,32+16($sp)
lw $23,28+16($sp)
lw $22,24+16($sp)
lw $21,20+16($sp)
lw $20,16+16($sp)
lw $19,12+16($sp)
lw $18, 8+16($sp)
lw $17, 4+16($sp)
lw $16, 0+16($sp) /* Restore callee-save */
add $sp,$sp,40 /* Deallocate reg save space. */
j $31 /* Return to caller. */
/*
** Non-varargs thread startup.
** Note: originally, 56 bytes were allocated on the stack.
** The thread restore routine (_blocki/_abort) removed 40
** of them, which means there is still 16 bytes for the
** argument area required by the MIPS calling convention.
*/
qt_start:
add $4, $16,$0 /* Load up user function pu. */
add $5, $17,$0 /* ... user function pt. */
add $6, $18,$0 /* ... user function userf. */
jal $31,$19 /* Call `only'. */
j qt_error
/*
** Save calle-save floating-point regs $f20-$f30
** See comment in `qt_block' about calling conventinos and
** reserved space. Use the same trick here, but here we
** actually have to allocate all the bytes since we have to
** leave 4 words leftover for `qt_blocki'.
**
** Return value from `qt_block' is the same as the return from
** `qt_blocki'. We get that for free since we don't touch $2
** between the return from `qt_blocki' and the return from
** `qt_block'.
*/
qt_block:
sub $sp, $sp,56 /* 6 8-byte regs, saved ret pc, aligned. */
swc1 $f20, 0+16($sp)
swc1 $f22, 8+16($sp)
swc1 $f24, 16+16($sp)
swc1 $f26, 24+16($sp)
swc1 $f28, 32+16($sp)
swc1 $f30, 40+16($sp)
sw $31, 48+16($sp)
jal qt_blocki
lwc1 $f20, 0+16($sp)
lwc1 $f22, 8+16($sp)
lwc1 $f24, 16+16($sp)
lwc1 $f26, 24+16($sp)
lwc1 $f28, 32+16($sp)
lwc1 $f30, 40+16($sp)
lw $31, 48+16($sp)
add $sp, $sp,56
j $31
/*
** First, call `startup' with the `pt' argument.
**
** Next, call the user's function with all arguments.
** Note that we don't know whether args were passed in
** integer regs, fp regs, or on the stack (See Gerry Kane
** "MIPS R2000 RISC Architecture" pg D-22), so we reload
** all the registers, possibly with garbage arguments.
**
** Finally, call `cleanup' with the `pt' argument and with
** the return value from the user's function. It is an error
** for `cleanup' to return.
*/
qt_vstart:
add $4, $17,$0 /* `pt' is arg0 to `startup'. */
jal $31, $18 /* Call `startup'. */
add $sp, $sp,16 /* Free extra save space. */
lw $4, 0($sp) /* Load up args. */
lw $5, 4($sp)
lw $6, 8($sp)
lw $7, 12($sp)
lwc1 $f12, 0($sp) /* Load up fp args. */
lwc1 $f14, 8($sp)
jal $31,$19 /* Call `userf'. */
add $4, $17,$0 /* `pt' is arg0 to `cleanup'. */
add $5, $2,$0 /* Ret. val is arg1 to `cleanup'. */
jal $31, $16 /* Call `cleanup'. */
j qt_error

View file

@ -1,99 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
.globl b_call_reg
.globl b_call_imm
.globl b_add
.globl b_load
.ent b_null
b_null:
j $31
.end b_null
.ent b_call_reg
b_call_reg:
la $5,b_null
add $6, $31,0
$L0:
jal $5
jal $5
jal $5
jal $5
jal $5
sub $4, $4,5
bgtz $4,$L0
j $6
.end
.ent b_call_imm
b_call_imm:
add $6, $31,0
$L1:
jal b_null
jal b_null
jal b_null
jal b_null
jal b_null
sub $4, $4,5
bgtz $4,$L1
j $6
.end
.ent b_add
b_add:
add $5, $0,$4
add $6, $0,$4
add $7, $0,$4
add $8, $0,$4
$L2:
sub $4, $4,5
sub $5, $5,5
sub $6, $6,5
sub $7, $7,5
sub $8, $8,5
sub $4, $4,5
sub $5, $5,5
sub $6, $6,5
sub $7, $7,5
sub $8, $8,5
bgtz $4,$L2
j $31
.end
.ent b_load
b_load:
$L3:
ld $0, 0($sp)
ld $0, 4($sp)
ld $0, 8($sp)
ld $0, 12($sp)
ld $0, 16($sp)
ld $0, 20($sp)
ld $0, 24($sp)
ld $0, 28($sp)
ld $0, 32($sp)
ld $0, 36($sp)
sub $4, $4,10
bgtz $4,$L3
j $31
.end

View file

View file

@ -1,14 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
char const qtmd_rcsid[] = "$Header: /home/ludo/src/guile.cvs/gitification/guile-cvs/guile/guile-core/qt/md/null.c,v 1.1 1996-10-01 03:34:16 mdj Exp $";

View file

@ -1,19 +0,0 @@
Solaris 2.x is like System V (maybe it *is* System V?) and is different
from older versions in that it uses no leading underscore for variable
and function names. That is, the old convention was:
foo(){}
got compiled as
.globl _foo
_foo:
and is now compiled as
.globl foo
foo:
The `config' script should fix up the older (leading underscore) versions
of the machine-dependent files to use the newer (no leading underscore)
calling conventions.

View file

@ -1,140 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
#ifndef QT_SPARC_H
#define QT_SPARC_H
typedef unsigned long qt_word_t;
/* Stack layout on the sparc:
non-varargs:
+---
| <blank space for alignment>
| %o7 == return address -> qt_start
| %i7
| %i6 == frame pointer -> 0 (NULL-terminated stack frame chain)
| %i5 -> only
| %i4 -> userf
| %i3
| %i2 -> pt
| %i1 -> pu
| %i0
| %l7
| %l6
| %l5
| %l4
| %l3
| %l2
| %l1
| %l0 <--- qt_t.sp
+---
varargs:
| :
| :
| argument list
| one-word aggregate return pointer
+---
| <blank space for alignment>
| %o7 == return address -> qt_vstart
| %i7
| %i6 == frame pointer -> 0 (NULL-terminated stack frame chain)
| %i5 -> startup
| %i4 -> userf
| %i3 -> cleanup
| %i2 -> pt
| %i1
| %i0
| %l7
| %l6
| %l5
| %l4
| %l3
| %l2
| %l1
| %l0 <--- qt_t.sp
+---
*/
/* What to do to start a thread running. */
extern void qt_start (void);
extern void qt_vstart (void);
/* Hold 17 saved registers + 1 word for alignment. */
#define QT_STKBASE (18 * 4)
#define QT_VSTKBASE QT_STKBASE
/* Stack must be doubleword aligned. */
#define QT_STKALIGN (8) /* Doubleword aligned. */
#define QT_ONLY_INDEX (QT_I5)
#define QT_USER_INDEX (QT_I4)
#define QT_ARGT_INDEX (QT_I2)
#define QT_ARGU_INDEX (QT_I1)
#define QT_VSTARTUP_INDEX (QT_I5)
#define QT_VUSERF_INDEX (QT_I4)
#define QT_VCLEANUP_INDEX (QT_I3)
#define QT_VARGT_INDEX (QT_I2)
#define QT_O7 (16)
#define QT_I6 (14)
#define QT_I5 (13)
#define QT_I4 (12)
#define QT_I3 (11)
#define QT_I2 (10)
#define QT_I1 ( 9)
/* The thread will ``return'' to the `qt_start' routine to get things
going. The normal return sequence takes us to QT_O7+8, so we
pre-subtract 8. The frame pointer chain is 0-terminated to prevent
the trap handler from chasing off in to random memory when flushing
stack windows. */
#define QT_ARGS_MD(top) \
(QT_SPUT ((top), QT_O7, ((void *)(((int)qt_start)-8))), \
QT_SPUT ((top), QT_I6, 0))
/* The varargs startup routine always reads 6 words of arguments
(6 argument registers) from the stack, offset by one word to
allow for an aggregate return area pointer. If the varargs
routine actually pushed fewer words than that, qt_vstart could read
off the top of the stack. To prevent errors, we always allocate 8
words. The space is often just wasted. */
#define QT_VARGS_MD0(sp, vabytes) \
((qt_t *)(((char *)(sp)) - 8*4 - QT_STKROUNDUP(vabytes)))
#define QT_VARGS_MD1(sp) \
(QT_SPUT (sp, QT_O7, ((void *)(((int)qt_vstart)-8))))
/* The SPARC has wierdo calling conventions which stores a hidden
parameter for returning aggregate values, so the rest of the
parameters are shoved up the stack by one place. */
#define QT_VARGS_ADJUST(sp) (((char *)sp)+4)
#define QT_VARGS_DEFAULT
#define QT_GROW_DOWN
#endif /* ndef QT_SPARC_H */

View file

@ -1,142 +0,0 @@
/* sparc.s -- assembly support for the `qt' thread building kit. */
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
/* #include <machine/trap.h> */
.text
.align 4
.global qt_blocki
.global qt_block
.global qt_abort
.global qt_start
.global qt_vstart
/* Register assignment:
// %o0: incoming `helper' function to call after cswap
// also used as outgoing sp of old thread (qt_t *)
// %o1, %o2:
// parameters to `helper' function called after cswap
// %o3: sp of new thread
// %o5: tmp used to save old thread sp, while using %o0
// to call `helper' f() after cswap.
//
//
// Aborting a thread is easy if there are no cached register window
// frames: just switch to the new stack and away we go. If there are
// cached register window frames they must all be written back to the
// old stack before we move to the new stack. If we fail to do the
// writeback then the old stack memory can be written with register
// window contents e.g., after the stack memory has been freed and
// reused.
//
// If you don't believe this, try setting the frame pointer to zero
// once we're on the new stack. This will not affect correctnes
// otherwise because the frame pointer will eventually get reloaded w/
// the new thread's frame pointer. But it will be zero briefly before
// the reload. You will eventually (100,000 cswaps later on a small
// SPARC machine that I tried) get an illegal instruction trap from
// the kernel trying to flush a cached window to location 0x0.
//
// Solution: flush windows before switching stacks, which invalidates
// all the other register windows. We could do the trap
// conditionally: if we're in the lowest frame of a thread, the fp is
// zero already so we know there's nothing cached. But we expect most
// aborts will be done from a first function that does a `save', so we
// will rarely save anything and always pay the cost of testing to see
// if we should flush.
//
// All floating-point registers are caller-save, so this routine
// doesn't need to do anything to save and restore them.
//
// `qt_block' and `qt_blocki' return the same value as the value
// returned by the helper function. We get this ``for free''
// since we don't touch the return value register between the
// return from the helper function and return from qt_block{,i}.
*/
qt_block:
qt_blocki:
sub %sp, 8, %sp /* Allocate save area for return pc. */
st %o7, [%sp+64] /* Save return pc. */
qt_abort:
ta 0x03 /* Save locals and ins. */
mov %sp, %o5 /* Remember old sp w/o chng ins/locals. */
sub %o3, 64, %sp /* Allocate kwsa, switch stacks. */
call %o0, 0 /* Call `helper' routine. */
mov %o5, %o0 /* Pass old thread to qt_after_t() */
/* .. along w/ args in %o1 & %o2. */
/* Restore callee-save regs. The kwsa
// is on this stack, so offset all
// loads by sizeof(kwsa), 64 bytes.
*/
ldd [%sp+ 0+64], %l0
ldd [%sp+ 8+64], %l2
ldd [%sp+16+64], %l4
ldd [%sp+24+64], %l6
ldd [%sp+32+64], %i0
ldd [%sp+40+64], %i2
ldd [%sp+48+64], %i4
ldd [%sp+56+64], %i6
ld [%sp+64+64], %o7 /* Restore return pc. */
retl /* Return to address in %o7. */
add %sp, 72, %sp /* Deallocate kwsa, ret pc area. */
/* The function calling conventions say there has to be a 1-word area
// in the caller's stack to hold a pointer to space for aggregate
// return values. It also says there should be a 6-word area to hold
// %o0..%o5 if the callee wants to save them (why? I don't know...)
// Round up to 8 words to maintain alignment.
//
// Parameter values were stored in callee-save regs and are moved to
// the parameter registers.
*/
qt_start:
mov %i1, %o0 /* `pu': Set up args to `only'. */
mov %i2, %o1 /* `pt'. */
mov %i4, %o2 /* `userf'. */
call %i5, 0 /* Call client function. */
sub %sp, 32, %sp /* Allocate 6-word callee space. */
call qt_error, 0 /* `only' erroniously returned. */
nop
/* Same comments as `qt_start' about allocating rounded-up 7-word
// save areas. */
qt_vstart:
sub %sp, 32, %sp /* Allocate 7-word callee space. */
call %i5, 0 /* call `startup'. */
mov %i2, %o0 /* .. with argument `pt'. */
add %sp, 32, %sp /* Use 7-word space in varargs. */
ld [%sp+ 4+64], %o0 /* Load arg0 ... */
ld [%sp+ 8+64], %o1
ld [%sp+12+64], %o2
ld [%sp+16+64], %o3
ld [%sp+20+64], %o4
call %i4, 0 /* Call `userf'. */
ld [%sp+24+64], %o5
/* Use 6-word space in varargs. */
mov %o0, %o1 /* Pass return value from userf */
call %i3, 0 /* .. when call `cleanup. */
mov %i2, %o0 /* .. along with argument `pt'. */
call qt_error, 0 /* `cleanup' erroniously returned. */
nop

View file

@ -1,106 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
.globl b_call_reg
.globl b_call_imm
.globl b_add
.globl b_load
b_null:
retl
nop
b_call_reg:
sethi %hi(b_null),%o4
or %o4,%lo(b_null),%o4
add %o7,%g0, %o3
L0:
call %o4
nop
call %o4
nop
call %o4
nop
call %o4
nop
call %o4
nop
subcc %o0,1,%o0
bg L0
nop
add %o3,%g0, %o7
retl
nop
b_call_imm:
sethi %hi(b_null),%o4
or %o4,%lo(b_null),%o4
add %o7,%g0, %o3
L1:
call b_null
call b_null
call b_null
call b_null
call b_null
subcc %o0,1,%o0
bg L0
nop
add %o3,%g0, %o7
retl
nop
b_add:
add %o0,%g0,%o1
add %o0,%g0,%o2
add %o0,%g0,%o3
add %o0,%g0,%o4
L2:
sub %o0,5,%o0
sub %o1,5,%o1
sub %o2,5,%o2
sub %o3,5,%o3
sub %o4,5,%o4
subcc %o0,5,%o0
sub %o1,5,%o1
sub %o2,5,%o2
sub %o3,5,%o3
sub %o4,5,%o4
bg L2
nop
retl
nop
b_load:
ld [%sp+ 0], %g0
L3:
ld [%sp+ 4],%g0
ld [%sp+ 8],%g0
ld [%sp+12],%g0
ld [%sp+16],%g0
ld [%sp+20],%g0
ld [%sp+24],%g0
ld [%sp+28],%g0
ld [%sp+32],%g0
ld [%sp+36],%g0
subcc %o0,10,%o0
bg L3
ld [%sp+ 0],%g0
retl
nop

View file

@ -1,130 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
#ifndef QT_VAX_H
#define QT_VAX_H
typedef unsigned long qt_word_t;
/* Thread's initial stack layout on the VAX:
non-varargs:
+---
| arg[2] === `userf' on startup
| arg[1] === `pt' on startup
| arg[0] === `pu' on startup
| ... === `only' on startup.
+---
| ret pc === `qt_start' on startup
| fp === 0 on startup
| ap === 0 on startup
| <mask>
| 0 (handler) <--- qt_t.sp
+---
When a non-varargs thread is started, it ``returns'' to the start
routine, which calls the client's `only' function.
The varargs case is clearly bad code. The various values should be
stored in a save area and snarfed in to callee-save registers on
startup. However, it's too painful to figure out the register
mask (right now), so do it the slow way.
+---
| arg[n-1]
| ..
| arg[0]
| nargs
+---
| === `cleanup'
| === `vuserf'
| === `startup'
| === `pt'
+---
| ret pc === `qt_start' on startup
| fp === 0 on startup
| ap === 0 on startup
| <mask>
| 0 (handler) <--- qt_t.sp
+---
When a varargs thread is started, it ``returns'' to the `qt_vstart'
startup code. The startup code pops all the extra arguments, then
calls the appropriate functions. */
/* What to do to start a thread running. */
extern void qt_start (void);
extern void qt_vstart (void);
/* Initial call frame for non-varargs and varargs cases. */
#define QT_STKBASE (10 * 4)
#define QT_VSTKBASE (9 * 4)
/* Stack "must be" 4-byte aligned. (Actually, no, but it's
easiest and probably fastest to do so.) */
#define QT_STKALIGN (4)
/* Where to place various arguments. */
#define QT_ONLY_INDEX (5)
#define QT_USER_INDEX (8)
#define QT_ARGT_INDEX (7)
#define QT_ARGU_INDEX (6)
#define QT_VSTARTUP_INDEX (6)
#define QT_VUSERF_INDEX (7)
#define QT_VCLEANUP_INDEX (8)
#define QT_VARGT_INDEX (5)
/* Stack grows down. The top of the stack is the first thing to
pop off (predecrement, postincrement). */
#define QT_GROW_DOWN
extern void qt_error (void);
#define QT_VAX_GMASK_NOREGS (0)
/* Push on the error return address, null termination to call chains,
number of arguments to `only', register save mask (save no
registers). */
#define QT_ARGS_MD(sto) \
(QT_SPUT (sto, 0, 0), \
QT_SPUT (sto, 1, QT_VAX_GMASK_NOREGS), \
QT_SPUT (sto, 2, 0), \
QT_SPUT (sto, 3, 0), \
QT_SPUT (sto, 4, qt_start))
#define QT_VARGS_MD0(sto, nbytes) \
(QT_SPUT (sto, (-(nbytes)/4)-1, (nbytes)/4), \
((char *)(((sto)-4) - QT_STKROUNDUP(nbytes))))
#define QT_VARGS_ADJUST(sp) ((char *)sp + 4)
#define QT_VARGS_MD1(sto) \
(QT_SPUT (sto, 0, 0), \
QT_SPUT (sto, 1, QT_VAX_GMASK_NOREGS), \
QT_SPUT (sto, 2, 0), \
QT_SPUT (sto, 3, 0), \
QT_SPUT (sto, 4, qt_vstart))
#define QT_VARGS_DEFAULT
#endif /* QT_VAX_H */

View file

@ -1,69 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
.text
.globl _qt_abort
.globl _qt_block
.globl _qt_blocki
.globl _qt_start
.globl _qt_vstart
/*
// Calls to these routines have the signature
//
// void *block (func, arg1, arg2, newsp)
//
// Since the prologue saves 5 registers, nargs, pc, fp, ap, mask, and
// a condition handler (at sp+0), the first argument is 40=4*10 bytes
// offset from the stack pointer.
*/
_qt_block:
_qt_blocki:
_qt_abort:
.word 0x7c0 /* Callee-save mask: 5 registers. */
movl 56(sp),r1 /* Get stack pointer of new thread. */
movl 52(sp),-(r1) /* Push arg2 */
movl 48(sp),-(r1) /* Push arg1 */
movl sp,-(r1) /* Push arg0 */
movl 44(sp),r0 /* Get helper to call. */
movl r1,sp /* Move to new thread's stack. */
addl3 sp,$12,fp /* .. including the frame pointer. */
calls $3,(r0) /* Call helper. */
ret
_qt_start:
movl (sp)+,r0 /* Get `only'. */
calls $3,(r0) /* Call `only'. */
calls $0,_qt_error /* `only' erroniously returned. */
_qt_vstart:
movl (sp)+,r10 /* Get `pt'. */
movl (sp)+,r9 /* Get `startup'. */
movl (sp)+,r8 /* Get `vuserf'. */
movl (sp)+,r7 /* Get `cleanup'. */
pushl r10 /* Push `qt'. */
calls $1,(r9) /* Call `startup', pop `qt' on return. */
calls (sp)+,(r8) /* Call user's function. */
pushl r0 /* Push `vuserf_retval'. */
pushl r10 /* Push `qt'. */
calls $2,(r7) /* Call `cleanup', never return. */
calls $0,_qt_error /* `cleanup' erroniously returned. */

View file

@ -1,92 +0,0 @@
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
.text
.globl _b_call_reg
.globl _b_call_imm
.globl _b_add
.globl _b_load
_b_null:
.word 0x0
ret
_b_call_reg:
.word 0x0
movl 4(ap),r0
moval _b_null,r1
L0:
calls $0,(r1)
calls $0,(r1)
calls $0,(r1)
calls $0,(r1)
calls $0,(r1)
subl2 $5,r0
bgtr L0
ret
_b_call_imm:
.word 0x0
movl 4(ap),r0
L1:
calls $0,_b_null
calls $0,_b_null
calls $0,_b_null
calls $0,_b_null
calls $0,_b_null
subl2 $5,r0
bgtr L1
ret
_b_add:
.word 0x0
movl 4(ap),r0
L2:
subl2 $1,r0
subl2 $1,r0
subl2 $1,r0
subl2 $1,r0
subl2 $1,r0
subl2 $1,r0
subl2 $1,r0
subl2 $1,r0
subl2 $1,r0
subl2 $1,r0
bgtr L2
ret
_b_load:
.word 0x0
movl 4(ap),r0
L3:
movl 0(sp),r1
movl 4(sp),r1
movl 8(sp),r1
movl 12(sp),r1
movl 16(sp),r1
movl 20(sp),r1
movl 24(sp),r1
movl 28(sp),r1
movl 32(sp),r1
movl 36(sp),r1
subl2 $1,r0
bgtr L3
ret

1049
qt/meas.c

File diff suppressed because it is too large Load diff

48
qt/qt.c
View file

@ -1,48 +0,0 @@
#include "qt/copyright.h"
#include "qt/qt.h"
#ifdef QT_VARGS_DEFAULT
/* If the stack grows down, `vargs' is a pointer to the lowest
address in the block of arguments. If the stack grows up, it is a
pointer to the highest address in the block. */
qt_t *
qt_vargs (qt_t *sp, int nbytes, void *vargs,
void *pt, qt_startup_t *startup,
qt_vuserf_t *vuserf, qt_cleanup_t *cleanup)
{
int i;
sp = QT_VARGS_MD0 (sp, nbytes);
#ifdef QT_GROW_UP
for (i=nbytes/sizeof(qt_word_t); i>0; --i) {
QT_SPUT (QT_VARGS_ADJUST(sp), i, ((qt_word_t *)vargs)[-i]);
}
#else
for (i=nbytes/sizeof(qt_word_t); i>0; --i) {
QT_SPUT (QT_VARGS_ADJUST(sp), i-1, ((qt_word_t *)vargs)[i-1]);
}
#endif
QT_VARGS_MD1 (QT_VADJ(sp));
QT_SPUT (QT_VADJ(sp), QT_VARGT_INDEX, pt);
QT_SPUT (QT_VADJ(sp), QT_VSTARTUP_INDEX, startup);
QT_SPUT (QT_VADJ(sp), QT_VUSERF_INDEX, vuserf);
QT_SPUT (QT_VADJ(sp), QT_VCLEANUP_INDEX, cleanup);
return ((qt_t *)QT_VADJ(sp));
}
#endif /* def QT_VARGS_DEFAULT */
void
qt_null (void)
{
}
void
qt_error (void)
{
extern void abort(void);
abort();
}

View file

@ -1,186 +0,0 @@
#ifndef QT_H
#define QT_H
#if defined (QT_IMPORT)
# define QT_API __declspec (dllimport) extern
#elif defined (QT_EXPORT) || defined (DLL_EXPORT)
# define QT_API __declspec (dllexport) extern
#else
# define QT_API extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <qt/@qtmd_h@>
/* A QuickThreads thread is represented by it's current stack pointer.
To restart a thread, you merely need pass the current sp (qt_t*) to
a QuickThreads primitive. `qt_t*' is a location on the stack. To
improve type checking, represent it by a particular struct. */
typedef struct qt_t {
char dummy;
} qt_t;
/* Alignment is guaranteed to be a power of two. */
#ifndef QT_STKALIGN
#error "Need to know the machine-dependent stack alignment."
#endif
#define QT_STKROUNDUP(bytes) \
(((bytes)+QT_STKALIGN) & ~(QT_STKALIGN-1))
/* Find ``top'' of the stack, space on the stack. */
#ifndef QT_SP
#ifdef QT_GROW_DOWN
#define QT_SP(sto, size) ((qt_t *)(&((char *)(sto))[(size)]))
#endif
#ifdef QT_GROW_UP
#define QT_SP(sto, size) ((void *)(sto))
#endif
#if !defined(QT_SP)
#error "QT_H: Stack must grow up or down!"
#endif
#endif
/* The type of the user function:
For non-varargs, takes one void* function.
For varargs, takes some number of arguments. */
typedef void *(qt_userf_t)(void *pu);
typedef void *(qt_vuserf_t)(int arg0, ...);
/* For non-varargs, just call a client-supplied function,
it does all startup and cleanup, and also calls the user's
function. */
typedef void (qt_only_t)(void *pu, void *pt, qt_userf_t *userf);
/* For varargs, call `startup', then call the user's function,
then call `cleanup'. */
typedef void (qt_startup_t)(void *pt);
typedef void (qt_cleanup_t)(void *pt, void *vuserf_return);
/* Internal helper for putting stuff on stack. */
#ifndef QT_SPUT
#define QT_SPUT(top, at, val) \
(((qt_word_t *)(top))[(at)] = (qt_word_t)(val))
#endif
/* Push arguments for the non-varargs case. */
#ifndef QT_ARGS
#ifndef QT_ARGS_MD
#define QT_ARGS_MD (0)
#endif
#ifndef QT_STKBASE
#error "Need to know the machine-dependent stack allocation."
#endif
/* All things are put on the stack relative to the final value of
the stack pointer. */
#ifdef QT_GROW_DOWN
#define QT_ADJ(sp) (((char *)sp) - QT_STKBASE)
#else
#define QT_ADJ(sp) (((char *)sp) + QT_STKBASE)
#endif
#define QT_ARGS(sp, pu, pt, userf, only) \
(QT_ARGS_MD (QT_ADJ(sp)), \
QT_SPUT (QT_ADJ(sp), QT_ONLY_INDEX, only), \
QT_SPUT (QT_ADJ(sp), QT_USER_INDEX, userf), \
QT_SPUT (QT_ADJ(sp), QT_ARGT_INDEX, pt), \
QT_SPUT (QT_ADJ(sp), QT_ARGU_INDEX, pu), \
((qt_t *)QT_ADJ(sp)))
#endif
/* Push arguments for the varargs case.
Has to be a function call because initialization is an expression
and we need to loop to copy nbytes of stuff on to the stack.
But that's probably OK, it's not terribly cheap, anyway. */
#ifdef QT_VARGS_DEFAULT
#ifndef QT_VARGS_MD0
#define QT_VARGS_MD0(sp, vasize) (sp)
#endif
#ifndef QT_VARGS_MD1
#define QT_VARGS_MD1(sp) do { ; } while (0)
#endif
#ifndef QT_VSTKBASE
#error "Need base stack size for varargs functions."
#endif
/* Sometimes the stack pointer needs to munged a bit when storing
the list of arguments. */
#ifndef QT_VARGS_ADJUST
#define QT_VARGS_ADJUST(sp) (sp)
#endif
/* All things are put on the stack relative to the final value of
the stack pointer. */
#ifdef QT_GROW_DOWN
#define QT_VADJ(sp) (((char *)sp) - QT_VSTKBASE)
#else
#define QT_VADJ(sp) (((char *)sp) + QT_VSTKBASE)
#endif
QT_API qt_t *qt_vargs (qt_t *sp, int nbytes, void *vargs,
void *pt, qt_startup_t *startup,
qt_vuserf_t *vuserf, qt_cleanup_t *cleanup);
#ifndef QT_VARGS
#define QT_VARGS(sp, nbytes, vargs, pt, startup, vuserf, cleanup) \
(qt_vargs (sp, nbytes, vargs, pt, startup, vuserf, cleanup))
#endif
#endif
QT_API void qt_null (void);
QT_API void qt_error (void);
/* Save the state of the thread and call the helper function
using the stack of the new thread. */
typedef void *(qt_helper_t)(qt_t *old, void *a0, void *a1);
typedef void *(qt_block_t)(qt_helper_t *helper, void *a0, void *a1,
qt_t *newthread);
/* Rearrange the parameters so that things passed to the helper
function are already in the right argument registers. */
#ifndef QT_ABORT
QT_API void qt_abort (qt_helper_t *h, void *a0, void *a1, qt_t *newthread);
/* The following does, technically, `return' a value, but the
user had better not rely on it, since the function never
returns. */
#define QT_ABORT(h, a0, a1, newthread) \
do { qt_abort (h, a0, a1, newthread); } while (0)
#endif
#ifndef QT_BLOCK
QT_API void *qt_block (qt_helper_t *h, void *a0, void *a1,
qt_t *newthread);
#define QT_BLOCK(h, a0, a1, newthread) \
(qt_block (h, a0, a1, newthread))
#endif
#ifndef QT_BLOCKI
QT_API void *qt_blocki (qt_helper_t *h, void *a0, void *a1,
qt_t *newthread);
#define QT_BLOCKI(h, a0, a1, newthread) \
(qt_blocki (h, a0, a1, newthread))
#endif
#ifdef __cplusplus
} /* Match `extern "C" {' at top. */
#endif
#endif /* ndef QT_H */

199
qt/stp.c
View file

@ -1,199 +0,0 @@
#include "copyright.h"
#include "qt.h"
#include "stp.h"
#ifndef NULL
#define NULL 0
#endif
#define STP_STKSIZE (0x1000)
/* `alignment' must be a power of 2. */
#define STP_STKALIGN(sp, alignment) \
((void *)((((qt_word_t)(sp)) + (alignment) - 1) & ~((alignment)-1)))
/* The notion of a thread is merged with the notion of a queue.
Thread stuff: thread status (sp) and stuff to use during
(re)initialization. Queue stuff: next thread in the queue
(next). */
struct stp_t {
qt_t *sp; /* QuickThreads handle. */
void *sto; /* `malloc'-allocated stack. */
struct stp_t *next; /* Next thread in the queue. */
};
/* A queue is a circular list of threads. The queue head is a
designated list element. If this is a uniprocessor-only
implementation we can store the `main' thread in this, but in a
multiprocessor there are several `heavy' threads but only one run
queue. A fancier implementation might have private run queues,
which would lead to a simpler (trivial) implementation */
typedef struct stp_q_t {
stp_t t;
stp_t *tail;
} stp_q_t;
/* Helper functions. */
extern void *malloc (unsigned size);
extern void perror (char const *msg);
extern void free (void *sto);
void *
xmalloc (unsigned size)
{
void *sto;
sto = malloc (size);
if (!sto) {
perror ("malloc");
exit (1);
}
return (sto);
}
/* Queue access functions. */
static void
stp_qinit (stp_q_t *q)
{
q->t.next = q->tail = &q->t;
}
static stp_t *
stp_qget (stp_q_t *q)
{
stp_t *t;
t = q->t.next;
q->t.next = t->next;
if (t->next == &q->t) {
if (t == &q->t) { /* If it was already empty .. */
return (NULL); /* .. say so. */
}
q->tail = &q->t; /* Else now it is empty. */
}
return (t);
}
static void
stp_qput (stp_q_t *q, stp_t *t)
{
q->tail->next = t;
t->next = &q->t;
q->tail = t;
}
/* Thread routines. */
static stp_q_t stp_global_runq; /* A queue of runable threads. */
static stp_t stp_global_main; /* Thread for the process. */
static stp_t *stp_global_curr; /* Currently-executing thread. */
static void *stp_starthelp (qt_t *old, void *ignore0, void *ignore1);
static void stp_only (void *pu, void *pt, qt_userf_t *f);
static void *stp_aborthelp (qt_t *sp, void *old, void *null);
static void *stp_yieldhelp (qt_t *sp, void *old, void *blockq);
void
stp_init()
{
stp_qinit (&stp_global_runq);
}
void
stp_start()
{
stp_t *next;
while ((next = stp_qget (&stp_global_runq)) != NULL) {
stp_global_curr = next;
QT_BLOCK (stp_starthelp, 0, 0, next->sp);
}
}
static void *
stp_starthelp (qt_t *old, void *ignore0, void *ignore1)
{
stp_global_main.sp = old;
stp_qput (&stp_global_runq, &stp_global_main);
/* return (garbage); */
}
void
stp_create (stp_userf_t *f, void *pu)
{
stp_t *t;
void *sto;
t = xmalloc (sizeof(stp_t));
t->sto = xmalloc (STP_STKSIZE);
sto = STP_STKALIGN (t->sto, QT_STKALIGN);
t->sp = QT_SP (sto, STP_STKSIZE - QT_STKALIGN);
t->sp = QT_ARGS (t->sp, pu, t, (qt_userf_t *)f, stp_only);
stp_qput (&stp_global_runq, t);
}
static void
stp_only (void *pu, void *pt, qt_userf_t *f)
{
stp_global_curr = (stp_t *)pt;
(*(stp_userf_t *)f)(pu);
stp_abort();
/* NOTREACHED */
}
void
stp_abort (void)
{
stp_t *old, *newthread;
newthread = stp_qget (&stp_global_runq);
old = stp_global_curr;
stp_global_curr = newthread;
QT_ABORT (stp_aborthelp, old, (void *)NULL, newthread->sp);
}
static void *
stp_aborthelp (qt_t *sp, void *old, void *null)
{
free (((stp_t *)old)->sto);
free (old);
/* return (garbage); */
}
void
stp_yield()
{
stp_t *old, *newthread;
newthread = stp_qget (&stp_global_runq);
old = stp_global_curr;
stp_global_curr = newthread;
QT_BLOCK (stp_yieldhelp, old, &stp_global_runq, newthread->sp);
}
static void *
stp_yieldhelp (qt_t *sp, void *old, void *blockq)
{
((stp_t *)old)->sp = sp;
stp_qput ((stp_q_t *)blockq, (stp_t *)old);
/* return (garbage); */
}

View file

@ -1,51 +0,0 @@
#ifndef STP_H
#define STP_H
/*
* QuickThreads -- Threads-building toolkit.
* Copyright (c) 1993 by David Keppel
*
* Permission to use, copy, modify and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice and this notice
* appear in all copies. This software is provided as a
* proof-of-concept and for demonstration purposes; there is no
* representation about the suitability of this software for any
* purpose.
*/
typedef struct stp_t stp_t;
/* Each thread starts by calling a user-supplied function of this
type. */
typedef void (stp_userf_t)(void *p0);
/* Call this before any other primitives. */
extern void stp_init();
/* When one or more threads are created by the main thread,
the system goes multithread when this is called. It is done
(no more runable threads) when this returns. */
extern void stp_start (void);
/* Create a thread and make it runable. When the thread starts
running it will call `f' with the argument `p0'. */
extern void stp_create (stp_userf_t *f, void *p0);
/* The current thread stops running but stays runable.
It is an error to call `stp_yield' before `stp_start'
is called or after `stp_start' returns. */
extern void stp_yield (void);
/* Like `stp_yield' but the thread is discarded. Any intermediate
state is lost. The thread can also terminate by simply
returning. */
extern void stp_abort (void);
#endif /* ndef STP_H */

View file

@ -1,24 +0,0 @@
## Process this file with automake to produce Makefile.in.
##
## Copyright (C) 1998, 2006 Free Software Foundation, Inc.
##
## This file is part of GUILE.
##
## GUILE is free software; you can redistribute it and/or modify it
## under the terms of the GNU Lesser General Public License as
## published by the Free Software Foundation; either version 3, or
## (at your option) any later version.
##
## GUILE is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public
## License along with GUILE; see the file COPYING.LESSER. If not,
## write to the Free Software Foundation, Inc., 51 Franklin Street,
## Fifth Floor, Boston, MA 02110-1301 USA
AUTOMAKE_OPTIONS = gnu
EXTRA_DIST = README.time assim cswap go init prim raw

View file

@ -1,17 +0,0 @@
The program `raw', when run in `..' runs the program `run' produced
from `meas.c'. It produces a raw output file (see `../tmp/*.raw').
`raw' will die with an error if run in the current directory. Note
that some versions of `time' produce output in an unexpected format;
edit them by hand.
`prim', `init', `cswap' and `go' produce formatted table entries used
in the documentation (in `../doc'). For example, from `..',
foreach i (tmp/*.raw)
time/prim $i
end
See notes in the QuickThreads document about the applicability of
these microbenchmark measurements -- in general, you can expect all
QuickThreads operations to be a bit slower when used in a real
application.

View file

@ -1,42 +0,0 @@
#! /bin/awk -f
BEGIN {
nmach = 0;
init_test = "1";
abort_test = "6";
blocki_test = "7";
block_test = "8";
}
{
mach = $1
test = $2
iter = $3
time = $6 + $8
if (machi[mach] == 0) {
machn[nmach] = mach;
machi[mach] = 1;
++nmach;
}
us_per_op = time / iter * 1000000
times[mach "_" test] = us_per_op;
}
END {
for (i=0; i<nmach; ++i) {
m = machn[i];
init = times[m "_" init_test];
printf ("init %s | %f\n", m, init);
init_abort_blocki = times[m "_" abort_test];
abort_blocki = init_abort_blocki - init;
blocki = times[m "_" blocki_test];
abort = abort_blocki - blocki;
blockf = times[m "_" block_test];
printf ("swap %s | %f | %f | %f\n", m, abort, blocki, blockf);
}
}

View file

@ -1,37 +0,0 @@
#! /bin/awk -f
BEGIN {
purpose = "report time used by int only and int+fp cswaps";
nmach = 0;
test_int = "7";
test_fp = "8";
}
{
mach = $1
test = $2
iter = $3
time = $6 + $8
if (machi[mach] == 0) {
machn[nmach] = mach;
machi[mach] = 1;
++nmach;
}
us_per_op = time / iter * 1000000
times[mach "_" test] = us_per_op;
}
END {
for (i=0; i<nmach; ++i) {
m = machn[i];
integer = times[m "_" test_int];
fp = times[m "_" test_fp];
printf ("%s|%3.1f|%3.1f\n", m, integer, fp);
}
}

View file

@ -1,43 +0,0 @@
#! /bin/awk -f
BEGIN {
purpose = "report times used for init/start/stop";
nmach = 0;
test_single = "6";
test_v0 = "10";
test_v2 = "11";
test_v4 = "12";
test_v8 = "13";
}
{
mach = $1
test = $2
iter = $3
time = $6 + $8
if (machi[mach] == 0) {
machn[nmach] = mach;
machi[mach] = 1;
++nmach;
}
us_per_op = time / iter * 1000000
times[mach "_" test] = us_per_op;
}
END {
for (i=0; i<nmach; ++i) {
m = machn[i];
single = times[m "_" test_single];
v0 = times[m "_" test_v0];
v2 = times[m "_" test_v2];
v4 = times[m "_" test_v4];
v8 = times[m "_" test_v8];
printf ("%s|%3.1f|%3.1f|%3.1f|%3.1f|%3.1f\n", m, single, v0, v2, v4, v8);
}
}

View file

@ -1,42 +0,0 @@
#! /bin/awk -f
BEGIN {
purpose = "Report time used to initialize a thread."
nmach = 0;
test_single = "1";
test_v0 = "14";
test_v2 = "15";
test_v4 = "16";
test_v8 = "17";
}
{
mach = $1
test = $2
iter = $3
time = $6 + $8
if (machi[mach] == 0) {
machn[nmach] = mach;
machi[mach] = 1;
++nmach;
}
us_per_op = time / iter * 1000000
times[mach "_" test] = us_per_op;
}
END {
for (i=0; i<nmach; ++i) {
m = machn[i];
single = times[m "_" test_single];
v0 = times[m "_" test_v0];
v2 = times[m "_" test_v2];
v4 = times[m "_" test_v4];
v8 = times[m "_" test_v8];
printf ("%s|%3.1f|%3.1f|%3.1f|%3.1f|%3.1f\n", m, single, v0, v2, v4, v8);
}
}

View file

@ -1,41 +0,0 @@
#! /bin/awk -f
BEGIN {
purpose = "report times for microbenchmarks"
nmach = 0;
test_callind = "18";
test_callimm = "18";
test_addreg = "20";
test_loadreg = "21";
}
{
mach = $1
test = $2
iter = $3
time = $6 + $8
if (machi[mach] == 0) {
machn[nmach] = mach;
machi[mach] = 1;
++nmach;
}
ns_per_op = time / iter * 1000000
times[mach "_" test] = ns_per_op;
}
END {
for (i=0; i<nmach; ++i) {
m = machn[i];
ind = times[m "_" test_callind];
imm = times[m "_" test_callimm];
add = times[m "_" test_addreg];
load = times[m "_" test_loadreg];
printf ("%s|%1.3f|%1.3f|%1.3f|%1.3f\n", m, ind, imm, add, load);
}
}

View file

@ -1,58 +0,0 @@
#! /bin/csh
rm -f timed
set init=1
set runone=6
set blockint=7
set blockfloat=8
set vainit0=14
set vainit2=15
set vainit4=16
set vainit8=17
set vastart0=10
set vastart2=11
set vastart4=12
set vastart8=13
set bench_regcall=18
set bench_immcall=19
set bench_add=20
set bench_load=21
source configuration
echo -n $config_machine $init $config_init
/bin/time run $init $config_init
echo -n $config_machine $runone $config_runone
/bin/time run $runone $config_runone
echo -n $config_machine $blockint $config_blockint
/bin/time run $blockint $config_blockint
echo -n $config_machine $blockfloat $config_blockfloat
/bin/time run $blockfloat $config_blockfloat
echo -n $config_machine $vainit0 $config_vainit0
/bin/time run $vainit0 $config_vainit0
echo -n $config_machine $vainit2 $config_vainit2
/bin/time run $vainit2 $config_vainit2
echo -n $config_machine $vainit4 $config_vainit4
/bin/time run $vainit4 $config_vainit4
echo -n $config_machine $vainit8 $config_vainit8
/bin/time run $vainit8 $config_vainit8
echo -n $config_machine $vastart0 $config_vastart0
/bin/time run $vastart0 $config_vastart0
echo -n $config_machine $vastart2 $config_vastart2
/bin/time run $vastart2 $config_vastart2
echo -n $config_machine $vastart4 $config_vastart4
/bin/time run $vastart4 $config_vastart4
echo -n $config_machine $vastart8 $config_vastart8
/bin/time run $vastart8 $config_vastart8
echo -n $config_machine $bench_regcall $config_bcall_reg
/bin/time run $bench_regcall $config_bcall_reg
echo -n $config_machine $bench_immcall $config_bcall_imm
/bin/time run $bench_immcall $config_bcall_imm
echo -n $config_machine $bench_add $config_b_add
/bin/time run $bench_add $config_b_add
echo -n $config_machine $bench_load $config_b_load
/bin/time run $bench_load $config_b_load