Skip to content

Commit

Permalink
Merge pull request #1026 from undingen/signal_handling6
Browse files Browse the repository at this point in the history
Add signal support
  • Loading branch information
undingen committed Feb 3, 2016
2 parents dc49df1 + 28c0c4b commit dc91299
Show file tree
Hide file tree
Showing 17 changed files with 300 additions and 53 deletions.
12 changes: 7 additions & 5 deletions from_cpython/Lib/test/test_signal.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# expected: fail
import unittest
from test import test_support
from contextlib import closing
Expand Down Expand Up @@ -80,7 +79,8 @@ def run_test(self):
# don't worry about re-setting the default handlers.
signal.signal(signal.SIGHUP, self.handlerA)
signal.signal(signal.SIGUSR1, self.handlerB)
signal.signal(signal.SIGUSR2, signal.SIG_IGN)
# Pyston change: pyston uses SIGUSR2 internally
# signal.signal(signal.SIGUSR2, signal.SIG_IGN)
signal.signal(signal.SIGALRM, signal.default_int_handler)

# Variables the signals will modify:
Expand Down Expand Up @@ -117,9 +117,11 @@ def run_test(self):
if test_support.verbose:
print "HandlerBCalled exception caught"

child = ignoring_eintr(subprocess.Popen, ['kill', '-USR2', str(pid)])
if child:
self.wait(child) # Nothing should happen.

# Pyston change: pyston uses SIGUSR2 internally
# child = ignoring_eintr(subprocess.Popen, ['kill', '-USR2', str(pid)])
# if child:
# self.wait(child) # Nothing should happen.

try:
signal.alarm(1)
Expand Down
8 changes: 3 additions & 5 deletions from_cpython/Modules/signalmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,9 @@ initsignal(void)
old_siginthandler = PyOS_setsig(SIGINT, signal_handler);
}

// Pyston change: let the GC scan the handlers
PyGC_AddPotentialRoot(Handlers, sizeof(Handlers));

#ifdef SIGHUP
x = PyInt_FromLong(SIGHUP);
PyDict_SetItemString(d, "SIGHUP", x);
Expand Down Expand Up @@ -895,10 +898,6 @@ PyErr_CheckSignals(void)
if (!is_tripped)
return 0;

// Pyston change:
Py_FatalError("TODO");

#if 0
int i;
PyObject *f;

Expand Down Expand Up @@ -943,7 +942,6 @@ PyErr_CheckSignals(void)
Py_DECREF(result);
}
}
#endif

return 0;
}
Expand Down
58 changes: 43 additions & 15 deletions src/codegen/ast_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -922,43 +922,66 @@ Value ASTInterpreter::visit_stmt(AST_stmt* node) {
printf("\n");
}

