This commit is contained in:
David Rose 2009-06-12 16:14:20 +00:00
parent 0e24827b9d
commit 704d7686f3
5 changed files with 286 additions and 96 deletions

View File

@ -52,7 +52,11 @@ P3DPythonRun(int argc, char *argv[]) {
_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) {
cerr << "unable to open read pipe\n";
}
@ -233,7 +237,7 @@ spawn_read_thread() {
_read_thread_continue = true;
#ifdef _WIN32
_read_thread = CreateThread(NULL, 0, &win_rt_thread_run, this, 0, NULL);
_read_thread = CreateThread(NULL, 0, &rt_thread_run, this, 0, NULL);
#else
pthread_attr_t attr;
pthread_attr_init(&attr);
@ -406,7 +410,7 @@ rt_thread_run() {
#ifdef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DPython::win_rt_thread_run
// Function: P3DPythonRun::win_rt_thread_run
// Access: Private, Static
// Description: The Windows flavor of the thread callback function.
////////////////////////////////////////////////////////////////////
@ -419,7 +423,7 @@ win_rt_thread_run(LPVOID data) {
#ifndef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DPython::win_rt_thread_run
// Function: P3DPythonRun::posix_rt_thread_run
// Access: Private, Static
// Description: The Posix flavor of the thread callback function.
////////////////////////////////////////////////////////////////////

View File

@ -114,7 +114,7 @@ private:
#ifdef _WIN32
HANDLE _read_thread;
#else
pthread_t _thread;
pthread_t _read_thread;
#endif
};

View File

@ -16,6 +16,10 @@
#include "p3dInstance.h"
#include "p3dInstanceManager.h"
#ifndef _WIN32
#include <fcntl.h>
#endif
////////////////////////////////////////////////////////////////////
// Function: P3DSession::Constructor
// Access: Public
@ -29,7 +33,12 @@ P3DSession::
P3DSession(P3DInstance *inst) {
_session_key = inst->get_session_key();
_python_version = inst->get_python_version();
#ifdef _WIN32
_python_root_dir = "C:/p3drun";
#else
_python_root_dir = "/Users/drose/p3drun";
#endif
_python_state = PS_init;
_started_read_thread = false;
@ -188,6 +197,7 @@ send_command(TiXmlDocument *command) {
////////////////////////////////////////////////////////////////////
void P3DSession::
download_p3dpython(P3DInstance *inst) {
/*
P3DFileDownload *download = new P3DFileDownload();
download->set_url("http://fewmet/~drose/p3drun.tgz");
@ -198,8 +208,9 @@ download_p3dpython(P3DInstance *inst) {
}
inst->start_download(download);
*/
// start_p3dpython();
start_p3dpython();
}
////////////////////////////////////////////////////////////////////
@ -209,8 +220,12 @@ download_p3dpython(P3DInstance *inst) {
////////////////////////////////////////////////////////////////////
void P3DSession::
start_p3dpython() {
#ifdef _WIN32
string p3dpython = "c:/cygwin/home/drose/player/direct/built/bin/p3dpython.exe";
// string p3dpython = _python_root_dir + "/p3dpython.exe";
#else
string p3dpython = "/Users/drose/player/direct/built/bin/p3dpython";
#endif
// Populate the new process' environment.
string env;
@ -243,78 +258,9 @@ start_p3dpython() {
env += _python_root_dir;
env += '\0';
// Create a bi-directional pipe to communicate with the sub-process.
#ifdef _WIN32
HANDLE r_to, w_to, r_from, w_from;
// Create the pipe to the process.
if (!CreatePipe(&r_to, &w_to, NULL, 0)) {
cerr << "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)) {
cerr << "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);
bool got_output_filename = !_output_filename.empty();
if (got_output_filename) {
// Open the named file for output and redirect the child's stderr
// into it.
HANDLE handle = CreateFile
(_output_filename.c_str(), GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, CREATE_ALWAYS, 0, NULL);
if (handle != INVALID_HANDLE_VALUE) {
error_handle = handle;
SetHandleInformation(error_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
} else {
cerr << "Unable to open " << _output_filename << "\n";
}
}
// Make sure we see an error dialog if there is a missing DLL.
SetErrorMode(0);
// Pass the appropriate ends of the bi-directional pipe as the
// standard input and standard output of the child process.
STARTUPINFO startup_info;
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(startup_info);
startup_info.hStdError = error_handle;
startup_info.hStdOutput = w_from;
startup_info.hStdInput = r_to;
startup_info.dwFlags |= STARTF_USESTDHANDLES;
// Make sure the "python" console window is hidden.
startup_info.wShowWindow = SW_HIDE;
startup_info.dwFlags |= STARTF_USESHOWWINDOW;
BOOL result = CreateProcess
(p3dpython.c_str(), NULL, NULL, NULL, TRUE, 0,
(void *)env.c_str(), _python_root_dir.c_str(),
&startup_info, &_p3dpython);
bool started_p3dpython = (result != 0);
// Close the pipe handles that are now owned by the child.
CloseHandle(w_from);
CloseHandle(r_to);
if (got_output_filename) {
CloseHandle(error_handle);
}
_pipe_read.open_read(r_from);
_pipe_write.open_write(w_to);
#endif // _WIN32
bool started_p3dpython = create_process
(p3dpython, _python_root_dir, env, _output_filename,
_pipe_read, _pipe_write);
if (!started_p3dpython) {
cerr << "Failed to create process.\n";
@ -322,7 +268,7 @@ start_p3dpython() {
}
_python_state = PS_running;
cerr << "Created process: " << _p3dpython.dwProcessId << "\n";
cerr << "Created child process\n";
if (!_pipe_read) {
cerr << "unable to open read pipe\n";
@ -364,6 +310,12 @@ spawn_read_thread() {
_read_thread_continue = true;
#ifdef _WIN32
_read_thread = CreateThread(NULL, 0, &win_rt_thread_run, this, 0, NULL);
#else
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_create(&_read_thread, &attr, &posix_rt_thread_run, (void *)this);
pthread_attr_destroy(&attr);
#endif
_started_read_thread = true;
}
@ -388,6 +340,9 @@ join_read_thread() {
WaitForSingleObject(_read_thread, INFINITE);
CloseHandle(_read_thread);
_read_thread = NULL;
#else
void *return_val;
pthread_join(_read_thread, &return_val);
#endif
cerr << "session done waiting for thread\n";
@ -448,7 +403,7 @@ rt_terminate() {
#ifdef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DPython::win_rt_thread_run
// Function: P3DSession::win_rt_thread_run
// Access: Private, Static
// Description: The Windows flavor of the thread callback function.
////////////////////////////////////////////////////////////////////
@ -458,3 +413,201 @@ win_rt_thread_run(LPVOID data) {
return 0;
}
#endif
#ifndef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DSession::posix_rt_thread_run
// Access: Private, Static
// Description: The Posix flavor of the thread callback function.
////////////////////////////////////////////////////////////////////
void *P3DSession::
posix_rt_thread_run(void *data) {
((P3DSession *)data)->rt_thread_run();
return NULL;
}
#endif
#ifdef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DSession::create_process
// Access: Private, Static
// Description: Creates a sub-process to run the named program
// executable, with the indicated environment string.
// Standard error is logged to output_filename, if that
// string is nonempty.
//
// Opens the two HandleStreams as the read and write
// pipes to the child process's standard output and
// standard input, respectively. Returns true on
// success, false on failure.
////////////////////////////////////////////////////////////////////
bool P3DSession::
create_process(const string &program, const string &start_dir,
const string &env, const string &output_filename,
HandleStream &pipe_read, HandleStream &pipe_write) {
// This is the Windows variant.
// 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)) {
cerr << "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)) {
cerr << "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);
bool got_output_filename = !output_filename.empty();
if (got_output_filename) {
// Open the named file for output and redirect the child's stderr
// into it.
HANDLE handle = CreateFile
(output_filename.c_str(), GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, CREATE_ALWAYS, 0, NULL);
if (handle != INVALID_HANDLE_VALUE) {
error_handle = handle;
SetHandleInformation(error_handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
} else {
cerr << "Unable to open " << output_filename << "\n";
}
}
// Make sure we see an error dialog if there is a missing DLL.
SetErrorMode(0);
// Pass the appropriate ends of the bi-directional pipe as the
// standard input and standard output of the child process.
STARTUPINFO startup_info;
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(startup_info);
startup_info.hStdError = error_handle;
startup_info.hStdOutput = w_from;
startup_info.hStdInput = r_to;
startup_info.dwFlags |= STARTF_USESTDHANDLES;
// Make sure the "python" console window is hidden.
startup_info.wShowWindow = SW_HIDE;
startup_info.dwFlags |= STARTF_USESHOWWINDOW;
BOOL result = CreateProcess
(program.c_str(), NULL, NULL, NULL, TRUE, 0,
(void *)env.c_str(), start_dir.c_str(),
&startup_info, &_program);
bool started_program = (result != 0);
// Close the pipe handles that are now owned by the child.
CloseHandle(w_from);
CloseHandle(r_to);
if (got_output_filename) {
CloseHandle(error_handle);
}
pipe_read.open_read(r_from);
pipe_write.open_write(w_to);
return started_program;
}
#endif // _WIN32
#ifndef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DSession::create_process
// Access: Private, Static
// Description: Creates a sub-process to run the named program
// executable, with the indicated environment string.
//
// Opens the two HandleStreams as the read and write
// pipes to the child process's standard output and
// standard input, respectively. Returns true on
// success, false on failure.
////////////////////////////////////////////////////////////////////
bool P3DSession::
create_process(const string &program, const string &start_dir,
const string &env, const string &output_filename,
HandleStream &pipe_read, HandleStream &pipe_write) {
// This is the Posix variant.
// 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.
pid_t child = fork();
if (child < 0) {
perror("fork");
return false;
}
if (child == 0) {
// Here we are in the child process.
bool got_output_filename = !output_filename.empty();
if (got_output_filename) {
// Open the named file for output and redirect the child's stderr
// into it.
int logfile_fd = open(output_filename.c_str(),
O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (logfile_fd < 0) {
cerr << "Unable to open " << output_filename << "\n";
} else {
dup2(logfile_fd, STDERR_FILENO);
close(logfile_fd);
}
}
// Set the appropriate ends of the bi-directional pipe as the
// standard input and standard output of the child process.
dup2(to_fd[0], STDIN_FILENO);
dup2(from_fd[1], STDOUT_FILENO);
close(to_fd[1]);
close(from_fd[0]);
if (chdir(start_dir.c_str()) < 0) {
cerr << "Could not chdir to " << start_dir << "\n";
_exit(1);
}
// build up an array of char strings for the environment.
vector<const char *> ptrs;
size_t p = 0;
size_t zero = env.find('\0', p);
while (zero != string::npos) {
ptrs.push_back(env.data() + p);
p = zero + 1;
zero = env.find('\0', p);
}
ptrs.push_back((char *)NULL);
execle(program.c_str(), program.c_str(), (char *)0, &ptrs[0]);
cerr << "Failed to exec " << program << "\n";
_exit(1);
}
pipe_read.open_read(from_fd[0]);
pipe_write.open_write(to_fd[1]);
close(to_fd[0]);
close(from_fd[1]);
return true;
}
#endif // _WIN32

View File

@ -59,6 +59,20 @@ private:
#ifdef _WIN32
static DWORD WINAPI win_rt_thread_run(LPVOID data);
#else
static void *posix_rt_thread_run(void *data);
#endif
#ifdef _WIN32
static bool
create_process(const string &program, const string &start_dir,
const string &env, const string &output_filename,
HandleStream &pipe_read, HandleStream &pipe_write);
#else
static bool
create_process(const string &program, const string &start_dir,
const string &env, const string &output_filename,
HandleStream &pipe_read, HandleStream &pipe_write);
#endif
private:
@ -99,6 +113,8 @@ private:
bool _read_thread_continue;
#ifdef _WIN32
HANDLE _read_thread;
#else
pthread_t _read_thread;
#endif
};

View File

@ -24,6 +24,8 @@
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include "httpClient.h"
@ -41,6 +43,14 @@
#endif
#endif
#ifdef _WIN32
static const string dll_ext = ".dll";
#elif defined(__APPLE__)
static const string dll_ext = ".dylib";
#else
static const string dll_ext = ".so";
#endif
static const string default_plugin_filename = "libp3d_plugin";
P3D_initialize_func *P3D_initialize;
@ -148,12 +158,7 @@ load_plugin(const string &p3d_plugin_filename) {
string filename = p3d_plugin_filename;
if (filename.empty()) {
// Look for the plugin along the path.
filename = default_plugin_filename;
#ifdef _WIN32
filename += ".dll";
#else
filename += ".so";
#endif
filename = default_plugin_filename + dll_ext;
}
#ifdef _WIN32
@ -163,16 +168,6 @@ load_plugin(const string &p3d_plugin_filename) {
return false;
}
// Get the full path to the DLL in case it was found along the path.
static const buffer_size = 4096;
static char buffer[buffer_size];
if (GetModuleFileName(module, buffer, buffer_size) != 0) {
if (GetLastError() != 0) {
filename = buffer;
}
}
cerr << filename << "\n";
// Now get all of the function pointers.
P3D_initialize = (P3D_initialize_func *)GetProcAddress(module, "P3D_initialize");
P3D_free_string = (P3D_free_string_func *)GetProcAddress(module, "P3D_free_string");
@ -185,6 +180,28 @@ load_plugin(const string &p3d_plugin_filename) {
P3D_check_request = (P3D_check_request_func *)GetProcAddress(module, "P3D_check_request");
P3D_request_finish = (P3D_request_finish_func *)GetProcAddress(module, "P3D_request_finish");
P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)GetProcAddress(module, "P3D_instance_feed_url_stream");
#else // _WIN32
// Posix case.
void *module = dlopen(filename.c_str(), RTLD_NOW | RTLD_LOCAL);
if (module == NULL) {
// Couldn't load the .so.
return false;
}
// Now get all of the function pointers.
P3D_initialize = (P3D_initialize_func *)dlsym(module, "P3D_initialize");
P3D_free_string = (P3D_free_string_func *)dlsym(module, "P3D_free_string");
P3D_create_instance = (P3D_create_instance_func *)dlsym(module, "P3D_create_instance");
P3D_instance_finish = (P3D_instance_finish_func *)dlsym(module, "P3D_instance_finish");
P3D_instance_has_property = (P3D_instance_has_property_func *)dlsym(module, "P3D_instance_has_property");
P3D_instance_get_property = (P3D_instance_get_property_func *)dlsym(module, "P3D_instance_get_property");
P3D_instance_set_property = (P3D_instance_set_property_func *)dlsym(module, "P3D_instance_set_property");
P3D_instance_get_request = (P3D_instance_get_request_func *)dlsym(module, "P3D_instance_get_request");
P3D_check_request = (P3D_check_request_func *)dlsym(module, "P3D_check_request");
P3D_request_finish = (P3D_request_finish_func *)dlsym(module, "P3D_request_finish");
P3D_instance_feed_url_stream = (P3D_instance_feed_url_stream_func *)dlsym(module, "P3D_instance_feed_url_stream");
#endif // _WIN32
// Ensure that all of the function pointers have been found.
@ -329,7 +346,7 @@ usage() {
<< "Options:\n\n"
<< " -p p3d_plugin.dll\n"
<< " -p p3d_plugin" << dll_ext << "\n"
<< " Specify the full path to the particular Panda plugin DLL to\n"
<< " run. Normally, this will be found by searching in the usual\n"
<< " places.\n\n"