clean exit and log reporting

This commit is contained in:
David Rose 2009-09-03 02:09:21 +00:00
parent 77b340fec7
commit 194979b51d
23 changed files with 388 additions and 113 deletions

View File

@ -113,6 +113,11 @@ class AppRunner(DirectObject):
# hosts we have imported packages from.
self.hosts = {}
# Application code can assign a callable object here; if so,
# it will be invoked when an uncaught exception propagates to
# the top of the TaskMgr.run() loop.
self.exceptionHandler = None
# Managing packages for runtime download.
self.downloadingPackages = []
self.downloadTask = None
@ -157,6 +162,49 @@ class AppRunner(DirectObject):
# call back to the main thread.
self.accept('AppRunner_startIfReady', self.__startIfReady)
def getToken(self, tokenName):
""" Returns the value of the indicated web token as a string,
if it was set, or None if it was not. """
return self.tokenDict.get(tokenName.lower(), None)
def getTokenInt(self, tokenName):
""" Returns the value of the indicated web token as an integer
value, if it was set, or None if it was not, or not an
integer. """
value = self.getToken(tokenName)
if value is not None:
try:
value = int(value)
except ValueError:
value = None
return value
def getTokenFloat(self, tokenName):
""" Returns the value of the indicated web token as a
floating-point value value, if it was set, or None if it was
not, or not a number. """
value = self.getToken(tokenName)
if value is not None:
try:
value = float(value)
except ValueError:
value = None
return value
def getTokenBool(self, tokenName):
""" Returns the value of the indicated web token as a boolean
value, if it was set, or None if it was not. """
value = self.getTokenInt(tokenName)
if value is not None:
value = bool(value)
return value
def installPackage(self, packageName, version = None, hostUrl = None):
""" Installs the named package, downloading it first if
@ -248,6 +296,33 @@ class AppRunner(DirectObject):
# shuts down.
taskMgr.doMethodLater(0.5, sys.exit, 'exit')
def run(self):
""" This method calls taskMgr.run(), with an optional
exception handler. This is generally the program's main loop
when running in a p3d environment (except on unusual platforms
like the iPhone, which have to hand the main loop off to the
OS, and don't use this interface. """
try:
taskMgr.run()
except SystemExit:
# 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.")
raise
except:
# Some unexpected Python exception; pass it to the
# optional handler, if it is defined.
if self.exceptionHandler:
self.exceptionHandler()
else:
raise
def setSessionId(self, sessionId):
""" This message should come in at startup. """
self.sessionId = sessionId

View File

@ -73,6 +73,17 @@ close() {
_buf.close();
}
////////////////////////////////////////////////////////////////////
// Function: HandleStream::close_handle
// Access: Public
// Description: Closes the underlying handle, *without* attempting to
// flush the stream.
////////////////////////////////////////////////////////////////////
inline void HandleStream::
close_handle() {
_buf.close_handle();
}
////////////////////////////////////////////////////////////////////
// Function: HandleStream::get_handle
// Access: Public

View File

@ -32,6 +32,7 @@ public:
inline void open_read(FHandle handle);
inline void open_write(FHandle handle);
inline void close();
inline void close_handle();
inline FHandle get_handle() const;

View File

@ -36,12 +36,9 @@ HandleStreamBuf() {
_is_open_read = false;
_is_open_write = false;
#ifdef _WIN32
// Windows case.
_handle = NULL;
#else
_handle = -1;
#endif // _WIN32
_handle = INVALID_HANDLE_VALUE;
INIT_LOCK(_lock);
_buffer = new char[handle_buffer_size];
char *ebuf = _buffer + handle_buffer_size;
@ -59,6 +56,8 @@ HandleStreamBuf::
close();
delete[] _buffer;
DESTROY_LOCK(_lock);
}
////////////////////////////////////////////////////////////////////
@ -123,6 +122,20 @@ close() {
// Make sure the write buffer is flushed.
sync();
close_handle();
pbump(pbase() - pptr());
gbump(egptr() - gptr());
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::close_handle
// Access: Public
// Description: Closes the underlying handle, *without* attempting to
// flush the stream.
////////////////////////////////////////////////////////////////////
void HandleStreamBuf::
close_handle() {
#ifdef _WIN32
if (_handle != NULL) {
CloseHandle(_handle);
@ -137,9 +150,6 @@ close() {
_is_open_read = false;
_is_open_write = false;
pbump(pbase() - pptr());
gbump(egptr() - gptr());
}
////////////////////////////////////////////////////////////////////
@ -150,11 +160,15 @@ close() {
////////////////////////////////////////////////////////////////////
int HandleStreamBuf::
overflow(int ch) {
ACQUIRE_LOCK(_lock);
bool okflag = true;
assert(pptr() >= pbase());
size_t n = pptr() - pbase();
if (n != 0) {
size_t wrote = write_chars(pbase(), n);
assert(wrote <= n);
pbump(-(int)wrote);
if (wrote != n) {
okflag = false;
@ -172,6 +186,8 @@ overflow(int ch) {
}
}
RELEASE_LOCK(_lock);
if (!okflag) {
return EOF;
}
@ -186,11 +202,16 @@ overflow(int ch) {
////////////////////////////////////////////////////////////////////
int HandleStreamBuf::
sync() {
ACQUIRE_LOCK(_lock);
assert(pptr() >= pbase());
size_t n = pptr() - pbase();
size_t wrote = write_chars(pbase(), n);
assert(wrote <= n);
pbump(-(int)wrote);
RELEASE_LOCK(_lock);
if (n != wrote) {
return EOF;
}
@ -205,6 +226,7 @@ sync() {
////////////////////////////////////////////////////////////////////
int HandleStreamBuf::
underflow() {
ACQUIRE_LOCK(_lock);
// Sometimes underflow() is called even if the buffer is not empty.
if (gptr() >= egptr()) {
// Mark the buffer filled (with buffer_size bytes).
@ -218,6 +240,7 @@ underflow() {
// Oops, we didn't read what we thought we would.
if (read_count == 0) {
gbump(num_bytes);
RELEASE_LOCK(_lock);
return EOF;
}
@ -229,7 +252,10 @@ underflow() {
}
}
return (unsigned char)*gptr();
unsigned char next = *gptr();
RELEASE_LOCK(_lock);
return next;
}
////////////////////////////////////////////////////////////////////
@ -309,6 +335,7 @@ write_chars(const char *start, size_t length) {
DWORD bytes_written = 0;
BOOL success = WriteFile(_handle, start, length, &bytes_written, NULL);
if (!success) {
assert(bytes_written <= length);
DWORD error = GetLastError();
if (error != ERROR_NO_DATA && error != ERROR_BROKEN_PIPE) {
cerr << "Error writing " << length

View File

@ -16,6 +16,7 @@
#define HANDLESTREAMBUF_H
#include "fhandle.h"
#include "p3d_lock.h"
#include <iostream>
using namespace std;
@ -34,6 +35,7 @@ public:
bool is_open_read() const;
bool is_open_write() const;
void close();
void close_handle();
inline FHandle get_handle() const;
@ -51,6 +53,7 @@ private:
bool _is_open_write;
FHandle _handle;
LOCK _lock;
char *_buffer;
};

View File

@ -61,14 +61,14 @@ get_session_key() const {
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::get_python_version
// Function: P3DInstance::get_session
// Access: Public
// Description: Returns a string that uniquely identifies this
// instance's required Python version.
// Description: Returns the P3DSession that is hosting this instance,
// or NULL if the instance is not running.
////////////////////////////////////////////////////////////////////
inline const string &P3DInstance::
get_python_version() const {
return _python_version;
inline P3DSession *P3DInstance::
get_session() const {
return _session;
}
////////////////////////////////////////////////////////////////////

View File

@ -58,6 +58,7 @@ P3DInstance(P3D_request_ready_func *func,
{
_browser_script_object = NULL;
_panda_script_object = new P3DMainObject;
_panda_script_object->set_instance(this);
_user_data = user_data;
_request_pending = false;
_temp_p3d_filename = NULL;
@ -113,6 +114,7 @@ P3DInstance::
nout << "panda_script_object ref = "
<< _panda_script_object->_ref_count << "\n";
_panda_script_object->set_instance(NULL);
P3D_OBJECT_DECREF(_panda_script_object);
// Tell all of the packages that we're no longer in business for
@ -458,7 +460,7 @@ bake_requests() {
// No more requests to process right now.
return;
}
// Now we've got a request in XML form; convert it to P3D_request
// form.
TiXmlElement *xrequest = doc->FirstChildElement("request");
@ -1000,6 +1002,11 @@ make_p3d_request(TiXmlElement *xrequest) {
// We no longer need to keep this reference.
_session->drop_p3dobj(object_id);
}
} else if (strcmp(rtype, "stop") == 0) {
// A stop request from Python code. This is kind of weird, but OK.
request = new P3D_request;
request->_request_type = P3D_RT_stop;
} else {
nout << "Ignoring request of type " << rtype << "\n";

View File

@ -82,7 +82,8 @@ public:
inline int get_instance_id() const;
inline const string &get_session_key() const;
inline const string &get_python_version() const;
inline P3DSession *get_session() const;
inline P3D_request_ready_func *get_request_ready_func() const;
@ -158,7 +159,6 @@ private:
int _instance_id;
string _session_key;
string _python_version;
string _log_basename;
bool _hidden;
bool _allow_python_dev;

View File

@ -89,6 +89,21 @@ get_log_directory() const {
return _log_directory;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_log_pathname
// Access: Public
// Description: Returns the filename of the system log file; this
// file is responsible for downloading and installing
// updates, and launching applications. This is
// different from the session log file(s), which
// represent the output from a particular Python
// session.
////////////////////////////////////////////////////////////////////
inline const string &P3DInstanceManager::
get_log_pathname() const {
return _log_pathname;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_keep_cwd
// Access: Public

View File

@ -58,6 +58,7 @@ public:
inline const string &get_root_dir() const;
inline const string &get_platform() const;
inline const string &get_log_directory() const;
inline const string &get_log_pathname() const;
inline bool get_keep_cwd() const;
P3DInstance *

View File

@ -13,6 +13,11 @@
////////////////////////////////////////////////////////////////////
#include "p3dMainObject.h"
#include "p3dInstance.h"
#include "p3dSession.h"
#include "p3dUndefinedObject.h"
#include "p3dStringObject.h"
#include "p3dInstanceManager.h"
////////////////////////////////////////////////////////////////////
// Function: P3DMainObject::Constructor
@ -178,6 +183,13 @@ set_property(const string &property, P3D_object *value) {
////////////////////////////////////////////////////////////////////
bool P3DMainObject::
has_method(const string &method_name) {
// Some special-case methods implemented in-place.
if (method_name == "read_game_log") {
return true;
} else if (method_name == "read_system_log") {
return true;
}
if (_pyobj == NULL) {
// No methods until we get our pyobj.
return false;
@ -202,6 +214,12 @@ has_method(const string &method_name) {
P3D_object *P3DMainObject::
call(const string &method_name, bool needs_response,
P3D_object *params[], int num_params) {
if (method_name == "read_game_log") {
return call_read_game_log();
} else if (method_name == "read_system_log") {
return call_read_system_log();
}
if (_pyobj == NULL) {
// No methods until we get our pyobj.
return NULL;
@ -263,3 +281,88 @@ P3D_object *P3DMainObject::
get_pyobj() const {
return _pyobj;
}
////////////////////////////////////////////////////////////////////
// Function: P3DMainObject::set_instance
// Access: Public
// Description: Sets a callback pointer to the instance that owns
// this object. When this instance destructs, it clears
// this pointer to NULL.
////////////////////////////////////////////////////////////////////
void P3DMainObject::
set_instance(P3DInstance *inst) {
_inst = inst;
}
////////////////////////////////////////////////////////////////////
// Function: P3DMainObject::call_read_game_log
// Access: Private
// Description: Reads the entire logfile as a string, and returns it
// to the calling JavaScript process.
////////////////////////////////////////////////////////////////////
P3D_object *P3DMainObject::
call_read_game_log() {
nout << "call_read_game_log: " << _inst << "\n";
if (_inst == NULL) {
return new P3DUndefinedObject();
}
P3DSession *session = _inst->get_session();
nout << "session = " << session << "\n";
string log_pathname = session->get_log_pathname();
nout << "log_pathname = " << log_pathname << "\n";
ifstream log(log_pathname.c_str(), ios::in);
// Get the size of the file.
log.seekg(0, ios::end);
size_t size = (size_t)log.tellg();
log.seekg(0, ios::beg);
// Read the entire file into memory all at once.
char *buffer = new char[size];
if (buffer == NULL) {
return NULL;
}
log.read(buffer, size);
P3D_object *result = new P3DStringObject(buffer, size);
delete[] buffer;
return result;
}
////////////////////////////////////////////////////////////////////
// Function: P3DMainObject::call_read_system_log
// Access: Private
// Description: As above, but reads the system log, the logfile for
// the installation process.
////////////////////////////////////////////////////////////////////
P3D_object *P3DMainObject::
call_read_system_log() {
nout << "call_read_system_log: " << _inst << "\n";
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
string log_pathname = inst_mgr->get_log_pathname();
nout << "log_pathname = " << log_pathname << "\n";
ifstream log(log_pathname.c_str(), ios::in);
// Get the size of the file.
log.seekg(0, ios::end);
size_t size = (size_t)log.tellg();
log.seekg(0, ios::beg);
// Read the entire file into memory all at once.
char *buffer = new char[size];
if (buffer == NULL) {
return NULL;
}
log.read(buffer, size);
P3D_object *result = new P3DStringObject(buffer, size);
delete[] buffer;
return result;
}

View File

@ -20,6 +20,7 @@
#include <map>
class P3DSession;
class P3DInstance;
////////////////////////////////////////////////////////////////////
// Class : P3DMainObject
@ -63,8 +64,15 @@ public:
void set_pyobj(P3D_object *pyobj);
P3D_object *get_pyobj() const;
void set_instance(P3DInstance *inst);
private:
P3D_object *call_read_game_log();
P3D_object *call_read_system_log();
private:
P3D_object *_pyobj;
P3DInstance *_inst;
// This map is used to store properties and retrieve until
// set_pyobj() is called for the firs ttime. At that point, the

View File

@ -32,7 +32,6 @@ main(int argc, char *argv[]) {
const char *archive_file = NULL;
const char *input_handle_str = NULL;
const char *output_handle_str = NULL;
const char *error_handle_str = NULL;
const char *interactive_console_str = NULL;
if (argc > 1) {
@ -45,10 +44,7 @@ main(int argc, char *argv[]) {
output_handle_str = argv[3];
}
if (argc > 4) {
error_handle_str = argv[4];
}
if (argc > 5) {
interactive_console_str = argv[5];
interactive_console_str = argv[4];
}
if (archive_file == NULL || *archive_file == '\0') {
@ -74,15 +70,6 @@ main(int argc, char *argv[]) {
}
}
FHandle error_handle = invalid_fhandle;
if (error_handle_str != NULL && *error_handle_str) {
stringstream stream(error_handle_str);
stream >> error_handle;
if (!stream) {
error_handle = invalid_fhandle;
}
}
bool interactive_console = false;
if (interactive_console_str != NULL && *interactive_console_str) {
stringstream stream(interactive_console_str);
@ -93,12 +80,11 @@ main(int argc, char *argv[]) {
}
}
cerr << "handles: " << input_handle << ", " << output_handle
<< ", " << error_handle << "\n";
cerr << "handles: " << input_handle << ", " << output_handle << "\n";
cerr << "interactive_console = " << interactive_console << "\n";
if (!run_p3dpython(program_name, archive_file, input_handle, output_handle,
error_handle, interactive_console)) {
NULL, interactive_console)) {
cerr << "Failure on startup.\n";
return 1;
}

View File

@ -31,7 +31,7 @@ P3DPythonRun *P3DPythonRun::_global_ptr = NULL;
P3DPythonRun::
P3DPythonRun(const char *program_name, const char *archive_file,
FHandle input_handle, FHandle output_handle,
FHandle error_handle, bool interactive_console) {
const char *log_pathname, bool interactive_console) {
_read_thread_continue = false;
_program_continue = true;
_session_terminated = false;
@ -74,11 +74,14 @@ P3DPythonRun(const char *program_name, const char *archive_file,
PySys_SetArgv(_py_argc, _py_argv);
// Open the error output before we do too much more.
_error_log.open_write(error_handle);
if (!_error_log.fail()) {
// Set up the indicated error log as the Notify output.
_error_log.setf(ios::unitbuf);
Notify::ptr()->set_ostream_ptr(&_error_log, false);
if (log_pathname != NULL && *log_pathname != '\0') {
Filename f = Filename::from_os_specific(log_pathname);
f.set_text();
if (f.open_write(_error_log)) {
// Set up the indicated error log as the Notify output.
_error_log.setf(ios::unitbuf);
Notify::ptr()->set_ostream_ptr(&_error_log, false);
}
}
// Open the pipe streams with the input and output handles from the
@ -103,6 +106,9 @@ P3DPythonRun(const char *program_name, const char *archive_file,
////////////////////////////////////////////////////////////////////
P3DPythonRun::
~P3DPythonRun() {
// Close the write pipe, so the parent process will terminate us.
_pipe_write.close();
Py_Finalize();
join_read_thread();
@ -339,22 +345,32 @@ run_python() {
Py_DECREF(check_comm);
// Finally, get lost in taskMgr.run().
bool okflag = true;
PyObject *done = PyObject_CallMethod(_taskMgr, (char *)"run", (char *)"");
// Finally, get lost in AppRunner.run() (which is really a call to
// taskMgr.run()).
PyObject *done = PyObject_CallMethod(_runner, (char *)"run", (char *)"");
if (done == NULL) {
// An uncaught application exception, and not handled by
// appRunner.exceptionHandler.
PyErr_Print();
okflag = false;
} else {
Py_DECREF(done);
if (_interactive_console) {
// Give an interactive user a chance to explore the exception.
run_interactive_console();
return true;
}
// We're done.
return false;
}
// A normal exit from the taskManager. We're presumably done.
Py_DECREF(done);
if (_interactive_console) {
run_interactive_console();
okflag = true;
}
return okflag;
return true;
}
////////////////////////////////////////////////////////////////////
@ -1032,8 +1048,6 @@ spawn_read_thread() {
void P3DPythonRun::
join_read_thread() {
_read_thread_continue = false;
_pipe_read.close();
JOIN_THREAD(_read_thread);
}

View File

@ -26,6 +26,7 @@
#include "p3d_lock.h"
#include "handleStream.h"
#include "p3dCInstance.h"
#include "pandaFileStreamBuf.h"
#include "pythonTask.h"
#include "pmap.h"
#include "pdeque.h"
@ -68,7 +69,7 @@ class P3DPythonRun {
public:
P3DPythonRun(const char *program_name, const char *archive_file,
FHandle input_handle, FHandle output_handle,
FHandle error_handle, bool interactive_console);
const char *log_pathname, bool interactive_console);
~P3DPythonRun();
bool run_python();
@ -155,7 +156,7 @@ private:
HandleStream _pipe_read;
HandleStream _pipe_write;
HandleStream _error_log;
pofstream _error_log;
bool _read_thread_continue;
bool _program_continue;

View File

@ -25,14 +25,16 @@ get_session_key() const {
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::get_python_version
// Function: P3DSession::get_log_pathname
// Access: Public
// Description: Returns a string that uniquely identifies this
// session's required Python version.
// Description: Returns the log filename for this particular session,
// if the session was started and if it has a log file.
// Returns empty string if the session never started or
// if it lacks a log file.
////////////////////////////////////////////////////////////////////
inline const string &P3DSession::
get_python_version() const {
return _python_version;
get_log_pathname() const {
return _log_pathname;
}
////////////////////////////////////////////////////////////////////

View File

@ -52,7 +52,6 @@ P3DSession(P3DInstance *inst) {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_session_id = inst_mgr->get_unique_id();
_session_key = inst->get_session_key();
_python_version = inst->get_python_version();
_start_dir = inst_mgr->get_root_dir() + "/start";
_p3dpython_one_process = false;
@ -180,9 +179,6 @@ shutdown() {
_p3dpython_running = false;
_p3dpython_started = false;
// Close the pipe now.
_pipe_read.close();
}
// If there are any leftover commands in the queue (presumably
@ -195,6 +191,9 @@ shutdown() {
_commands.clear();
join_read_thread();
// Close the pipe now.
_pipe_read.close();
}
////////////////////////////////////////////////////////////////////
@ -211,7 +210,6 @@ void P3DSession::
start_instance(P3DInstance *inst) {
assert(inst->_session == NULL);
assert(inst->get_session_key() == _session_key);
assert(inst->get_python_version() == _python_version);
inst->ref();
ACQUIRE_LOCK(_instances_lock);
@ -684,6 +682,10 @@ start_p3dpython(P3DInstance *inst) {
mkdir_complete(_start_dir, nout);
}
// Also make sure the prc directory is present.
string prc_root = inst_mgr->get_root_dir() + "/prc";
mkdir_complete(prc_root, nout);
#ifdef _WIN32
char sep = ';';
#else
@ -716,7 +718,14 @@ start_p3dpython(P3DInstance *inst) {
string dyld_path = search_path;
string python_path = search_path;
string prc_path = search_path;
string prc_path = prc_root + sep + search_path;
string prc_name = inst->get_fparams().lookup_token("prc_name");
if (!prc_name.empty()) {
// Add the prc_name to the path too, even if this directory doesn't
// actually exist.
prc_path = inst_mgr->get_root_dir() + "/" + prc_name + sep + prc_path;
}
if (keep_pythonpath) {
// With keep_pythonpath true, we preserve the PYTHONPATH setting
@ -929,34 +938,8 @@ start_p3dpython(P3DInstance *inst) {
// Create the error stream for log output. This means opening the
// logfile, if we have one, or keeping the standard error if we
// don't.
_got_error_handle = false;
#ifdef _WIN32
_error_handle = GetStdHandle(STD_ERROR_HANDLE);
if (!_log_pathname.empty()) {
HANDLE handle = CreateFile
(_log_pathname.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);
_got_error_handle = true;
} else {
nout << "Unable to open " << _log_pathname << "\n";
}
}
#else // _WIN32
_error_handle = STDERR_FILENO;
if (!_log_pathname.empty()) {
int logfile_fd = open(_log_pathname.c_str(),
O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (logfile_fd < 0) {
nout << "Unable to open " << _log_pathname << "\n";
} else {
_error_handle = logfile_fd;
_got_error_handle = true;
}
}
#endif // _WIN32
// Get the filename of the Panda3D multifile. We need to pass this
@ -1049,7 +1032,6 @@ join_read_thread() {
}
_read_thread_continue = false;
_pipe_read.close();
JOIN_THREAD(_read_thread);
_started_read_thread = false;
@ -1171,10 +1153,34 @@ win_create_process() {
// Make sure we see an error dialog if there is a missing DLL.
SetErrorMode(0);
// Open the log file.
HANDLE error_handle = GetStdHandle(STD_ERROR_HANDLE);
bool got_error_handle = false;
if (!_log_pathname.empty()) {
HANDLE handle = CreateFile
(_log_pathname.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);
got_error_handle = true;
} else {
nout << "Unable to open " << _log_pathname << "\n";
}
}
STARTUPINFO startup_info;
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(startup_info);
// Set up the I/O handles. We send stderr and stdout to our
// error_handle.
startup_info.hStdError = error_handle;
startup_info.hStdOutput = error_handle;
startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startup_info.dwFlags |= STARTF_USESTDHANDLES;
// Make sure the "python" console window is hidden.
startup_info.wShowWindow = SW_HIDE;
startup_info.dwFlags |= STARTF_USESHOWWINDOW;
@ -1191,8 +1197,7 @@ win_create_process() {
ostringstream stream;
stream << "\"" << _p3dpython_exe << "\" \"" << _mf_filename
<< "\" \"" << _input_handle << "\" \"" << _output_handle
<< "\" \"" << _error_handle << "\" \"" << _interactive_console
<< "\"";
<< "\" \"" << _interactive_console << "\"";
// I'm not sure why CreateProcess wants a non-const char pointer for
// its command-line string, but I'm not taking chances. It gets a
@ -1213,8 +1218,8 @@ win_create_process() {
// Close the pipe handles that are now owned by the child.
CloseHandle(_output_handle);
CloseHandle(_input_handle);
if (_got_error_handle) {
CloseHandle(_error_handle);
if (got_error_handle) {
CloseHandle(error_handle);
}
if (!started_program) {
@ -1263,6 +1268,20 @@ posix_create_process() {
_pipe_read.close();
_pipe_write.close();
if (!_log_pathname.empty()) {
// Open a logfile.
int logfile_fd = open(_log_pathname.c_str(),
O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (logfile_fd < 0) {
nout << "Unable to open " << _log_pathname << "\n";
} else {
// Redirect stderr and stdout onto our logfile.
dup2(logfile_fd, STDERR_FILENO);
dup2(logfile_fd, STDOUT_FILENO);
close(logfile_fd);
}
}
if (_use_start_dir) {
if (chdir(_start_dir.c_str()) < 0) {
nout << "Could not chdir to " << _start_dir << "\n";
@ -1290,13 +1309,9 @@ posix_create_process() {
output_handle_stream << _output_handle;
string output_handle_str = output_handle_stream.str();
stringstream error_handle_stream;
error_handle_stream << _error_handle;
string error_handle_str = error_handle_stream.str();
execle(_p3dpython_exe.c_str(), _p3dpython_exe.c_str(),
_mf_filename.c_str(), input_handle_str.c_str(),
output_handle_str.c_str(), error_handle_str.c_str(),
output_handle_str.c_str(),
_interactive_console ? "1" : "0", (char *)0, &ptrs[0]);
nout << "Failed to exec " << _p3dpython_exe << "\n";
_exit(1);
@ -1305,9 +1320,6 @@ posix_create_process() {
// Close the handles that are now owned by the child.
close(_input_handle);
close(_output_handle);
if (_got_error_handle) {
close(_error_handle);
}
return child;
}
@ -1391,7 +1403,7 @@ p3dpython_thread_run() {
}
if (!run_p3dpython(libp3dpython.c_str(), _mf_filename.c_str(),
_input_handle, _output_handle, _error_handle,
_input_handle, _output_handle, _log_pathname.c_str(),
_interactive_console)) {
nout << "Failure on startup.\n";
}

View File

@ -43,7 +43,7 @@ public:
void shutdown();
inline const string &get_session_key() const;
inline const string &get_python_version() const;
inline const string &get_log_pathname() const;
void start_instance(P3DInstance *inst);
void terminate_instance(P3DInstance *inst);
@ -88,7 +88,6 @@ private:
private:
int _session_id;
string _session_key;
string _python_version;
string _log_pathname;
string _python_root_dir;
string _start_dir;
@ -100,8 +99,7 @@ private:
string _p3dpython_dll;
string _mf_filename;
string _env;
FHandle _input_handle, _output_handle, _error_handle;
bool _got_error_handle;
FHandle _input_handle, _output_handle;
bool _interactive_console;
typedef map<int, P3DInstance *> Instances;

View File

@ -23,6 +23,15 @@ P3DStringObject::
P3DStringObject(const string &value) : _value(value) {
}
////////////////////////////////////////////////////////////////////
// Function: P3DStringObject::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DStringObject::
P3DStringObject(const char *data, size_t size) : _value(data, size) {
}
////////////////////////////////////////////////////////////////////
// Function: P3DStringObject::Copy Constructor
// Access: Public

View File

@ -25,6 +25,7 @@
class P3DStringObject : public P3DObject {
public:
P3DStringObject(const string &value);
P3DStringObject(const char *data, size_t size);
P3DStringObject(const P3DStringObject &copy);
public:

View File

@ -24,10 +24,10 @@
bool
run_p3dpython(const char *program_name, const char *archive_file,
FHandle input_handle, FHandle output_handle,
FHandle error_handle, bool interactive_console) {
const char *log_pathname, bool interactive_console) {
P3DPythonRun::_global_ptr =
new P3DPythonRun(program_name, archive_file, input_handle, output_handle,
error_handle, interactive_console);
log_pathname, interactive_console);
bool result = P3DPythonRun::_global_ptr->run_python();
delete P3DPythonRun::_global_ptr;
P3DPythonRun::_global_ptr = NULL;

View File

@ -29,12 +29,12 @@
typedef bool
run_p3dpython_func(const char *program_name, const char *archive_file,
FHandle input_handle, FHandle output_handle,
FHandle error_handle, bool interactive_console);
const char *log_pathname, bool interactive_console);
extern "C" EXPCL_P3DPYTHON bool
run_p3dpython(const char *program_name, const char *archive_file,
FHandle input_handle, FHandle output_handle,
FHandle error_handle, bool interactive_console);
const char *log_pathname, bool interactive_console);
#endif

View File

@ -182,6 +182,7 @@ class VFSLoader:
filename = Filename(self.filename)
filename.setExtension('py')
filename.setText()
vfile = vfs.getFile(filename)
if not vfile:
raise IOError