Last active
December 26, 2015 18:54
-
-
Save cheery/f6690a600449b1c770e7 to your computer and use it in GitHub Desktop.
RPython crash, a bug or user-error?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# compile with: | |
# PYTHONPATH=./pypy-4.0.1-src/ python pypy-4.0.1-src/rpython/bin/rpython crash.py | |
# This thing produces inconsistent results that seem like stack corruption. | |
from rpython.rlib.objectmodel import we_are_translated, keepalive_until_here | |
from rpython.config.translationoption import get_combined_translation_config | |
from rpython.rlib.rstacklet import StackletThread | |
import time | |
config = get_combined_translation_config(translating=True) | |
config.translation.continuation = True | |
class GlobalState(object): | |
sthread = None | |
cont = None | |
eventloop = None | |
ev_queue = None | |
ev_sleepers = None | |
origin = None | |
target = None | |
error = None | |
g = GlobalState() | |
def entry_point(raw_argv): | |
g.ev_queue = [] | |
g.ev_sleepers = [] | |
g.sthread = sthread = StackletThread(config) | |
g.cont = None | |
g.target = Greenlet(None, []) | |
g.eventloop = g.target | |
switch([schedule([])]) | |
rno = 0 | |
keepalive_until_here(sthread) | |
return rno | |
def schedule(argv): | |
if len(argv) > 0 and isinstance(argv[0], Greenlet): | |
c = argv.pop(0) | |
assert isinstance(c, Greenlet) | |
c.argv += argv | |
else: | |
c = Greenlet(g.eventloop, argv) | |
g.ev_queue.append(c) | |
return c | |
class Suspended(object): | |
def __init__(self, wakeup, greenlet): | |
assert isinstance(greenlet, Greenlet), "suspended object must be a greenlet" | |
self.wakeup = wakeup | |
self.greenlet = greenlet | |
def sleep_greenlet(duration): | |
if g.target == g.eventloop: | |
print 'target is eventloop' | |
assert False, "bad context for greenlet sleep" | |
print 'counting wakeup time' | |
wakeup = time.time() + duration | |
print 'adding suspended sleeper' | |
assert g.ev_sleepers is not None | |
print 'sleepers in queue', len(g.ev_sleepers) | |
if g.target is None: | |
print 'g.target is None' | |
else: | |
print 'g.target is something else' #g.target.repr() | |
g.ev_sleepers.append(Suspended(wakeup, g.target)) | |
print 'sleep setup, goin sleep' | |
return switch([g.eventloop]) | |
class Greenlet(object): | |
def __init__(self, parent, argv): | |
self.parent = parent | |
self.handle = None | |
self.argv = argv | |
def new_greenlet(head, arg): | |
cont = Continuation.entry(g, head, arg) | |
g.origin.handle, self = cont, g.target | |
g.origin = None | |
argv, self.argv = self.argv, [] | |
print "greenlet received arguments" | |
print "hello in greenlet" | |
result = sleep_greenlet(1.0)#space.Float(1.0)) | |
parent = self.parent | |
while parent and parent.handle.is_empty(): # note that non-initiated or non-activated parent is invalid. | |
parent = parent.parent | |
assert parent is not None | |
g.origin = self | |
g.target = parent | |
self.handle, parent.handle = parent.handle, self.handle | |
return self.handle.exit() # XXX: note that the handle must not be null for this to work. | |
def switch(argv): | |
print "switch" | |
assert len(argv) > 0 | |
target = argv.pop(0) | |
self = g.target | |
if not isinstance(target, Greenlet): | |
assert False | |
if g.target is target: | |
argv, self.argv = self.argv, [] | |
argv.extend(argv) | |
if target.handle and target.handle.is_empty(): | |
assert False | |
target.argv.extend(argv) | |
print "amount of arguments given:", len(target.argv) | |
g.origin = self | |
g.target = target | |
g.error = None | |
print "amount of arguments in eventloop:", len(g.eventloop.argv) | |
if self is g.eventloop: | |
print "switch from eventloop" | |
if target.handle: | |
self.handle, target.handle = target.handle, self.handle | |
self.handle.switch() | |
else: | |
Continuation.new(g, new_greenlet) # the side that can permute without error will do so. | |
g.origin = None | |
print "switch returned" | |
if self is None: | |
print "wtf, self is None" | |
if self.argv is None: | |
print "self.argv is None, will crash" | |
if self is g.eventloop: | |
print "switch into eventloop" | |
print "amount of arguments in eventloop:", len(g.eventloop.argv) | |
print "amount of returned args", len(self.argv) | |
assert len(self.argv) == 0 | |
argv, self.argv = self.argv, [] | |
# Continuation represents either live or empty continuation. | |
# It is never 'blank' | |
class Continuation(object): | |
def __init__(self, sthread, h, gate): | |
self.sthread = sthread | |
self.h = h | |
self.gate = gate | |
def is_empty(self): | |
return self.sthread.is_empty_handle(self.h) or not self.gate | |
@staticmethod | |
def new(context, callback): | |
assert context.cont is None | |
sthread = context.sthread | |
context.cont = cont = Continuation(sthread, sthread.get_null_handle(), False) | |
cont.h = sthread.new(callback) | |
return cont | |
@staticmethod | |
def entry(context, h, arg): | |
this = context.cont | |
this.h = h | |
this.gate = True | |
context.cont = None | |
return this | |
def exit(self): | |
assert not self.is_empty(), "fatal error: empty return continuation" | |
self.gate = False | |
return self.h | |
def switch(self): | |
assert not self.is_empty(), "not so fatal error: empty switch continuation" | |
self.gate = False | |
self.h = self.sthread.switch(self.h) | |
def target(*args): | |
return entry_point, None | |
if __name__=='__main__': | |
sys.exit(entry_point(sys.argv)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This small change is enough that it doesn't crash. | |
from rpython.config.translationoption import get_combined_translation_config | |
from rpython.rlib import rgc | |
from rpython.rlib.rstacklet import StackletThread | |
config = get_combined_translation_config(translating=True) | |
config.translation.continuation = True | |
class Process: | |
sthread = None | |
proc = Process() | |
def entry_point(argv): | |
print "creating stacklet thread" | |
proc.sthread = sthread = StackletThread(config) | |
print "entering a new stacklet" | |
h = sthread.new(do_gc) | |
print "success" | |
return 0 | |
def do_gc(head, _): | |
print "doing GC collect inside stacklet thread" | |
rgc.collect() | |
print "done with GC collect" | |
return head | |
def target(*args): | |
return entry_point, None | |
if __name__=='__main__': | |
import sys | |
sys.exit(entry_point(sys.argv)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The following code results in Segmentation fault on ubuntu 15.10, when compiled like this: | |
# PYTHONPATH=./pypy-4.0.1-src/ python pypy-4.0.1-src/rpython/bin/rpython main.py | |
# | |
# Segmentation fault results before the "success" -message prints out. | |
from rpython.config.translationoption import get_combined_translation_config | |
from rpython.rlib import rgc | |
from rpython.rlib.rstacklet import StackletThread | |
config = get_combined_translation_config(translating=True) | |
config.translation.continuation = True | |
def entry_point(argv): | |
print "creating stacklet thread" | |
sthread = StackletThread(config) | |
print "entering a new stacklet" | |
h = sthread.new(do_gc) | |
print "success" | |
return 0 | |
def do_gc(head, _): | |
print "doing GC collect inside stacklet thread" | |
rgc.collect() | |
print "done with GC collect" | |
return head | |
def target(*args): | |
return entry_point, None | |
if __name__=='__main__': | |
import sys | |
sys.exit(entry_point(sys.argv)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment