Skip to content

Instantly share code, notes, and snippets.

@cheery
Last active December 26, 2015 18:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cheery/f6690a600449b1c770e7 to your computer and use it in GitHub Desktop.
Save cheery/f6690a600449b1c770e7 to your computer and use it in GitHub Desktop.
RPython crash, a bug or user-error?
# 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 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))
# 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