changeset 66:b49180c39d0a

Pymonkey now handles the GIL properly so that Python code can run while JS code does.
author Atul Varma <varmaa@toolness.com>
date Sun, 26 Jul 2009 15:06:19 -0700
parents f89a582c1276
children b5160c82be65
files context.c function.c test_pymonkey.py utils.h
diffstat 4 files changed, 50 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/context.c	Sun Jul 26 13:09:58 2009 -0700
+++ b/context.c	Sun Jul 26 15:06:19 2009 -0700
@@ -42,6 +42,7 @@
 static JSBool
 PYM_operationCallback(JSContext *cx)
 {
+  PYM_PyAutoEnsureGIL gil;
   PYM_JSContextObject *context = (PYM_JSContextObject *)
     JS_GetContextPrivate(cx);
 
@@ -66,6 +67,8 @@
 static void
 PYM_reportError(JSContext *cx, const char *message, JSErrorReport *report)
 {
+  PYM_PyAutoEnsureGIL gil;
+
   // Convert JS warnings into Python warnings.
   if (JSREPORT_IS_WARNING(report->flags)) {
     if (report->filename)
@@ -138,9 +141,14 @@
   }
 
   jsval val;
-  if (!JS_GetUCProperty(self->cx, object->obj,
-                        JS_GetStringChars(jsString),
-                        JS_GetStringLength(jsString), &val)) {
+  JSBool result;
+  Py_BEGIN_ALLOW_THREADS;
+  result = JS_GetUCProperty(self->cx, object->obj,
+                            JS_GetStringChars(jsString),
+                            JS_GetStringLength(jsString), &val);
+  Py_END_ALLOW_THREADS;
+
+  if (!result) {
     // TODO: Get the actual JS exception. Any exception that exists
     // here will probably still be pending on the JS context.
     PyErr_SetString(PYM_error, "Getting property failed.");
@@ -195,8 +203,13 @@
   JS_BeginRequest(self->cx);
 
   jsval rval;
-  if (!JS_EvaluateScript(self->cx, object->obj, source, sourceLen,
-                         filename, lineNo, &rval)) {
+  JSBool result;
+  Py_BEGIN_ALLOW_THREADS;
+  result = JS_EvaluateScript(self->cx, object->obj, source, sourceLen,
+                             filename, lineNo, &rval);
+  Py_END_ALLOW_THREADS;
+
+  if (!result) {
     PYM_jsExceptionToPython(self);
     JS_EndRequest(self->cx);
     return NULL;
@@ -266,8 +279,14 @@
   // TODO: This assumes that a JSFunction * is actually a subclass of
   // a JSObject *, which may or may not be regarded as an implementation
   // detail.
-  if (!JS_CallFunction(self->cx, obj->obj, (JSFunction *) fun->base.obj,
-                       argc, argv, &rval)) {
+  JSBool result;
+  Py_BEGIN_ALLOW_THREADS;
+  result = JS_CallFunction(self->cx, obj->obj,
+                           (JSFunction *) fun->base.obj,
+                           argc, argv, &rval);
+  Py_END_ALLOW_THREADS;
+
+  if (!result) {
     PYM_jsExceptionToPython(self);
     return NULL;
   }
--- a/function.c	Sun Jul 26 13:09:58 2009 -0700
+++ b/function.c	Sun Jul 26 15:06:19 2009 -0700
@@ -52,6 +52,7 @@
 static void
 PYM_finalizeFunctionHolder(JSContext *cx, JSObject *obj)
 {
+  PYM_PyAutoEnsureGIL gil;
   PyObject *callable;
   if (PYM_getHeldFunction(cx, obj, &callable))
     Py_DECREF(callable);
@@ -95,6 +96,7 @@
                                jsval *argv,
                                jsval *rval)
 {
+  PYM_PyAutoEnsureGIL gil;
   jsval callee = JS_ARGV_CALLEE(argv);
   jsval functionHolder;
   if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(callee), 0, &functionHolder)) {
--- a/test_pymonkey.py	Sun Jul 26 13:09:58 2009 -0700
+++ b/test_pymonkey.py	Sun Jul 26 15:06:19 2009 -0700
@@ -1,6 +1,8 @@
 import sys
 import unittest
 import weakref
+import time
+import threading
 
 import pymonkey
 
@@ -38,12 +40,12 @@
         obj = cx.new_object()
         cx.init_standard_classes(obj)
 
-        # TODO: This isn't a very good test; we need to actually
-        # set up a signal or launch a separate thread to call
-        # this method as though it were a watchdog to limit the
-        # amount of time the JS can run. However, Pymonkey doesn't
-        # yet handle the GIL properly so this isn't possible.
-        cx.trigger_operation_callback()
+        def watchdog():
+            time.sleep(0.1)
+            cx.trigger_operation_callback()
+
+        thread = threading.Thread(target = watchdog)
+        thread.start()
 
         self.assertRaises(
             pymonkey.error,
--- a/utils.h	Sun Jul 26 13:09:58 2009 -0700
+++ b/utils.h	Sun Jul 26 15:06:19 2009 -0700
@@ -43,6 +43,20 @@
 #include <jsdhash.h>
 #include <Python/Python.h>
 
+class PYM_PyAutoEnsureGIL {
+public:
+  PYM_PyAutoEnsureGIL() {
+    state = PyGILState_Ensure();
+  }
+
+  ~PYM_PyAutoEnsureGIL() {
+    PyGILState_Release(state);
+  }
+
+protected:
+  PyGILState_STATE state;
+};
+
 typedef struct {
   JSDHashEntryStub base;
   void *value;