Commits

Ronald Oussoren  committed 656ba4c

With this patch it is possible to acquire the mutex for an object
using a context manager::

with objc.object_lock(anObject):
print "Mutex for anObject held here"

NOTE: the naming is sligtly different from the pure python code that
was posted on the list.

NOTE2: unittests are conspicuously absent for now.

  • Participants
  • Parent commits 7c91299
  • Branches pyobjc2

Comments (0)

Files changed (6)

File pyobjc-core/Lib/objc/__init__.py

 from _compat import *
 from _pythonify import *
 from _functions import *
+from _locking import *
 
 ###
 # This can be usefull to hunt down memory problems in the testsuite.

File pyobjc-core/Lib/objc/_locking.py

+"""
+Support for @synchronized blocks
+
+The python class object_lock is a contextmanager for with statements that 
+can also be used manually. 
+"""
+import objc as _objc
+
+class object_lock(object):
+    """
+    A context manager that implements the same feature as
+    @synchronized statements in Objective-C. Locking can also
+    be done manually using the ``lock`` and ``unlock`` methods.
+
+    The mutex for object ``anObject`` is represented by 
+    ``objc.object_lock(anObject)``.
+    """
+    def __init__(self, value):
+        self.__value = value
+
+    def __enter__(self):
+        _objc._objc_sync_enter(self.__value)
+
+    def __exit__(self, type, value, tp):
+        _objc._objc_sync_exit(self.__value)
+
+    def lock(self):
+        _objc._objc_sync_enter(self.__value)
+
+    def unlock(self):
+        _objc._objc_sync_exit(self.__value)

File pyobjc-core/Modules/objc/module.m

 #include "pyobjc.h"
 #include "OC_NSBundleHack.h"
 #include <objc/Protocol.h>
+#include <objc/objc-sync.h>
 
 #include <stddef.h>
 #include <ctype.h>
 	return Py_None;
 }
 
+/* Support for locking */
+static PyObject*
+PyObjC_objc_sync_enter(PyObject* self __attribute__((__unused__)), PyObject* args)
+{
+	NSObject* object;
+	int rv;
+
+	if (!PyArg_ParseTuple(args, "O&", 
+			PyObjCObject_Convert, &object)) {
+		return NULL;
+	}
+
+	rv = objc_sync_enter(object);
+	if (rv == OBJC_SYNC_SUCCESS) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+
+	PyErr_Format(PyObjCExc_LockError, "objc_sync_enter failed: %d", rv);
+	return NULL;
+}
+
+static PyObject*
+PyObjC_objc_sync_exit(PyObject* self __attribute__((__unused__)), PyObject* args)
+{
+	NSObject* object;
+	int rv;
+
+	if (!PyArg_ParseTuple(args, "O&", 
+			PyObjCObject_Convert, &object)) {
+		return NULL;
+	}
+
+	rv = objc_sync_exit(object);
+	if (rv == OBJC_SYNC_SUCCESS) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+
+	PyErr_Format(PyObjCExc_LockError, "objc_sync_exit failed: %d", rv);
+	return NULL;
+}
+
+static PyObject*
+PyObjC_objc_sync_notify(PyObject* self __attribute__((__unused__)), PyObject* args)
+{
+	NSObject* object;
+	int rv;
+
+	if (!PyArg_ParseTuple(args, "O&", 
+			PyObjCObject_Convert, &object)) {
+		return NULL;
+	}
+
+	rv = objc_sync_notify(object);
+	if (rv == OBJC_SYNC_SUCCESS) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+
+	PyErr_Format(PyObjCExc_LockError, "objc_sync_notify failed: %d", rv);
+	return NULL;
+}
+
+static PyObject*
+PyObjC_objc_sync_notifyAll(PyObject* self __attribute__((__unused__)), PyObject* args)
+{
+	NSObject* object;
+	int rv;
+
+	if (!PyArg_ParseTuple(args, "O&", 
+			PyObjCObject_Convert, &object)) {
+		return NULL;
+	}
+
+	rv = objc_sync_notifyAll(object);
+	if (rv == OBJC_SYNC_SUCCESS) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+
+	PyErr_Format(PyObjCExc_LockError, "objc_sync_notifyAll failed: %d", rv);
+	return NULL;
+}
+
+
+static PyObject*
+PyObjC_objc_sync_wait(PyObject* self __attribute__((__unused__)), PyObject* args)
+{
+	NSObject* object;
+	long long timeout;
+	int rv;
+
+	if (!PyArg_ParseTuple(args, "O&L", 
+			PyObjCObject_Convert, &object, &timeout)) {
+		return NULL;
+	}
+
+	rv = objc_sync_wait(object, timeout);
+	if (rv == OBJC_SYNC_SUCCESS) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+
+	PyErr_Format(PyObjCExc_LockError, "objc_sync_wait failed: %d", rv);
+	return NULL;
+}
+
+
 PyDoc_STRVAR(parseBridgeSupport_doc,
  "parseBridgeSupport(xmldata, globals, framework [, dylib_path] [, inlineTab]) -> None\n"
  "\n"
 		METH_O, "private function" },
 	{ "_ivar_dict", (PyCFunction)ivar_dict, METH_NOARGS, "private functions" },
 
+	{ "_objc_sync_enter", (PyCFunction)PyObjC_objc_sync_enter,
+		METH_VARARGS, "acquire mutex for an object" },
+	{ "_objc_sync_exit", (PyCFunction)PyObjC_objc_sync_exit,
+		METH_VARARGS, "release mutex for an object" },
+	{ "_objc_sync_wait", (PyCFunction)PyObjC_objc_sync_exit,
+		METH_VARARGS, "wait for mutex for an object" },
+	{ "_objc_sync_notify", (PyCFunction)PyObjC_objc_sync_notify,
+		METH_VARARGS, 
+		"notify a thread waiting for mutex for an object" },
+	{ "_objc_sync_notifyAll", (PyCFunction)PyObjC_objc_sync_notifyAll,
+		METH_VARARGS, 
+		"notify a all threads waiting for mutex for an object" },
+
 
 	{ 0, 0, 0, 0 } /* sentinel */
 };

File pyobjc-core/Modules/objc/objc_util.h

 extern PyObject* PyObjCExc_InternalError;
 extern PyObject* PyObjCExc_UnInitDeallocWarning;
 extern PyObject* PyObjCExc_ObjCRevivalWarning;
+extern PyObject* PyObjCExc_LockError;
 
 int PyObjCUtil_Init(PyObject* module);
 

File pyobjc-core/Modules/objc/objc_util.m

 PyObject* PyObjCExc_InternalError;
 PyObject* PyObjCExc_UnInitDeallocWarning;
 PyObject* PyObjCExc_ObjCRevivalWarning;
+PyObject* PyObjCExc_LockError;
 
 
 int 
 	NEW_EXC(PyObjCExc_InternalError, "internal_error", PyObjCExc_Error);
 	NEW_EXC(PyObjCExc_UnInitDeallocWarning, "UninitializedDeallocWarning", PyExc_Warning);
 	NEW_EXC(PyObjCExc_ObjCRevivalWarning, "RevivedObjectiveCObjectWarning", PyExc_Warning);
+	NEW_EXC(PyObjCExc_LockError, "LockError", PyObjCExc_Error);
 
 	return 0;
 }

File pyobjc-core/NEWS.txt

 
 An overview of the relevant changes in new, and older, releases.
 
+Version 2.1 (...)
+-----------------
+
+- Add support for interacting with '@synchronized' blocks in Objective-C.
+
+  The function ``object_lock(object)`` is a contextmanager that acquires and
+  releases the '@synchronized' mutex for an object, and can also be used
+  manually.
+
+  That is (as context manager)::
+  	from __future__ import with_statement
+
+	obj = NSObject.new()
+
+	with objc.object_lock(obj):
+	    # Perform work while owning the @synchronize lock
+	    pass
+
+   or (manually)::
+
+   	obj = NSObject.new()
+	mutex = objc.object_lock(obj)
+	mutex.lock()
+	try:
+	    # Perform work while owning the @synchronized lock
+	    pass
+	finally:
+	    mutex.unlock()
+
+   Note that the first version is slightly saver (see the documentation
+   for with-statements for the details).
+
+
+Version 2.0.1 (...)
+-------------------
+
+- Fix crash when printing CF objects that are magic cookies.
+
+
 Version 2.0 (LEOPARD, post WWDC07)
 ----------------------------------