[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