Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Explicitly hold references to PyObject*s after conversion to char*.

If we are holding onto the char* version of a PyObject*, we need to
hold a reference to that PyObject itself. In CPython, the previous
code generally works because the ZNotice object would hold a reference
from __dict__. This assumption is not true in PyPy, and would also
break in weirder cases like someone subclassing ZNotice and replacing
'cls' with a property.

We can't just hold the objects in a Python list, because again, in
PyPy, that results in conversion to PyPy's internal format, which does
not hold onto the specific PyObject* generated by cpyext. So instead,
write some C code to maintain an object poo of objects to which we
need references.
  • Loading branch information...
commit cc6e791687adc19732edd52d4aaa56d1c259036e 1 parent 41015a2
@nelhage authored
Showing with 82 additions and 29 deletions.
  1. +9 −0 _zephyr.pxd
  2. +33 −27 _zephyr.pyx
  3. +29 −0 pool.c
  4. +9 −0 pool.h
  5. +2 −2 setup.py
View
9 _zephyr.pxd
@@ -102,3 +102,12 @@ cdef extern from "stdlib.h":
cdef extern from "string.h":
void * memset(void *, int, unsigned int)
+cdef extern from "pool.h":
+ ctypedef struct object_pool:
+ void **objects
+ size_t alloc
+ size_t count
+
+ void object_pool_init(object_pool *pool)
+ void object_pool_append(object_pool *pool, object obj)
+ void object_pool_free(object_pool *pool)
View
60 _zephyr.pyx
@@ -13,12 +13,6 @@ cdef object _string_c2p(char * string):
else:
return string
-cdef char * _string_p2c(object string) except *:
- if string is None:
- return NULL
- else:
- return string
-
class ZUid(object):
"""
A per-transaction unique ID for zephyrs
@@ -28,7 +22,7 @@ class ZUid(object):
self.address = ''
self.time = 0
-cdef void _ZUid_c2p(ZUnique_Id_t * uid, object p_uid):
+cdef void _ZUid_c2p(ZUnique_Id_t * uid, object p_uid) except *:
p_uid.address = inet_ntoa(uid.zuid_addr)
p_uid.time = uid.tv.tv_sec + (uid.tv.tv_usec / 100000.0)
@@ -37,6 +31,13 @@ cdef void _ZUid_p2c(object uid, ZUnique_Id_t * c_uid) except *:
c_uid.tv.tv_usec = int(uid.time)
c_uid.tv.tv_usec = int((uid.time - c_uid.tv.tv_usec) * 100000)
+cdef char * _string_p2c(object_pool *pool, object string) except *:
+ if string is None:
+ return NULL
+ else:
+ object_pool_append(pool, string);
+ return string
+
class ZNotice(object):
"""
A zephyr message
@@ -70,22 +71,27 @@ class ZNotice(object):
message = property(getmessage, setmessage)
def send(self):
+ cdef object_pool pool
cdef ZNotice_t notice
- _ZNotice_p2c(self, &notice)
+ try:
+ object_pool_init(&pool)
+ _ZNotice_p2c(self, &notice, &pool)
- original_message = self.message
+ original_message = self.message
- if self.auth:
- errno = ZSendNotice(&notice, ZAUTH)
- else:
- errno = ZSendNotice(&notice, ZNOAUTH)
- __error(errno)
+ if self.auth:
+ errno = ZSendNotice(&notice, ZAUTH)
+ else:
+ errno = ZSendNotice(&notice, ZNOAUTH)
+ __error(errno)
- _ZNotice_c2p(&notice, self)
+ _ZNotice_c2p(&notice, self)
- self.message = original_message
+ self.message = original_message
- ZFreeNotice(&notice)
+ ZFreeNotice(&notice)
+ finally:
+ object_pool_free(&pool);
cdef void _ZNotice_c2p(ZNotice_t * notice, object p_notice) except *:
p_notice.kind = notice.z_kind
@@ -109,7 +115,7 @@ cdef void _ZNotice_c2p(ZNotice_t * notice, object p_notice) except *:
else:
p_notice.message = PyString_FromStringAndSize(notice.z_message, notice.z_message_len)
-cdef void _ZNotice_p2c(object notice, ZNotice_t * c_notice) except *:
+cdef void _ZNotice_p2c(object notice, ZNotice_t * c_notice, object_pool *pool) except *:
memset(c_notice, 0, sizeof(ZNotice_t))
c_notice.z_kind = notice.kind
@@ -121,22 +127,22 @@ cdef void _ZNotice_p2c(object notice, ZNotice_t * c_notice) except *:
c_notice.z_port = notice.port
c_notice.z_auth = int(notice.auth)
- c_notice.z_class = _string_p2c(notice.cls)
- c_notice.z_class_inst = _string_p2c(notice.instance)
- c_notice.z_recipient = _string_p2c(notice.recipient)
- c_notice.z_sender = _string_p2c(notice.sender)
- c_notice.z_opcode = _string_p2c(notice.opcode)
- c_notice.z_default_format = _string_p2c(notice.format)
+ c_notice.z_class = _string_p2c(pool, notice.cls)
+ c_notice.z_class_inst = _string_p2c(pool, notice.instance)
+ c_notice.z_recipient = _string_p2c(pool, notice.recipient)
+ c_notice.z_sender = _string_p2c(pool, notice.sender)
+ c_notice.z_opcode = _string_p2c(pool, notice.opcode)
+ c_notice.z_default_format = _string_p2c(pool, notice.format)
c_notice.z_num_other_fields = len(notice.other_fields)
for i in range(c_notice.z_num_other_fields):
- c_notice.z_other_fields[i] = _string_p2c(notice.other_fields[i])
+ c_notice.z_other_fields[i] = _string_p2c(pool, notice.other_fields[i])
if isinstance(notice.message, unicode):
notice.encoded_message = notice.message.encode('utf-8')
else:
notice.encoded_message = notice.message
- c_notice.z_message = _string_p2c(notice.encoded_message)
+ c_notice.z_message = _string_p2c(pool, notice.encoded_message)
c_notice.z_message_len = len(notice.encoded_message)
def initialize():
@@ -245,7 +251,7 @@ def getSubscriptions():
__error(errno)
subs = []
- for i in xrange(num):
+ for i in range(num):
subs.append((csubs[i].zsub_class, csubs[i].zsub_classinst, csubs[i].zsub_recipient))
return subs
finally:
View
29 pool.c
@@ -0,0 +1,29 @@
+#include "Python.h"
+
+#include <stdlib.h>
+
+#include "pool.h"
+
+void object_pool_init(struct object_pool *pool) {
+ pool->objects = NULL;
+ pool->count = pool->alloc = 0;
+}
+
+void object_pool_append(struct object_pool *pool, PyObject *obj) {
+ if (pool->count == pool->alloc) {
+ size_t new_alloc = pool->alloc ? 2 * pool->alloc : 8;
+ pool->objects = realloc(pool->objects, new_alloc * sizeof(*pool->objects));
+ pool->alloc = new_alloc;
+ }
+ pool->objects[pool->count++] = obj;
+ Py_INCREF(obj);
+}
+
+void object_pool_free(struct object_pool *pool) {
+ int i;
+ for (i = 0; i < pool->count; i++) {
+ Py_DECREF(pool->objects[i]);
+ }
+ free(pool->objects);
+ object_pool_init(pool);
+}
View
9 pool.h
@@ -0,0 +1,9 @@
+typedef struct object_pool {
+ void **objects;
+ size_t count;
+ size_t alloc;
+} object_pool;
+
+void object_pool_init(struct object_pool *pool);
+void object_pool_append(struct object_pool *pool, PyObject *obj);
+void object_pool_free(struct object_pool *pool);
View
4 setup.py
@@ -16,8 +16,8 @@
py_modules=['zephyr'],
ext_modules=[
Extension("_zephyr",
- ["_zephyr.pyx"],
+ ["_zephyr.pyx", "pool.c"],
libraries=["zephyr"])
],
- cmdclass= {"build_ext": build_ext}
+ cmdclass= {"build_ext": build_ext},
)
Please sign in to comment.
Something went wrong with that request. Please try again.