Value rtn;
switch (node->type) {
case AST_TYPE::Assert:
return visit_assert((AST_Assert*)node);
rtn = visit_assert((AST_Assert*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
break;
case AST_TYPE::Assign:
return visit_assign((AST_Assign*)node);
rtn = visit_assign((AST_Assign*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
break;
case AST_TYPE::Delete:
return visit_delete((AST_Delete*)node);
rtn = visit_delete((AST_Delete*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
break;
case AST_TYPE::Exec:
return visit_exec((AST_Exec*)node);
rtn = visit_exec((AST_Exec*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
break;
case AST_TYPE::Expr:
// docstrings are str constant expression statements.
// ignore those while interpreting.
if ((((AST_Expr*)node)->value)->type != AST_TYPE::Str)
return visit_expr((AST_Expr*)node);
if ((((AST_Expr*)node)->value)->type != AST_TYPE::Str) {
rtn = visit_expr((AST_Expr*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
}
break;
case AST_TYPE::Pass:
return Value(); // nothing todo
ASTInterpreterJitInterface::pendingCallsCheckHelper();
break; // nothing todo
case AST_TYPE::Print:
return visit_print((AST_Print*)node);
rtn = visit_print((AST_Print*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
break;
case AST_TYPE::Raise:
return visit_raise((AST_Raise*)node);
rtn = visit_raise((AST_Raise*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
break;
case AST_TYPE::Return:
return visit_return((AST_Return*)node);
rtn = visit_return((AST_Return*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
break;
case AST_TYPE::Global:
return visit_global((AST_Global*)node);
rtn = visit_global((AST_Global*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
break;

// pseudo
case AST_TYPE::Branch:
return visit_branch((AST_Branch*)node);
rtn = visit_branch((AST_Branch*)node);
break;
case AST_TYPE::Jump:
return visit_jump((AST_Jump*)node);
rtn = visit_jump((AST_Jump*)node);
break;
case AST_TYPE::Invoke:
return visit_invoke((AST_Invoke*)node);
rtn = visit_invoke((AST_Invoke*)node);
break;
default:
RELEASE_ASSERT(0, "not implemented");
};
return Value();
return rtn;
}

Value ASTInterpreter::visit_return(AST_Return* node) {
Expand Down Expand Up @@ -1652,6 +1675,11 @@ Box* ASTInterpreterJitInterface::landingpadHelper(void* _interpreter) {
return rtn;
}

void ASTInterpreterJitInterface::pendingCallsCheckHelper() {
if (unlikely(_pendingcalls_to_do))
makePendingCalls();
}

Box* ASTInterpreterJitInterface::setExcInfoHelper(void* _interpreter, Box* type, Box* value, Box* traceback) {
ASTInterpreter* interpreter = (ASTInterpreter*)_interpreter;
interpreter->getFrameInfo()->exc = ExcInfo(type, value, traceback);
Expand Down
1 change: 1 addition & 0 deletions src/codegen/ast_interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ struct ASTInterpreterJitInterface {
static Box* derefHelper(void* interp, InternedString s);
static Box* doOSRHelper(void* interp, AST_Jump* node);
static Box* landingpadHelper(void* interp);
static void pendingCallsCheckHelper();
static Box* setExcInfoHelper(void* interp, Box* type, Box* value, Box* traceback);
static void setLocalClosureHelper(void* interp, long vreg, InternedString id, Box* v);
static Box* uncacheExcInfoHelper(void* interp);
Expand Down
11 changes: 10 additions & 1 deletion src/codegen/baseline_jit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,10 @@ void JitFragmentWriter::emitOSRPoint(AST_Jump* node) {
addAction([=]() { _emitOSRPoint(result, node_var); }, { result, node_var, getInterp() }, ActionType::NORMAL);
}

void JitFragmentWriter::emitPendingCallsCheck() {
call(false, (void*)ASTInterpreterJitInterface::pendingCallsCheckHelper);
}

void JitFragmentWriter::emitPrint(RewriterVar* dest, RewriterVar* var, bool nl) {
if (!dest)
dest = call(false, (void*)getSysStdout);
Expand Down Expand Up @@ -696,12 +700,17 @@ RewriterVar* JitFragmentWriter::emitPPCall(void* func_addr, llvm::ArrayRef<Rewri
RewriterVar* obj_cls_var = result->getAttr(offsetof(Box, cls));
addAction([=]() { _emitRecordType(type_recorder_var, obj_cls_var); }, { type_recorder_var, obj_cls_var },
ActionType::NORMAL);

emitPendingCallsCheck();
return result;
}
emitPendingCallsCheck();
return result;
#else
assert(args_vec.size() < 7);
return call(false, func_addr, args_vec);
RewriterVar* result = call(false, func_addr, args_vec);
emitPendingCallsCheck();
return result;
#endif
}

Expand Down
1 change: 1 addition & 0 deletions src/codegen/baseline_jit.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ class JitFragmentWriter : public Rewriter {
void emitExec(RewriterVar* code, RewriterVar* globals, RewriterVar* locals, FutureFlags flags);
void emitJump(CFGBlock* b);
void emitOSRPoint(AST_Jump* node);
void emitPendingCallsCheck();
void emitPrint(RewriterVar* dest, RewriterVar* var, bool nl);
void emitRaise0();
void emitRaise3(RewriterVar* arg0, RewriterVar* arg1, RewriterVar* arg2);
Expand Down
15 changes: 2 additions & 13 deletions src/codegen/entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,16 +378,6 @@ static void handle_sigprof_investigate_stattimer(int signum) {
}
#endif

static void handle_sigint(int signum) {
assert(signum == SIGINT);
// TODO: this should set a flag saying a KeyboardInterrupt is pending.
// For now, just call abort(), so that we get a traceback at least.
fprintf(stderr, "SIGINT!\n");
joinRuntime();
Stats::dump(false);
abort();
}

void initCodegen() {
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
Expand Down Expand Up @@ -481,9 +471,8 @@ void initCodegen() {

setupRuntime();

// signal(SIGFPE, &handle_sigfpe);
signal(SIGUSR1, &handle_sigusr1);
signal(SIGINT, &handle_sigint);
// signal(SIGFPE, &handle_sigfpe);
// signal(SIGUSR1, &handle_sigusr1);

#if ENABLE_SAMPLING_PROFILER
struct itimerval prof_timer;
Expand Down
77 changes: 67 additions & 10 deletions src/codegen/irgen/irgenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,11 +347,53 @@ class IREmitterImpl : public IREmitter {
llvm::BasicBlock*& curblock;
IRGenerator* irgenerator;

void emitPendingCallsCheck(llvm::BasicBlock* exc_dest) {
auto&& builder = *getBuilder();

llvm::GlobalVariable* pendingcalls_to_do_gv = g.cur_module->getGlobalVariable("_pendingcalls_to_do");
if (!pendingcalls_to_do_gv) {
static_assert(sizeof(_pendingcalls_to_do) == 4, "");
pendingcalls_to_do_gv = new llvm::GlobalVariable(
*g.cur_module, g.i32, false, llvm::GlobalValue::ExternalLinkage, 0, "_pendingcalls_to_do");
pendingcalls_to_do_gv->setAlignment(4);
}

llvm::BasicBlock* cur_block = builder.GetInsertBlock();

llvm::BasicBlock* pendingcalls_set = createBasicBlock("_pendingcalls_set");
pendingcalls_set->moveAfter(cur_block);
llvm::BasicBlock* join_block = createBasicBlock("continue_after_pendingcalls_check");
join_block->moveAfter(pendingcalls_set);

llvm::Value* pendingcalls_to_do_val = builder.CreateLoad(pendingcalls_to_do_gv, true /* volatile */);
llvm::Value* is_zero
= builder.CreateICmpEQ(pendingcalls_to_do_val, getConstantInt(0, pendingcalls_to_do_val->getType()));

llvm::Metadata* md_vals[]
= { llvm::MDString::get(g.context, "branch_weights"), llvm::ConstantAsMetadata::get(getConstantInt(1000)),
llvm::ConstantAsMetadata::get(getConstantInt(1)) };
llvm::MDNode* branch_weights = llvm::MDNode::get(g.context, llvm::ArrayRef<llvm::Metadata*>(md_vals));


builder.CreateCondBr(is_zero, join_block, pendingcalls_set, branch_weights);
{
setCurrentBasicBlock(pendingcalls_set);

if (exc_dest) {
builder.CreateInvoke(g.funcs.makePendingCalls, join_block, exc_dest);
} else {
builder.CreateCall(g.funcs.makePendingCalls);
builder.CreateBr(join_block);
}
}

cur_block = join_block;
setCurrentBasicBlock(join_block);
}

llvm::CallSite emitCall(const UnwindInfo& unw_info, llvm::Value* callee, const std::vector<llvm::Value*>& args,
ExceptionStyle target_exception_style) {
llvm::Value* stmt = unw_info.current_stmt ? embedRelocatablePtr(unw_info.current_stmt, g.llvm_aststmt_type_ptr)
: getNullPtr(g.llvm_aststmt_type_ptr);
getBuilder()->CreateStore(stmt, irstate->getStmtVar());
emitSetCurrentStmt(unw_info.current_stmt);

if (target_exception_style == CXX && (unw_info.hasHandler() || irstate->getExceptionStyle() == CAPI)) {
// Create the invoke:
Expand All @@ -375,9 +417,13 @@ class IREmitterImpl : public IREmitter {
// Normal case:
getBuilder()->SetInsertPoint(normal_dest);
curblock = normal_dest;
emitPendingCallsCheck(exc_dest);
return rtn;
} else {

llvm::CallInst* cs = getBuilder()->CreateCall(callee, args);
if (target_exception_style == CXX)
emitPendingCallsCheck(NULL);
return cs;
}
}
Expand Down Expand Up @@ -479,6 +525,15 @@ class IREmitterImpl : public IREmitter {
return llvm::BasicBlock::Create(g.context, name, irstate->getLLVMFunction());
}

// Our current frame introspection approach requires that we update the currently executed stmt before doing a call
// to a function which could throw an exception, inspect the python call frame,...
// Only patchpoint don't need to set the current statement because the stmt will be inluded in the stackmap args.
void emitSetCurrentStmt(AST_stmt* stmt) {
getBuilder()->CreateStore(stmt ? embedRelocatablePtr(stmt, g.llvm_aststmt_type_ptr)
: getNullPtr(g.llvm_aststmt_type_ptr),
irstate->getStmtVar());
}

llvm::Value* createCall(const UnwindInfo& unw_info, llvm::Value* callee, const std::vector<llvm::Value*>& args,
ExceptionStyle target_exception_style = CXX) override {
#ifndef NDEBUG
Expand Down Expand Up @@ -2137,7 +2192,7 @@ class IRGeneratorImpl : public IRGenerator {

// Don't call deinitFrame when this is a OSR function because the interpreter will call it
if (!irstate->getCurFunction()->entry_descriptor)
emitter.createCall(unw_info, g.funcs.deinitFrame, irstate->getFrameInfoVar());
emitter.getBuilder()->CreateCall(g.funcs.deinitFrame, irstate->getFrameInfoVar());

for (auto& p : symbol_table) {
p.second->decvref(emitter);
Expand Down Expand Up @@ -2878,9 +2933,10 @@ class IRGeneratorImpl : public IRGenerator {
}

void doSafePoint(AST_stmt* next_statement) override {
// Unwind info is always needed in allowGLReadPreemption if it has any chance of
// running arbitrary code like finalizers.
emitter.createCall(UnwindInfo(next_statement, NULL), g.funcs.allowGLReadPreemption);
// We need to setup frame introspection by updating the current stmt because we can run can run arbitrary code
// like finalizers inside allowGLReadPreemption.
emitter.emitSetCurrentStmt(next_statement);
emitter.getBuilder()->CreateCall(g.funcs.allowGLReadPreemption);
}

// Create a (or reuse an existing) block that will catch a CAPI exception, and then forward
Expand All @@ -2902,16 +2958,17 @@ class IRGeneratorImpl : public IRGenerator {
assert(!phi_node);
phi_node = emitter.getBuilder()->CreatePHI(g.llvm_aststmt_type_ptr, 0);

emitter.createCall(UnwindInfo(current_stmt, NULL), g.funcs.caughtCapiException,
{ phi_node, embedRelocatablePtr(irstate->getSourceInfo(), g.i8_ptr) });
emitter.emitSetCurrentStmt(current_stmt);
emitter.getBuilder()->CreateCall(g.funcs.caughtCapiException,
{ phi_node, embedRelocatablePtr(irstate->getSourceInfo(), g.i8_ptr) });

if (!final_dest) {
// Propagate the exception out of the function:
if (irstate->getExceptionStyle() == CXX) {
emitter.getBuilder()->CreateCall(g.funcs.reraiseCapiExcAsCxx);
emitter.getBuilder()->CreateUnreachable();
} else {
emitter.createCall(UnwindInfo(current_stmt, NULL), g.funcs.deinitFrame, irstate->getFrameInfoVar());
emitter.getBuilder()->CreateCall(g.funcs.deinitFrame, irstate->getFrameInfoVar());
emitter.getBuilder()->CreateRet(getNullPtr(g.llvm_value_type_ptr));
}
} else {
Expand Down
1 change: 1 addition & 0 deletions src/codegen/runtime_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(createSet);
GET(initFrame);
GET(deinitFrame);
GET(makePendingCalls);

GET(getattr);
GET(getattr_capi);
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/runtime_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct GlobalFuncs {

llvm::Value* boxInt, *unboxInt, *boxFloat, *unboxFloat, *createFunctionFromMetadata, *getFunctionMetadata,
*boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice,
*createUserClass, *createClosure, *createGenerator, *createSet, *initFrame, *deinitFrame;
*createUserClass, *createClosure, *createGenerator, *createSet, *initFrame, *deinitFrame, *makePendingCalls;
llvm::Value* getattr, *getattr_capi, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare,
*augbinop, *unboxedLen, *getitem, *getitem_capi, *getclsattr, *getGlobal, *setitem, *unaryop, *import,
*importFrom, *importStar, *repr, *exceptionMatches, *yield, *getiterHelper, *hasnext, *setGlobal, *apply_slice;
Expand Down
Loading

0 comments on commit dc91299

Please sign in to comment.