mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 01:07:51 -04:00
one_process support. Some issues.
This commit is contained in:
parent
034a977c3d
commit
4388b853e5
@ -2185,10 +2185,12 @@ class Packager:
|
|||||||
# This is the main program that drives the runtime Python. It
|
# This is the main program that drives the runtime Python. It
|
||||||
# is responsible for loading _vfsimporter.pyd, and then
|
# is responsible for loading _vfsimporter.pyd, and then
|
||||||
# importing direct.p3d.AppRunner, to start an application
|
# importing direct.p3d.AppRunner, to start an application
|
||||||
# running. Note that the .exe extension is automatically
|
# running. The program comes in two parts: an executable, and
|
||||||
# replaced with the platform-specific extension appropriate
|
# an associated dynamic library. Note that the .exe and .dll
|
||||||
# for an executable.
|
# extensions are automatically replaced with the appropriate
|
||||||
|
# platform-specific extensions.
|
||||||
self.do_file('p3dpython.exe')
|
self.do_file('p3dpython.exe')
|
||||||
|
self.do_file('libp3dpython.dll')
|
||||||
|
|
||||||
def do_freeze(self, filename, compileToExe = False):
|
def do_freeze(self, filename, compileToExe = False):
|
||||||
""" Freezes all of the current Python code into either an
|
""" Freezes all of the current Python code into either an
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
find_root_dir.cxx find_root_dir.h \
|
find_root_dir.cxx find_root_dir.h \
|
||||||
get_tinyxml.h \
|
get_tinyxml.h \
|
||||||
binaryXml.cxx binaryXml.h \
|
binaryXml.cxx binaryXml.h \
|
||||||
|
fhandle.h \
|
||||||
handleStream.cxx handleStream.h handleStream.I \
|
handleStream.cxx handleStream.h handleStream.I \
|
||||||
handleStreamBuf.cxx handleStreamBuf.h handleStreamBuf.I \
|
handleStreamBuf.cxx handleStreamBuf.h handleStreamBuf.I \
|
||||||
mkdir_complete.cxx mkdir_complete.h \
|
mkdir_complete.cxx mkdir_complete.h \
|
||||||
@ -51,7 +52,8 @@
|
|||||||
p3dUndefinedObject.h \
|
p3dUndefinedObject.h \
|
||||||
p3dWinSplashWindow.h p3dWinSplashWindow.I \
|
p3dWinSplashWindow.h p3dWinSplashWindow.I \
|
||||||
p3dX11SplashWindow.h \
|
p3dX11SplashWindow.h \
|
||||||
p3dWindowParams.h p3dWindowParams.I
|
p3dWindowParams.h p3dWindowParams.I \
|
||||||
|
run_p3dpython.h
|
||||||
|
|
||||||
#define INCLUDED_SOURCES \
|
#define INCLUDED_SOURCES \
|
||||||
p3d_plugin.cxx \
|
p3d_plugin.cxx \
|
||||||
@ -91,7 +93,7 @@
|
|||||||
|
|
||||||
#end lib_target
|
#end lib_target
|
||||||
|
|
||||||
#begin bin_target
|
#begin lib_target
|
||||||
#define BUILD_TARGET $[HAVE_PYTHON]
|
#define BUILD_TARGET $[HAVE_PYTHON]
|
||||||
#define USE_PACKAGES tinyxml python
|
#define USE_PACKAGES tinyxml python
|
||||||
#define TARGET p3dpython
|
#define TARGET p3dpython
|
||||||
@ -105,19 +107,31 @@
|
|||||||
|
|
||||||
#define SOURCES \
|
#define SOURCES \
|
||||||
binaryXml.cxx binaryXml.h \
|
binaryXml.cxx binaryXml.h \
|
||||||
|
fhandle.h \
|
||||||
handleStream.cxx handleStream.h handleStream.I \
|
handleStream.cxx handleStream.h handleStream.I \
|
||||||
handleStreamBuf.cxx handleStreamBuf.h handleStreamBuf.I \
|
handleStreamBuf.cxx handleStreamBuf.h handleStreamBuf.I \
|
||||||
p3d_lock.h p3d_plugin.h \
|
p3d_lock.h p3d_plugin.h \
|
||||||
p3d_plugin_config.h \
|
p3d_plugin_config.h \
|
||||||
p3dCInstance.cxx \
|
p3dCInstance.cxx \
|
||||||
p3dCInstance.h p3dCInstance.I \
|
p3dCInstance.h p3dCInstance.I \
|
||||||
p3dPythonRun.cxx p3dPythonRun.h p3dPythonRun.I
|
p3dPythonRun.cxx p3dPythonRun.h p3dPythonRun.I \
|
||||||
|
run_p3dpython.h
|
||||||
|
|
||||||
#define WIN_SYS_LIBS user32.lib
|
#define WIN_SYS_LIBS user32.lib
|
||||||
|
|
||||||
// If you have to link with a static Python library, define it here.
|
// If you have to link with a static Python library, define it here.
|
||||||
#define EXTRA_LIBS $[EXTRA_P3DPYTHON_LIBS]
|
#define EXTRA_LIBS $[EXTRA_P3DPYTHON_LIBS]
|
||||||
|
|
||||||
|
#end lib_target
|
||||||
|
|
||||||
|
#begin bin_target
|
||||||
|
#define BUILD_TARGET $[HAVE_PYTHON]
|
||||||
|
#define TARGET p3dpython
|
||||||
|
|
||||||
|
#define SOURCES \
|
||||||
|
fhandle.h \
|
||||||
|
p3dPythonMain.cxx \
|
||||||
|
run_p3dpython.h
|
||||||
#end bin_target
|
#end bin_target
|
||||||
|
|
||||||
#begin static_lib_target
|
#begin static_lib_target
|
||||||
|
29
direct/src/plugin/fhandle.h
Normal file
29
direct/src/plugin/fhandle.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Filename: fhandle.h
|
||||||
|
// Created by: drose (29Aug09)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the revised BSD
|
||||||
|
// license. You should have received a copy of this license along
|
||||||
|
// with this source code in a file named "LICENSE."
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef FHANDLE_H
|
||||||
|
#define FHANDLE_H
|
||||||
|
|
||||||
|
// This header file simply defines the FHandle type, which is used to
|
||||||
|
// pass around a handle to an open file object.
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
typedef HANDLE FHandle;
|
||||||
|
#else
|
||||||
|
// On POSIX, we use a file descriptor as a "handle".
|
||||||
|
typedef int FHandle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -15,14 +15,7 @@
|
|||||||
#ifndef HANDLESTREAMBUF_H
|
#ifndef HANDLESTREAMBUF_H
|
||||||
#define HANDLESTREAMBUF_H
|
#define HANDLESTREAMBUF_H
|
||||||
|
|
||||||
#ifdef _WIN32
|
#include "fhandle.h"
|
||||||
#include <windows.h>
|
|
||||||
typedef HANDLE FHandle;
|
|
||||||
#else
|
|
||||||
// On POSIX, we use a file descriptor as a "handle".
|
|
||||||
typedef int FHandle;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -29,28 +29,27 @@ P3DPythonRun *P3DPythonRun::_global_ptr = NULL;
|
|||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
P3DPythonRun::
|
P3DPythonRun::
|
||||||
P3DPythonRun(int argc, char *argv[]) {
|
P3DPythonRun(const char *program_name, const char *archive_file,
|
||||||
|
FHandle input, FHandle output) {
|
||||||
_read_thread_continue = false;
|
_read_thread_continue = false;
|
||||||
_program_continue = true;
|
_program_continue = true;
|
||||||
|
_session_terminated = false;
|
||||||
INIT_LOCK(_commands_lock);
|
INIT_LOCK(_commands_lock);
|
||||||
INIT_THREAD(_read_thread);
|
INIT_THREAD(_read_thread);
|
||||||
|
|
||||||
_session_id = 0;
|
_session_id = 0;
|
||||||
_next_sent_id = 0;
|
_next_sent_id = 0;
|
||||||
|
|
||||||
if (argc >= 1) {
|
if (program_name != NULL) {
|
||||||
_program_name = argv[0];
|
_program_name = program_name;
|
||||||
}
|
}
|
||||||
if (argc >= 2) {
|
if (archive_file != NULL) {
|
||||||
_archive_file = Filename::from_os_specific(argv[1]);
|
_archive_file = Filename::from_os_specific(archive_file);
|
||||||
}
|
|
||||||
if (_archive_file.empty()) {
|
|
||||||
nout << "No archive filename specified on command line.\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_py_argc = 1;
|
_py_argc = 1;
|
||||||
_py_argv = (char **)malloc(2 * sizeof(char *));
|
_py_argv = (char **)malloc(2 * sizeof(char *));
|
||||||
|
|
||||||
_py_argv[0] = (char *)_program_name.c_str();
|
_py_argv[0] = (char *)_program_name.c_str();
|
||||||
_py_argv[1] = NULL;
|
_py_argv[1] = NULL;
|
||||||
|
|
||||||
@ -66,28 +65,15 @@ P3DPythonRun(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// Initialize Python. It appears to be important to do this before
|
// Initialize Python. It appears to be important to do this before
|
||||||
// we open the pipe streams and spawn the thread, below.
|
// we open the pipe streams and spawn the thread, below.
|
||||||
|
PyEval_InitThreads();
|
||||||
Py_SetProgramName((char *)_program_name.c_str());
|
Py_SetProgramName((char *)_program_name.c_str());
|
||||||
Py_Initialize();
|
Py_Initialize();
|
||||||
PySys_SetArgv(_py_argc, _py_argv);
|
PySys_SetArgv(_py_argc, _py_argv);
|
||||||
|
|
||||||
// Open the pipe streams with the input and output handles from the
|
// Open the pipe streams with the input and output handles from the
|
||||||
// parent.
|
// parent.
|
||||||
#ifdef _WIN32
|
_pipe_read.open_read(input);
|
||||||
HANDLE read = GetStdHandle(STD_INPUT_HANDLE);
|
_pipe_write.open_write(output);
|
||||||
HANDLE write = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
if (!SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE)) {
|
|
||||||
nout << "unable to reset input handle\n";
|
|
||||||
}
|
|
||||||
if (!SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE)) {
|
|
||||||
nout << "unable to reset input handle\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
_pipe_read.open_read(read);
|
|
||||||
_pipe_write.open_write(write);
|
|
||||||
#else
|
|
||||||
_pipe_read.open_read(STDIN_FILENO);
|
|
||||||
_pipe_write.open_write(STDOUT_FILENO);
|
|
||||||
#endif // _WIN32
|
|
||||||
|
|
||||||
if (!_pipe_read) {
|
if (!_pipe_read) {
|
||||||
nout << "unable to open read pipe\n";
|
nout << "unable to open read pipe\n";
|
||||||
@ -125,7 +111,6 @@ run_python() {
|
|||||||
// "_d", so that the Panda DLL preloader can import the correct
|
// "_d", so that the Panda DLL preloader can import the correct
|
||||||
// filenames.
|
// filenames.
|
||||||
PyRun_SimpleString("import sys; sys.dll_suffix = '_d'");
|
PyRun_SimpleString("import sys; sys.dll_suffix = '_d'");
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We'll need libpandaexpress to be imported before we can load
|
// We'll need libpandaexpress to be imported before we can load
|
||||||
@ -696,6 +681,9 @@ check_comm() {
|
|||||||
_commands.pop_front();
|
_commands.pop_front();
|
||||||
RELEASE_LOCK(_commands_lock);
|
RELEASE_LOCK(_commands_lock);
|
||||||
handle_command(doc);
|
handle_command(doc);
|
||||||
|
if (_session_terminated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ACQUIRE_LOCK(_commands_lock);
|
ACQUIRE_LOCK(_commands_lock);
|
||||||
}
|
}
|
||||||
RELEASE_LOCK(_commands_lock);
|
RELEASE_LOCK(_commands_lock);
|
||||||
@ -704,6 +692,7 @@ check_comm() {
|
|||||||
// The low-level thread detected an error, for instance pipe
|
// The low-level thread detected an error, for instance pipe
|
||||||
// closed. We should exit gracefully.
|
// closed. We should exit gracefully.
|
||||||
terminate_session();
|
terminate_session();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sleep to yield the timeslice, but only if we're not running in
|
// Sleep to yield the timeslice, but only if we're not running in
|
||||||
@ -758,6 +747,9 @@ wait_script_response(int response_id) {
|
|||||||
_commands.erase(ci);
|
_commands.erase(ci);
|
||||||
RELEASE_LOCK(_commands_lock);
|
RELEASE_LOCK(_commands_lock);
|
||||||
handle_command(doc);
|
handle_command(doc);
|
||||||
|
if (_session_terminated) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
ACQUIRE_LOCK(_commands_lock);
|
ACQUIRE_LOCK(_commands_lock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -791,6 +783,7 @@ wait_script_response(int response_id) {
|
|||||||
|
|
||||||
if (!_program_continue) {
|
if (!_program_continue) {
|
||||||
terminate_session();
|
terminate_session();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -839,6 +832,9 @@ py_request_func(PyObject *args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TiXmlDocument *doc = wait_script_response(response_id);
|
TiXmlDocument *doc = wait_script_response(response_id);
|
||||||
|
if (_session_terminated) {
|
||||||
|
return Py_BuildValue("");
|
||||||
|
}
|
||||||
assert(doc != NULL);
|
assert(doc != NULL);
|
||||||
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
||||||
assert(xcommand != NULL);
|
assert(xcommand != NULL);
|
||||||
@ -1230,10 +1226,7 @@ terminate_session() {
|
|||||||
}
|
}
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
|
|
||||||
// The task manager is cleaned up. Let's exit immediately here,
|
_session_terminated = true;
|
||||||
// rather than returning all the way up. This just makes it easier
|
|
||||||
// when we call terminate_session() from a deeply-nested loop.
|
|
||||||
exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -1561,16 +1554,18 @@ rt_thread_run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: main
|
// Function: run_p3dpython
|
||||||
// Description: Starts the program running.
|
// 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.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int
|
bool
|
||||||
main(int argc, char *argv[]) {
|
run_p3dpython(const char *program_name, const char *archive_file,
|
||||||
P3DPythonRun::_global_ptr = new P3DPythonRun(argc, argv);
|
FHandle input, FHandle output) {
|
||||||
|
P3DPythonRun::_global_ptr =
|
||||||
if (!P3DPythonRun::_global_ptr->run_python()) {
|
new P3DPythonRun(program_name, archive_file, input, output);
|
||||||
nout << "Couldn't initialize Python.\n";
|
bool result = P3DPythonRun::_global_ptr->run_python();
|
||||||
return 1;
|
delete P3DPythonRun::_global_ptr;
|
||||||
}
|
P3DPythonRun::_global_ptr = NULL;
|
||||||
return 0;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "run_p3dpython.h"
|
||||||
#include "p3d_lock.h"
|
#include "p3d_lock.h"
|
||||||
#include "handleStream.h"
|
#include "handleStream.h"
|
||||||
#include "p3dCInstance.h"
|
#include "p3dCInstance.h"
|
||||||
@ -65,7 +66,8 @@ using namespace std;
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
class P3DPythonRun {
|
class P3DPythonRun {
|
||||||
public:
|
public:
|
||||||
P3DPythonRun(int argc, char *argv[]);
|
P3DPythonRun(const char *program_name, const char *archive_file,
|
||||||
|
FHandle input, FHandle output);
|
||||||
~P3DPythonRun();
|
~P3DPythonRun();
|
||||||
|
|
||||||
bool run_python();
|
bool run_python();
|
||||||
@ -153,6 +155,7 @@ private:
|
|||||||
|
|
||||||
bool _read_thread_continue;
|
bool _read_thread_continue;
|
||||||
bool _program_continue;
|
bool _program_continue;
|
||||||
|
bool _session_terminated;
|
||||||
THREAD _read_thread;
|
THREAD _read_thread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "p3dConcreteStruct.h"
|
#include "p3dConcreteStruct.h"
|
||||||
#include "binaryXml.h"
|
#include "binaryXml.h"
|
||||||
#include "mkdir_complete.h"
|
#include "mkdir_complete.h"
|
||||||
|
#include "run_p3dpython.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
@ -34,6 +35,7 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -53,6 +55,7 @@ P3DSession(P3DInstance *inst) {
|
|||||||
_python_version = inst->get_python_version();
|
_python_version = inst->get_python_version();
|
||||||
|
|
||||||
_start_dir = inst_mgr->get_root_dir() + "/start";
|
_start_dir = inst_mgr->get_root_dir() + "/start";
|
||||||
|
_p3dpython_one_process = false;
|
||||||
_p3dpython_started = false;
|
_p3dpython_started = false;
|
||||||
_p3dpython_running = false;
|
_p3dpython_running = false;
|
||||||
|
|
||||||
@ -100,67 +103,86 @@ shutdown() {
|
|||||||
|
|
||||||
static const int max_wait_ms = 2000;
|
static const int max_wait_ms = 2000;
|
||||||
|
|
||||||
|
if (_p3dpython_one_process) {
|
||||||
|
// Since it's running in a thread, we can't reliably force-kill
|
||||||
|
// it. So, just wait.
|
||||||
|
nout << "Waiting for Python thread to exit\n";
|
||||||
|
JOIN_THREAD(_p3dpython_thread);
|
||||||
|
nout << "Done waiting.\n";
|
||||||
|
_p3dpython_one_process = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Python's running in a sub-process, the preferred way. In
|
||||||
|
// this case, we can wait a brief amount of time before it
|
||||||
|
// closes itself; but if it doesn't, we can safely force-kill
|
||||||
|
// it.
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Now give the process a chance to terminate itself cleanly.
|
// Wait for a certain amount of time for the process to stop by
|
||||||
if (WaitForSingleObject(_p3dpython_handle, max_wait_ms) == WAIT_TIMEOUT) {
|
// itself.
|
||||||
// It didn't shut down cleanly, so kill it the hard way.
|
if (WaitForSingleObject(_p3dpython_handle, max_wait_ms) == WAIT_TIMEOUT) {
|
||||||
nout << "Force-killing python process.\n";
|
// It didn't shut down cleanly, so kill it the hard way.
|
||||||
TerminateProcess(_p3dpython_handle, 2);
|
nout << "Force-killing python process.\n";
|
||||||
}
|
TerminateProcess(_p3dpython_handle, 2);
|
||||||
|
|
||||||
CloseHandle(_p3dpython_handle);
|
|
||||||
#else // _WIN32
|
|
||||||
|
|
||||||
// Wait for a certain amount of time for the process to stop by
|
|
||||||
// itself.
|
|
||||||
struct timeval start;
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
int start_ms = start.tv_sec * 1000 + start.tv_usec / 1000;
|
|
||||||
|
|
||||||
int status;
|
|
||||||
pid_t result = waitpid(_p3dpython_pid, &status, WNOHANG);
|
|
||||||
while (result != _p3dpython_pid) {
|
|
||||||
if (result == -1) {
|
|
||||||
perror("waitpid");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct timeval now;
|
|
||||||
gettimeofday(&now, NULL);
|
|
||||||
int now_ms = now.tv_sec * 1000 + now.tv_usec / 1000;
|
|
||||||
int elapsed = now_ms - start_ms;
|
|
||||||
|
|
||||||
if (elapsed > max_wait_ms) {
|
|
||||||
// Tired of waiting. Kill the process.
|
|
||||||
nout << "Force-killing python process, pid " << _p3dpython_pid
|
|
||||||
<< "\n";
|
|
||||||
kill(_p3dpython_pid, SIGKILL);
|
|
||||||
start_ms = now_ms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yield the timeslice and wait some more.
|
CloseHandle(_p3dpython_handle);
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = 0;
|
|
||||||
tv.tv_usec = 1;
|
|
||||||
select(0, NULL, NULL, NULL, &tv);
|
|
||||||
result = waitpid(_p3dpython_pid, &status, WNOHANG);
|
|
||||||
}
|
|
||||||
|
|
||||||
nout << "Python process has successfully stopped.\n";
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
nout << " exited normally, status = "
|
|
||||||
<< WEXITSTATUS(status) << "\n";
|
|
||||||
} else if (WIFSIGNALED(status)) {
|
|
||||||
nout << " signalled by " << WTERMSIG(status) << ", core = "
|
|
||||||
<< WCOREDUMP(status) << "\n";
|
|
||||||
} else if (WIFSTOPPED(status)) {
|
|
||||||
nout << " stopped by " << WSTOPSIG(status) << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#else // _WIN32
|
||||||
|
// Wait for a certain amount of time for the process to stop by
|
||||||
|
// itself.
|
||||||
|
struct timeval start;
|
||||||
|
gettimeofday(&start, NULL);
|
||||||
|
int start_ms = start.tv_sec * 1000 + start.tv_usec / 1000;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
pid_t result = waitpid(_p3dpython_pid, &status, WNOHANG);
|
||||||
|
while (result != _p3dpython_pid) {
|
||||||
|
if (result == -1) {
|
||||||
|
perror("waitpid");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
int now_ms = now.tv_sec * 1000 + now.tv_usec / 1000;
|
||||||
|
int elapsed = now_ms - start_ms;
|
||||||
|
|
||||||
|
if (elapsed > max_wait_ms) {
|
||||||
|
// Tired of waiting. Kill the process.
|
||||||
|
nout << "Force-killing python process, pid " << _p3dpython_pid
|
||||||
|
<< "\n";
|
||||||
|
kill(_p3dpython_pid, SIGKILL);
|
||||||
|
start_ms = now_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yield the timeslice and wait some more.
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 1;
|
||||||
|
select(0, NULL, NULL, NULL, &tv);
|
||||||
|
result = waitpid(_p3dpython_pid, &status, WNOHANG);
|
||||||
|
}
|
||||||
|
|
||||||
|
nout << "Python process has successfully stopped.\n";
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
nout << " exited normally, status = "
|
||||||
|
<< WEXITSTATUS(status) << "\n";
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
nout << " signalled by " << WTERMSIG(status) << ", core = "
|
||||||
|
<< WCOREDUMP(status) << "\n";
|
||||||
|
} else if (WIFSTOPPED(status)) {
|
||||||
|
nout << " stopped by " << WSTOPSIG(status) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
}
|
||||||
|
|
||||||
_p3dpython_running = false;
|
_p3dpython_running = false;
|
||||||
_p3dpython_started = false;
|
_p3dpython_started = false;
|
||||||
|
|
||||||
|
// Close the pipe now.
|
||||||
|
_pipe_read.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are any leftover commands in the queue (presumably
|
// If there are any leftover commands in the queue (presumably
|
||||||
@ -657,10 +679,9 @@ start_p3dpython(P3DInstance *inst) {
|
|||||||
// Change the current directory to the standard start directory, but
|
// Change the current directory to the standard start directory, but
|
||||||
// only if the runtime environment told us the original current
|
// only if the runtime environment told us the original current
|
||||||
// directory isn't meaningful.
|
// directory isn't meaningful.
|
||||||
string start_dir;
|
_use_start_dir = !inst_mgr->get_keep_cwd();
|
||||||
if (!inst_mgr->get_keep_cwd()) {
|
if (_use_start_dir) {
|
||||||
start_dir = _start_dir;
|
mkdir_complete(_start_dir, nout);
|
||||||
mkdir_complete(start_dir, nout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -725,16 +746,30 @@ start_p3dpython(P3DInstance *inst) {
|
|||||||
<< "PRC_PATH set to: " << prc_path << "\n";
|
<< "PRC_PATH set to: " << prc_path << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
string p3dpython = P3D_PLUGIN_P3DPYTHON;
|
// Get the name of the executable and dynamic library to run.
|
||||||
if (p3dpython.empty()) {
|
// Ideally, we'll run the executable successfully, in a sub-process;
|
||||||
p3dpython = _python_root_dir + "/p3dpython";
|
// this will in turn load and run the dynamic library. If that
|
||||||
|
// fails for some reason, we can fall back to loading and running
|
||||||
|
// the library directly.
|
||||||
|
_p3dpython_exe = _python_root_dir + "/p3dpython";
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
p3dpython += ".exe";
|
_p3dpython_exe += ".exe";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_p3dpython_dll = P3D_PLUGIN_P3DPYTHON;
|
||||||
|
if (_p3dpython_dll.empty()) {
|
||||||
|
_p3dpython_dll = _python_root_dir + "/libp3dpython";
|
||||||
|
#ifdef _WIN32
|
||||||
|
_p3dpython_dll += ".dll";
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
_p3dpython_dll += ".dylib";
|
||||||
|
#else
|
||||||
|
_p3dpython_dll += ".so";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the new process' environment.
|
// Populate the new process' environment.
|
||||||
string env;
|
_env = string();
|
||||||
|
|
||||||
// These are the enviroment variables we forward from the current
|
// These are the enviroment variables we forward from the current
|
||||||
// environment, if they are set.
|
// environment, if they are set.
|
||||||
@ -748,41 +783,41 @@ start_p3dpython(P3DInstance *inst) {
|
|||||||
for (int ki = 0; keep[ki] != NULL; ++ki) {
|
for (int ki = 0; keep[ki] != NULL; ++ki) {
|
||||||
char *value = getenv(keep[ki]);
|
char *value = getenv(keep[ki]);
|
||||||
if (value != NULL) {
|
if (value != NULL) {
|
||||||
env += keep[ki];
|
_env += keep[ki];
|
||||||
env += "=";
|
_env += "=";
|
||||||
env += value;
|
_env += value;
|
||||||
env += '\0';
|
_env += '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define some new environment variables.
|
// Define some new environment variables.
|
||||||
env += "PATH=";
|
_env += "PATH=";
|
||||||
env += search_path;
|
_env += search_path;
|
||||||
env += '\0';
|
_env += '\0';
|
||||||
|
|
||||||
env += "LD_LIBRARY_PATH=";
|
_env += "LD_LIBRARY_PATH=";
|
||||||
env += search_path;
|
_env += search_path;
|
||||||
env += '\0';
|
_env += '\0';
|
||||||
|
|
||||||
env += "DYLD_LIBRARY_PATH=";
|
_env += "DYLD_LIBRARY_PATH=";
|
||||||
env += search_path;
|
_env += search_path;
|
||||||
env += '\0';
|
_env += '\0';
|
||||||
|
|
||||||
env += "PYTHONPATH=";
|
_env += "PYTHONPATH=";
|
||||||
env += python_path;
|
_env += python_path;
|
||||||
env += '\0';
|
_env += '\0';
|
||||||
|
|
||||||
env += "PYTHONHOME=";
|
_env += "PYTHONHOME=";
|
||||||
env += _python_root_dir;
|
_env += _python_root_dir;
|
||||||
env += '\0';
|
_env += '\0';
|
||||||
|
|
||||||
env += "PRC_PATH=";
|
_env += "PRC_PATH=";
|
||||||
env += prc_path;
|
_env += prc_path;
|
||||||
env += '\0';
|
_env += '\0';
|
||||||
|
|
||||||
env += "PANDA_PRC_PATH=";
|
_env += "PANDA_PRC_PATH=";
|
||||||
env += prc_path;
|
_env += prc_path;
|
||||||
env += '\0';
|
_env += '\0';
|
||||||
|
|
||||||
// Define each package's root directory in an environment variable
|
// Define each package's root directory in an environment variable
|
||||||
// named after the package, for the convenience of the packages in
|
// named after the package, for the convenience of the packages in
|
||||||
@ -793,11 +828,11 @@ start_p3dpython(P3DInstance *inst) {
|
|||||||
for (string::const_iterator si = package_name.begin();
|
for (string::const_iterator si = package_name.begin();
|
||||||
si != package_name.end();
|
si != package_name.end();
|
||||||
++si) {
|
++si) {
|
||||||
env += toupper(*si);
|
_env += toupper(*si);
|
||||||
}
|
}
|
||||||
env += string("_ROOT=");
|
_env += string("_ROOT=");
|
||||||
env += package->get_package_dir();
|
_env += package->get_package_dir();
|
||||||
env += '\0';
|
_env += '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the log filename from the p3d_info.xml file.
|
// Get the log filename from the p3d_info.xml file.
|
||||||
@ -809,6 +844,7 @@ start_p3dpython(P3DInstance *inst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool console_output = (inst->get_fparams().lookup_token_int("console_output") != 0);
|
bool console_output = (inst->get_fparams().lookup_token_int("console_output") != 0);
|
||||||
|
bool one_process = (inst->get_fparams().lookup_token_int("one_process") != 0);
|
||||||
|
|
||||||
#ifdef P3D_PLUGIN_LOG_BASENAME3
|
#ifdef P3D_PLUGIN_LOG_BASENAME3
|
||||||
if (log_basename.empty()) {
|
if (log_basename.empty()) {
|
||||||
@ -840,24 +876,82 @@ start_p3dpython(P3DInstance *inst) {
|
|||||||
_log_pathname += ".log";
|
_log_pathname += ".log";
|
||||||
}
|
}
|
||||||
|
|
||||||
string archive_file = inst->_panda3d->get_archive_file_pathname();
|
// Create the pipes for communication.
|
||||||
|
|
||||||
nout << "Attempting to start python from " << p3dpython << "\n";
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
_p3dpython_handle = win_create_process
|
// Create a bi-directional pipe to communicate with the sub-process.
|
||||||
(p3dpython, archive_file, start_dir, env, _log_pathname,
|
HANDLE r_to, w_to, r_from, w_from;
|
||||||
_pipe_read, _pipe_write);
|
|
||||||
bool started_p3dpython = (_p3dpython_handle != INVALID_HANDLE_VALUE);
|
// Create the pipe to the process.
|
||||||
|
if (!CreatePipe(&r_to, &w_to, NULL, 0)) {
|
||||||
|
nout << "failed to create pipe\n";
|
||||||
|
} else {
|
||||||
|
// Make sure the right end of the pipe is inheritable.
|
||||||
|
SetHandleInformation(r_to, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||||
|
SetHandleInformation(w_to, HANDLE_FLAG_INHERIT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the pipe from the process.
|
||||||
|
if (!CreatePipe(&r_from, &w_from, NULL, 0)) {
|
||||||
|
nout << "failed to create pipe\n";
|
||||||
|
} else {
|
||||||
|
// Make sure the right end of the pipe is inheritable.
|
||||||
|
SetHandleInformation(w_from, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||||
|
SetHandleInformation(r_from, HANDLE_FLAG_INHERIT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_output = w_from;
|
||||||
|
_input = r_to;
|
||||||
|
_pipe_read.open_read(r_from);
|
||||||
|
_pipe_write.open_write(w_to);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
_p3dpython_pid = posix_create_process
|
// Create a bi-directional pipe to communicate with the sub-process.
|
||||||
(p3dpython, archive_file, start_dir, env, _log_pathname,
|
int to_fd[2];
|
||||||
_pipe_read, _pipe_write);
|
if (pipe(to_fd) < 0) {
|
||||||
bool started_p3dpython = (_p3dpython_pid > 0);
|
perror("failed to create pipe");
|
||||||
|
}
|
||||||
|
int from_fd[2];
|
||||||
|
if (pipe(from_fd) < 0) {
|
||||||
|
perror("failed to create pipe");
|
||||||
|
}
|
||||||
|
|
||||||
|
_input = to_fd[0];
|
||||||
|
_output = from_fd[1];
|
||||||
|
_pipe_read.open_read(from_fd[0]);
|
||||||
|
_pipe_write.open_write(to_fd[1]);
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
// Get the filename to the Panda3D multifile. We need to pass this
|
||||||
|
// to p3dpython.
|
||||||
|
_mf_filename = inst->_panda3d->get_archive_file_pathname();
|
||||||
|
|
||||||
|
bool started_p3dpython;
|
||||||
|
if (one_process) {
|
||||||
|
nout << "one_process is set; running Python within parent process.\n";
|
||||||
|
started_p3dpython = false;
|
||||||
|
} else {
|
||||||
|
nout << "Attempting to start python from " << _p3dpython_exe
|
||||||
|
<< " and " << _p3dpython_dll << "\n";
|
||||||
|
#ifdef _WIN32
|
||||||
|
_p3dpython_handle = win_create_process();
|
||||||
|
started_p3dpython = (_p3dpython_handle != INVALID_HANDLE_VALUE);
|
||||||
|
#else
|
||||||
|
_p3dpython_pid = posix_create_process();
|
||||||
|
started_p3dpython = (_p3dpython_pid > 0);
|
||||||
#endif
|
#endif
|
||||||
|
if (!started_p3dpython) {
|
||||||
|
nout << "Failed to create process.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!started_p3dpython) {
|
if (!started_p3dpython) {
|
||||||
nout << "Failed to create process.\n";
|
// Well, we couldn't run python in a sub-process, for some reason.
|
||||||
return;
|
// Fall back to running it in a sub-thread within the same
|
||||||
|
// process. This isn't nearly as good, but I guess it's better
|
||||||
|
// than nothing.
|
||||||
|
INIT_THREAD(_p3dpython_thread);
|
||||||
|
SPAWN_THREAD(_p3dpython_thread, p3dpython_thread_run, this);
|
||||||
|
_p3dpython_one_process = true;
|
||||||
}
|
}
|
||||||
_p3dpython_started = true;
|
_p3dpython_started = true;
|
||||||
_p3dpython_running = true;
|
_p3dpython_running = true;
|
||||||
@ -1019,60 +1113,37 @@ rt_terminate() {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DSession::win_create_process
|
// Function: P3DSession::win_create_process
|
||||||
// Access: Private, Static
|
// Access: Private
|
||||||
// Description: Creates a sub-process to run the named program
|
// Description: Creates a sub-process to run _p3dpython_exe, with
|
||||||
// executable, with the indicated environment string.
|
// the appropriate command-line arguments, and the
|
||||||
// Standard error is logged to log_pathname, if that
|
// environment string defined in _env. Standard error
|
||||||
// string is nonempty.
|
// is logged to _log_pathname, if that string is
|
||||||
|
// nonempty.
|
||||||
//
|
//
|
||||||
// Opens the two HandleStreams as the read and write
|
// Opens the two HandleStreams _pipe_read and
|
||||||
// pipes to the child process's standard output and
|
// _pipe_write as the read and write pipes to the child
|
||||||
// standard input, respectively.
|
// process's standard output and standard input,
|
||||||
|
// respectively.
|
||||||
//
|
//
|
||||||
// Returns the handle to the created process on success,
|
// Returns the handle to the created process on success,
|
||||||
// or INVALID_HANDLE_VALUE on falure.
|
// or INVALID_HANDLE_VALUE on falure.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
HANDLE P3DSession::
|
HANDLE P3DSession::
|
||||||
win_create_process(const string &program, const string &archive_file,
|
win_create_process() {
|
||||||
const string &start_dir,
|
|
||||||
const string &env, const string &log_pathname,
|
|
||||||
HandleStream &pipe_read, HandleStream &pipe_write) {
|
|
||||||
|
|
||||||
// Create a bi-directional pipe to communicate with the sub-process.
|
|
||||||
HANDLE r_to, w_to, r_from, w_from;
|
|
||||||
|
|
||||||
// Create the pipe to the process.
|
|
||||||
if (!CreatePipe(&r_to, &w_to, NULL, 0)) {
|
|
||||||
nout << "failed to create pipe\n";
|
|
||||||
} else {
|
|
||||||
// Make sure the right end of the pipe is inheritable.
|
|
||||||
SetHandleInformation(r_to, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
|
||||||
SetHandleInformation(w_to, HANDLE_FLAG_INHERIT, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the pipe from the process.
|
|
||||||
if (!CreatePipe(&r_from, &w_from, NULL, 0)) {
|
|
||||||
nout << "failed to create pipe\n";
|
|
||||||
} else {
|
|
||||||
// Make sure the right end of the pipe is inheritable.
|
|
||||||
SetHandleInformation(w_from, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
|
||||||
SetHandleInformation(r_from, HANDLE_FLAG_INHERIT, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
HANDLE error_handle = GetStdHandle(STD_ERROR_HANDLE);
|
HANDLE error_handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
bool got_log_pathname = !log_pathname.empty();
|
bool got_log_pathname = !_log_pathname.empty();
|
||||||
if (got_log_pathname) {
|
if (got_log_pathname) {
|
||||||
// Open the named file for output and redirect the child's stderr
|
// Open the named file for output and redirect the child's stderr
|
||||||
// into it.
|
// into it.
|
||||||
HANDLE handle = CreateFile
|
HANDLE handle = CreateFile
|
||||||
(log_pathname.c_str(), GENERIC_WRITE,
|
(_log_pathname.c_str(), GENERIC_WRITE,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
NULL, CREATE_ALWAYS, 0, NULL);
|
NULL, CREATE_ALWAYS, 0, NULL);
|
||||||
if (handle != INVALID_HANDLE_VALUE) {
|
if (handle != INVALID_HANDLE_VALUE) {
|
||||||
error_handle = handle;
|
error_handle = handle;
|
||||||
SetHandleInformation(error_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
SetHandleInformation(error_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
|
||||||
} else {
|
} else {
|
||||||
nout << "Unable to open " << log_pathname << "\n";
|
nout << "Unable to open " << _log_pathname << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1085,8 +1156,8 @@ win_create_process(const string &program, const string &archive_file,
|
|||||||
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
|
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
|
||||||
startup_info.cb = sizeof(startup_info);
|
startup_info.cb = sizeof(startup_info);
|
||||||
startup_info.hStdError = error_handle;
|
startup_info.hStdError = error_handle;
|
||||||
startup_info.hStdOutput = w_from;
|
startup_info.hStdOutput = _output;
|
||||||
startup_info.hStdInput = r_to;
|
startup_info.hStdInput = _input;
|
||||||
startup_info.dwFlags |= STARTF_USESTDHANDLES;
|
startup_info.dwFlags |= STARTF_USESTDHANDLES;
|
||||||
|
|
||||||
// Make sure the "python" console window is hidden.
|
// Make sure the "python" console window is hidden.
|
||||||
@ -1096,15 +1167,18 @@ win_create_process(const string &program, const string &archive_file,
|
|||||||
// If the start directory is empty, meaning not to change the
|
// If the start directory is empty, meaning not to change the
|
||||||
// current directory, then pass NULL in to CreateProcess().
|
// current directory, then pass NULL in to CreateProcess().
|
||||||
const char *start_dir_cstr = NULL;
|
const char *start_dir_cstr = NULL;
|
||||||
if (!start_dir.empty()) {
|
if (_use_start_dir) {
|
||||||
start_dir_cstr = start_dir.c_str();
|
start_dir_cstr = _start_dir.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Construct the command-line string, containing the quoted
|
||||||
|
// command-line arguments.
|
||||||
ostringstream stream;
|
ostringstream stream;
|
||||||
stream << "\"" << program << "\" \"" << archive_file << "\"";
|
stream << "\"" << _p3dpython_exe << "\" \"" << _p3dpython_dll
|
||||||
|
<< "\" \"" << _mf_filename << "\"";
|
||||||
|
|
||||||
// I'm not sure why CreateProcess wants a non-const char pointer for
|
// I'm not sure why CreateProcess wants a non-const char pointer for
|
||||||
// the command-line argument, but I'm not taking chances. It gets a
|
// its command-line string, but I'm not taking chances. It gets a
|
||||||
// non-const char array that it can modify.
|
// non-const char array that it can modify.
|
||||||
string command_line_str = stream.str();
|
string command_line_str = stream.str();
|
||||||
char *command_line = new char[command_line_str.size() + 1];
|
char *command_line = new char[command_line_str.size() + 1];
|
||||||
@ -1112,29 +1186,26 @@ win_create_process(const string &program, const string &archive_file,
|
|||||||
|
|
||||||
PROCESS_INFORMATION process_info;
|
PROCESS_INFORMATION process_info;
|
||||||
BOOL result = CreateProcess
|
BOOL result = CreateProcess
|
||||||
(program.c_str(), command_line, NULL, NULL, TRUE, 0,
|
(_p3dpython_exe.c_str(), command_line, NULL, NULL, TRUE, 0,
|
||||||
(void *)env.c_str(), start_dir_cstr,
|
(void *)_env.c_str(), _start_dir_cstr,
|
||||||
&startup_info, &process_info);
|
&startup_info, &process_info);
|
||||||
bool started_program = (result != 0);
|
bool started_program = (result != 0);
|
||||||
|
|
||||||
delete[] command_line;
|
delete[] command_line;
|
||||||
|
|
||||||
// Close the pipe handles that are now owned by the child.
|
// Close the pipe handles that are now owned by the child.
|
||||||
CloseHandle(w_from);
|
CloseHandle(_output);
|
||||||
CloseHandle(r_to);
|
CloseHandle(_input);
|
||||||
if (got_log_pathname) {
|
if (got_log_pathname) {
|
||||||
CloseHandle(error_handle);
|
CloseHandle(error_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!started_program) {
|
if (!started_program) {
|
||||||
CloseHandle(r_from);
|
_pipe_read.close();
|
||||||
CloseHandle(w_to);
|
_pipe_write.close();
|
||||||
return INVALID_HANDLE_VALUE;
|
return INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipe_read.open_read(r_from);
|
|
||||||
pipe_write.open_write(w_to);
|
|
||||||
|
|
||||||
CloseHandle(process_info.hThread);
|
CloseHandle(process_info.hThread);
|
||||||
return process_info.hProcess;
|
return process_info.hProcess;
|
||||||
}
|
}
|
||||||
@ -1144,54 +1215,40 @@ win_create_process(const string &program, const string &archive_file,
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DSession::posix_create_process
|
// Function: P3DSession::posix_create_process
|
||||||
// Access: Private, Static
|
// Access: Private
|
||||||
// Description: Creates a sub-process to run the named program
|
// Description: Creates a sub-process to run _p3dpython_exe, with
|
||||||
// executable, with the indicated environment string.
|
// the appropriate command-line arguments, and the
|
||||||
|
// environment string defined in _env. Standard error
|
||||||
|
// is logged to _log_pathname, if that string is
|
||||||
|
// nonempty.
|
||||||
//
|
//
|
||||||
// Opens the two HandleStreams as the read and write
|
// Opens the two HandleStreams _pipe_read and
|
||||||
// pipes to the child process's standard output and
|
// _pipe_write as the read and write pipes to the child
|
||||||
// standard input, respectively. Returns true on
|
// process's standard output and standard input,
|
||||||
// success, false on failure.
|
// respectively.
|
||||||
//
|
//
|
||||||
// Returns the pid of the created process on success, or
|
// Returns the handle to the created process on success,
|
||||||
// -1 on falure.
|
// or INVALID_HANDLE_VALUE on falure.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int P3DSession::
|
int P3DSession::
|
||||||
posix_create_process(const string &program, const string &archive_file,
|
posix_create_process() {
|
||||||
const string &start_dir,
|
|
||||||
const string &env, const string &log_pathname,
|
|
||||||
HandleStream &pipe_read, HandleStream &pipe_write) {
|
|
||||||
// Create a bi-directional pipe to communicate with the sub-process.
|
|
||||||
int to_fd[2];
|
|
||||||
if (pipe(to_fd) < 0) {
|
|
||||||
perror("failed to create pipe");
|
|
||||||
}
|
|
||||||
int from_fd[2];
|
|
||||||
if (pipe(from_fd) < 0) {
|
|
||||||
perror("failed to create pipe");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fork and exec.
|
// Fork and exec.
|
||||||
pid_t child = fork();
|
pid_t child = fork();
|
||||||
if (child < 0) {
|
if (child < 0) {
|
||||||
close(to_fd[0]);
|
|
||||||
close(to_fd[1]);
|
|
||||||
close(from_fd[0]);
|
|
||||||
close(from_fd[1]);
|
|
||||||
perror("fork");
|
perror("fork");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child == 0) {
|
if (child == 0) {
|
||||||
// Here we are in the child process.
|
// Here we are in the child process.
|
||||||
bool got_log_pathname = !log_pathname.empty();
|
bool got_log_pathname = !_log_pathname.empty();
|
||||||
if (got_log_pathname) {
|
if (got_log_pathname) {
|
||||||
// Open the named file for output and redirect the child's stderr
|
// Open the named file for output and redirect the child's stderr
|
||||||
// into it.
|
// into it.
|
||||||
int logfile_fd = open(log_pathname.c_str(),
|
int logfile_fd = open(_log_pathname.c_str(),
|
||||||
O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||||
if (logfile_fd < 0) {
|
if (logfile_fd < 0) {
|
||||||
nout << "Unable to open " << log_pathname << "\n";
|
nout << "Unable to open " << _log_pathname << "\n";
|
||||||
} else {
|
} else {
|
||||||
dup2(logfile_fd, STDERR_FILENO);
|
dup2(logfile_fd, STDERR_FILENO);
|
||||||
close(logfile_fd);
|
close(logfile_fd);
|
||||||
@ -1200,41 +1257,108 @@ posix_create_process(const string &program, const string &archive_file,
|
|||||||
|
|
||||||
// Set the appropriate ends of the bi-directional pipe as the
|
// Set the appropriate ends of the bi-directional pipe as the
|
||||||
// standard input and standard output of the child process.
|
// standard input and standard output of the child process.
|
||||||
dup2(to_fd[0], STDIN_FILENO);
|
dup2(_input, STDIN_FILENO);
|
||||||
dup2(from_fd[1], STDOUT_FILENO);
|
dup2(_output, STDOUT_FILENO);
|
||||||
close(to_fd[1]);
|
_pipe_read.close();
|
||||||
close(from_fd[0]);
|
_pipe_write.close();
|
||||||
|
|
||||||
if (!start_dir.empty()) {
|
if (_use_start_dir) {
|
||||||
if (chdir(start_dir.c_str()) < 0) {
|
if (chdir(_start_dir.c_str()) < 0) {
|
||||||
nout << "Could not chdir to " << start_dir << "\n";
|
nout << "Could not chdir to " << _start_dir << "\n";
|
||||||
_exit(1);
|
// This is a warning, not an error. We don't actually care
|
||||||
|
// that much about the starting directory.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// build up an array of char strings for the environment.
|
// build up an array of char strings for the environment.
|
||||||
vector<const char *> ptrs;
|
vector<const char *> ptrs;
|
||||||
size_t p = 0;
|
size_t p = 0;
|
||||||
size_t zero = env.find('\0', p);
|
size_t zero = _env.find('\0', p);
|
||||||
while (zero != string::npos) {
|
while (zero != string::npos) {
|
||||||
ptrs.push_back(env.data() + p);
|
ptrs.push_back(_env.data() + p);
|
||||||
p = zero + 1;
|
p = zero + 1;
|
||||||
zero = env.find('\0', p);
|
zero = _env.find('\0', p);
|
||||||
}
|
}
|
||||||
ptrs.push_back((char *)NULL);
|
ptrs.push_back((char *)NULL);
|
||||||
|
|
||||||
execle(program.c_str(),
|
execle(_p3dpython_exe.c_str(),
|
||||||
program.c_str(), archive_file.c_str(), (char *)0,
|
_p3dpython_exe.c_str(), _p3dpython_dll.c_str(), _mf_filename.c_str(), (char *)0,
|
||||||
&ptrs[0]);
|
&ptrs[0]);
|
||||||
nout << "Failed to exec " << program << "\n";
|
nout << "Failed to exec " << _p3dpython_exe << "\n";
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pipe_read.open_read(from_fd[0]);
|
close(_input);
|
||||||
pipe_write.open_write(to_fd[1]);
|
close(_output);
|
||||||
close(to_fd[0]);
|
|
||||||
close(from_fd[1]);
|
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DSession::p3dpython_thread_run
|
||||||
|
// Access: Private
|
||||||
|
// Description: This method is called in a sub-thread to fire up
|
||||||
|
// p3dpython within this same process, but only if the
|
||||||
|
// above attempt to create a sub-process failed.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DSession::
|
||||||
|
p3dpython_thread_run() {
|
||||||
|
nout << "running p3dpython_thread_run()\n";
|
||||||
|
|
||||||
|
// Set the environment. Hopefully this won't be too destructive to
|
||||||
|
// the current process, and hopefully these changes will be read
|
||||||
|
// properly by Python.
|
||||||
|
size_t p = 0;
|
||||||
|
size_t zero = _env.find('\0', p);
|
||||||
|
while (zero != string::npos) {
|
||||||
|
const char *start = _env.data() + p;
|
||||||
|
const char *equals = strchr(start, '=');
|
||||||
|
if (equals != NULL) {
|
||||||
|
string variable(start, equals - start);
|
||||||
|
#ifdef _WIN32
|
||||||
|
_putenv_s(variable.c_str(), equals + 1);
|
||||||
|
#else
|
||||||
|
setenv(variable.c_str(), equals + 1, true);
|
||||||
|
#endif // _WIN32
|
||||||
|
}
|
||||||
|
p = zero + 1;
|
||||||
|
zero = _env.find('\0', p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now load the library.
|
||||||
|
#ifdef _WIN32
|
||||||
|
SetErrorMode(0);
|
||||||
|
HMODULE module = LoadLibrary(_p3dpython_dll.c_str());
|
||||||
|
if (module == NULL) {
|
||||||
|
// Couldn't load the DLL.
|
||||||
|
nout << "Couldn't load " << _p3dpython_dll << "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define get_func GetProcAddress
|
||||||
|
|
||||||
|
#else // _WIN32
|
||||||
|
// Posix case.
|
||||||
|
void *module = dlopen(_p3dpython_dll.c_str(), RTLD_GLOBAL);
|
||||||
|
if (module == NULL) {
|
||||||
|
// Couldn't load the .so.
|
||||||
|
nout << "Couldn't load " << _p3dpython_dll << "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define get_func dlsym
|
||||||
|
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
run_p3dpython_func *run_p3dpython = (run_p3dpython_func *)get_func(module, "run_p3dpython");
|
||||||
|
if (run_p3dpython == NULL) {
|
||||||
|
nout << "Couldn't find run_p3dpython\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!run_p3dpython(_p3dpython_dll.c_str(), _mf_filename.c_str(),
|
||||||
|
_input, _output)) {
|
||||||
|
nout << "Failure on startup.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -75,19 +75,16 @@ private:
|
|||||||
void rt_handle_request(TiXmlDocument *doc);
|
void rt_handle_request(TiXmlDocument *doc);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
static HANDLE
|
HANDLE win_create_process();
|
||||||
win_create_process(const string &program, const string &archive_file,
|
|
||||||
const string &start_dir,
|
|
||||||
const string &env, const string &output_filename,
|
|
||||||
HandleStream &pipe_read, HandleStream &pipe_write);
|
|
||||||
#else
|
#else
|
||||||
static int
|
int posix_create_process();
|
||||||
posix_create_process(const string &program, const string &archive_file,
|
|
||||||
const string &start_dir,
|
|
||||||
const string &env, const string &output_filename,
|
|
||||||
HandleStream &pipe_read, HandleStream &pipe_write);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// In case we can't get a separate process, we'll run p3dpython in a
|
||||||
|
// sub-thread.
|
||||||
|
THREAD_CALLBACK_DECLARATION(P3DSession, p3dpython_thread_run);
|
||||||
|
void p3dpython_thread_run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _session_id;
|
int _session_id;
|
||||||
string _session_key;
|
string _session_key;
|
||||||
@ -95,6 +92,15 @@ private:
|
|||||||
string _log_pathname;
|
string _log_pathname;
|
||||||
string _python_root_dir;
|
string _python_root_dir;
|
||||||
string _start_dir;
|
string _start_dir;
|
||||||
|
bool _use_start_dir;
|
||||||
|
|
||||||
|
// This information is passed to create_process(), or to
|
||||||
|
// p3dpython_thread_run().
|
||||||
|
string _p3dpython_exe;
|
||||||
|
string _p3dpython_dll;
|
||||||
|
string _mf_filename;
|
||||||
|
string _env;
|
||||||
|
FHandle _input, _output;
|
||||||
|
|
||||||
typedef map<int, P3DInstance *> Instances;
|
typedef map<int, P3DInstance *> Instances;
|
||||||
Instances _instances;
|
Instances _instances;
|
||||||
@ -114,12 +120,21 @@ private:
|
|||||||
|
|
||||||
P3DPackage *_panda3d;
|
P3DPackage *_panda3d;
|
||||||
|
|
||||||
// Members for communicating with the p3dpython child process.
|
// If this is true, then CreateProcess() or fork() failed (or we had
|
||||||
|
// one_process set true in the tokens), and we're forced to run
|
||||||
|
// p3dpython in a sub-thread within the same process, rather than in
|
||||||
|
// a separate process. This means we can't have multiple sessions
|
||||||
|
// running simultaneously, because Python don't play that way.
|
||||||
|
bool _p3dpython_one_process;
|
||||||
|
|
||||||
|
// Members for communicating with the p3dpython child process (or
|
||||||
|
// thread, as the case may be).
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE _p3dpython_handle;
|
HANDLE _p3dpython_handle;
|
||||||
#else
|
#else
|
||||||
int _p3dpython_pid;
|
int _p3dpython_pid;
|
||||||
#endif
|
#endif
|
||||||
|
THREAD _p3dpython_thread;
|
||||||
bool _p3dpython_started;
|
bool _p3dpython_started;
|
||||||
bool _p3dpython_running;
|
bool _p3dpython_running;
|
||||||
|
|
||||||
|
37
direct/src/plugin/run_p3dpython.h
Normal file
37
direct/src/plugin/run_p3dpython.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Filename: run_p3dpython.h
|
||||||
|
// Created by: drose (29Aug09)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// PANDA 3D SOFTWARE
|
||||||
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||||
|
//
|
||||||
|
// All use of this software is subject to the terms of the revised BSD
|
||||||
|
// license. You should have received a copy of this license along
|
||||||
|
// with this source code in a file named "LICENSE."
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef RUN_P3DPYTHON_H
|
||||||
|
#define RUN_P3DPYTHON_H
|
||||||
|
|
||||||
|
// This header file defines the prototype for run_p3dpython(), the
|
||||||
|
// main entry point to this DLL.
|
||||||
|
|
||||||
|
#include "fhandle.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define EXPCL_P3DPYTHON __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define EXPCL_P3DPYTHON
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef bool run_p3dpython_func(const char *program_name, const char *archive_file,
|
||||||
|
FHandle input, FHandle output);
|
||||||
|
|
||||||
|
EXPCL_P3DPYTHON extern "C" bool
|
||||||
|
run_p3dpython(const char *program_name, const char *archive_file,
|
||||||
|
FHandle input, FHandle output);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -12,7 +12,7 @@
|
|||||||
prc:c dtoolutil:c dtoolbase:c dtool:m \
|
prc:c dtoolutil:c dtoolbase:c dtool:m \
|
||||||
interrogatedb:c dconfig:c dtoolconfig:m \
|
interrogatedb:c dconfig:c dtoolconfig:m \
|
||||||
express:c downloader:c pandaexpress:m \
|
express:c downloader:c pandaexpress:m \
|
||||||
pystub
|
$[if $[WINDOWS_PLATFORM],pystub,]
|
||||||
|
|
||||||
#define OSX_SYS_FRAMEWORKS Foundation AppKit Carbon
|
#define OSX_SYS_FRAMEWORKS Foundation AppKit Carbon
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user