File: rstacklet.py

package info (click to toggle)
pypy3 7.3.19%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 212,236 kB
  • sloc: python: 2,098,316; ansic: 540,565; sh: 21,462; asm: 14,419; cpp: 4,451; makefile: 4,209; objc: 761; xml: 530; exp: 499; javascript: 314; pascal: 244; lisp: 45; csh: 12; awk: 4
file content (136 lines) | stat: -rw-r--r-- 4,536 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import sys
from rpython.rlib import _rffi_stacklet as _c
from rpython.rlib import jit
from rpython.rlib.objectmodel import fetch_translated_config
from rpython.rtyper.lltypesystem import lltype, llmemory
from rpython.rlib import rvmprof

DEBUG = False


class StackletThread(object):

    @jit.dont_look_inside
    def __init__(self, _argument_ignored_for_backward_compatibility=None):
        self._gcrootfinder = _getgcrootfinder(fetch_translated_config())
        self._thrd = _c.newthread()
        if not self._thrd:
            raise MemoryError
        self._thrd_deleter = StackletThreadDeleter(self._thrd)
        if DEBUG:
            assert debug.sthread is None, "multithread debug support missing"
            debug.sthread = self

    @jit.dont_look_inside
    def new(self, callback, arg=llmemory.NULL):
        if DEBUG:
            callback = _debug_wrapper(callback)
        x = rvmprof.save_stack()
        try:
            rvmprof.empty_stack()
            h = self._gcrootfinder.new(self, callback, arg)
        finally:
            rvmprof.restore_stack(x)
        if DEBUG:
            debug.add(h)
        return h
    new._annspecialcase_ = 'specialize:arg(1)'

    @jit.dont_look_inside
    def switch(self, stacklet):
        if DEBUG:
            debug.remove(stacklet)
        x = rvmprof.save_stack()
        try:
            h = self._gcrootfinder.switch(stacklet)
        finally:
            rvmprof.restore_stack(x)
        if DEBUG:
            debug.add(h)
        return h

    def is_empty_handle(self, stacklet):
        # note that "being an empty handle" and being equal to
        # "get_null_handle()" may be the same, or not; don't rely on it
        return self._gcrootfinder.is_empty_handle(stacklet)

    def get_null_handle(self):
        return self._gcrootfinder.get_null_handle()

    def _freeze_(self):
        raise Exception("StackletThread instances must not be seen during"
                        " translation.")


class StackletThreadDeleter(object):
    # quick hack: the __del__ is on another object, so that
    # if the main StackletThread ends up in random circular
    # references, on pypy deletethread() is only called
    # when all that circular reference mess is gone.
    def __init__(self, thrd):
        self._thrd = thrd
    def __del__(self):
        thrd = self._thrd
        if thrd:
            self._thrd = lltype.nullptr(_c.thread_handle.TO)
            _c.deletethread(thrd)

# ____________________________________________________________

def _getgcrootfinder(config):
    if config is None and '__pypy__' in sys.builtin_module_names:
        import py
        py.test.skip("cannot run the stacklet tests on top of pypy: "
                     "calling directly the C function stacklet_switch() "
                     "will crash, depending on details of your config")
    if config is not None:
        assert config.translation.continuation, (
            "stacklet: you have to translate with --continuation")
    if (config is None or
        config.translation.gc in ('ref', 'boehm', 'none')):   # for tests
        gcrootfinder = 'n/a'
    else:
        gcrootfinder = config.translation.gcrootfinder
    gcrootfinder = gcrootfinder.replace('/', '_')
    module = __import__('rpython.rlib._stacklet_%s' % gcrootfinder,
                        None, None, ['__doc__'])
    return module.gcrootfinder
_getgcrootfinder._annspecialcase_ = 'specialize:memo'


class StackletDebugError(Exception):
    pass

class Debug(object):
    def __init__(self):
        self.sthread = None
        self.active = []
    def _cleanup_(self):
        self.__init__()
    def add(self, h):
        if not self.sthread.is_empty_handle(h):
            if h == self.sthread.get_null_handle():
                raise StackletDebugError("unexpected null handle")
            self.active.append(h)
    def remove(self, h):
        try:
            i = self.active.index(h)
        except ValueError:
            if self.sthread.is_empty_handle(h):
                msg = "empty stacklet handle"
            elif h == self.sthread.get_null_handle():
                msg = "unexpected null handle"
            else:
                msg = "double usage of handle %r" % (h,)
            raise StackletDebugError(msg)
        del self.active[i]
debug = Debug()

def _debug_wrapper(callback):
    def wrapper(h, arg):
        debug.add(h)
        h = callback(h, arg)
        debug.remove(h)
        return h
    return wrapper
_debug_wrapper._annspecialcase_ = 'specialize:memo'