Commit 7c1ee4cc authored by Kevin Modzelewski's avatar Kevin Modzelewski Committed by GitHub

Merge pull request #1334 from kmod/threading

Threading fixes to get cffi-1.7 working
parents e9ced458 9b46190c
...@@ -20,12 +20,13 @@ typedef struct _is { ...@@ -20,12 +20,13 @@ typedef struct _is {
struct _is *next; struct _is *next;
struct _ts *tstate_head; struct _ts *tstate_head;
PyObject *modules;
PyObject *builtins;
// Pyston change // Pyston change
// Note: any changes here need to show up in PyInterpreterState_Clear as well // Note: any changes here need to show up in PyInterpreterState_Clear as well
#if 0 #if 0
PyObject *modules;
PyObject *sysdict; PyObject *sysdict;
PyObject *builtins;
PyObject *modules_reloading; PyObject *modules_reloading;
PyObject *codec_search_path; PyObject *codec_search_path;
...@@ -136,10 +137,7 @@ PyAPI_FUNC(int) PyThreadState_SetAsyncExc(long, PyObject *) PYSTON_NOEXCEPT; ...@@ -136,10 +137,7 @@ PyAPI_FUNC(int) PyThreadState_SetAsyncExc(long, PyObject *) PYSTON_NOEXCEPT;
/* Variable and macro for in-line access to current thread state */ /* Variable and macro for in-line access to current thread state */
// Pyston change: use our internal name for this PyAPI_DATA(PyThreadState *) _PyThreadState_Current;
//PyAPI_DATA(PyThreadState *) _PyThreadState_Current;
PyAPI_DATA(__thread PyThreadState) cur_thread_state;
#define _PyThreadState_Current (&cur_thread_state)
#ifdef Py_DEBUG #ifdef Py_DEBUG
#define PyThreadState_GET() PyThreadState_Get() #define PyThreadState_GET() PyThreadState_Get()
......
...@@ -3164,6 +3164,17 @@ imp_load_dynamic(PyObject *self, PyObject *args) ...@@ -3164,6 +3164,17 @@ imp_load_dynamic(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "ss|O!:load_dynamic", &name, &pathname, if (!PyArg_ParseTuple(args, "ss|O!:load_dynamic", &name, &pathname,
&PyFile_Type, &fob)) &PyFile_Type, &fob))
return NULL; return NULL;
// Pyston change: warn if it doesn't look like a pyston-built so.
// Some libraries (cffi) want to load things with names that don't even end
// in ".so", so allow those through.
int len = strlen(name);
if (len >= 3 && strcmp(&name[len - 3], ".so") == 0 &&
(len < 10 || strcmp(&name[len - 10], ".pyston.so") != 0)) {
PyErr_Format(PyExc_ValueError, "Pyston refusing to load a non-pyston .so \"%.200s\"", name);
return NULL;
}
if (fob) { if (fob) {
fp = get_file(pathname, fob, "r"); fp = get_file(pathname, fob, "r");
if (fp == NULL) if (fp == NULL)
......
...@@ -1664,11 +1664,11 @@ Value ASTInterpreter::visit_dict(AST_Dict* node) { ...@@ -1664,11 +1664,11 @@ Value ASTInterpreter::visit_dict(AST_Dict* node) {
} }
Value ASTInterpreter::visit_set(AST_Set* node) { Value ASTInterpreter::visit_set(AST_Set* node) {
BoxedSet* set = (BoxedSet*)createSet();
try { try {
// insert the elements in reverse like cpython does // insert the elements in reverse like cpython does
// important for {1, 1L} // important for {1, 1L}
llvm::SmallVector<RewriterVar*, 8> items; llvm::SmallVector<RewriterVar*, 8> items;
BoxedSet* set = (BoxedSet*)createSet();
for (auto it = node->elts.rbegin(), it_end = node->elts.rend(); it != it_end; ++it) { for (auto it = node->elts.rbegin(), it_end = node->elts.rend(); it != it_end; ++it) {
Value v = visit_expr(*it); Value v = visit_expr(*it);
_setAddStolen(set, v.o); _setAddStolen(set, v.o);
...@@ -1676,7 +1676,8 @@ Value ASTInterpreter::visit_set(AST_Set* node) { ...@@ -1676,7 +1676,8 @@ Value ASTInterpreter::visit_set(AST_Set* node) {
} }
return Value(set, jit ? jit->emitCreateSet(items) : NULL); return Value(set, jit ? jit->emitCreateSet(items) : NULL);
} catch (ExcInfo e) { } catch (ExcInfo e) {
RELEASE_ASSERT(0, "this leaks in case of an exception"); Py_DECREF(set);
throw e;
} }
} }
......
...@@ -37,8 +37,6 @@ ...@@ -37,8 +37,6 @@
namespace pyston { namespace pyston {
DS_DEFINE_RWLOCK(codegen_rwlock);
FunctionMetadata::FunctionMetadata(int num_args, bool takes_varargs, bool takes_kwargs, FunctionMetadata::FunctionMetadata(int num_args, bool takes_varargs, bool takes_kwargs,
std::unique_ptr<SourceInfo> source) std::unique_ptr<SourceInfo> source)
: code_obj(NULL), : code_obj(NULL),
......
...@@ -90,8 +90,6 @@ extern GlobalState g; ...@@ -90,8 +90,6 @@ extern GlobalState g;
// in runtime_hooks.cpp: // in runtime_hooks.cpp:
void initGlobalFuncs(GlobalState& g); void initGlobalFuncs(GlobalState& g);
DS_DECLARE_RWLOCK(codegen_rwlock);
} }
#endif #endif
...@@ -341,9 +341,6 @@ CompiledFunction* compileFunction(FunctionMetadata* f, FunctionSpecialization* s ...@@ -341,9 +341,6 @@ CompiledFunction* compileFunction(FunctionMetadata* f, FunctionSpecialization* s
void compileAndRunModule(AST_Module* m, BoxedModule* bm) { void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
FunctionMetadata* md; FunctionMetadata* md;
{ // scope for limiting the locked region:
LOCK_REGION(codegen_rwlock.asWrite());
Timer _t("for compileModule()"); Timer _t("for compileModule()");
const char* fn = PyModule_GetFilename(bm); const char* fn = PyModule_GetFilename(bm);
...@@ -364,7 +361,6 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) { ...@@ -364,7 +361,6 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
bm->setattr(builtins_str, PyModule_GetDict(builtins_module), NULL); bm->setattr(builtins_str, PyModule_GetDict(builtins_module), NULL);
md = new FunctionMetadata(0, false, false, std::move(si)); md = new FunctionMetadata(0, false, false, std::move(si));
}
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_interpreted_module_toplevel"); UNAVOIDABLE_STAT_TIMER(t0, "us_timer_interpreted_module_toplevel");
Box* r = astInterpretFunction(md, NULL, NULL, NULL, NULL, NULL, NULL, NULL); Box* r = astInterpretFunction(md, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
...@@ -395,8 +391,6 @@ Box* evalOrExec(FunctionMetadata* md, Box* globals, Box* boxedLocals) { ...@@ -395,8 +391,6 @@ Box* evalOrExec(FunctionMetadata* md, Box* globals, Box* boxedLocals) {
static FunctionMetadata* compileForEvalOrExec(AST* source, llvm::ArrayRef<AST_stmt*> body, BoxedString* fn, static FunctionMetadata* compileForEvalOrExec(AST* source, llvm::ArrayRef<AST_stmt*> body, BoxedString* fn,
PyCompilerFlags* flags) { PyCompilerFlags* flags) {
LOCK_REGION(codegen_rwlock.asWrite());
Timer _t("for evalOrExec()"); Timer _t("for evalOrExec()");
ScopingAnalysis* scoping = new ScopingAnalysis(source, false); ScopingAnalysis* scoping = new ScopingAnalysis(source, false);
...@@ -655,8 +649,6 @@ void exec(Box* boxedCode, Box* globals, Box* locals, FutureFlags caller_future_f ...@@ -655,8 +649,6 @@ void exec(Box* boxedCode, Box* globals, Box* locals, FutureFlags caller_future_f
// TODO we should have logic like this at the CLFunc level that detects that we keep // TODO we should have logic like this at the CLFunc level that detects that we keep
// on creating functions with failing speculations, and then stop speculating. // on creating functions with failing speculations, and then stop speculating.
void CompiledFunction::speculationFailed() { void CompiledFunction::speculationFailed() {
LOCK_REGION(codegen_rwlock.asWrite());
this->times_speculation_failed++; this->times_speculation_failed++;
if (this->times_speculation_failed == 4) { if (this->times_speculation_failed == 4) {
...@@ -735,8 +727,6 @@ ConcreteCompilerType* CompiledFunction::getReturnType() { ...@@ -735,8 +727,6 @@ ConcreteCompilerType* CompiledFunction::getReturnType() {
/// The cf must be an active version in its parents FunctionMetadata; the given /// The cf must be an active version in its parents FunctionMetadata; the given
/// version will be replaced by the new version, which will be returned. /// version will be replaced by the new version, which will be returned.
static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel new_effort) { static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel new_effort) {
LOCK_REGION(codegen_rwlock.asWrite());
assert(cf->md->versions.size()); assert(cf->md->versions.size());
assert(cf); assert(cf);
...@@ -773,8 +763,6 @@ static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel new_effort) ...@@ -773,8 +763,6 @@ static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel new_effort)
static StatCounter stat_osrexits("num_osr_exits"); static StatCounter stat_osrexits("num_osr_exits");
static StatCounter stat_osr_compiles("num_osr_compiles"); static StatCounter stat_osr_compiles("num_osr_compiles");
CompiledFunction* compilePartialFuncInternal(OSRExit* exit) { CompiledFunction* compilePartialFuncInternal(OSRExit* exit) {
LOCK_REGION(codegen_rwlock.asWrite());
assert(exit); assert(exit);
stat_osrexits.log(); stat_osrexits.log();
......
This diff is collapsed.
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <ucontext.h> #include <ucontext.h>
#include <vector> #include <vector>
#include "Python.h"
#include "core/common.h" #include "core/common.h"
#include "core/thread_utils.h" #include "core/thread_utils.h"
...@@ -33,6 +35,8 @@ extern int sigprof_pending; ...@@ -33,6 +35,8 @@ extern int sigprof_pending;
void _printStacktrace(); void _printStacktrace();
#endif #endif
extern __thread PyThreadState cur_thread_state;
namespace threading { namespace threading {
// Whether or not a second thread was ever started: // Whether or not a second thread was ever started:
...@@ -47,35 +51,10 @@ void finishMainThread(); ...@@ -47,35 +51,10 @@ void finishMainThread();
bool isMainThread(); bool isMainThread();
#ifndef THREADING_USE_GIL
#define THREADING_USE_GIL 1
#define THREADING_USE_GRWL 0
#endif
#define THREADING_SAFE_DATASTRUCTURES THREADING_USE_GRWL
#if THREADING_SAFE_DATASTRUCTURES
#define DS_DEFINE_MUTEX(name) pyston::threading::PthreadFastMutex name
#define DS_DECLARE_RWLOCK(name) extern pyston::threading::PthreadRWLock name
#define DS_DEFINE_RWLOCK(name) pyston::threading::PthreadRWLock name
#define DS_DEFINE_SPINLOCK(name) pyston::threading::PthreadSpinLock name
#else
#define DS_DEFINE_MUTEX(name) pyston::threading::NopLock name
#define DS_DECLARE_RWLOCK(name) extern pyston::threading::NopLock name
#define DS_DEFINE_RWLOCK(name) pyston::threading::NopLock name
#define DS_DEFINE_SPINLOCK(name) pyston::threading::NopLock name
#endif
void acquireGLRead();
void releaseGLRead();
void acquireGLWrite();
void releaseGLWrite();
void _allowGLReadPreemption(); void _allowGLReadPreemption();
#define GIL_CHECK_INTERVAL 1000 #define GIL_CHECK_INTERVAL 1000
// Note: this doesn't need to be an atomic, since it should // Note: this doesn't need to be an atomic, since it should
// only be accessed by the thread that holds the gil: // only be accessed by the thread that holds the gil:
extern int gil_check_count; extern int gil_check_count;
...@@ -104,26 +83,8 @@ extern "C" inline void allowGLReadPreemption() { ...@@ -104,26 +83,8 @@ extern "C" inline void allowGLReadPreemption() {
_allowGLReadPreemption(); _allowGLReadPreemption();
} }
// Note: promoteGL is free to drop the lock and then reacquire
void promoteGL();
void demoteGL();
// Helper macro for creating a RAII wrapper around two functions.
#define MAKE_REGION(name, start, end) \
class name { \
public: \
name() { start(); } \
~name() { end(); } \
};
MAKE_REGION(GLReadRegion, acquireGLRead, releaseGLRead);
MAKE_REGION(GLPromoteRegion, promoteGL, demoteGL);
// MAKE_REGION(GLReadReleaseRegion, releaseGLRead, acquireGLRead);
// MAKE_REGION(GLWriteReleaseRegion, releaseGLWrite, acquireGLWrite);
#undef MAKE_REGION
extern "C" void beginAllowThreads() noexcept; extern "C" void beginAllowThreads() noexcept;
extern "C" void endAllowThreads() noexcept; extern "C" void endAllowThreads() noexcept;
...@@ -134,37 +95,6 @@ public: ...@@ -134,37 +95,6 @@ public:
}; };
#if THREADING_USE_GIL
inline void acquireGLRead() {
acquireGLWrite();
}
inline void releaseGLRead() {
releaseGLWrite();
}
inline void promoteGL() {
}
inline void demoteGL() {
}
#endif
#if !THREADING_USE_GIL && !THREADING_USE_GRWL
inline void acquireGLRead() {
}
inline void releaseGLRead() {
}
inline void acquireGLWrite() {
}
inline void releaseGLWrite() {
}
inline void promoteGL() {
}
inline void demoteGL() {
}
extern "C" inline void allowGLReadPreemption() __attribute__((visibility("default")));
extern "C" inline void allowGLReadPreemption() {
}
#endif
extern bool forgot_refs_via_fork; extern bool forgot_refs_via_fork;
} // namespace threading } // namespace threading
......
...@@ -369,7 +369,6 @@ static int main(int argc, char** argv) noexcept { ...@@ -369,7 +369,6 @@ static int main(int argc, char** argv) noexcept {
const char* fn = NULL; const char* fn = NULL;
threading::registerMainThread(); threading::registerMainThread();
threading::acquireGLRead();
Py_SetProgramName(argv[0]); Py_SetProgramName(argv[0]);
...@@ -540,11 +539,6 @@ static int main(int argc, char** argv) noexcept { ...@@ -540,11 +539,6 @@ static int main(int argc, char** argv) noexcept {
threading::finishMainThread(); threading::finishMainThread();
// Acquire the GIL to make sure we stop the other threads, since we will tear down
// data structures they are potentially running on.
// Note: we will purposefully not release the GIL on exiting.
threading::promoteGL();
_t.split("Py_Finalize"); _t.split("Py_Finalize");
Py_Finalize(); Py_Finalize();
......
...@@ -2376,6 +2376,7 @@ void setupBuiltins() { ...@@ -2376,6 +2376,7 @@ void setupBuiltins() {
builtins_module = createModule(autoDecref(boxString("__builtin__")), NULL, builtins_module = createModule(autoDecref(boxString("__builtin__")), NULL,
"Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is " "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is "
"the `nil' object; Ellipsis represents `...' in slices."); "the `nil' object; Ellipsis represents `...' in slices.");
PyThreadState_GET()->interp->builtins = incref(builtins_module->getAttrWrapper());
ellipsis_cls ellipsis_cls
= BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(Box), false, "ellipsis", false, NULL, NULL, false); = BoxedClass::create(type_cls, object_cls, 0, 0, sizeof(Box), false, "ellipsis", false, NULL, NULL, false);
......
...@@ -795,6 +795,8 @@ static int _check_and_flush(FILE* stream) { ...@@ -795,6 +795,8 @@ static int _check_and_flush(FILE* stream) {
void setupSys() { void setupSys() {
sys_modules_dict = new BoxedDict(); sys_modules_dict = new BoxedDict();
PyThreadState_GET()->interp->modules = incref(sys_modules_dict);
constants.push_back(sys_modules_dict); constants.push_back(sys_modules_dict);
// This is ok to call here because we've already created the sys_modules_dict // This is ok to call here because we've already created the sys_modules_dict
......
...@@ -1483,31 +1483,6 @@ extern "C" void PyEval_InitThreads(void) noexcept { ...@@ -1483,31 +1483,6 @@ extern "C" void PyEval_InitThreads(void) noexcept {
// nothing to do here // nothing to do here
} }
extern "C" void PyEval_AcquireThread(PyThreadState* tstate) noexcept {
Py_FatalError("Unimplemented");
}
extern "C" void PyEval_ReleaseThread(PyThreadState* tstate) noexcept {
Py_FatalError("Unimplemented");
}
extern "C" PyThreadState* PyThreadState_Get(void) noexcept {
if (_PyThreadState_Current == NULL)
Py_FatalError("PyThreadState_Get: no current thread");
return _PyThreadState_Current;
}
extern "C" PyThreadState* PyEval_SaveThread(void) noexcept {
beginAllowThreads();
return PyThreadState_GET();
}
extern "C" void PyEval_RestoreThread(PyThreadState* tstate) noexcept {
RELEASE_ASSERT(tstate == PyThreadState_GET(), "");
endAllowThreads();
}
extern "C" BORROWED(struct _frame*) PyEval_GetFrame(void) noexcept { extern "C" BORROWED(struct _frame*) PyEval_GetFrame(void) noexcept {
Box* frame = NULL; Box* frame = NULL;
try { try {
......
...@@ -139,8 +139,9 @@ extern "C" Box* import(int level, Box* from_imports, llvm::StringRef module_name ...@@ -139,8 +139,9 @@ extern "C" Box* import(int level, Box* from_imports, llvm::StringRef module_name
BoxedModule* importCExtension(BoxedString* full_name, const std::string& last_name, const std::string& path) { BoxedModule* importCExtension(BoxedString* full_name, const std::string& last_name, const std::string& path) {
void* handle = dlopen(path.c_str(), RTLD_NOW); void* handle = dlopen(path.c_str(), RTLD_NOW);
if (!handle) { if (!handle) {
const char* s = dlerror();
// raiseExcHelper(ImportError, "%s", dlerror()); // raiseExcHelper(ImportError, "%s", dlerror());
fprintf(stderr, "%s\n", dlerror()); fprintf(stderr, "%s\n", s);
exit(1); exit(1);
} }
assert(handle); assert(handle);
......
...@@ -3967,8 +3967,6 @@ static StatCounter slowpath_pickversion("slowpath_pickversion"); ...@@ -3967,8 +3967,6 @@ static StatCounter slowpath_pickversion("slowpath_pickversion");
template <ExceptionStyle S> template <ExceptionStyle S>
static CompiledFunction* pickVersion(FunctionMetadata* f, int num_output_args, Box* oarg1, Box* oarg2, Box* oarg3, static CompiledFunction* pickVersion(FunctionMetadata* f, int num_output_args, Box* oarg1, Box* oarg2, Box* oarg3,
Box** oargs) { Box** oargs) {
LOCK_REGION(codegen_rwlock.asWrite());
// if always_use_version is set use it even if the exception style does not match. // if always_use_version is set use it even if the exception style does not match.
// But prefer using the correct style if both are available // But prefer using the correct style if both are available
if (f->always_use_version.get(S)) if (f->always_use_version.get(S))
......
# Note: the expected counts here are set to match the CI, and I can't reproduce them locally
import os, sys, subprocess, shutil
sys.path.append(os.path.dirname(__file__) + "/../lib")
from test_helper import create_virtenv, run_test
ENV_NAME = "cffi17_test_env_" + os.path.basename(sys.executable)
SRC_DIR = os.path.abspath(os.path.join(ENV_NAME, "src"))
PYTHON_EXE = os.path.abspath(os.path.join(ENV_NAME, "bin", "python"))
PYTEST_EXE = os.path.abspath(os.path.join(ENV_NAME, "bin", "py.test"))
def install_and_test_cffi():
shutil.rmtree(SRC_DIR, ignore_errors=True)
os.makedirs(SRC_DIR)
url = "https://pypi.python.org/packages/83/3c/00b553fd05ae32f27b3637f705c413c4ce71290aa9b4c4764df694e906d9/cffi-1.7.0.tar.gz#md5=34122a545060cee58bab88feab57006d"
subprocess.check_call(["wget", url], cwd=SRC_DIR)
subprocess.check_call(["tar", "-zxf", "cffi-1.7.0.tar.gz"], cwd=SRC_DIR)
CFFI_DIR = os.path.abspath(os.path.join(SRC_DIR, "cffi-1.7.0"))
subprocess.check_call([PYTHON_EXE, "setup.py", "install"], cwd=CFFI_DIR)
# looks like clang 3.5 causes more errors like: 214 != -42 doing casts
if os.environ.has_key("CC") and "clang" in os.environ["CC"]:
expected = [{'xfailed': 4, 'failed': 3, 'skipped': 10, 'passed': 539}]
else:
expected = [{'xfailed': 4, 'failed': 2, 'skipped': 10, 'passed': 540}]
# Ideally we would run all the tests, but they take ~10min to run.
# dir_to_test = "."
# I just picked a subdirectory; I don't really know what it's testing.
dir_to_test = os.path.join(CFFI_DIR, "testing", "cffi1")
run_test([PYTEST_EXE, dir_to_test], cwd=CFFI_DIR, expected=expected)
create_virtenv(ENV_NAME, ["pytest==2.8.7", "py==1.4.31", "pycparser==2.14"], force_create = True)
install_and_test_cffi()
# Note: the expected counts here are set to match the CI, and I can't re[rpduce them locally # Note: the expected counts here are set to match the CI, and I can't reproduce them locally
import os, sys, subprocess, shutil import os, sys, subprocess, shutil
sys.path.append(os.path.dirname(__file__) + "/../lib") sys.path.append(os.path.dirname(__file__) + "/../lib")
......
...@@ -66,6 +66,8 @@ def run_test(cmd, cwd, expected, env = None): ...@@ -66,6 +66,8 @@ def run_test(cmd, cwd, expected, env = None):
print print
print "Return code:", errcode print "Return code:", errcode
assert errcode in (0, 1), "\n\n%s\nTest process crashed" % output
if expected == result: if expected == result:
print "Received expected output" print "Received expected output"
else: else:
......
...@@ -540,3 +540,4 @@ False ...@@ -540,3 +540,4 @@ False
set([1L]) set([1]) set([1]) set([1L]) set([1L]) set([1]) set([1]) set([1L])
set([1]) set([1])
4 4
unhashable type: 'dict'
...@@ -274,3 +274,8 @@ from api_test import set_size ...@@ -274,3 +274,8 @@ from api_test import set_size
s = set([1, 2, 3, 4]) s = set([1, 2, 3, 4])
print(set_size(s)) print(set_size(s))
try:
{{}}
except Exception as e:
print e
...@@ -25,12 +25,10 @@ namespace pyston { ...@@ -25,12 +25,10 @@ namespace pyston {
class PystonTestEnvironment : public testing::Environment { class PystonTestEnvironment : public testing::Environment {
void SetUp() override { void SetUp() override {
threading::registerMainThread(); threading::registerMainThread();
threading::acquireGLRead();
} }
void TearDown() override { void TearDown() override {
threading::releaseGLRead(); // threading::releaseGLRead();
} }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment