[pypy-commit] pypy gc-incminimark-pinning: added pinning functions to rgc, rfile, rffi and ll_os

groggi noreply at buildbot.pypy.org
Mon Jun 2 17:23:42 CEST 2014


Author: Gregor Wegberg <code at gregorwegberg.com>
Branch: gc-incminimark-pinning
Changeset: r71807:d6c6003d1ae9
Date: 2014-05-08 13:34 +0200
http://bitbucket.org/pypy/pypy/changeset/d6c6003d1ae9/

Log:	added pinning functions to rgc, rfile, rffi and ll_os

	work in progress (for a long time). RFile example compiles and runs.

diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -476,6 +476,11 @@
         self.set_major_threshold_from(0.0)
         ll_assert(self.extra_threshold == 0, "extra_threshold set too early")
         self.initial_cleanup = self.nursery_size
+
+        # XXX remove (groggi)
+        debug_print("nursery start ", self.nursery)
+        debug_print("nursery top ", self.nursery_top)
+
         debug_stop("gc-set-nursery-size")
 
 
diff --git a/rpython/rlib/rfile.py b/rpython/rlib/rfile.py
--- a/rpython/rlib/rfile.py
+++ b/rpython/rlib/rfile.py
@@ -133,7 +133,7 @@
         if not ll_file:
             raise ValueError("I/O operation on closed file")
         assert value is not None
-        ll_value = rffi.get_nonmovingbuffer(value)
+        ll_value, is_pinned, is_raw = rffi.get_nonmovingbuffer(value)
         try:
             # note that since we got a nonmoving buffer, it is either raw
             # or already cannot move, so the arithmetics below are fine
@@ -143,7 +143,7 @@
                 errno = rposix.get_errno()
                 raise OSError(errno, os.strerror(errno))
         finally:
-            rffi.free_nonmovingbuffer(value, ll_value)
+            rffi.free_nonmovingbuffer(value, ll_value, is_pinned, is_raw)
 
     def close(self):
         """Closes the described file.
diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py
--- a/rpython/rlib/rgc.py
+++ b/rpython/rlib/rgc.py
@@ -18,6 +18,34 @@
     """
     pass
 
+def pin(obj):
+    """If 'obj' can move, then attempt to temporarily fix it.  This
+    function returns True if and only if 'obj' could be pinned; this is
+    a special state in the GC.  Note that can_move(obj) still returns
+    True even on pinned objects, because once unpinned it will indeed be
+    able to move again.  In other words, the code that succeeded in
+    pinning 'obj' can assume that it won't move until the corresponding
+    call to unpin(obj), despite can_move(obj) still being True.  (This
+    is important if multiple threads try to os.write() the same string:
+    only one of them will succeed in pinning the string.)
+
+    Note that this can return False for any reason, e.g. if the 'obj' is
+    already non-movable or already pinned, if the GC doesn't support
+    pinning, or if there are too many pinned objects.
+    """
+    # XXX doc string based on gc-minimark-pinning branch
+    # XXX use doc string a basis for implementation behavior
+    # XXX update doc string to match actual behavior
+    return False
+
+def unpin(obj):
+    """Unpin 'obj', allowing it to move again.
+    Must only be called after a call to pin(obj) returned True.
+    """
+    # XXX update doc string to match actual behavior
+    raise AssertionError("pin() always returns False, "
+                         "so unpin() should not be called")
+
 # ____________________________________________________________
 # Annotation and specialization
 
diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -23,6 +23,9 @@
 from rpython.translator.platform import CompilationError
 import os, sys
 
+# XXX remove (groggi)
+from rpython.rlib.debug import debug_print, debug_start, debug_stop
+
 class CConstant(Symbolic):
     """ A C-level constant, maybe #define, rendered directly.
     """
@@ -735,7 +738,7 @@
             i += 1
         return assert_str0(b.build())
 
-    # str -> char*
+    # str -> char*, bool, bool
     # Can't inline this because of the raw address manipulation.
     @jit.dont_look_inside
     def get_nonmovingbuffer(data):
@@ -744,23 +747,52 @@
         arithmetic to return a pointer to the characters of a string if the
         string is already nonmovable.  Must be followed by a
         free_nonmovingbuffer call.
+
+        First bool returned indicates if 'data' was pinned. Second bool returned
+        indicates if we did a raw alloc because pinning didn't work. Bot bools
+        should never be true at the same time.
         """
+        # XXX update doc string
+
+        debug_start("groggi-get_nonmovingbuffer")
+        debug_print("data address ", cast_ptr_to_adr(data))
+
         lldata = llstrtype(data)
+        count = len(data)
+
+        pinned = False
         if rgc.can_move(data):
-            count = len(data)
-            buf = lltype.malloc(TYPEP.TO, count, flavor='raw')
-            copy_string_to_raw(lldata, buf, 0, count)
-            return buf
+            if rgc.pin(data):
+                debug_print("raw_and_pinned: len = %s" % count)
+                pinned = True
+            else:
+                debug_print("allocating_raw_and_copying: len = %s" % count)
+
+                buf = lltype.malloc(TYPEP.TO, count, flavor='raw')
+                copy_string_to_raw(lldata, buf, 0, count)
+
+                debug_stop("groggi-get_nonmovingbuffer")
+                return buf, pinned, True
+                # ^^^ raw malloc used to get a nonmovable copy
         else:
-            data_start = cast_ptr_to_adr(lldata) + \
-                offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0)
-            return cast(TYPEP, data_start)
+            debug_print("raw_and_nonmovable: len = %s" % count)
+
+        # following code is executed if:
+        # - rgc.can_move(data) and rgc.pin(data) both returned true
+        # - rgc.can_move(data) returned false
+        data_start = cast_ptr_to_adr(lldata) + \
+            offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0)
+
+        debug_stop("groggi-get_nonmovingbuffer")
+        return cast(TYPEP, data_start), pinned, False
+        # ^^^ already nonmovable. Therefore it's not raw allocated nor
+        # pinned.
     get_nonmovingbuffer._annenforceargs_ = [strtype]
 
-    # (str, char*) -> None
+    # (str, char*, bool, bool) -> None
     # Can't inline this because of the raw address manipulation.
     @jit.dont_look_inside
-    def free_nonmovingbuffer(data, buf):
+    def free_nonmovingbuffer(data, buf, is_pinned, is_raw):
         """
         Either free a non-moving buffer or keep the original storage alive.
         """
@@ -769,14 +801,23 @@
         # if 'buf' points inside 'data'.  This is only possible if we
         # followed the 2nd case in get_nonmovingbuffer(); in the first case,
         # 'buf' points to its own raw-malloced memory.
-        data = llstrtype(data)
-        data_start = cast_ptr_to_adr(data) + \
-            offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0)
-        followed_2nd_path = (buf == cast(TYPEP, data_start))
+
+        debug_start("groggi-free_nonmovingbuffer")
+        debug_print("data address ", cast_ptr_to_adr(data))
+
+        assert not (is_pinned and is_raw)
+
+        if is_pinned:
+            rgc.unpin(data)
+        elif is_raw:
+            lltype.free(buf, flavor='raw')
+        # if is_pinned and is_raw are false: data was already nonmovable,
+        # we have nothing to clean up
+
         keepalive_until_here(data)
-        if not followed_2nd_path:
-            lltype.free(buf, flavor='raw')
-    free_nonmovingbuffer._annenforceargs_ = [strtype, None]
+
+        debug_stop("groggi-free_nonmovingbuffer")
+    free_nonmovingbuffer._annenforceargs_ = [strtype, None, bool, bool]
 
     # int -> (char*, str)
     def alloc_buffer(count):
diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py
--- a/rpython/rtyper/module/ll_os.py
+++ b/rpython/rtyper/module/ll_os.py
@@ -1028,7 +1028,7 @@
         def os_write_llimpl(fd, data):
             count = len(data)
             rposix.validate_fd(fd)
-            buf = rffi.get_nonmovingbuffer(data)
+            buf, is_pinned, is_raw = rffi.get_nonmovingbuffer(data)
             try:
                 written = rffi.cast(lltype.Signed, os_write(
                     rffi.cast(rffi.INT, fd),
@@ -1036,7 +1036,7 @@
                 if written < 0:
                     raise OSError(rposix.get_errno(), "os_write failed")
             finally:
-                rffi.free_nonmovingbuffer(data, buf)
+                rffi.free_nonmovingbuffer(data, buf, is_pinned, is_raw)
             return written
 
         return extdef([int, str], SomeInteger(nonneg=True),


More information about the pypy-commit mailing list