File: rgil.py

package info (click to toggle)
pypy 5.6.0%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 97,040 kB
  • ctags: 185,069
  • sloc: python: 1,147,862; ansic: 49,642; cpp: 5,245; asm: 5,169; makefile: 529; sh: 481; xml: 232; lisp: 45
file content (145 lines) | stat: -rw-r--r-- 5,507 bytes parent folder | download
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
137
138
139
140
141
142
143
144
145
import py
from rpython.translator import cdir
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.rtyper.extregistry import ExtRegistryEntry

# these functions manipulate directly the GIL, whose definition does not
# escape the C code itself
translator_c_dir = py.path.local(cdir)

eci = ExternalCompilationInfo(
    includes = ['src/thread.h'],
    separate_module_files = [translator_c_dir / 'src' / 'thread.c'],
    include_dirs = [translator_c_dir],
    post_include_bits = ['#define RPY_WITH_GIL'])

llexternal = rffi.llexternal


_gil_allocate = llexternal('RPyGilAllocate', [], lltype.Void,
                           _nowrapper=True, sandboxsafe=True,
                           compilation_info=eci)

_gil_yield_thread = llexternal('RPyGilYieldThread', [], lltype.Signed,
                               _nowrapper=True, sandboxsafe=True,
                               compilation_info=eci)

_gil_release      = llexternal('RPyGilRelease', [], lltype.Void,
                               _nowrapper=True, sandboxsafe=True,
                               compilation_info=eci)

_gil_acquire      = llexternal('RPyGilAcquire', [], lltype.Void,
                              _nowrapper=True, sandboxsafe=True,
                              compilation_info=eci)

gil_fetch_fastgil = llexternal('RPyFetchFastGil', [], llmemory.Address,
                               _nowrapper=True, sandboxsafe=True,
                               compilation_info=eci)

# ____________________________________________________________


def invoke_after_thread_switch(callback):
    """Invoke callback() after a thread switch.

    This is a hook used by pypy.module.signal.  Several callbacks should
    be easy to support (but not right now).

    This function should be called from the translated RPython program
    (i.e. *not* at module level!), but registers the callback
    statically.  The exact point at which invoke_after_thread_switch()
    is called has no importance: the callback() will be called anyway.
    """
    print "NOTE: invoke_after_thread_switch() is meant to be translated "
    print "and not called directly.  Using some emulation."
    global _emulated_after_thread_switch
    _emulated_after_thread_switch = callback

_emulated_after_thread_switch = None

def _after_thread_switch():
    """NOT_RPYTHON"""
    if _emulated_after_thread_switch is not None:
        _emulated_after_thread_switch()


class Entry(ExtRegistryEntry):
    _about_ = invoke_after_thread_switch

    def compute_result_annotation(self, s_callback):
        assert s_callback.is_constant()
        callback = s_callback.const
        bk = self.bookkeeper
        translator = bk.annotator.translator
        if hasattr(translator, '_rgil_invoke_after_thread_switch'):
            assert translator._rgil_invoke_after_thread_switch == callback, (
                "not implemented yet: several invoke_after_thread_switch()")
        else:
            translator._rgil_invoke_after_thread_switch = callback
        bk.emulate_pbc_call("rgil.invoke_after_thread_switch", s_callback, [])

    def specialize_call(self, hop):
        # the actual call is not done here
        hop.exception_cannot_occur()

class Entry(ExtRegistryEntry):
    _about_ = _after_thread_switch

    def compute_result_annotation(self):
        # the call has been emulated already in invoke_after_thread_switch()
        pass

    def specialize_call(self, hop):
        translator = hop.rtyper.annotator.translator
        if hasattr(translator, '_rgil_invoke_after_thread_switch'):
            func = translator._rgil_invoke_after_thread_switch
            graph = translator._graphof(func)
            llfn = hop.rtyper.getcallable(graph)
            c_callback = hop.inputconst(lltype.typeOf(llfn), llfn)
            hop.exception_is_here()
            hop.genop("direct_call", [c_callback])
        else:
            hop.exception_cannot_occur()


def allocate():
    _gil_allocate()

def release():
    # this function must not raise, in such a way that the exception
    # transformer knows that it cannot raise!
    _gil_release()
release._gctransformer_hint_cannot_collect_ = True
release._dont_reach_me_in_del_ = True

def acquire():
    from rpython.rlib import rthread
    _gil_acquire()
    rthread.gc_thread_run()
    _after_thread_switch()
acquire._gctransformer_hint_cannot_collect_ = True
acquire._dont_reach_me_in_del_ = True

# The _gctransformer_hint_cannot_collect_ hack is needed for
# translations in which the *_external_call() functions are not inlined.
# They tell the gctransformer not to save and restore the local GC
# pointers in the shadow stack.  This is necessary because the GIL is
# not held after the call to gil.release() or before the call
# to gil.acquire().

def yield_thread():
    # explicitly release the gil, in a way that tries to give more
    # priority to other threads (as opposed to continuing to run in
    # the same thread).
    if _gil_yield_thread():
        from rpython.rlib import rthread
        rthread.gc_thread_run()
        _after_thread_switch()
yield_thread._gctransformer_hint_close_stack_ = True
yield_thread._dont_reach_me_in_del_ = True
yield_thread._dont_inline_ = True

# yield_thread() needs a different hint: _gctransformer_hint_close_stack_.
# The *_external_call() functions are themselves called only from the rffi
# module from a helper function that also has this hint.