changeset 87:345d4c0e3dd3

Thread safety exceptions are now properly raised by all relevant pymonkey functions.
author Atul Varma <varmaa@toolness.com>
date Sun, 09 Aug 2009 16:17:25 -0700
parents 16a3e99e9b77
children 0b2970e8cd67
files context.c runtime.c runtime.h test_pymonkey.py
diffstat 4 files changed, 33 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/context.c	Sun Aug 09 15:46:40 2009 -0700
+++ b/context.c	Sun Aug 09 16:17:25 2009 -0700
@@ -113,6 +113,7 @@
 static PyObject *
 PYM_getObjectPrivate(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
   PYM_JSObject *object;
 
   if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object))
@@ -152,6 +153,7 @@
 static PyObject *
 PYM_clearObjectPrivate(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
   PYM_JSObject *object;
 
   if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object))
@@ -185,6 +187,7 @@
 static PyObject *
 PYM_newObject(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
   PyObject *privateObj = NULL;
 
   if (!PyArg_ParseTuple(args, "|O", &privateObj))
@@ -204,6 +207,7 @@
 static PyObject *
 PYM_getProperty(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
 #ifndef Py_UNICODE_WIDE
   PYM_JSObject *object;
   Py_UNICODE *string;
@@ -244,6 +248,7 @@
 static PyObject *
 PYM_gc(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
   JS_GC(self->cx);
   Py_RETURN_NONE;
 }
@@ -251,6 +256,7 @@
 static PyObject *
 PYM_initStandardClasses(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
   PYM_JSObject *object;
 
   if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object))
@@ -267,6 +273,7 @@
 static PyObject *
 PYM_evaluateScript(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
   PYM_JSObject *object;
   const char *source;
   int sourceLen;
@@ -296,6 +303,7 @@
 static PyObject *
 PYM_defineProperty(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
   PYM_JSObject *object;
   PyObject *value;
   const char *name;
@@ -324,6 +332,7 @@
 static PyObject *
 PYM_callFunction(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
   PYM_JSObject *obj;
   PYM_JSFunction *fun;
   PyObject *funcArgs;
@@ -368,6 +377,7 @@
 static PyObject *
 PYM_newFunction(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
   PyObject *callable;
   const char *name;
 
@@ -380,6 +390,7 @@
 static PyObject *
 PYM_setOperationCallback(PYM_JSContextObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self->runtime);
   PyObject *callable;
 
   if (!PyArg_ParseTuple(args, "O", &callable))
--- a/runtime.c	Sun Aug 09 15:46:40 2009 -0700
+++ b/runtime.c	Sun Aug 09 16:17:25 2009 -0700
@@ -46,6 +46,7 @@
 
   self = (PYM_JSRuntimeObject *) type->tp_alloc(type, 0);
   if (self != NULL) {
+    self->thread = PyThread_get_thread_ident();
     self->rt = NULL;
     self->cx = NULL;
     self->objects.ops = NULL;
@@ -106,6 +107,7 @@
 static PyObject *
 PYM_newContext(PYM_JSRuntimeObject *self, PyObject *args)
 {
+  PYM_SANITY_CHECK(self);
   JSContext *cx = JS_NewContext(self->rt, 8192);
   if (cx == NULL) {
     PyErr_SetString(PYM_error, "JS_NewContext() failed");
--- a/runtime.h	Sun Aug 09 15:46:40 2009 -0700
+++ b/runtime.h	Sun Aug 09 16:17:25 2009 -0700
@@ -40,12 +40,20 @@
 #include <jsapi.h>
 #include <jsdhash.h>
 #include <Python/Python.h>
+#include <Python/pythread.h>
+
+#define PYM_SANITY_CHECK(runtime) \
+  if (PyThread_get_thread_ident() != runtime->thread) {               \
+    PyErr_SetString(PYM_error, "Function called from wrong thread"); \
+    return NULL; \
+  }
 
 typedef struct {
   PyObject_HEAD
   JSRuntime *rt;
   JSContext *cx;
   JSDHashTable objects;
+  long thread;
 } PYM_JSRuntimeObject;
 
 extern PyTypeObject PYM_JSRuntimeType;
--- a/test_pymonkey.py	Sun Aug 09 15:46:40 2009 -0700
+++ b/test_pymonkey.py	Sun Aug 09 16:17:25 2009 -0700
@@ -31,6 +31,18 @@
             was_raised = True
         self.assertTrue(was_raised)
 
+    def testThreadSafetyExceptionIsRaised(self):
+        stuff = {}
+        def make_runtime():
+            stuff['rt'] = pymonkey.Runtime()
+        thread = threading.Thread(target = make_runtime)
+        thread.start()
+        thread.join()
+        self.assertRaises(pymonkey.error,
+                          stuff['rt'].new_context)
+        self.assertEqual(self.last_exception.message,
+                         'Function called from wrong thread')
+
     def testClearObjectPrivateWorks(self):
         class Foo(object):
             pass