Ronald Oussoren avatar Ronald Oussoren committed 8cd6af6

- Change my e-mail address
- Python 2.2 work:
- revive autoGIL
- don't give up GIL when calling into Objective-C
- both only for Python 2.2
- Fix compile time warnings
- PyObjCGILState_Ensure is an alias for PyGILState_Ensure again,
the additional work should no longer be necessary now that we don't
use autoreleased objects when converting strings to Python.

Comments (0)

Files changed (21)

Examples/CurrencyConverter/00README.txt

 ==================
 
 :author: Ronald Oussoren
-:contact: oussoren@cistron.nl
+:contact: ronaldoussoren@mac.com
 
 .. contents:
 
 
 History:
 
-Ronald Oussoren <oussoren@cistron.nl> rewrote most of the module in 2002.  Ronald made it possible to subclass Objective-C classes from Python and added nearly complete support for the Foundation, the AppKit and the AddressBook frameworks.
+Ronald Oussoren <ronaldoussoren@mac.com> rewrote most of the module in 2002.  Ronald made it possible to subclass Objective-C classes from Python and added nearly complete support for the Foundation, the AppKit and the AddressBook frameworks.
 
 In the fall of 2002, Bill Bumgarner<bbum@codefab.com> added support for non-Framework builds of python.  Ronald and Bill subsequently added support for the Apple supplied build of Python.   Bill created the Project Builder template that allows for building standalone Cocoa applications that are implemented in Project Builder.
 

Installer Package/10.2/Resources/ReadMe.txt

     http://pyobjc.sourceforge.net/
 
 b.bum                   Ronald Oussoren
-bbum@codefab.com        oussoren@cistron.nl
+bbum@codefab.com        ronaldoussoren@mac.com

Installer Package/10.3/Resources/ReadMe.txt

     http://pyobjc.sourceforge.net/
 
 b.bum                   Ronald Oussoren
-bbum@codefab.com        oussoren@cistron.nl
+bbum@codefab.com        ronaldoussoren@mac.com

Installer Package/Resources/ReadMe.txt

 
     http://pyobjc.sourceforge.net/
 
-Ronald Oussoren <oussoren@cistron.nl>, b.bum <bbum@codefab.com>
+Ronald Oussoren <ronaldoussoren@mac.com>, b.bum <bbum@codefab.com>
 

Lib/AppKit/test/guitest_graphics.py

 
     def makeArray(self, points):
 
-        a = array.array('f', len(points) * (0, 0, 0, 0))
+        a = array.array('f', len(points) * [0, 0, 0, 0])
         for i in range(len(points)):
             p = points[i]
             a[(i*4) + 0] = p[0][0]

Lib/Foundation/__init__.py

         if initPath:
             execfile(initPath, globals(), locals())
 
+# Install an observer callback in the current CFRunLoop that will
+# automatically release and acquire the Global Interpreter Lock
+# when needed. This is needed so other Python threads get a chance
+# to run while we're inside the event loop.
+#
+# The autoGIL module is only present when using Python 2.2 on MacOS X
+try:
+    import autoGIL
+except ImportError:
+    pass
+else:
+    autoGIL.installAutoGIL()
+
 import protocols  # no need to export these, just register with PyObjC
 
 #

Lib/Foundation/test/test_threading.py

 import sys
 import time
 
+from objc.test import testbndl
+
 
 if "%02d%02d"%(sys.version_info[:2]) >= '0203':
     # On Python 2.3 and later we use the API from PEP311 to make it possible
             time.sleep(2)
             self.assertEquals(lst, range(100))
 
+        def testCalling(self):
+            class Dummy:
+                pass
+            class PyObjCTestCalling (objc.runtime.NSObject) :
+                def call(self):
+                    return Dummy()
+
+            my = testbndl.PyObjC_TestClass4.alloc().init()
+            cb = PyObjCTestCalling.alloc().init()
+
+            objc.runtime.NSThread.detachNewThreadSelector_toTarget_withObject_(
+                    'runThread:', my,  cb)
+
+            time.sleep(2)
+            
+            retval = my.returnObject()
+            self.assert_(isinstance(retval, Dummy))
 
 if __name__ == "__main__":
     unittest.main()

