/*********************************************************************************************************************************** Execute main function in Perl ***********************************************************************************************************************************/ int perlExec(void) { FUNCTION_LOG_VOID(logLevelDebug); // Initialize Perl perlInit(); // Run perl main function perlEval(perlMain()); // Return result code int code = (int)SvIV(get_sv("iResult", 0)); bool errorC = (int)SvIV(get_sv("bErrorC", 0)); char *message = SvPV_nolen(get_sv("strMessage", 0)); // {uncovered - internal Perl macro branch} if (code >= errorTypeCode(&AssertError)) // {uncovered - success tested in integration} { if (errorC) // {+uncovered} RETHROW(); // {+uncovered} else THROW_CODE(code, strlen(message) == 0 ? PERL_EMBED_ERROR : message); // {+uncovered} } FUNCTION_LOG_RETURN(INT, code); // {+uncovered} }
/*********************************************************************************************************************************** Catch signals ***********************************************************************************************************************************/ static void exitOnSignal(int signalType) { FUNCTION_LOG_BEGIN(logLevelTrace); FUNCTION_LOG_PARAM(INT, signalType); FUNCTION_LOG_END(); exit(exitSafe(errorTypeCode(&TermError), false, (SignalType)signalType)); FUNCTION_LOG_RETURN_VOID(); }
/*********************************************************************************************************************************** Execute main function in Perl ***********************************************************************************************************************************/ static int perlExecResult(int code, bool errorC, const char *message) { FUNCTION_TEST_BEGIN(); FUNCTION_TEST_PARAM(INT, code); FUNCTION_TEST_PARAM(BOOL, errorC); FUNCTION_TEST_PARAM(STRINGZ, message); FUNCTION_TEST_END(); int result = code; if (code >= errorTypeCode(&AssertError)) { if (errorC) RETHROW(); else THROW_CODE(code, strlen(message) == 0 ? PERL_EMBED_ERROR : message); } FUNCTION_TEST_RETURN(result); }
/*********************************************************************************************************************************** Do cleanup and return result code ***********************************************************************************************************************************/ int exitSafe(int result, bool error, SignalType signalType) { FUNCTION_LOG_BEGIN(logLevelDebug); FUNCTION_LOG_PARAM(INT, result); FUNCTION_LOG_PARAM(BOOL, error); FUNCTION_LOG_PARAM(ENUM, signalType); FUNCTION_LOG_END(); // Report error if one was thrown if (error) { // Don't log the error if it has already been logged by Perl #ifdef HAVE_LIBPERL if (strcmp(errorMessage(), PERL_EMBED_ERROR) != 0) { #endif LogLevel logLevel = errorCode() == errorTypeCode(&AssertError) ? logLevelAssert : logLevelError; // Assert errors always output a stack trace if (logLevel == logLevelAssert) LOG(logLevel, errorCode(), "%s\nSTACK TRACE:\n%s", errorMessage(), errorStackTrace()); else { // Log just the error to non-debug levels LOG_INTERNAL(logLevel, LOG_LEVEL_MIN, logLevelDetail, 0, errorCode(), errorMessage()); // Log the stack trace debug levels if (logAny(logLevelDebug)) { LOG_INTERNAL( logLevel, logLevelDebug, LOG_LEVEL_MAX, 0, errorCode(), "%s\nSTACK TRACE:\n%s", errorMessage(), errorStackTrace()); } } #ifdef HAVE_LIBPERL } #endif result = errorCode(); } // Free protocol objects but ignore errors TRY_BEGIN() { protocolFree(); } TRY_END(); // Free Perl but ignore errors #ifdef HAVE_LIBPERL TRY_BEGIN() { perlFree(result); } TRY_END(); #endif // Log command end if a command is set if (cfgCommand() != cfgCmdNone) { String *errorMessage = NULL; // On error generate an error message if (result != 0) { // On process terminate if (result == errorTypeCode(&TermError)) { errorMessage = strNew("terminated on signal "); // Terminate from a child if (signalType == signalTypeNone) strCat(errorMessage, "from child process"); // Else terminated directly else strCatFmt(errorMessage, "[SIG%s]", exitSignalName(signalType)); } // Standard error exit message else if (error) errorMessage = strNewFmt("aborted with exception [%03d]", result); } cmdEnd(result, errorMessage); } // Release any locks but ignore errors TRY_BEGIN() { lockRelease(false); } TRY_END(); // Return result - caller should immediate pass this result to exit() FUNCTION_LOG_RETURN(INT, result); }