| /*********************************************************** |
| Copyright 1991, 1992, 1993 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 "ceval.h" |
| |
| #include "thread.h" |
| |
| int threads_started = 0; |
| |
| static 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) |
| |
| type_lock |
| getlocklock(lock) |
| object *lock; |
| { |
| if (lock == NULL || !is_lockobject(lock)) |
| return NULL; |
| else |
| return ((lockobject *) lock)->lock_lock; |
| } |
| |
| 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; |
| { |
| int i; |
| |
| if (args != NULL) { |
| if (!getargs(args, "i", &i)) |
| return NULL; |
| } |
| else |
| i = 1; |
| |
| BGN_SAVE |
| i = acquire_lock(self->lock_lock, i); |
| END_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; |
| |
| threads_started++; |
| |
| restore_thread((void *)NULL); |
| func = gettupleitem(args, 0); |
| arg = gettupleitem(args, 1); |
| res = call_object(func, arg); |
| DECREF(args); /* Matches the INCREF(args) in thread_start_new_thread */ |
| if (res == NULL) { |
| fprintf(stderr, "Unhandled exception in thread:\n"); |
| print_error(); /* From pythonmain.c */ |
| } |
| (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); |
| /* Initialize the interpreter's stack save/restore mechanism */ |
| init_save_thread(); |
| 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); /* Calls exit_prog(sts) or _exit_prog(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 (object *) 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(); |
| } |