* Makefile adapted to changes below.
* split pythonmain.c in two: most stuff goes to pythonrun.c, in the library.
* new optional built-in threadmodule.c, build upon Sjoerd's thread.{c,h}.
* new module from Sjoerd: mmmodule.c (dynamically loaded).
* new module from Sjoerd: sv (svgen.py, svmodule.c.proto).
* new files thread.{c,h} (from Sjoerd).
* new xxmodule.c (example only).
* myselect.h: bzero -> memset
* select.c: bzero -> memset; removed global variable
diff --git a/Include/pythread.h b/Include/pythread.h
new file mode 100644
index 0000000..91bac2a
--- /dev/null
+++ b/Include/pythread.h
@@ -0,0 +1,27 @@
+#ifndef _THREAD_H_included
+#define _THREAD_H_included
+
+#ifdef __STDC__
+#define _P(args)	args
+#else
+#define _P(args)	()
+#endif
+
+void init_thread _P((void));
+int start_new_thread _P((void (*)(void *), void *));
+void exit_thread _P((void));
+
+typedef void *type_lock;
+
+type_lock allocate_lock _P((void));
+void free_lock _P((type_lock));
+int acquire_lock _P((type_lock, int));
+#define WAIT_LOCK	1
+#define NOWAIT_LOCK	0
+void release_lock _P((type_lock));
+
+void exit_prog _P((int));
+
+#undef _P
+
+#endif
diff --git a/Include/thread.h b/Include/thread.h
new file mode 100644
index 0000000..91bac2a
--- /dev/null
+++ b/Include/thread.h
@@ -0,0 +1,27 @@
+#ifndef _THREAD_H_included
+#define _THREAD_H_included
+
+#ifdef __STDC__
+#define _P(args)	args
+#else
+#define _P(args)	()
+#endif
+
+void init_thread _P((void));
+int start_new_thread _P((void (*)(void *), void *));
+void exit_thread _P((void));
+
+typedef void *type_lock;
+
+type_lock allocate_lock _P((void));
+void free_lock _P((type_lock));
+int acquire_lock _P((type_lock, int));
+#define WAIT_LOCK	1
+#define NOWAIT_LOCK	0
+void release_lock _P((type_lock));
+
+void exit_prog _P((int));
+
+#undef _P
+
+#endif
diff --git a/Modules/config.c.in b/Modules/config.c.in
index 0973b77..8ed889a 100644
--- a/Modules/config.c.in
+++ b/Modules/config.c.in
@@ -123,6 +123,7 @@
 extern void initgrp();
 extern void initmarshal();
 extern void initselect();
+extern void initsocket();
 
 #ifdef USE_AUDIO
 extern void initaudio();
@@ -148,15 +149,15 @@
 #ifdef USE_STDWIN
 extern void initstdwin();
 #endif
-#ifdef USE_SOCKET
-extern void initsocket();
-#endif
 #ifdef USE_JPEG
 extern void initjpeg();
 #endif
 #ifdef USE_CD
 extern void initcd();
 #endif
+#ifdef USE_THREAD
+extern void initthread();
+#endif
 
 struct {
 	char *name;
@@ -173,6 +174,7 @@
 	{"grp",		initgrp},
 	{"marshal",	initmarshal},
 	{"select",	initselect},
+	{"socket",	initsocket},
 
 
 	/* Optional modules */
@@ -206,10 +208,6 @@
 	{"stdwin",	initstdwin},
 #endif
 
-#ifdef USE_SOCKET
-	{"socket",	initsocket},
-#endif
-
 #ifdef USE_JPEG
 	{"jpeg",	initjpeg},
 #endif
@@ -218,5 +216,9 @@
 	{"cd",		initcd},
 #endif
 
+#ifdef USE_THREAD
+	{"thread",	initthread},
+#endif
+
 	{0,		0}		/* Sentinel */
 };
