From 1984f1e1c6306d4e8073c28d2395638f80ea509b Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 4 Aug 1992 12:41:02 +0000 Subject: * 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 --- Include/pythread.h | 27 ++++ Include/thread.h | 27 ++++ Modules/config.c.in | 16 +- Modules/threadmodule.c | 294 ++++++++++++++++++++++++++++++++++ Modules/timemodule.c | 8 + Modules/xxmodule.c | 92 +++++++++++ Objects/fileobject.c | 11 +- Python/ceval.c | 96 ++++++++++- Python/pythonmain.c | 384 +------------------------------------------- Python/pythonrun.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++ Python/thread.c | 263 ++++++++++++++++++++++++++++++ 11 files changed, 1249 insertions(+), 393 deletions(-) create mode 100644 Include/pythread.h create mode 100644 Include/thread.h create mode 100644 Modules/threadmodule.c create mode 100644 Modules/xxmodule.c create mode 100644 Python/pythonrun.c create mode 100644 Python/thread.c 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 initpwd(); extern void initgrp(); extern void initmarshal(); extern void initselect(); +extern void initsocket(); #ifdef USE_AUDIO extern void initaudio(); @@ -148,15 +149,15 @@ extern void initpanel(); #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 @@ struct { {"grp", initgrp}, {"marshal", initmarshal}, {"select", initselect}, + {"socket", initsocket}, /* Optional modules */ @@ -206,10 +208,6 @@ struct { {"stdwin", initstdwin}, #endif -#ifdef USE_SOCKET - {"socket", initsocket}, -#endif - #ifdef USE_JPEG {"jpeg", initjpeg}, #endif @@ -218,5 +216,9 @@ struct { {"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 @@ time_sleep(self, args) 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 @@ time_sleep(self, args) 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 @@ time_millisleep(self, args) 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 @@ time_millisleep(self, args) 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 @@ getline(f, n) fileobject *f; int n; { + void *save, *save_thread(), restore_thread(); register FILE *fp; register int c; register char *buf, *end; @@ -334,16 +335,19 @@ getline(f, n) 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 @@ getline(f, n) 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 object *build_class PROTO((object *, object *)); 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 +#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 @@ eval_code(co, globals, locals, arg) 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 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #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 @@ main(argc, argv) 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 @@ main(argc, argv) 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, "", 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, "", 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 +#include +#include +#include +#include +#include + +static usptr_t *shared_arena; +static int exit_status; +static int do_exit; +static int exiting; +#endif +#ifdef sun +#include +#include + +#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 +#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 +} -- cgit v0.12