mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 22:02:27 +00:00
Begin incorporating Python unit tests into build
We now build a separate APE binary for each test so they can run in parallel. We've got 148 tests running fast and stable so far.
This commit is contained in:
parent
51904e2687
commit
b5f743cdc3
121 changed files with 4995 additions and 4767 deletions
169
third_party/python/Python/fatality.c
vendored
Normal file
169
third_party/python/Python/fatality.c
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Python 3 │
|
||||
│ https://docs.python.org/3/license.html │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "third_party/python/Include/abstract.h"
|
||||
#include "third_party/python/Include/pyerrors.h"
|
||||
#include "third_party/python/Include/pylifecycle.h"
|
||||
#include "third_party/python/Include/pythonrun.h"
|
||||
#include "third_party/python/Include/sysmodule.h"
|
||||
#include "third_party/python/Include/traceback.h"
|
||||
/* clang-format off */
|
||||
|
||||
_Py_IDENTIFIER(flush);
|
||||
_Py_IDENTIFIER(stdout);
|
||||
_Py_IDENTIFIER(stderr);
|
||||
|
||||
/* Import the site module (not into __main__ though) */
|
||||
|
||||
static void
|
||||
_Py_FatalError_DumpTracebacks(int fd)
|
||||
{
|
||||
fputc('\n', stderr);
|
||||
fflush(stderr);
|
||||
/* display the current Python stack */
|
||||
_Py_DumpTracebackThreads(fd, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Print the current exception (if an exception is set) with its traceback,
|
||||
or display the current Python stack.
|
||||
|
||||
Don't call PyErr_PrintEx() and the except hook, because Py_FatalError() is
|
||||
called on catastrophic cases.
|
||||
|
||||
Return 1 if the traceback was displayed, 0 otherwise. */
|
||||
|
||||
static int
|
||||
_Py_FatalError_PrintExc(int fd)
|
||||
{
|
||||
PyObject *ferr, *res;
|
||||
PyObject *exception, *v, *tb;
|
||||
int has_tb;
|
||||
|
||||
PyErr_Fetch(&exception, &v, &tb);
|
||||
if (exception == NULL) {
|
||||
/* No current exception */
|
||||
return 0;
|
||||
}
|
||||
|
||||
ferr = _PySys_GetObjectId(&PyId_stderr);
|
||||
if (ferr == NULL || ferr == Py_None) {
|
||||
/* sys.stderr is not set yet or set to None,
|
||||
no need to try to display the exception */
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyErr_NormalizeException(&exception, &v, &tb);
|
||||
if (tb == NULL) {
|
||||
tb = Py_None;
|
||||
Py_INCREF(tb);
|
||||
}
|
||||
PyException_SetTraceback(v, tb);
|
||||
if (exception == NULL) {
|
||||
/* PyErr_NormalizeException() failed */
|
||||
return 0;
|
||||
}
|
||||
|
||||
has_tb = (tb != Py_None);
|
||||
PyErr_Display(exception, v, tb);
|
||||
Py_XDECREF(exception);
|
||||
Py_XDECREF(v);
|
||||
Py_XDECREF(tb);
|
||||
|
||||
/* sys.stderr may be buffered: call sys.stderr.flush() */
|
||||
res = _PyObject_CallMethodId(ferr, &PyId_flush, NULL);
|
||||
if (res == NULL)
|
||||
PyErr_Clear();
|
||||
else
|
||||
Py_DECREF(res);
|
||||
|
||||
return has_tb;
|
||||
}
|
||||
|
||||
/* Print fatal error message and abort */
|
||||
|
||||
void
|
||||
Py_FatalError(const char *msg)
|
||||
{
|
||||
const int fd = fileno(stderr);
|
||||
static int reentrant = 0;
|
||||
#ifdef MS_WINDOWS
|
||||
size_t len;
|
||||
WCHAR* buffer;
|
||||
size_t i;
|
||||
#endif
|
||||
|
||||
if (reentrant) {
|
||||
/* Py_FatalError() caused a second fatal error.
|
||||
Example: _Py_FlushStdFiles() raises a recursion error. */
|
||||
goto exit;
|
||||
}
|
||||
reentrant = 1;
|
||||
|
||||
fprintf(stderr, "Fatal Python error: %s\n", msg);
|
||||
fflush(stderr); /* it helps in Windows debug build */
|
||||
|
||||
/* Check if the current thread has a Python thread state
|
||||
and holds the GIL */
|
||||
PyThreadState *tss_tstate = NULL; // PyGILState_GetThisThreadState();
|
||||
if (tss_tstate != NULL) {
|
||||
PyThreadState *tstate = PyThreadState_GET();
|
||||
if (tss_tstate != tstate) {
|
||||
/* The Python thread does not hold the GIL */
|
||||
tss_tstate = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Py_FatalError() has been called from a C thread
|
||||
which has no Python thread state. */
|
||||
}
|
||||
int has_tstate_and_gil = (tss_tstate != NULL);
|
||||
|
||||
if (has_tstate_and_gil) {
|
||||
/* If an exception is set, print the exception with its traceback */
|
||||
if (!_Py_FatalError_PrintExc(fd)) {
|
||||
/* No exception is set, or an exception is set without traceback */
|
||||
_Py_FatalError_DumpTracebacks(fd);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_Py_FatalError_DumpTracebacks(fd);
|
||||
}
|
||||
|
||||
/* The main purpose of faulthandler is to display the traceback. We already
|
||||
* did our best to display it. So faulthandler can now be disabled.
|
||||
* (Don't trigger it on abort().) */
|
||||
_PyFaulthandler_Fini();
|
||||
|
||||
/* Check if the current Python thread hold the GIL */
|
||||
if (has_tstate_and_gil) {
|
||||
/* Flush sys.stdout and sys.stderr */
|
||||
_Py_FlushStdFiles();
|
||||
}
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
len = strlen(msg);
|
||||
|
||||
/* Convert the message to wchar_t. This uses a simple one-to-one
|
||||
conversion, assuming that the this error message actually uses ASCII
|
||||
only. If this ceases to be true, we will have to convert. */
|
||||
buffer = alloca( (len+1) * (sizeof *buffer));
|
||||
for( i=0; i<=len; ++i)
|
||||
buffer[i] = msg[i];
|
||||
OutputDebugStringW(L"Fatal Python error: ");
|
||||
OutputDebugStringW(buffer);
|
||||
OutputDebugStringW(L"\n");
|
||||
#endif /* MS_WINDOWS */
|
||||
|
||||
exit:
|
||||
#if defined(MS_WINDOWS) && defined(_DEBUG)
|
||||
DebugBreak();
|
||||
#endif
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
abort();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue