From 4342ff741bacf11a595d1aa8e59d33a2efd8620e Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 20 Aug 2015 21:26:39 +0200 Subject: [PATCH] Pass exit status of panda process on to panda3d process (non-Windows only so far) --- direct/src/p3d/AppRunner.py | 4 +- direct/src/plugin/p3dPythonMain.cxx | 8 ++-- direct/src/plugin/p3dPythonRun.cxx | 64 ++++++++++++++++++----------- direct/src/plugin/p3dPythonRun.h | 2 +- direct/src/plugin/p3dSession.cxx | 44 ++++++++++++++------ direct/src/plugin/run_p3dpython.cxx | 13 +++--- direct/src/plugin/run_p3dpython.h | 8 ++-- 7 files changed, 89 insertions(+), 54 deletions(-) diff --git a/direct/src/p3d/AppRunner.py b/direct/src/p3d/AppRunner.py index ff63e5aa8d..7c080ad8e2 100644 --- a/direct/src/p3d/AppRunner.py +++ b/direct/src/p3d/AppRunner.py @@ -634,13 +634,13 @@ class AppRunner(DirectObject): try: taskMgr.run() - except SystemExit: + except SystemExit as err: # Presumably the window has already been shut down here, but shut # it down again for good measure. if hasattr(__builtin__, "base"): base.destroy() - self.notify.info("Normal exit.") + self.notify.info("Normal exit with status %d." % err.code) raise except: diff --git a/direct/src/plugin/p3dPythonMain.cxx b/direct/src/plugin/p3dPythonMain.cxx index bf218a8cb9..ef5b83e282 100644 --- a/direct/src/plugin/p3dPythonMain.cxx +++ b/direct/src/plugin/p3dPythonMain.cxx @@ -150,10 +150,10 @@ main(int argc, char *argv[]) { } } - if (!run_p3dpython(program_name, archive_file, input_handle, output_handle, - NULL, interactive_console)) { + int status = run_p3dpython(program_name, archive_file, input_handle, + output_handle, NULL, interactive_console); + if (status != 0) { cerr << "Failure on startup.\n"; - return 1; } - return 0; + return status; } diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index 667f34e7dc..6ef80cd224 100644 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -137,8 +137,10 @@ P3DPythonRun:: // Access: Public // Description: Runs the embedded Python process. This method does // not return until the plugin is ready to exit. +// +// Returns the exit status, which will be 0 on success. //////////////////////////////////////////////////////////////////// -bool P3DPythonRun:: +int P3DPythonRun:: run_python() { #if defined(_WIN32) && defined(USE_DEBUG_PYTHON) // On Windows, in a debug build, we have to preload sys.dll_suffix = @@ -156,7 +158,7 @@ run_python() { if (panda3d_module == NULL) { nout << "Failed to create panda3d module:\n"; PyErr_Print(); - return false; + return 1; } // Set the __path__ such that it can find panda3d/core.pyd, etc. @@ -174,7 +176,7 @@ run_python() { if (vfsimporter == NULL) { nout << "Failed to import _vfsimporter:\n"; PyErr_Print(); - return false; + return 1; } Py_DECREF(vfsimporter); @@ -183,7 +185,7 @@ run_python() { if (vfsimporter_module == NULL) { nout << "Failed to import VFSImporter:\n"; PyErr_Print(); - return false; + return 1; } // And register the VFSImporter. @@ -191,7 +193,7 @@ run_python() { if (result == NULL) { nout << "Failed to call VFSImporter.register():\n"; PyErr_Print(); - return false; + return 1; } Py_DECREF(result); Py_DECREF(vfsimporter_module); @@ -203,12 +205,12 @@ run_python() { PT(Multifile) mf = new Multifile; if (!mf->open_read(_archive_file)) { nout << "Could not read " << _archive_file << "\n"; - return false; + return 1; } VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); if (!vfs->mount(mf, dir, VirtualFileSystem::MF_read_only)) { nout << "Could not mount " << _archive_file << "\n"; - return false; + return 1; } // And finally, we can import the startup module. @@ -216,7 +218,7 @@ run_python() { if (app_runner_module == NULL) { nout << "Failed to import direct.p3d.AppRunner\n"; PyErr_Print(); - return false; + return 1; } // Get the pointers to the objects needed within the module. @@ -224,7 +226,7 @@ run_python() { if (app_runner_class == NULL) { nout << "Failed to get AppRunner class\n"; PyErr_Print(); - return false; + return 1; } // Construct an instance of AppRunner. @@ -232,7 +234,7 @@ run_python() { if (_runner == NULL) { nout << "Failed to construct AppRunner instance\n"; PyErr_Print(); - return false; + return 1; } Py_DECREF(app_runner_class); @@ -240,35 +242,35 @@ run_python() { _undefined_object_class = PyObject_GetAttrString(app_runner_module, "UndefinedObject"); if (_undefined_object_class == NULL) { PyErr_Print(); - return false; + return 1; } // And the "Undefined" instance. _undefined = PyObject_GetAttrString(app_runner_module, "Undefined"); if (_undefined == NULL) { PyErr_Print(); - return false; + return 1; } // Get the ConcreteStruct class. _concrete_struct_class = PyObject_GetAttrString(app_runner_module, "ConcreteStruct"); if (_concrete_struct_class == NULL) { PyErr_Print(); - return false; + return 1; } // Get the BrowserObject class. _browser_object_class = PyObject_GetAttrString(app_runner_module, "BrowserObject"); if (_browser_object_class == NULL) { PyErr_Print(); - return false; + return 1; } // Get the global TaskManager. _taskMgr = PyObject_GetAttrString(app_runner_module, "taskMgr"); if (_taskMgr == NULL) { PyErr_Print(); - return false; + return 1; } Py_DECREF(app_runner_module); @@ -285,12 +287,12 @@ run_python() { PyObject *p3dpython = Py_InitModule("p3dpython", p3dpython_methods); if (p3dpython == NULL) { PyErr_Print(); - return false; + return 1; } PyObject *request_func = PyObject_GetAttrString(p3dpython, "request_func"); if (request_func == NULL) { PyErr_Print(); - return false; + return 1; } // Now pass that func pointer back to our AppRunner instance, so it @@ -298,7 +300,7 @@ run_python() { result = PyObject_CallMethod(_runner, (char *)"setRequestFunc", (char *)"N", request_func); if (result == NULL) { PyErr_Print(); - return false; + return 1; } Py_DECREF(result); @@ -318,7 +320,7 @@ run_python() { PyObject *check_comm = PyObject_GetAttrString(p3dpython, "check_comm"); if (check_comm == NULL) { PyErr_Print(); - return false; + return 1; } // Add it to the task manager. We do this instead of constructing a @@ -326,7 +328,7 @@ run_python() { result = PyObject_CallMethod(_taskMgr, (char *)"add", (char *)"Ns", check_comm, "check_comm"); if (result == NULL) { PyErr_Print(); - return false; + return 1; } Py_DECREF(result); @@ -334,18 +336,30 @@ run_python() { // taskMgr.run()). PyObject *done = PyObject_CallMethod(_runner, (char *)"run", (char *)""); if (done == NULL) { + int status = 1; + // An uncaught application exception, and not handled by - // appRunner.exceptionHandler. - PyErr_Print(); + // appRunner.exceptionHandler. If it is a SystemExit, extract + // the exit status that we should return. + if (PyErr_Occurred() == PyExc_SystemExit) { + PyObject *ptype, *ptraceback; + PySystemExitObject *value = NULL; + PyErr_Fetch(&ptype, (PyObject **)&value, &ptraceback); + if (value != NULL) { + status = (int)PyInt_AsLong(value->code); + } + } else { + PyErr_Print(); + } if (_interactive_console) { // Give an interactive user a chance to explore the exception. run_interactive_console(); - return true; + return 0; } // We're done. - return false; + return status; } // A normal exit from the taskManager. We're presumably done. @@ -355,7 +369,7 @@ run_python() { run_interactive_console(); } - return true; + return 0; } //////////////////////////////////////////////////////////////////// diff --git a/direct/src/plugin/p3dPythonRun.h b/direct/src/plugin/p3dPythonRun.h index 1f52c5eeb1..824def1cfe 100644 --- a/direct/src/plugin/p3dPythonRun.h +++ b/direct/src/plugin/p3dPythonRun.h @@ -71,7 +71,7 @@ public: const char *log_pathname, bool interactive_console); ~P3DPythonRun(); - bool run_python(); + int run_python(); void set_window_open(P3DCInstance *inst, bool is_open); void request_keyboard_focus(P3DCInstance *inst); diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index 2d6f8b8e94..da9b30874f 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -179,18 +179,27 @@ shutdown() { result = waitpid(_p3dpython_pid, &status, WNOHANG); } _p3dpython_pid = -1; - + nout << "Python process has successfully stopped.\n"; if (WIFEXITED(status)) { - nout << " exited normally, status = " - << WEXITSTATUS(status) << "\n"; + int code = WEXITSTATUS(status); + + nout << " exited normally, status = " << code << "\n"; + if (code != 0) { + _exit(code); + } + } else if (WIFSIGNALED(status)) { - nout << " signalled by " << WTERMSIG(status) << ", core = " + nout << " signalled by " << WTERMSIG(status) << ", core = " << WCOREDUMP(status) << "\n"; + + // This seems to be a popular shell convention. + _exit(128 + WTERMSIG(status)); + } else if (WIFSTOPPED(status)) { nout << " stopped by " << WSTOPSIG(status) << "\n"; } - + #endif // _WIN32 } @@ -1708,15 +1717,24 @@ posix_create_process() { // its process. Report an error condition. nout << "Python process stopped immediately.\n"; if (WIFEXITED(status)) { - nout << " exited normally, status = " - << WEXITSTATUS(status) << "\n"; + int code = WEXITSTATUS(status); + + nout << " exited normally, status = " << code << "\n"; + if (code != 0) { + _exit(code); + } + } else if (WIFSIGNALED(status)) { - nout << " signalled by " << WTERMSIG(status) << ", core = " + nout << " signalled by " << WTERMSIG(status) << ", core = " << WCOREDUMP(status) << "\n"; + + // This seems to be a popular shell convention. + _exit(128 + WTERMSIG(status)); + } else if (WIFSTOPPED(status)) { nout << " stopped by " << WSTOPSIG(status) << "\n"; } - + return -1; } #endif // _WIN32 @@ -1798,10 +1816,12 @@ p3dpython_thread_run() { return; } - if (!run_p3dpython(libp3dpython.c_str(), _mf_filename.c_str(), - _input_handle, _output_handle, _log_pathname.c_str(), - _interactive_console)) { + int status = run_p3dpython(libp3dpython.c_str(), _mf_filename.c_str(), + _input_handle, _output_handle, _log_pathname.c_str(), + _interactive_console); + if (status != 0) { nout << "Failure on startup.\n"; + _exit(status); } } diff --git a/direct/src/plugin/run_p3dpython.cxx b/direct/src/plugin/run_p3dpython.cxx index e5db32d10e..5a7dc4c742 100644 --- a/direct/src/plugin/run_p3dpython.cxx +++ b/direct/src/plugin/run_p3dpython.cxx @@ -19,16 +19,17 @@ // Function: run_p3dpython // Description: This externally-visible function is the main entry // point to this DLL, and it starts the whole thing -// running. Returns true on success, false on failure. +// running. Returns the exit status, which will be +// 0 on success, 1 or otherwise on failure. //////////////////////////////////////////////////////////////////// -bool +int run_p3dpython(const char *program_name, const char *archive_file, - FHandle input_handle, FHandle output_handle, + FHandle input_handle, FHandle output_handle, const char *log_pathname, bool interactive_console) { - P3DPythonRun::_global_ptr = - new P3DPythonRun(program_name, archive_file, input_handle, output_handle, + P3DPythonRun::_global_ptr = + new P3DPythonRun(program_name, archive_file, input_handle, output_handle, log_pathname, interactive_console); - bool result = P3DPythonRun::_global_ptr->run_python(); + int result = P3DPythonRun::_global_ptr->run_python(); delete P3DPythonRun::_global_ptr; P3DPythonRun::_global_ptr = NULL; return result; diff --git a/direct/src/plugin/run_p3dpython.h b/direct/src/plugin/run_p3dpython.h index 21d5430f54..6b358b742b 100644 --- a/direct/src/plugin/run_p3dpython.h +++ b/direct/src/plugin/run_p3dpython.h @@ -26,14 +26,14 @@ #define EXPCL_P3DPYTHON #endif -typedef bool +typedef int run_p3dpython_func(const char *program_name, const char *archive_file, - FHandle input_handle, FHandle output_handle, + FHandle input_handle, FHandle output_handle, const char *log_pathname, bool interactive_console); -extern "C" EXPCL_P3DPYTHON bool +extern "C" EXPCL_P3DPYTHON int run_p3dpython(const char *program_name, const char *archive_file, - FHandle input_handle, FHandle output_handle, + FHandle input_handle, FHandle output_handle, const char *log_pathname, bool interactive_console); #endif