Commits

Amaury Forgeot d'Arc  committed eedcddb

Use RWeakValueDictionary for _rawffi callbacks

  • Participants
  • Parent commits 9a46f08
  • Branches extend-rweakdict

Comments (0)

Files changed (2)

File pypy/module/_rawffi/callback.py

      wrap_value, unwrap_value, unwrap_truncate_int, unpack_argshapes
 from pypy.rlib.clibffi import USERDATA_P, CallbackFuncPtr, FUNCFLAG_CDECL
 from pypy.rlib.clibffi import ffi_type_void
+from pypy.rlib import rweakref
 from pypy.module._rawffi.tracker import tracker
 from pypy.interpreter.error import OperationError
 from pypy.interpreter import gateway
 
 def callback(ll_args, ll_res, ll_userdata):
     userdata = rffi.cast(USERDATA_P, ll_userdata)
-    callback_ptr = global_counter.CallbackPtr_by_number[userdata.addarg]
+    callback_ptr = global_counter.get(userdata.addarg)
     w_callable = callback_ptr.w_callable
     argtypes = callback_ptr.argtypes
     space = callback_ptr.space
             for i in range(resshape.size):
                 ll_res[i] = '\x00'
 
-# XXX some weird hackery to be able to recover W_CallbackPtr object
-#     out of number    
-class GlobalCounter:
-    def __init__(self):
-        self.CallbackPtr_id = 0
-        self.CallbackPtr_by_number = {}
+class W_CallbackPtr(W_DataInstance):
 
-global_counter = GlobalCounter()
-
-class W_CallbackPtr(W_DataInstance):
-    global_counter = global_counter
-    
     def __init__(self, space, w_callable, w_args, w_result,
                  flags=FUNCFLAG_CDECL):
         self.space = space
         else:
             self.result = None
             ffiresult = ffi_type_void
-        # necessary to keep stuff alive
-        number = global_counter.CallbackPtr_id
-        global_counter.CallbackPtr_id += 1
-        global_counter.CallbackPtr_by_number[number] = self
-        self.number = number
+        self.number = global_counter.add(self)
         self.ll_callback = CallbackFuncPtr(ffiargs, ffiresult,
-                                           callback, number, flags)
+                                           callback, self.number, flags)
         self.ll_buffer = rffi.cast(rffi.VOIDP, self.ll_callback.ll_closure)
         if tracker.DO_TRACING:
             addr = rffi.cast(lltype.Signed, self.ll_callback.ll_closure)
         if tracker.DO_TRACING:
             addr = rffi.cast(lltype.Signed, self.ll_callback.ll_closure)
             tracker.trace_free(addr)
-        del self.global_counter.CallbackPtr_by_number[self.number]
+        global_counter.remove(self.number)
+
+# A global storage to be able to recover W_CallbackPtr object out of number
+class GlobalCounter:
+    def __init__(self):
+        self.callback_id = 0
+        self.callbacks = rweakref.RWeakValueDictionary(int, W_CallbackPtr)
+
+    def add(self, w_callback):
+        self.callback_id += 1
+        id = self.callback_id
+        self.callbacks.set(id, w_callback)
+        return id
+
+    def remove(self, id):
+        self.callbacks.set(id, None)
+
+    def get(self, id):
+        return self.callbacks.get(id)
+
+global_counter = GlobalCounter()
 
 @unwrap_spec(flags=int)
 def descr_new_callbackptr(space, w_type, w_callable, w_args, w_result,

File pypy/module/_rawffi/test/test__rawffi.py

         cls.w_sizes_and_alignments = space.wrap(dict(
             [(k, (v.c_size, v.c_alignment)) for k,v in TYPEMAP.iteritems()]))
 
-    def teardown_method(self, func):
-        from pypy.module._rawffi.callback import global_counter
-        global_counter.CallbackPtr_by_number.clear()
-
     def test_libload(self):
         import _rawffi
         _rawffi.CDLL(self.libc_name)