Lib/objc/test/testbndl.m

 
 @interface PyObjC_TestClass4 : NSObject
 {
+	id returnObject;
 }
 - (void)encodeWithCoder:(NSCoder*)coder;
+- (void)runThread:(id)object;
+- (id)returnObject;
 
 + (int)fetchInt:(NSCoder*)coder;
 + (double)fetchDouble:(NSCoder*)coder;
 @end
 
 @implementation PyObjC_TestClass4
+- (void)runThread:(id)object
+{
+	NSObject* pool = [[NSAutoreleasePool alloc] init];
+	returnObject = (id)[object call];
+	[returnObject retain];
+	[pool release];
+}
+
+- (id)returnObject;
+{
+	return returnObject;
+}
+
 - (void)encodeWithCoder:(NSCoder*)coder
 {
 	double d = 1.5;

Modules/AppKit/_AppKitMapping_NSBitmap.m

 {
 	PyObject* result;
 	struct objc_super super;
-	unsigned char *bitmapData;
+	unsigned char * volatile bitmapData;
 	int bytesPerPlane;
   
 	if (!PyArg_ParseTuple(arguments, "")) {
 	PyObjC_HANDLER
 		PyObjCErr_FromObjC(localException);
 		result = NULL;
+		bitmapData = NULL;
 		bytesPerPlane = -1;
 	PyObjC_ENDHANDLER
 

Modules/Foundation/_FoundationMapping_NSCoder.m

 	char* bytes;
 	int    size;
 	id     key;
-	PyObject* result;
 	struct objc_super super;
 
 	if  (!PyArg_ParseTuple(arguments, "t#O&", &bytes, &size, 
 		}
 	PyObjC_HANDLER
 		PyObjCErr_FromObjC(localException);
-		result = NULL;
 	PyObjC_ENDHANDLER
 
-	if (!PyErr_Occurred()) {
-		result = Py_None;
-		Py_INCREF(result);
-	}
+	if (PyErr_Occurred()) return NULL;
 
-	return result;
+	Py_INCREF(Py_None);
+	return Py_None;
 }
 
 static void 

Modules/autoGIL.c

+/*
+ * autoGIL - automaticly give up the GIL when the runloop is sleeping
+ *
+ * This module exports one function: installAutoGIL. 
+ */
+#include "Python.h"
+#include <CoreFoundation/CFRunLoop.h>
+
+/* These macros are defined in Python 2.3 but not 2.2 */
+#ifndef PyMODINIT_FUNC
+#define PyMODINIT_FUNC void
+#endif
+#ifndef PyDoc_STRVAR
+#define PyDoc_STRVAR(Var,Str) static char Var[] = Str
+#endif
+
+
+#undef AUTOGIL_DEBUG
+
+static PyObject *AutoGILError;
+
+
+static void autoGILCallback(
+		CFRunLoopObserverRef observer __attribute__((__unused__)),
+		CFRunLoopActivity activity,
+		void *info) 
+{
+        PyThreadState **p_tstate = (PyThreadState **)info;
+
+        switch (activity) {
+        case kCFRunLoopBeforeWaiting:
+                /* going to sleep, release GIL */
+#ifdef AUTOGIL_DEBUG
+                fprintf(stderr, "going to sleep, release GIL\n");
+#endif
+                *p_tstate = PyEval_SaveThread();
+                break;
+        case kCFRunLoopAfterWaiting:
+                /* waking up, acquire GIL */
+#ifdef AUTOGIL_DEBUG
+                fprintf(stderr, "waking up, acquire GIL\n");
+#endif
+                PyEval_RestoreThread(*p_tstate);
+                *p_tstate = NULL;
+                break;
+        default:
+                break;
+        }
+}
+
+static void infoRelease(const void *info) {
+        /* XXX This should get called when the run loop is deallocated,
+           but this doesn't seem to happen. So for now: leak. */
+        PyMem_Free((void *)info);
+}
+
+static PyObject *
+autoGIL_installAutoGIL(PyObject *self __attribute__((__unused__)))
+{
+        PyObject *tstate_dict = PyThreadState_GetDict();
+        PyObject *v;
+        CFRunLoopRef rl;
+        PyThreadState **p_tstate;  /* for use in the info field */
+        CFRunLoopObserverContext context = {0, NULL, NULL, NULL, NULL};
+        CFRunLoopObserverRef observer;
+
+        if (tstate_dict == NULL)
+                return NULL;
+        v = PyDict_GetItemString(tstate_dict, "autoGIL.InstalledAutoGIL");
+        if (v != NULL) {
+                /* we've already installed a callback for this thread */
+                Py_INCREF(Py_None);
+                return Py_None;
+        }
+
+        rl = CFRunLoopGetCurrent();
+        if (rl == NULL) {
+                PyErr_SetString(AutoGILError,
+                                "can't get run loop for current thread");
+                return NULL;
+        }
+
+        p_tstate = PyMem_Malloc(sizeof(PyThreadState *));
+        if (p_tstate == NULL) {
+                PyErr_SetString(PyExc_MemoryError,
+                                "not enough memory to allocate "
+                                "tstate pointer");
+                return NULL;
+        }
+        *p_tstate = NULL;
+        context.info = (void *)p_tstate;
+        context.release = infoRelease;
+
+        observer = CFRunLoopObserverCreate(
+                NULL,
+                kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting,
+                1, 0, autoGILCallback, &context);
+        if (observer == NULL) {
+                PyErr_SetString(AutoGILError,
+                                "can't create event loop observer");
+                return NULL;
+        }
+        CFRunLoopAddObserver(rl, observer, kCFRunLoopDefaultMode);
+        /* XXX how to check for errors? */
+
+        /* register that we have installed a callback for this thread */
+        if (PyDict_SetItemString(tstate_dict, "autoGIL.InstalledAutoGIL",
+                                 Py_None) < 0)
+                return NULL;
+
+        Py_INCREF(Py_None);
+        return Py_None;
+}
+
+PyDoc_STRVAR(autoGIL_installAutoGIL_doc,
+"installAutoGIL() -> None\n\
+Install an observer callback in the event loop (CFRunLoop) for the\n\
+current thread that will lock and unlock the Global Interpreter Lock\n\
+(GIL) at appropriate times, allowing other Python threads to run while\n\
+the event loop is running."
+);
+
+static PyMethodDef autoGIL_methods[] = {
+        {
+                "installAutoGIL",
+                (PyCFunction)autoGIL_installAutoGIL,
+                METH_NOARGS,
+                autoGIL_installAutoGIL_doc
+        },
+        { 0, 0, 0, 0 } /* sentinel */
+};
+
+PyDoc_STRVAR(autoGIL_docs,
+"The autoGIL module provides a function (installAutoGIL) that\n\
+automatically locks and unlocks Python's Global Interpreter Lock\n\
+when running an event loop."
+);
+
+void initautoGIL(void); /* Avoid warning about an undeclared function */
+
+PyMODINIT_FUNC
+initautoGIL(void)
+{
+        PyObject *mod;
+
+        mod = Py_InitModule4("autoGIL", autoGIL_methods, autoGIL_docs,
+                             NULL, PYTHON_API_VERSION);
+        if (mod == NULL) {
+                return;	
+	}
+
+        AutoGILError = PyErr_NewException("autoGIL.AutoGILError",
+                                          PyExc_Exception, NULL);
+        if (AutoGILError == NULL) {
+                return;
+	}
+        Py_INCREF(AutoGILError);
+        if (PyModule_AddObject(mod, "AutoGILError", AutoGILError) < 0) {
+                return;
+	}
+}

Modules/objc/OC_PythonObject.m

 	const char*        rettype = [msign methodReturnType];
 	int		   err;
 	PyObject*          args = NULL;
-	unsigned int       i;
+	volatile unsigned int       i;
 	unsigned int       argcount;      
 	int		   retsize;
 	char*              retbuffer;

Modules/objc/class-builder.m

 
 
 static void
-free_ivars(id self, PyObject* cls)
+free_ivars(id self, PyObject* volatile cls )
 {
 	/* Free all instance variables introduced through python */
-	PyObjCRT_Ivar_t var;
+	volatile PyObjCRT_Ivar_t var;
 
 	var = class_getInstanceVariable(PyObjCClass_GetClass(cls), "__dict__");
 	if (var != NULL) {
 		PyObject* clsDict; 
 		PyObject* clsValues;
 		PyObject* o;
-		int       len, i;
+		volatile int       i;
+		int len;
 
 		if (objcClass == nil) break;
 
 	int   arglen;
 	PyObject* pymeth;
 	PyObject* pyself;
-	int have_output = 0;
+	volatile int have_output = 0;
 	PyGILState_STATE state = PyObjCGILState_Ensure();
 
 	pyself = PyObjCObject_New(self);

Modules/objc/instance-var.m

 static int
 ivar_descr_set(PyObjCInstanceVariable* self, PyObject* obj, PyObject* value)
 {
-	PyObjCRT_Ivar_t var;
+	volatile PyObjCRT_Ivar_t var;
 	id   objc;
 	int  size;
 	int res;

Modules/objc/libffi_support.m

 	void*		  arg;
 	volatile int      flags;
 	SEL		  theSel;
-	PyThreadState* volatile    _save = NULL;
 
 	if (PyObjCIMP_Check(aMeth)) {
 		methinfo = PyObjCIMP_GetSignature(aMeth);
 		goto error_cleanup;
 	}
 
-	NS_DURING
+	PyObjC_DURING
 		if (PyObjCIMP_Check(aMeth)) {
-			_save = PyEval_SaveThread();
 			ffi_call(&cif, FFI_FN(PyObjCIMP_GetIMP(aMeth)), 
 				msgResult, values);
-			PyEval_RestoreThread(_save); _save = NULL;
 
 		} else {
 #ifdef GNU_RUNTIME
 			Method_t m = class_get_instance_method(super.class, 
 				meth->sel_selector);
 
-			_save = PyEval_SaveThread();
 			if (m == NULL) {
 				/* Class doesn't really have an IMP for the 
 				 * selector, find a forwarder for the method 
 				ffi_call(&cif, FFI_FN(m->method_imp), 
 					msgResult, values);
 			}
-			PyEval_RestoreThread(_save); _save = NULL;
 
 #else /* !GNU_RUNTIME */
 
-			_save = PyEval_SaveThread();
 			if (arglistOffset) {
 				ffi_call(&cif, FFI_FN(objc_msgSendSuper_stret), 
 					NULL, values);
 					msgResult, values);
 
 			}
-			PyEval_RestoreThread(_save); _save = NULL;
 #endif /* !GNU_RUNTIME */
 		}
 
-	NS_HANDLER
-		if (_save != NULL) {
-			PyEval_RestoreThread(_save); _save = NULL;
-		}
+	PyObjC_HANDLER
 		PyObjCErr_FromObjC(localException);
-	NS_ENDHANDLER
+	PyObjC_ENDHANDLER
 
 	if (PyErr_Occurred()) goto error_cleanup;
 

Modules/objc/module.m

 		return NULL;
 	}
 
-	Py_BEGIN_ALLOW_THREADS
-	[global_release_pool release];
-	global_release_pool = [[NSAutoreleasePool alloc] init];
-	Py_END_ALLOW_THREADS
+	PyObjC_DURING
+		[global_release_pool release];
+		global_release_pool = [[NSAutoreleasePool alloc] init];
+	PyObjC_HANDLER
+		PyObjCErr_FromObjC(localException);
+	PyObjC_ENDHANDLER
+
+	if (PyErr_Occurred()) return NULL;
 
 	Py_INCREF(Py_None);
 	return Py_None;

Modules/objc/objc_util.m

 
 PyGILState_STATE PyObjCGILState_Ensure(void)
 {
+	/* Now that PyObjCUnicode_New no longer uses autorelead objects it 
+	 * should no longer be necessaryt to create a transient release-pool
+	 * for calls from ObjC to python. 
+	 * The pool might also be unsafe because at least some python methods
+	 * return objects whose only reference is in the autorelease pool (
+	 * it is unverified if this really is a problem)
+	 */
+#if 1
+	return PyGILState_Ensure();
+#else
 	int shouldCreateThreadPool = (PyGILState_GetThisThreadState() == NULL) ? 1 : 0;
 	PyGILState_STATE state = PyGILState_Ensure();
 	if (shouldCreateThreadPool) {
 		Py_DECREF(pypool);
 	}
 	return state;
+#endif
 }
 
 int ObjCUtil_Init(PyObject* module)

Modules/objc/pyobjc-api.h

  * This is the *only* header file that should be used to access 
  * functionality in the core bridge.
  *
- * $Id: pyobjc-api.h,v 1.31 2004/04/07 11:43:13 ronaldoussoren Exp $
+ * $Id: pyobjc-api.h,v 1.32 2004/04/11 12:52:37 ronaldoussoren Exp $
  */
 
 #include <Python.h>
 
 #endif
 
-#endif
+/* threading support */
+#define PyObjC_DURING \
+		NS_DURING
 
+#define PyObjC_HANDLER NS_HANDLER
+
+#define PyObjC_ENDHANDLER \
+		NS_ENDHANDLER \
+
+#define PyObjC_BEGIN_WITH_GIL \
+	{ \
+		PyGILState_STATE _GILState; \
+		_GILState = PyObjCGILState_Ensure(); 
+
+#define PyObjC_GIL_FORWARD_EXC() \
+		do { \
+            PyObjCErr_ToObjCWithGILState(&_GILState); \
+		} while (0)
+
+
+#define PyObjC_GIL_RETURN(val) \
+		do { \
+			PyGILState_Release(_GILState); \
+			return (val); \
+		} while (0)
+
+#define PyObjC_GIL_RETURNVOID \
+		do { \
+			PyGILState_Release(_GILState); \
+			return; \
+		} while (0)
+
+
+#define PyObjC_END_WITH_GIL \
+		PyGILState_Release(_GILState); \
+	}
+
+
+#else /* Python 2.3 and later */
 
 /* threading support */
 #define PyObjC_DURING \
 		PyGILState_Release(_GILState); \
 	}
 
+#endif
+
+
+
 
 #ifndef GNU_RUNTIME
 #include <objc/objc-runtime.h>
 
     http://lists.sourceforge.net/lists/listinfo/pyobjc-dev
 
-b.bum <bbum@codefab.com>, Ronald Oussoren <oussoren@cistron.nl>
+b.bum <bbum@codefab.com>, Ronald Oussoren <ronaldoussoren@mac.com>
         #"-pedantic",
 
         "-Wno-import",
-        "-O0", "-g",
+        #"-O0", "-g",
         #"-Werror",
         #"-O3", "-mcpu=7450", "-maltivec",
         ]
               extra_link_args=OBJC_LDFLAGS),
     ]
 
+if sys.version == '2.2' or sys.version.startswith('2.2.'):
+    CoreExtensions.append(
+            Extension("autoGIL",
+                ["Modules/autoGIL.c"],
+                extra_link_args=OBJC_LDFLAGS))
+
 # Provide some dependency information on Python 2.3 and later, this
 # makes development slightly more convenient.
 if sys.version >= '2.3':
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.