File: handler.py

package info (click to toggle)
pypy3 7.0.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 111,848 kB
  • sloc: python: 1,291,746; ansic: 74,281; asm: 5,187; cpp: 3,017; sh: 2,533; makefile: 544; xml: 243; lisp: 45; csh: 21; awk: 4
file content (208 lines) | stat: -rw-r--r-- 7,445 bytes parent folder | download | duplicates (3)
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import os
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.rlib.rarithmetic import widen, ovfcheck_float_to_longlong
from rpython.rlib.objectmodel import keepalive_until_here
from rpython.rtyper.annlowlevel import llhelper

from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.error import exception_from_saved_errno
from pypy.interpreter.gateway import unwrap_spec
from pypy.module.faulthandler import cintf, dumper


class Handler(object):
    def __init__(self, space):
        "NOT_RPYTHON"
        self.space = space
        self._cleanup_()

    def _cleanup_(self):
        self.fatal_error_w_file = None
        self.dump_traceback_later_w_file = None
        self.user_w_files = None

    def check_err(self, p_err):
        if p_err:
            raise oefmt(self.space.w_RuntimeError, 'faulthandler: %8',
                        rffi.charp2str(p_err))

    def get_fileno_and_file(self, w_file):
        space = self.space
        if space.is_none(w_file):
            w_file = space.sys.get('stderr')
            if space.is_none(w_file):
                raise oefmt(space.w_RuntimeError, "sys.stderr is None")
        elif space.isinstance_w(w_file, space.w_int):
            fd = space.c_int_w(w_file)
            if fd < 0:
                raise oefmt(space.w_ValueError,
                            "file is not a valid file descriptor")
            return fd, None

        fd = space.c_int_w(space.call_method(w_file, 'fileno'))
        try:
            space.call_method(w_file, 'flush')
        except OperationError as e:
            if e.async(space):
                raise
            pass   # ignore flush() error
        return fd, w_file

    def setup(self):
        dump_callback = llhelper(cintf.DUMP_CALLBACK, dumper._dump_callback)
        self.check_err(cintf.pypy_faulthandler_setup(dump_callback))

    def enable(self, w_file, all_threads):
        fileno, w_file = self.get_fileno_and_file(w_file)
        self.setup()
        self.fatal_error_w_file = w_file
        self.check_err(cintf.pypy_faulthandler_enable(
            rffi.cast(rffi.INT, fileno),
            rffi.cast(rffi.INT, all_threads)))

    def disable(self):
        cintf.pypy_faulthandler_disable()
        self.fatal_error_w_file = None

    def is_enabled(self):
        return bool(widen(cintf.pypy_faulthandler_is_enabled()))

    def dump_traceback(self, w_file, all_threads):
        fileno, w_file = self.get_fileno_and_file(w_file)
        self.setup()
        cintf.pypy_faulthandler_dump_traceback(
            rffi.cast(rffi.INT, fileno),
            rffi.cast(rffi.INT, all_threads),
            llmemory.NULL)
        keepalive_until_here(w_file)

    def dump_traceback_later(self, timeout, repeat, w_file, exit):
        space = self.space
        timeout *= 1e6
        try:
            microseconds = ovfcheck_float_to_longlong(timeout)
        except OverflowError:
            raise oefmt(space.w_OverflowError, "timeout value is too large")
        if microseconds <= 0:
            raise oefmt(space.w_ValueError, "timeout must be greater than 0")
        fileno, w_file = self.get_fileno_and_file(w_file)
        self.setup()
        self.check_err(cintf.pypy_faulthandler_dump_traceback_later(
            rffi.cast(rffi.LONGLONG, microseconds),
            rffi.cast(rffi.INT, repeat),
            rffi.cast(rffi.INT, fileno),
            rffi.cast(rffi.INT, exit)))
        self.dump_traceback_later_w_file = w_file

    def cancel_dump_traceback_later(self):
        cintf.pypy_faulthandler_cancel_dump_traceback_later()
        self.dump_traceback_later_w_file = None

    def check_signum(self, signum):
        err = rffi.cast(lltype.Signed,
                        cintf.pypy_faulthandler_check_signum(signum))
        if err < 0:
            space = self.space
            if err == -1:
                raise oefmt(space.w_RuntimeError,
                            "signal %d cannot be registered, "
                            "use enable() instead", signum)
            else:
                raise oefmt(space.w_ValueError, "signal number out of range")

    def register(self, signum, w_file, all_threads, chain):
        self.check_signum(signum)
        fileno, w_file = self.get_fileno_and_file(w_file)
        self.setup()
        self.check_err(cintf.pypy_faulthandler_register(
            rffi.cast(rffi.INT, signum),
            rffi.cast(rffi.INT, fileno),
            rffi.cast(rffi.INT, all_threads),
            rffi.cast(rffi.INT, chain)))
        if self.user_w_files is None:
            self.user_w_files = {}
        self.user_w_files[signum] = w_file

    def unregister(self, signum):
        self.check_signum(signum)
        change = cintf.pypy_faulthandler_unregister(
            rffi.cast(rffi.INT, signum))
        if self.user_w_files is not None:
            self.user_w_files.pop(signum, None)
        return rffi.cast(lltype.Signed, change) == 1

    def finish(self):
        cintf.pypy_faulthandler_teardown()
        self._cleanup_()


def finish(space):
    "Finalize the faulthandler logic (called from shutdown())"
    space.fromcache(Handler).finish()


@unwrap_spec(all_threads=int)
def enable(space, w_file=None, all_threads=0):
    "enable(file=sys.stderr, all_threads=True): enable the fault handler"
    space.fromcache(Handler).enable(w_file, all_threads)

def disable(space):
    "disable(): disable the fault handler"
    space.fromcache(Handler).disable()

def is_enabled(space):
    "is_enabled()->bool: check if the handler is enabled"
    return space.newbool(space.fromcache(Handler).is_enabled())

@unwrap_spec(all_threads=int)
def dump_traceback(space, w_file=None, all_threads=0):
    """dump the traceback of the current thread into file
    including all threads if all_threads is True"""
    space.fromcache(Handler).dump_traceback(w_file, all_threads)

@unwrap_spec(timeout=float, repeat=int, exit=int)
def dump_traceback_later(space, timeout, repeat=0, w_file=None, exit=0):
    """dump the traceback of all threads in timeout seconds,
    or each timeout seconds if repeat is True. If exit is True,
    call _exit(1) which is not safe."""
    space.fromcache(Handler).dump_traceback_later(timeout, repeat, w_file, exit)

def cancel_dump_traceback_later(space):
    """cancel the previous call to dump_traceback_later()."""
    space.fromcache(Handler).cancel_dump_traceback_later()

@unwrap_spec(signum=int, all_threads=int, chain=int)
def register(space, signum, w_file=None, all_threads=1, chain=0):
    space.fromcache(Handler).register(signum, w_file, all_threads, chain)

@unwrap_spec(signum=int)
def unregister(space, signum):
    return space.newbool(space.fromcache(Handler).unregister(signum))


# for tests...

@unwrap_spec(release_gil=int)
def read_null(space, release_gil=0):
    if release_gil:
        cintf.pypy_faulthandler_read_null_releasegil()
    else:
        cintf.pypy_faulthandler_read_null()

@unwrap_spec(release_gil=int)
def sigsegv(space, release_gil=0):
    if release_gil:
        cintf.pypy_faulthandler_sigsegv_releasegil()
    else:
        cintf.pypy_faulthandler_sigsegv()

def sigfpe(space):
    cintf.pypy_faulthandler_sigfpe()

def sigabrt(space):
    cintf.pypy_faulthandler_sigabrt()

@unwrap_spec(levels=int)
def stack_overflow(space, levels=100000000):
    levels = float(levels)
    return space.newfloat(cintf.pypy_faulthandler_stackoverflow(levels))