diff --git a/Modules/threadmodule.c b/Modules/threadmodule.c
new file mode 100644
index 0000000..c4de295
--- /dev/null
+++ b/Modules/threadmodule.c
@@ -0,0 +1,294 @@
+/***********************************************************
+Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+                        All Rights Reserved
+
+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 appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Thread module */
+/* Interface to Sjoerd's portable C thread library */
+
+#include "allobjects.h"
+#include "modsupport.h"
+#include "compile.h"
+#include "ceval.h"
+
+#include "thread.h"
+
+extern void init_save_thread PROTO((void));
+extern void* save_thread PROTO((void));
+extern void restore_thread PROTO((void *));
+
+object *ThreadError;
+
+
+/* Lock objects */
+
+typedef struct {
+	OB_HEAD
+	type_lock lock_lock;
+} lockobject;
+
+extern typeobject Locktype;	/* Really static, forward */
+
+#define is_lockobject(v)		((v)->ob_type == &Locktype)
+
+static lockobject *
+newlockobject()
+{
+	lockobject *self;
+	self = NEWOBJ(lockobject, &Locktype);
+	if (self == NULL)
+		return NULL;
+	self->lock_lock = allocate_lock();
+	if (self->lock_lock == NULL) {
+		DEL(self);
+		self = NULL;
+		err_setstr(ThreadError, "can't allocate lock");
+	}
+	return self;
+}
+
+static void
+lock_dealloc(self)
+	lockobject *self;
+{
+	/* Unlock the lock so it's safe to free it */
+	acquire_lock(self->lock_lock, 0);
+	release_lock(self->lock_lock);
+	
+	free_lock(self->lock_lock);
+	DEL(self);
+}
+
+static object *
+lock_acquire_lock(self, args)
+	lockobject *self;
+	object *args;
+{
+	void *save;
+	int i;
+
+	if (args != NULL) {
+		if (!getargs(args, "i", &i))
+			return NULL;
+	}
+	else
+		i = 1;
+
+	save = save_thread();
+
+	i = acquire_lock(self->lock_lock, i);
+
+	restore_thread(save);
+
+	if (args == NULL) {
+		INCREF(None);
+		return None;
+	}
+	else
+		return newintobject((long)i);
+}
+
+static object *
+lock_release_lock(self, args)
+	lockobject *self;
+	object *args;
+{
+	if (!getnoarg(args))
+		return NULL;
+
+	/* Sanity check: the lock must be locked */
+	if (acquire_lock(self->lock_lock, 0)) {
+		release_lock(self->lock_lock);
+		err_setstr(ThreadError, "release unlocked lock");
+		return NULL;
+	}
+
+	release_lock(self->lock_lock);
+	INCREF(None);
+	return None;
+}
+
+static object *
+lock_locked_lock(self, args)
+	lockobject *self;
+	object *args;
+{
+	if (!getnoarg(args))
+		return NULL;
+
+	if (acquire_lock(self->lock_lock, 0)) {
+		release_lock(self->lock_lock);
+		return newintobject(0L);
+	}
+	return newintobject(1L);
+}
+
+static struct methodlist lock_methods[] = {
+	{"acquire_lock",	lock_acquire_lock},
+	{"acquire",		lock_acquire_lock},
+	{"release_lock",	lock_release_lock},
+	{"release",		lock_release_lock},
+	{"locked_lock",		lock_locked_lock},
+	{"locked",		lock_locked_lock},
+	{NULL,			NULL}		/* sentinel */
+};
+
+static object *
+lock_getattr(self, name)
+	lockobject *self;
+	char *name;
+{
+	return findmethod(lock_methods, (object *)self, name);
+}
+
+static typeobject Locktype = {
+	OB_HEAD_INIT(&Typetype)
+	0,			/*ob_size*/
+	"lock",			/*tp_name*/
+	sizeof(lockobject),	/*tp_size*/
+	0,			/*tp_itemsize*/
+	/* methods */
+	lock_dealloc,	/*tp_dealloc*/
+	0,		/*tp_print*/
+	lock_getattr,	/*tp_getattr*/
+	0,		/*tp_setattr*/
+	0,		/*tp_compare*/
+	0,		/*tp_repr*/
+};
+
+
+/* Module functions */
+
+static void
+t_bootstrap(args_raw)
+	void *args_raw;
+{
+	object *args = (object *) args_raw;
+	object *func, *arg, *res;
+
+	restore_thread((void *)NULL);
+	func = gettupleitem(args, 0);
+	arg = gettupleitem(args, 1);
+	res = call_object(func, arg);
+	DECREF(arg); /* Matches the INCREF(arg) in thread_start_new_thread */
+	if (res == NULL) {
+		fprintf(stderr, "Unhandled exception in thread:\n");
+		print_error(); /* From pythonmain.c */
+		fprintf(stderr, "Exiting the entire program\n");
+		goaway(1);
+	}
+	(void) save_thread();
+	exit_thread();
+}
+
+static object *
+thread_start_new_thread(self, args)
+	object *self; /* Not used */
+	object *args;
+{
+	object *func, *arg;
+
+	if (!getargs(args, "(OO)", &func, &arg))
+		return NULL;
+	INCREF(args);
+	if (!start_new_thread(t_bootstrap, (void*) args)) {
+		DECREF(args);
+		err_setstr(ThreadError, "can't start new thread\n");
+		return NULL;
+	}
+	/* Otherwise the DECREF(args) is done by t_bootstrap */
+	INCREF(None);
+	return None;
+}
+
+static object *
+thread_exit_thread(self, args)
+	object *self; /* Not used */
+	object *args;
+{
+	if (!getnoarg(args))
+		return NULL;
+	(void) save_thread();
+	exit_thread();
+	for (;;) { } /* Should not be reached */
+}
+
+static object *
+thread_exit_prog(self, args)
+	object *self; /* Not used */
+	object *args;
+{
+	int sts;
+	if (!getargs(args, "i", &sts))
+		return NULL;
+	goaway(sts);
+	for (;;) { } /* Should not be reached */
+}
+
+static object *
+thread_allocate_lock(self, args)
+	object *self; /* Not used */
+	object *args;
+{
+	if (!getnoarg(args))
+		return NULL;
+	return newlockobject();
+}
+
+static struct methodlist thread_methods[] = {
+	{"start_new_thread",	thread_start_new_thread},
+	{"start_new",		thread_start_new_thread},
+	{"allocate_lock",	thread_allocate_lock},
+	{"allocate",		thread_allocate_lock},
+	{"exit_thread",		thread_exit_thread},
+	{"exit",		thread_exit_thread},
+	{"exit_prog",		thread_exit_prog},
+	{NULL,			NULL}		/* sentinel */
+};
+
+
+/* Initialization function */
+
+void
+initthread()
+{
+	object *m, *d, *x;
+
+	/* Create the module and add the functions */
+	m = initmodule("thread", thread_methods);
+
+	/* Add a symbolic constant */
+	d = getmoduledict(m);
+	ThreadError = newstringobject("thread.error");
+	INCREF(ThreadError);
+	dictinsert(d, "error", ThreadError);
+
+	/* Check for errors */
+	if (err_occurred())
+		fatal("can't initialize module thread");
+
+	/* Initialize the C thread library */
+	init_thread();
+
+	/* Initialize the interpreter's stack save/restore mechanism */
+	init_save_thread();
+}
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index 4a921f0..5a278a9bd 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -104,11 +104,14 @@
 	object *self;
 	object *args;
 {
+	void *save, *save_thread(), restore_thread();
 	int secs;
 	SIGTYPE (*sigsave)() = 0; /* Initialized to shut lint up */
 	if (!getintarg(args, &secs))
 		return NULL;
+	save = save_thread();
 	if (setjmp(sleep_intr)) {
+		restore_thread(save);
 		signal(SIGINT, sigsave);
 		err_set(KeyboardInterrupt);
 		return NULL;
@@ -117,6 +120,7 @@
 	if (sigsave != (SIGTYPE (*)()) SIG_IGN)
 		signal(SIGINT, sleep_catcher);
 	sleep(secs);
+	restore_thread(save);
 	signal(SIGINT, sigsave);
 	INCREF(None);
 	return None;
@@ -147,11 +151,14 @@
 	object *self;
 	object *args;
 {
+	void *save, *save_thread(), restore_thread();
 	long msecs;
 	SIGTYPE (*sigsave)();
 	if (!getlongarg(args, &msecs))
 		return NULL;
+	save = save_thread();
 	if (setjmp(sleep_intr)) {
+		restore_thread(save);
 		signal(SIGINT, sigsave);
 		err_set(KeyboardInterrupt);
 		return NULL;
@@ -160,6 +167,7 @@
 	if (sigsave != (SIGTYPE (*)()) SIG_IGN)
 		signal(SIGINT, sleep_catcher);
 	millisleep(msecs);
+	restore_thread(save);
 	signal(SIGINT, sigsave);
 	INCREF(None);
 	return None;
diff --git a/Modules/xxmodule.c b/Modules/xxmodule.c
new file mode 100644
index 0000000..070a622
--- /dev/null
+++ b/Modules/xxmodule.c
@@ -0,0 +1,92 @@
+/***********************************************************
+Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+                        All Rights Reserved
+
+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 appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* xx module */
+
+#include "allobjects.h"
+#include "modsupport.h"
+
+
+/* Function of two integers returning integer */
+
+static object *
+xx_foo(self, args)
+	object *self; /* Not used */
+	object *args;
+{
+	long i, j;
+	long res;
+	if (!getargs(args, "(ll)", &i, &j))
+		return NULL;
+	res = i+j; /* XXX Do something here */
+	return newintobject(res);
+}
+
+
+/* Function of no arguments returning None */
+
+static object *
+xx_bar(self, args)
+	object *self; /* Not used */
+	object *args;
+{
+	int i, j;
+	if (!getnoarg(args))
+		return NULL;
+	/* XXX Do something here */
+	INCREF(None);
+	return None;
+}
+
+
+/* List of functions defined in the module */
+
+static struct methodlist xx_methods[] = {
+	{"foo",		xx_foo},
+	{"bar",		xx_bar},
+	{NULL,		NULL}		/* sentinel */
+};
+
+
+/* Initialization function for the module (*must* be called initxx) */
+
+void
+initxx()
+{
+	object *m, *d, *x;
+
+	/* Create the module and add the functions */
+	m = initmodule("xx", xx_methods);
+
+	/* Add some symbolic constants to the module */
+	d = getmoduledict(m);
+	x = newstringobject("xx.error");
+	dictinsert(d, "error", x);
+	x = newintobject(42L);
+	dictinsert(d, "magic", x);
+
+	/* Check for errors */
+	if (err_occurred())
+		fatal("can't initialize module xx");
+}
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index b026413..99f4e5e 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -321,6 +321,7 @@
 	fileobject *f;
 	int n;
 {
+	void *save, *save_thread(), restore_thread();
 	register FILE *fp;
 	register int c;
 	register char *buf, *end;
@@ -334,16 +335,19 @@
 		return NULL;
 	buf = BUF(v);
 	end = buf + n2;
-	
+
+	save = save_thread();
 	for (;;) {
 		if ((c = getc(fp)) == EOF) {
 			clearerr(fp);
 			if (intrcheck()) {
+				restore_thread(save);
 				DECREF(v);
 				err_set(KeyboardInterrupt);
 				return NULL;
 			}
 			if (n < 0 && buf == BUF(v)) {
+				restore_thread(save);
 				DECREF(v);
 				err_setstr(EOFError,
 					   "EOF when reading a line");
@@ -361,13 +365,16 @@
 				break;
 			n1 = n2;
 			n2 += 1000;
+			restore_thread(save);
 			if (resizestring(&v, n2) < 0)
 				return NULL;
+			save = save_thread();
 			buf = BUF(v) + n1;
 			end = BUF(v) + n2;
 		}
 	}
-	
+	restore_thread(save);
+
 	n1 = buf - BUF(v);
 	if (n1 != n2)
 		resizestring(&v, n1);
diff --git a/Python/ceval.c b/Python/ceval.c
index 0b2f924..32c52c7 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -84,6 +84,79 @@
 static frameobject *current_frame;
 
 
+/* Interface for threads.
+
+   A module that plans to do a blocking system call (or something else
+   that lasts a long time and doesn't touch Python data) can allow other
+   threads to run as follows:
+
+	void *x;
+
+	...preparations here...
+	x = save_thread();
+	...blocking system call here...
+	restore_thread(x);
+	...interpretr result here...
+
+   For convenience, that the value of 'errno' is restored across the
+   the call to restore_thread().
+
+   The function init_save_thread() should be called only from
+   initthread() in "threadmodule.c".
+
+   Note that not yet all candidates have been converted to use this
+   mechanism!
+*/
+
+#ifdef USE_THREAD
+#include <errno.h>
+#include "thread.h"
+static type_lock interpreter_lock;
+
+void
+init_save_thread()
+{
+#ifdef USE_THREAD
+	if (interpreter_lock)
+		fatal("2nd call to init_save_thread");
+	interpreter_lock = allocate_lock();
+	acquire_lock(interpreter_lock, 1);
+#endif
+}
+#endif
+
+void *
+save_thread()
+{
+#ifdef USE_THREAD
+	if (interpreter_lock) {
+		void *res;
+		res = (void *)current_frame;
+		current_frame = NULL;
+		release_lock(interpreter_lock);
+		return res;
+	}
+	else
+		return NULL;
+#endif
+}
+
+void
+restore_thread(x)
+	void *x;
+{
+#ifdef USE_THREAD
+	if (interpreter_lock) {
+		int err;
+		err = errno;
+		acquire_lock(interpreter_lock, 1);
+		errno = err;
+		current_frame = (frameobject *)x;
+	}
+#endif
+}
+
+
 /* Status code for main loop (reason for stack unwind) */
 
 enum why_code {
@@ -210,17 +283,34 @@
 	for (;;) {
 		static int ticker;
 		
-		/* Do periodic things */
+		/* Do periodic things.
+		   Doing this every time through the loop would add
+		   too much overhead (a function call per instruction).
+		   So we do it only every tenth instruction. */
 		
 		if (--ticker < 0) {
-			ticker = 100;
+			ticker = 10;
 			if (intrcheck()) {
 				err_set(KeyboardInterrupt);
 				why = WHY_EXCEPTION;
 				goto on_error;
 			}
+
+#ifdef USE_THREAD
+			if (interpreter_lock) {
+				/* Give another thread a chance */
+
+				current_frame = NULL;
+				release_lock(interpreter_lock);
+
+				/* Other threads may run now */
+
+				acquire_lock(interpreter_lock, 1);
+				current_frame = f;
+			}
+#endif
 		}
-		
+
 		/* Extract opcode and argument */
 		
 		opcode = NEXTOP();
diff --git a/Python/pythonmain.c b/Python/pythonmain.c
index a141168..0f76bfd 100644
--- a/Python/pythonmain.c
+++ b/Python/pythonmain.c
@@ -26,23 +26,10 @@
 
 #include "allobjects.h"
 
-#include "grammar.h"
-#include "node.h"
-#include "parsetok.h"
-#include "graminit.h"
-#include "errcode.h"
-#include "sysmodule.h"
-#include "compile.h"
-#include "ceval.h"
-#include "pythonrun.h"
-#include "import.h"
-
 extern char *getpythonpath();
 
-extern grammar gram; /* From graminit.c */
-
-int debugging; /* Needed by parser.c */
-int verbose; /* Needed by import.c */
+extern int debugging; /* Needed by parser.c */
+extern int verbose; /* Needed by import.c */
 
 /* Interface to getopt(): */
 extern int optind;
@@ -108,12 +95,12 @@
 	
 	initall();
 	
-	setpythonpath(getpythonpath());
 	if (command != NULL) {
 		/* Backup optind and force sys.argv[0] = '-c' */
 		optind--;
 		argv[optind] = "-c";
 	}
+
 	setpythonargv(argc-optind, argv+optind);
 
 	if (command) {
@@ -126,368 +113,3 @@
 	goaway(sts);
 	/*NOTREACHED*/
 }
-
-/* Initialize all */
-
-void
-initall()
-{
-	static int inited;
-	
-	if (inited)
-		return;
-	inited = 1;
-	
-	initimport();
-	
-	/* Modules 'builtin' and 'sys' are initialized here,
-	   they are needed by random bits of the interpreter.
-	   All other modules are optional and should be initialized
-	   by the initcalls() of a specific configuration. */
-	
-	initbuiltin(); /* Also initializes builtin exceptions */
-	initsys();
-	
-	initcalls(); /* Configuration-dependent initializations */
-	
-	initintr(); /* For intrcheck() */
-}
-
-/* Parse input from a file and execute it */
-
-int
-run(fp, filename)
-	FILE *fp;
-	char *filename;
-{
-	if (filename == NULL)
-		filename = "???";
-	if (isatty((int)fileno(fp)))
-		return run_tty_loop(fp, filename);
-	else
-		return run_script(fp, filename);
-}
-
-int
-run_tty_loop(fp, filename)
-	FILE *fp;
-	char *filename;
-{
-	object *v;
-	int ret;
-	v = sysget("ps1");
-	if (v == NULL) {
-		sysset("ps1", v = newstringobject(">>> "));
-		XDECREF(v);
-	}
-	v = sysget("ps2");
-	if (v == NULL) {
-		sysset("ps2", v = newstringobject("... "));
-		XDECREF(v);
-	}
-	for (;;) {
-		ret = run_tty_1(fp, filename);
-#ifdef REF_DEBUG
-		fprintf(stderr, "[%ld refs]\n", ref_total);
-#endif
-		if (ret == E_EOF)
-			return 0;
-		/*
-		if (ret == E_NOMEM)
-			return -1;
-		*/
-	}
-}
-
-int
-run_tty_1(fp, filename)
-	FILE *fp;
-	char *filename;
-{
-	object *m, *d, *v, *w;
-	node *n;
-	char *ps1, *ps2;
-	int err;
-	v = sysget("ps1");
-	w = sysget("ps2");
-	if (v != NULL && is_stringobject(v)) {
-		INCREF(v);
-		ps1 = getstringvalue(v);
-	}
-	else {
-		v = NULL;
-		ps1 = "";
-	}
-	if (w != NULL && is_stringobject(w)) {
-		INCREF(w);
-		ps2 = getstringvalue(w);
-	}
-	else {
-		w = NULL;
-		ps2 = "";
-	}
-	err = parsefile(fp, filename, &gram, single_input, ps1, ps2, &n);
-	XDECREF(v);
-	XDECREF(w);
-	if (err == E_EOF)
-		return E_EOF;
-	if (err != E_DONE) {
-		err_input(err);
-		print_error();
-		return err;
-	}
-	m = add_module("__main__");
-	if (m == NULL)
-		return -1;
-	d = getmoduledict(m);
-	v = run_node(n, filename, d, d);
-	flushline();
-	if (v == NULL) {
-		print_error();
-		return -1;
-	}
-	DECREF(v);
-	return 0;
-}
-
-int
-run_script(fp, filename)
-	FILE *fp;
-	char *filename;
-{
-	object *m, *d, *v;
-	m = add_module("__main__");
-	if (m == NULL)
-		return -1;
-	d = getmoduledict(m);
-	v = run_file(fp, filename, file_input, d, d);
-	flushline();
-	if (v == NULL) {
-		print_error();
-		return -1;
-	}
-	DECREF(v);
-	return 0;
-}
-
-int
-run_command(command)
-	char *command;
-{
-	object *m, *d, *v;
-	m = add_module("__main__");
-	if (m == NULL)
-		return -1;
-	d = getmoduledict(m);
-	v = run_string(command, file_input, d, d);
-	flushline();
-	if (v == NULL) {
-		print_error();
-		return -1;
-	}
-	DECREF(v);
-	return 0;
-}
-
-void
-print_error()
-{
-	object *exception, *v;
-	err_get(&exception, &v);
-	if (exception == SystemExit) {
-		if (v == NULL || v == None)
-			goaway(0);
-		if (is_intobject(v))
-			goaway((int)getintvalue(v));
-		else {
-			printobject(v, stderr, PRINT_RAW);
-			fprintf(stderr, "\n");
-			goaway(1);
-		}
-	}
-	sysset("last_type", exception);
-	sysset("last_value", v);
-	if (printobject(exception, stderr, PRINT_RAW) != 0)
-		err_clear();
-	if (v != NULL && v != None) {
-		fprintf(stderr, ": ");
-		if (printobject(v, stderr, PRINT_RAW) != 0)
-			err_clear();
-	}
-	fprintf(stderr, "\n");
-	XDECREF(exception);
-	XDECREF(v);
-	printtraceback(stderr);
-}
-
-object *
-run_string(str, start, globals, locals)
-	char *str;
-	int start;
-	/*dict*/object *globals, *locals;
-{
-	node *n;
-	int err;
-	err = parse_string(str, start, &n);
-	return run_err_node(err, n, "<string>", globals, locals);
-}
-
-object *
-run_file(fp, filename, start, globals, locals)
-	FILE *fp;
-	char *filename;
-	int start;
-	/*dict*/object *globals, *locals;
-{
-	node *n;
-	int err;
-	err = parse_file(fp, filename, start, &n);
-	return run_err_node(err, n, filename, globals, locals);
-}
-
-object *
-run_err_node(err, n, filename, globals, locals)
-	int err;
-	node *n;
-	char *filename;
-	/*dict*/object *globals, *locals;
-{
-	if (err != E_DONE) {
-		err_input(err);
-		return NULL;
-	}
-	return run_node(n, filename, globals, locals);
-}
-
-object *
-run_node(n, filename, globals, locals)
-	node *n;
-	char *filename;
-	/*dict*/object *globals, *locals;
-{
-	if (globals == NULL) {
-		globals = getglobals();
-		if (locals == NULL)
-			locals = getlocals();
-	}
-	else {
-		if (locals == NULL)
-			locals = globals;
-	}
-	return eval_node(n, filename, globals, locals);
-}
-
-object *
-eval_node(n, filename, globals, locals)
-	node *n;
-	char *filename;
-	object *globals;
-	object *locals;
-{
-	codeobject *co;
-	object *v;
-	co = compile(n, filename);
-	freetree(n);
-	if (co == NULL)
-		return NULL;
-	v = eval_code(co, globals, locals, (object *)NULL);
-	DECREF(co);
-	return v;
-}
-
-/* Simplified interface to parsefile */
-
-int
-parse_file(fp, filename, start, n_ret)
-	FILE *fp;
-	char *filename;
-	int start;
-	node **n_ret;
-{
-	return parsefile(fp, filename, &gram, start,
-				(char *)0, (char *)0, n_ret);
-}
-
-/* Simplified interface to parsestring */
-
-int
-parse_string(str, start, n_ret)
-	char *str;
-	int start;
-	node **n_ret;
-{
-	int err = parsestring(str, &gram, start, n_ret);
-	/* Don't confuse early end of string with early end of input */
-	if (err == E_EOF)
-		err = E_SYNTAX;
-	return err;
-}
-
-/* Print fatal error message and abort */
-
-void
-fatal(msg)
-	char *msg;
-{
-	fprintf(stderr, "Fatal error: %s\n", msg);
-	abort();
-}
-
-/* Clean up and exit */
-
-void
-goaway(sts)
-	int sts;
-{
-	flushline();
-	
-	/* XXX Call doneimport() before donecalls(), since donecalls()
-	   calls wdone(), and doneimport() may close windows */
-	doneimport();
-	donecalls();
-	
-	err_clear();
-
-#ifdef REF_DEBUG
-	fprintf(stderr, "[%ld refs]\n", ref_total);
-#endif
-
-#ifdef TRACE_REFS
-	if (askyesno("Print left references?")) {
-		printrefs(stderr);
-	}
-#endif /* TRACE_REFS */
-
-	exit(sts);
-	/*NOTREACHED*/
-}
-
-#ifdef TRACE_REFS
-/* Ask a yes/no question */
-
-static int
-askyesno(prompt)
-	char *prompt;
-{
-	char buf[256];
-	
-	printf("%s [ny] ", prompt);
-	if (fgets(buf, sizeof buf, stdin) == NULL)
-		return 0;
-	return buf[0] == 'y' || buf[0] == 'Y';
-}
-#endif
-
-#ifdef applec /* MPW (also usable for Think C 3.0) */
-
-/* Check for file descriptor connected to interactive device.
-   Pretend that stdin is always interactive, other files never. */
-
-int
-isatty(fd)
-	int fd;
-{
-	return fd == fileno(stdin);
-}
-
-#endif
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
new file mode 100644
index 0000000..2a68f24
--- /dev/null
+++ b/Python/pythonrun.c
@@ -0,0 +1,424 @@
+/***********************************************************
+Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+                        All Rights Reserved
+
+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 appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Python interpreter top-level routines, including init/exit */
+
+#include "allobjects.h"
+
+#include "grammar.h"
+#include "node.h"
+#include "parsetok.h"
+#include "graminit.h"
+#include "errcode.h"
+#include "sysmodule.h"
+#include "compile.h"
+#include "ceval.h"
+#include "pythonrun.h"
+#include "import.h"
+
+#ifdef USE_THREAD
+extern void *save_thread();
+#endif
+
+extern char *getpythonpath();
+
+extern grammar gram; /* From graminit.c */
+
+int debugging; /* Needed by parser.c */
+int verbose; /* Needed by import.c */
+
+/* Initialize all */
+
+void
+initall()
+{
+	static int inited;
+	
+	if (inited)
+		return;
+	inited = 1;
+	
+	initimport();
+	
+	/* Modules 'builtin' and 'sys' are initialized here,
+	   they are needed by random bits of the interpreter.
+	   All other modules are optional and are initialized
+	   when they are first imported. */
+	
+	initbuiltin(); /* Also initializes builtin exceptions */
+	initsys();
+	
+	initcalls(); /* Configuration-dependent initializations */
+	
+	initintr(); /* For intrcheck() */
+
+	setpythonpath(getpythonpath());
+}
+
+/* Parse input from a file and execute it */
+
+int
+run(fp, filename)
+	FILE *fp;
+	char *filename;
+{
+	if (filename == NULL)
+		filename = "???";
+	if (isatty((int)fileno(fp)))
+		return run_tty_loop(fp, filename);
+	else
+		return run_script(fp, filename);
+}
+
+int
+run_tty_loop(fp, filename)
+	FILE *fp;
+	char *filename;
+{
+	object *v;
+	int ret;
+	v = sysget("ps1");
+	if (v == NULL) {
+		sysset("ps1", v = newstringobject(">>> "));
+		XDECREF(v);
+	}
+	v = sysget("ps2");
+	if (v == NULL) {
+		sysset("ps2", v = newstringobject("... "));
+		XDECREF(v);
+	}
+	for (;;) {
+		ret = run_tty_1(fp, filename);
+#ifdef REF_DEBUG
+		fprintf(stderr, "[%ld refs]\n", ref_total);
+#endif
+		if (ret == E_EOF)
+			return 0;
+		/*
+		if (ret == E_NOMEM)
+			return -1;
+		*/
+	}
+}
+
+int
+run_tty_1(fp, filename)
+	FILE *fp;
+	char *filename;
+{
+	void *save, *save_thread(), restore_thread();
+	object *m, *d, *v, *w;
+	node *n;
+	char *ps1, *ps2;
+	int err;
+	v = sysget("ps1");
+	w = sysget("ps2");
+	if (v != NULL && is_stringobject(v)) {
+		INCREF(v);
+		ps1 = getstringvalue(v);
+	}
+	else {
+		v = NULL;
+		ps1 = "";
+	}
+	if (w != NULL && is_stringobject(w)) {
+		INCREF(w);
+		ps2 = getstringvalue(w);
+	}
+	else {
+		w = NULL;
+		ps2 = "";
+	}
+	save = save_thread();
+	err = parsefile(fp, filename, &gram, single_input, ps1, ps2, &n);
+	restore_thread(save);
+	XDECREF(v);
+	XDECREF(w);
+	if (err == E_EOF)
+		return E_EOF;
+	if (err != E_DONE) {
+		err_input(err);
+		print_error();
+		return err;
+	}
+	m = add_module("__main__");
+	if (m == NULL)
+		return -1;
+	d = getmoduledict(m);
+	v = run_node(n, filename, d, d);
+	flushline();
+	if (v == NULL) {
+		print_error();
+		return -1;
+	}
+	DECREF(v);
+	return 0;
+}
+
+int
+run_script(fp, filename)
+	FILE *fp;
+	char *filename;
+{
+	object *m, *d, *v;
+	m = add_module("__main__");
+	if (m == NULL)
+		return -1;
+	d = getmoduledict(m);
+	v = run_file(fp, filename, file_input, d, d);
+	flushline();
+	if (v == NULL) {
+		print_error();
+		return -1;
+	}
+	DECREF(v);
+	return 0;
+}
+
+int
+run_command(command)
+	char *command;
+{
+	object *m, *d, *v;
+	m = add_module("__main__");
+	if (m == NULL)
+		return -1;
+	d = getmoduledict(m);
+	v = run_string(command, file_input, d, d);
+	flushline();
+	if (v == NULL) {
+		print_error();
+		return -1;
+	}
+	DECREF(v);
+	return 0;
+}
+
+void
+print_error()
+{
+	object *exception, *v;
+	err_get(&exception, &v);
+	if (exception == SystemExit) {
+		if (v == NULL || v == None)
+			goaway(0);
+		if (is_intobject(v))
+			goaway((int)getintvalue(v));
+		else {
+			printobject(v, stderr, PRINT_RAW);
+			fprintf(stderr, "\n");
+			goaway(1);
+		}
+	}
+	sysset("last_type", exception);
+	sysset("last_value", v);
+	if (printobject(exception, stderr, PRINT_RAW) != 0)
+		err_clear();
+	if (v != NULL && v != None) {
+		fprintf(stderr, ": ");
+		if (printobject(v, stderr, PRINT_RAW) != 0)
+			err_clear();
+	}
+	fprintf(stderr, "\n");
+	XDECREF(exception);
+	XDECREF(v);
+	printtraceback(stderr);
+}
+
+object *
+run_string(str, start, globals, locals)
+	char *str;
+	int start;
+	/*dict*/object *globals, *locals;
+{
+	node *n;
+	int err;
+	err = parse_string(str, start, &n);
+	return run_err_node(err, n, "<string>", globals, locals);
+}
+
+object *
+run_file(fp, filename, start, globals, locals)
+	FILE *fp;
+	char *filename;
+	int start;
+	/*dict*/object *globals, *locals;
+{
+	node *n;
+	int err;
+	err = parse_file(fp, filename, start, &n);
+	return run_err_node(err, n, filename, globals, locals);
+}
+
+object *
+run_err_node(err, n, filename, globals, locals)
+	int err;
+	node *n;
+	char *filename;
+	/*dict*/object *globals, *locals;
+{
+	if (err != E_DONE) {
+		err_input(err);
+		return NULL;
+	}
+	return run_node(n, filename, globals, locals);
+}
+
+object *
+run_node(n, filename, globals, locals)
+	node *n;
+	char *filename;
+	/*dict*/object *globals, *locals;
+{
+	if (globals == NULL) {
+		globals = getglobals();
+		if (locals == NULL)
+			locals = getlocals();
+	}
+	else {
+		if (locals == NULL)
+			locals = globals;
+	}
+	return eval_node(n, filename, globals, locals);
+}
+
+object *
+eval_node(n, filename, globals, locals)
+	node *n;
+	char *filename;
+	object *globals;
+	object *locals;
+{
+	codeobject *co;
+	object *v;
+	co = compile(n, filename);
+	freetree(n);
+	if (co == NULL)
+		return NULL;
+	v = eval_code(co, globals, locals, (object *)NULL);
+	DECREF(co);
+	return v;
+}
+
+/* Simplified interface to parsefile */
+
+int
+parse_file(fp, filename, start, n_ret)
+	FILE *fp;
+	char *filename;
+	int start;
+	node **n_ret;
+{
+	return parsefile(fp, filename, &gram, start,
+				(char *)0, (char *)0, n_ret);
+}
+
+/* Simplified interface to parsestring */
+
+int
+parse_string(str, start, n_ret)
+	char *str;
+	int start;
+	node **n_ret;
+{
+	int err = parsestring(str, &gram, start, n_ret);
+	/* Don't confuse early end of string with early end of input */
+	if (err == E_EOF)
+		err = E_SYNTAX;
+	return err;
+}
+
+/* Print fatal error message and abort */
+
+void
+fatal(msg)
+	char *msg;
+{
+	fprintf(stderr, "Fatal error: %s\n", msg);
+	abort();
+}
+
+/* Clean up and exit */
+
+void
+goaway(sts)
+	int sts;
+{
+	flushline();
+	
+	/* XXX Call doneimport() before donecalls(), since donecalls()
+	   calls wdone(), and doneimport() may close windows */
+	doneimport();
+	donecalls();
+	
+	err_clear();
+
+#ifdef REF_DEBUG
+	fprintf(stderr, "[%ld refs]\n", ref_total);
+#endif
+
+#ifdef TRACE_REFS
+	if (askyesno("Print left references?")) {
+		printrefs(stderr);
+	}
+#endif /* TRACE_REFS */
+
+#ifdef USE_THREAD
+	(void) save_thread();
+	exit_prog(sts);
+#else
+	exit(sts);
+#endif
+	/*NOTREACHED*/
+}
+
+#ifdef TRACE_REFS
+/* Ask a yes/no question */
+
+static int
+askyesno(prompt)
+	char *prompt;
+{
+	char buf[256];
+	
+	printf("%s [ny] ", prompt);
+	if (fgets(buf, sizeof buf, stdin) == NULL)
+		return 0;
+	return buf[0] == 'y' || buf[0] == 'Y';
+}
+#endif
+
+#ifdef applec /* MPW (also usable for Think C 3.0) */
+
+/* Check for file descriptor connected to interactive device.
+   Pretend that stdin is always interactive, other files never. */
+
+int
+isatty(fd)
+	int fd;
+{
+	return fd == fileno(stdin);
+}
+
+#endif
diff --git a/Python/thread.c b/Python/thread.c
new file mode 100644
index 0000000..1f0633a
--- /dev/null
+++ b/Python/thread.c
@@ -0,0 +1,263 @@
+#include "thread.h"
+
+#ifdef __sgi
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+#include <ulocks.h>
+
+static usptr_t *shared_arena;
+static int exit_status;
+static int do_exit;
+static int exiting;
+#endif
+#ifdef sun
+#include <lwp/lwp.h>
+#include <lwp/stackdep.h>
+
+#define STACKSIZE	1000	/* stacksize for a thread */
+#define NSTACKS		2	/* # stacks to be put in cache initialy */
+
+struct lock {
+	int lock_locked;
+	cv_t lock_condvar;
+	mon_t lock_monitor;
+};
+#endif
+#ifdef C_THREADS
+#include <cthreads.h>
+#endif
+
+#ifdef __STDC__
+#define _P(args)		args
+#define _P0()			(void)
+#define _P1(v,t)		(t)
+#define _P2(v1,t1,v2,t2)	(t1,t2)
+#else
+#define _P(args)		()
+#define _P0()			()
+#define _P1(v,t)		(v) t;
+#define _P2(v1,t1,v2,t2)	(v1,v2) t1; t2;
+#endif
+
+static int initialized;
+
+int start_new_thread _P2(func, void (*func) _P((void *)), arg, void *arg)
+{
+#ifdef sun
+	thread_t tid;
+#endif
+#ifdef DEBUG
+	printf("start_new_thread called\n");
+#endif
+	if (!initialized)
+		init_thread();
+#ifdef __sgi
+	if (sproc(func, PR_SALL, arg) < 0)
+		return 0;
+	return 1;
+#endif
+#ifdef SOLARIS
+	(void) thread_create(0, 0, func, arg, THREAD_NEW_LWP);
+#endif
+#ifdef sun
+	if (lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg) < 0)
+		return 0;
+	return 1;
+#endif
+#ifdef C_THREADS
+	(void) cthread_fork(func, arg);
+#endif
+}
+
+#ifdef __sgi
+void maybe_exit _P0()
+{
+	if (exiting)
+		return;
+	exit_prog(0);
+}
+#endif
+
+void exit_thread _P0()
+{
+#ifdef DEBUG
+	printf("exit_thread called\n");
+#endif
+	if (!initialized)
+		exit(0);
+#ifdef __sgi
+	exiting = 1;
+	exit(0);
+#endif
+#ifdef SOLARIS
+	thread_exit();
+#endif
+#ifdef sun
+	lwp_destroy(SELF);
+#endif
+#ifdef C_THREADS
+	cthread_exit(0);
+#endif
+}
+
+#ifdef __sgi
+static void exit_sig _P0()
+{
+#ifdef DEBUG
+	printf("exit_sig called\n");
+#endif
+	if (do_exit) {
+#ifdef DEBUG
+		printf("exiting in exit_sig\n");
+#endif
+		exit(exit_status);
+	}
+}
+#endif
+
+void init_thread _P0()
+{
+#ifdef __sgi
+	struct sigaction s;
+#endif
+
+#ifdef DEBUG
+	printf("init_thread called\n");
+#endif
+	initialized = 1;
+
+#ifdef __sgi
+	atexit(maybe_exit);
+	s.sa_handler = exit_sig;
+	sigemptyset(&s.sa_mask);
+	sigaddset(&s.sa_mask, SIGUSR1);
+	s.sa_flags = 0;
+	sigaction(SIGUSR1, &s, 0);
+	prctl(PR_SETEXITSIG, SIGUSR1);
+	usconfig(CONF_ARENATYPE, US_SHAREDONLY);
+	/*usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);*/
+	shared_arena = usinit(tmpnam(0));
+#endif
+#ifdef sun
+	lwp_setstkcache(STACKSIZE, NSTACKS);
+#endif
+#ifdef C_THREADS
+	cthread_init();
+#endif
+}
+
+type_lock allocate_lock _P0()
+{
+#ifdef __sgi
+	ulock_t lock;
+#endif
+#ifdef sun
+	struct lock *lock;
+	extern char *malloc();
+#endif
+
+#ifdef DEBUG
+	printf("allocate_lock called\n");
+#endif
+	if (!initialized)
+		init_thread();
+
+#ifdef __sgi
+	lock = usnewlock(shared_arena);
+	(void) usinitlock(lock);
+#endif
+#ifdef sun
+	lock = (struct lock *) malloc(sizeof(struct lock));
+	lock->lock_locked = 0;
+	(void) mon_create(&lock->lock_monitor);
+	(void) cv_create(&lock->lock_condvar, lock->lock_monitor);
+#endif
+#ifdef DEBUG
+	printf("allocate_lock() -> %lx\n", (long)lock);
+#endif
+	return (type_lock) lock;
+}
+
+void free_lock _P1(lock, type_lock lock)
+{
+#ifdef DEBUG
+	printf("free_lock(%lx) called\n", (long)lock);
+#endif
+#ifdef __sgi
+	usfreelock((ulock_t) lock, shared_arena);
+#endif
+#ifdef sun
+	mon_destroy(((struct lock *) lock)->lock_monitor);
+	free((char *) lock);
+#endif
+}
+
+int acquire_lock _P2(lock, type_lock lock, waitflag, int waitflag)
+{
+	int success;
+
+#ifdef DEBUG
+	printf("acquire_lock(%lx, %d) called\n", (long)lock, waitflag);
+#endif
+#ifdef __sgi
+	if (waitflag)
+		success = ussetlock((ulock_t) lock);
+	else
+		success = uscsetlock((ulock_t) lock, 1); /* Try it once */
+#endif
+#ifdef sun
+	success = 0;
+
+	(void) mon_enter(((struct lock *) lock)->lock_monitor);
+	if (waitflag)
+		while (((struct lock *) lock)->lock_locked)
+			cv_wait(((struct lock *) lock)->lock_condvar);
+	if (!((struct lock *) lock)->lock_locked) {
+		success = 1;
+		((struct lock *) lock)->lock_locked = 1;
+	}
+	cv_broadcast(((struct lock *) lock)->lock_condvar);
+	mon_exit(((struct lock *) lock)->lock_monitor);
+#endif
+#ifdef DEBUG
+	printf("acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success);
+#endif
+	return success;
+}
+
+void release_lock _P1(lock, type_lock lock)
+{
+#ifdef DEBUG
+	printf("release lock(%lx) called\n", (long)lock);
+#endif
+#ifdef __sgi
+	(void) usunsetlock((ulock_t) lock);
+#endif
+#ifdef sun
+	(void) mon_enter(((struct lock *) lock)->lock_monitor);
+	((struct lock *) lock)->lock_locked = 0;
+	cv_broadcast(((struct lock *) lock)->lock_condvar);
+	mon_exit(((struct lock *) lock)->lock_monitor);
+#endif
+}
+
+void exit_prog _P1(status, int status)
+{
+#ifdef DEBUG
+	printf("exit_prog(%d) called\n", status);
+#endif
+	if (!initialized)
+		exit(status);
+#ifdef __sgi
+	exiting = 1;
+	do_exit = 1;
+	exit_status = status;
+	exit(status);
+#endif
+#ifdef sun
+	pod_exit(status);
+#endif
+}