more plugin work

This commit is contained in:
David Rose 2009-06-08 18:08:53 +00:00
parent be2883308b
commit 027e5fdc9e
24 changed files with 1145 additions and 619 deletions

View File

@ -3,24 +3,25 @@
#define BUILD_DIRECTORY $[HAVE_P3D_PLUGIN]
#begin lib_target
#define USE_PACKAGES tinyxml
#define TARGET p3d_plugin
#define COMBINED_SOURCES \
$[TARGET]_composite1.cxx
#define SOURCES \
p3d_plugin.h \
handleStream.cxx handleStream.h handleStream.I \
handleStreamBuf.cxx handleStreamBuf.h \
p3d_lock.h p3d_plugin.h \
p3d_plugin_common.h \
p3dInstance.h p3dInstance.I \
p3dInstanceManager.h p3dInstanceManager.I \
p3dPython.h p3dPython.I \
p3dSession.h p3dSession.I
#define INCLUDED_SOURCES \
p3d_plugin.cxx \
p3dInstance.cxx \
p3dInstanceManager.cxx \
p3dPython.cxx \
p3dSession.cxx
#define INSTALL_HEADERS \
@ -28,6 +29,18 @@
#end lib_target
#begin bin_target
#define USE_PACKAGES tinyxml
#define TARGET p3dpython
#define SOURCES \
handleStream.cxx handleStream.h handleStream.I \
handleStreamBuf.cxx handleStreamBuf.h \
p3d_lock.h \
p3dPythonRun.cxx p3dPythonRun.h p3dPythonRun.I
#end bin_target
#begin bin_target
#define TARGET panda3d

View File

@ -0,0 +1,74 @@
// Filename: handleStream.I
// Created by: drose (05Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: HandleStream::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
inline HandleStream::
HandleStream() : iostream(&_buf) {
}
////////////////////////////////////////////////////////////////////
// Function: HandleStream::Destructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
inline HandleStream::
~HandleStream() {
close();
}
////////////////////////////////////////////////////////////////////
// Function: HandleStream::open_read
// Access: Published
// Description: Attempts to open the given handle for input. The
// stream may not be simultaneously open for input and
// output.
////////////////////////////////////////////////////////////////////
inline void HandleStream::
open_read(Handle handle) {
clear((ios::iostate)0);
_buf.open_read(handle);
if (!_buf.is_open_read()) {
clear(ios::failbit);
}
}
////////////////////////////////////////////////////////////////////
// Function: HandleStream::open_write
// Access: Published
// Description: Attempts to open the given handle for output. The
// stream may not be simultaneously open for input and
// output.
////////////////////////////////////////////////////////////////////
inline void HandleStream::
open_write(Handle handle) {
clear((ios::iostate)0);
_buf.open_write(handle);
if (!_buf.is_open_write()) {
clear(ios::failbit);
}
}
////////////////////////////////////////////////////////////////////
// Function: HandleStream::close
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
inline void HandleStream::
close() {
_buf.close();
}

View File

@ -0,0 +1,15 @@
// Filename: handleStream.cxx
// Created by: drose (05Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#include "handleStream.h"

View File

@ -0,0 +1,42 @@
// Filename: handleStream.h
// Created by: drose (05Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 HANDLESTREAM_H
#define HANDLESTREAM_H
#include "handleStreamBuf.h"
////////////////////////////////////////////////////////////////////
// Class : HandleStream
// Description : Implements a C++ stream object suitable for reading
// from and writing to Windows' HANDLE objects, or Posix
// file descriptors. This is necessary to map low-level
// pipes into an iostream for tinyxml.
////////////////////////////////////////////////////////////////////
class HandleStream : public iostream {
public:
inline HandleStream();
inline ~HandleStream();
inline void open_read(Handle handle);
inline void open_write(Handle handle);
inline void close();
private:
HandleStreamBuf _buf;
};
#include "handleStream.I"
#endif

View File

@ -0,0 +1,14 @@
// Filename: handleStreamBuf.I
// Created by: drose (05Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,339 @@
// Filename: handleStreamBuf.cxx
// Created by: drose (05Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#include "handleStreamBuf.h"
#include <assert.h>
#ifndef _WIN32
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#endif // _WIN32
static const size_t handle_buffer_size = 4096;
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
HandleStreamBuf::
HandleStreamBuf() {
_is_open_read = false;
_is_open_write = false;
#ifdef _WIN32
// Windows case.
_handle = NULL;
#else
_handle = -1;
#endif // _WIN32
_buffer = new char[handle_buffer_size];
char *ebuf = _buffer + handle_buffer_size;
setg(_buffer, ebuf, ebuf);
setp(_buffer, ebuf);
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
HandleStreamBuf::
~HandleStreamBuf() {
close();
delete[] _buffer;
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::open_read
// Access: Public
// Description: Attempts to open the given handle for input. The
// stream may not be simultaneously open for input and
// output.
////////////////////////////////////////////////////////////////////
void HandleStreamBuf::
open_read(Handle handle) {
close();
_handle = handle;
_is_open_read = true;
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::open_write
// Access: Public
// Description: Attempts to open the given handle for output. The
// stream may not be simultaneously open for input and
// output.
////////////////////////////////////////////////////////////////////
void HandleStreamBuf::
open_write(Handle handle) {
close();
_handle = handle;
_is_open_write = true;
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::is_open_read
// Access: Public
// Description: Returns true if the file is open for input, false
// otherwise.
////////////////////////////////////////////////////////////////////
bool HandleStreamBuf::
is_open_read() const {
return _is_open_read;
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::is_open_write
// Access: Public
// Description: Returns true if the file is open for output, false
// otherwise.
////////////////////////////////////////////////////////////////////
bool HandleStreamBuf::
is_open_write() const {
return _is_open_write;
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::close
// Access: Public
// Description: Empties the buffer and closes the file.
////////////////////////////////////////////////////////////////////
void HandleStreamBuf::
close() {
// Make sure the write buffer is flushed.
sync();
#ifdef _WIN32
if (_handle != NULL) {
CloseHandle(_handle);
}
_handle = NULL;
#else
if (_handle != -1) {
::close(_handle);
}
_handle = -1;
#endif // _WIN32
_is_open_read = false;
_is_open_write = false;
pbump(pbase() - pptr());
gbump(egptr() - gptr());
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::overflow
// Access: Protected, Virtual
// Description: Called by the system ostream implementation when its
// internal buffer is filled, plus one character.
////////////////////////////////////////////////////////////////////
int HandleStreamBuf::
overflow(int ch) {
bool okflag = true;
size_t n = pptr() - pbase();
if (n != 0) {
size_t wrote = write_chars(pbase(), n);
pbump(-(int)wrote);
if (wrote != n) {
okflag = false;
}
}
if (okflag && ch != EOF) {
if (pptr() != epptr()) {
// Store the extra character back in the buffer.
*(pptr()) = ch;
pbump(1);
} else {
// No room to store ch.
okflag = false;
}
}
if (!okflag) {
return EOF;
}
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::sync
// Access: Protected, Virtual
// Description: Called by the system iostream implementation to
// implement a flush operation.
////////////////////////////////////////////////////////////////////
int HandleStreamBuf::
sync() {
size_t n = pptr() - pbase();
size_t wrote = write_chars(pbase(), n);
pbump(-(int)wrote);
if (n != wrote) {
return EOF;
}
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::underflow
// Access: Protected, Virtual
// Description: Called by the system istream implementation when its
// internal buffer needs more characters.
////////////////////////////////////////////////////////////////////
int HandleStreamBuf::
underflow() {
// Sometimes underflow() is called even if the buffer is not empty.
if (gptr() >= egptr()) {
// Mark the buffer filled (with buffer_size bytes).
size_t buffer_size = egptr() - eback();
gbump(-(int)buffer_size);
size_t num_bytes = buffer_size;
size_t read_count = read_chars(gptr(), buffer_size);
if (read_count != num_bytes) {
// Oops, we didn't read what we thought we would.
if (read_count == 0) {
gbump(num_bytes);
return EOF;
}
// Slide what we did read to the top of the buffer.
assert(read_count < num_bytes);
size_t delta = num_bytes - read_count;
memmove(gptr() + delta, gptr(), read_count);
gbump(delta);
}
}
return (unsigned char)*gptr();
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::read_chars
// Access: Private
// Description: Attempts to extract the indicated number of
// characters from the current file position. Returns
// the number of characters extracted.
////////////////////////////////////////////////////////////////////
size_t HandleStreamBuf::
read_chars(char *start, size_t length) {
if (length == 0 || !_is_open_read) {
// Trivial no-op.
return 0;
}
// Make sure the write buffer is flushed.
sync();
if (length == 0) {
return 0;
}
#ifdef _WIN32
// Windows case.
DWORD bytes_read = 0;
BOOL success = ReadFile(_handle, start, length, &bytes_read, NULL);
if (!success) {
DWORD error = GetLastError();
if (error != ERROR_HANDLE_EOF) {
cerr
<< "Error reading " << length
<< " bytes, windows error code 0x" << hex
<< error << dec << ".\n";
return 0;
}
}
length = bytes_read;
#else
// Posix case.
ssize_t result = ::read(_handle, start, length);
if (result < 0) {
cerr
<< "Error reading " << length << " bytes\n";
return 0;
}
length = result;
#endif // _WIN32
return length;
}
////////////////////////////////////////////////////////////////////
// Function: HandleStreamBuf::write_chars
// Access: Private
// Description: Outputs the indicated stream of characters to the
// current file position.
////////////////////////////////////////////////////////////////////
size_t HandleStreamBuf::
write_chars(const char *start, size_t length) {
if (length == 0) {
// Trivial no-op.
return 0;
}
// Make sure the read buffer is flushed.
size_t n = egptr() - gptr();
gbump(n);
if (length == 0 || !_is_open_write) {
return 0;
}
#ifdef _WIN32
// Windows case.
DWORD bytes_written = 0;
BOOL success = WriteFile(_handle, start, length, &bytes_written, NULL);
if (!success) {
DWORD error = GetLastError();
cerr
<< "Error writing " << length
<< " bytes, windows error code 0x" << hex
<< error << dec << ".\n";
return bytes_written;
}
assert(bytes_written == length);
#else
// Posix case.
size_t remaining = length;
while (remaining > 0) {
ssize_t result = ::write(_handle, start, remaining);
if (result < 0) {
cerr
<< "Error writing " << remaining << " bytes\n";
return length - remaining;
}
start += result;
remaining -= result;
}
#endif // _WIN32
return length;
}

View File

@ -0,0 +1,64 @@
// Filename: handleStreamBuf.h
// Created by: drose (05Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 HANDLESTREAMBUF_H
#define HANDLESTREAMBUF_H
#ifdef _WIN32
#include <windows.h>
typedef HANDLE Handle;
#else
// On POSIX, we use a file descriptor as a "handle".
typedef int Handle;
#endif
#include <iostream>
#include <iostream>
using namespace std;
////////////////////////////////////////////////////////////////////
// Class : HandleStreamBuf
// Description :
////////////////////////////////////////////////////////////////////
class HandleStreamBuf : public streambuf {
public:
HandleStreamBuf();
virtual ~HandleStreamBuf();
void open_read(Handle handle);
void open_write(Handle handle);
bool is_open_read() const;
bool is_open_write() const;
void close();
protected:
virtual int overflow(int c);
virtual int sync();
virtual int underflow();
private:
size_t read_chars(char *start, size_t length);
size_t write_chars(const char *start, size_t length);
private:
bool _is_open_read;
bool _is_open_write;
Handle _handle;
char *_buffer;
};
#endif

View File

@ -38,16 +38,15 @@ P3DInstance(P3D_request_ready_func *func,
_parent_window(parent_window)
{
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
cerr << "creating instance\n";
INIT_LOCK(_request_lock);
// For the moment, all sessions will be shared.
/*
// For the moment, all sessions will be unique.
ostringstream strm;
strm << inst_mgr->get_unique_session_index();
_session_key = strm.str();
*/
_session_key = "common";
_python_version = "python24";
_session = NULL;

View File

@ -84,7 +84,6 @@ private:
Requests _pending_requests;
friend class P3DSession;
friend class P3DPython;
};
#include "p3dInstance.I"

View File

@ -15,7 +15,6 @@
#include "p3dInstanceManager.h"
#include "p3dInstance.h"
#include "p3dSession.h"
#include "p3dPython.h"
P3DInstanceManager *P3DInstanceManager::_global_ptr;
@ -26,8 +25,8 @@ P3DInstanceManager *P3DInstanceManager::_global_ptr;
////////////////////////////////////////////////////////////////////
P3DInstanceManager::
P3DInstanceManager() {
cerr << "creating instance manager\n";
_unique_session_index = 0;
_current_python = NULL;
_request_seq = 0;
#ifdef _WIN32
@ -172,47 +171,6 @@ wait_request() {
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::start_python
// Access: Public
// Description: Returns a P3DPython object corresponding to the
// requested Python version. The P3DPython object is
// loaded into the current memory address space; because
// of Python version conflicts, only one version of
// Python may be resident at a given time. Thus,
// calling this will implicitly terminate any running
// instances that are currently using a different
// version of Python.
//
// This may return NULL if the Python interpreter cannot
// be successfully started for some reason.
////////////////////////////////////////////////////////////////////
P3DPython *P3DInstanceManager::
start_python(const string &python_version) {
if (_current_python != NULL && !_current_python->is_valid()) {
// The current python has gone bad.
delete _current_python;
_current_python = NULL;
}
if (_current_python != NULL && _current_python->get_python_version() != python_version) {
// The current python is the wrong version. We should kill it and
// all of the instances using it. TODO.
return NULL;
}
if (_current_python == NULL) {
_current_python = new P3DPython(python_version);
if (!_current_python->is_valid()) {
// Couldn't successfully start Python.
delete _current_python;
_current_python = NULL;
}
}
return _current_python;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::get_unique_session_index
// Access: Public

View File

@ -22,7 +22,6 @@
class P3DInstance;
class P3DSession;
class P3DPython;
////////////////////////////////////////////////////////////////////
// Class : P3DInstanceManager
@ -52,8 +51,6 @@ public:
P3DInstance *check_request();
void wait_request();
P3DPython *start_python(const string &python_version);
INLINE int get_num_instances() const;
INLINE const string &get_dll_filename() const;
@ -73,7 +70,6 @@ private:
typedef map<string, P3DSession *> Sessions;
Sessions _sessions;
P3DPython *_current_python;
int _unique_session_index;
// Implements a condition-var like behavior.

View File

@ -1,49 +0,0 @@
// Filename: p3dPython.I
// Created by: drose (04Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: P3DPython::get_python_version
// Access: Public
// Description: Returns a string that uniquely identifies this
// Python version. You cannot have two different
// versions of Python loaded simultaneously within the
// same address space.
////////////////////////////////////////////////////////////////////
INLINE const string &P3DPython::
get_python_version() const {
return _python_version;
}
////////////////////////////////////////////////////////////////////
// Function: P3DPython::get_num_sessions
// Access: Public
// Description: Returns the number of sessions currently sharing
// this Python address space.
////////////////////////////////////////////////////////////////////
INLINE int P3DPython::
get_num_sessions() const {
return _sessions.size();
}
////////////////////////////////////////////////////////////////////
// Function: P3DPython::is_valid
// Access: Public
// Description: Returns true if the Python interpreter is up and
// ready to run code, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool P3DPython::
is_valid() const {
return _is_valid;
}

View File

@ -1,372 +0,0 @@
// Filename: p3dPython.cxx
// Created by: drose (04Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#include "p3dPython.h"
#include "p3dSession.h"
#include "p3dInstanceManager.h"
#include <malloc.h>
////////////////////////////////////////////////////////////////////
// Function: P3DPython::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DPython::
P3DPython(const string &python_version) {
_python_version = python_version;
_is_valid = false;
_runPackedApp = NULL;
_setupWindow = NULL;
_run = NULL;
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_program_name = inst_mgr->get_dll_filename();
size_t slash = _program_name.rfind('/');
#ifdef _WIN32
// Windows tolerates slashes or backslashes. Look for the rightmost
// of either.
size_t backslash = _program_name.rfind('\\');
if (backslash != string::npos && (slash == string::npos || backslash > slash)) {
slash = backslash;
}
#endif
// _root_dir = _program_name.substr(0, slash);
_root_dir = "C:/p3drun";
_py_argc = 1;
_py_argv = (char **)malloc(2 * sizeof(char *));
_py_argv[0] = (char *)_program_name.c_str();
_py_argv[1] = NULL;
// Guess everything's OK.
_is_valid = true;
}
////////////////////////////////////////////////////////////////////
// Function: P3DPython::Destructor
// Access: Public
// Description: Terminates the python by shutting down Python and
// stopping the subprocess.
////////////////////////////////////////////////////////////////////
P3DPython::
~P3DPython() {
if (_python_module != NULL) {
if (_is_valid) {
Py_XDECREF(_runPackedApp);
Py_XDECREF(_setupWindow);
Py_XDECREF(_run);
}
Py_Finalize();
FreeLibrary(_python_module);
_python_module = NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DPython::start_session
// Access: Public
// Description: Starts the indicated session running within the
// Python interpreter. For the moment, each session
// must contain only a single P3DInstance, which is also
// started.
////////////////////////////////////////////////////////////////////
void P3DPython::
start_session(P3DSession *session, P3DInstance *inst) {
assert(_is_valid);
assert(session->_python == NULL);
assert(session->get_python_version() == _python_version);
// For now, only one session at a time is allowed.
assert(_sessions.empty());
session->_python = this;
bool inserted = _sessions.insert(session).second;
assert(inserted);
_inst = inst;
spawn_thread();
}
////////////////////////////////////////////////////////////////////
// Function: P3DPython::terminate_session
// Access: Public
// Description: Removes the indicated session from the python, and
// stops it. It is an error if the session is not
// already running on this python.
////////////////////////////////////////////////////////////////////
void P3DPython::
terminate_session(P3DSession *session) {
join_thread();
if (session->_python == this) {
session->_python = NULL;
_sessions.erase(session);
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DPython::spawn_thread
// Access: Private
// Description: Starts the sub-thread. All calls to Python are made
// within the sub-thread.
////////////////////////////////////////////////////////////////////
void P3DPython::
spawn_thread() {
#ifdef _WIN32
_thread = CreateThread(NULL, 0, &win_thread_func, this, 0, NULL);
#endif
}
////////////////////////////////////////////////////////////////////
// Function: P3DPython::join_thread
// Access: Private
// Description: Waits for the sub-thread to stop.
////////////////////////////////////////////////////////////////////
void P3DPython::
join_thread() {
cerr << "waiting for thread\n";
#ifdef _WIN32
assert(_thread != NULL);
WaitForSingleObject(_thread, INFINITE);
CloseHandle(_thread);
_thread = NULL;
#endif
cerr << "done waiting for thread\n";
}
////////////////////////////////////////////////////////////////////
// Function: P3DPython::tr_init_python
// Access: Private
// Description: Initializes the Python interpreter. This method, and
// all methods that interact with Python, is called only
// within the sub-thread. Returns true if successful,
// false on failure.
////////////////////////////////////////////////////////////////////
bool P3DPython::
tr_init_python() {
#ifdef _WIN32
string python_dll_filename = _root_dir + string("/python24.dll");
_python_module = LoadLibrary(python_dll_filename.c_str());
if (_python_module == NULL) {
// Couldn't load Python.
cerr << "Unable to load " << python_dll_filename << "\n";
return false;
}
Py_SetProgramName = (Py_SetProgramName_func *)GetProcAddress(_python_module, "Py_SetProgramName");
PySys_SetArgv = (PySys_SetArgv_func *)GetProcAddress(_python_module, "PySys_SetArgv");
Py_SetPythonHome = (Py_SetPythonHome_func *)GetProcAddress(_python_module, "Py_SetPythonHome");
Py_Initialize = (Py_Initialize_func *)GetProcAddress(_python_module, "Py_Initialize");
Py_Finalize = (Py_Finalize_func *)GetProcAddress(_python_module, "Py_Finalize");
PyEval_InitThreads = (PyEval_InitThreads_func *)GetProcAddress(_python_module, "PyEval_InitThreads");
PyEval_AcquireLock = (PyEval_AcquireLock_func *)GetProcAddress(_python_module, "PyEval_AcquireLock");
PyEval_ReleaseLock = (PyEval_ReleaseLock_func *)GetProcAddress(_python_module, "PyEval_ReleaseLock");
PyRun_SimpleString = (PyRun_SimpleString_func *)GetProcAddress(_python_module, "PyRun_SimpleString");
PyErr_Print = (PyErr_Print_func *)GetProcAddress(_python_module, "PyErr_Print");
Py_XDECREF = (Py_XDECREF_func *)GetProcAddress(_python_module, "Py_DecRef");
PyImport_ImportModule = (PyImport_ImportModule_func *)GetProcAddress(_python_module, "PyImport_ImportModule");
PyObject_SetAttrString = (PyObject_SetAttrString_func *)GetProcAddress(_python_module, "PyObject_SetAttrString");
PyObject_GetAttrString = (PyObject_GetAttrString_func *)GetProcAddress(_python_module, "PyObject_GetAttrString");
Py_BuildValue = (Py_BuildValue_func *)GetProcAddress(_python_module, "Py_BuildValue");
PyObject_CallFunction = (PyObject_CallFunction_func *)GetProcAddress(_python_module, "PyObject_CallFunction");
#endif // _WIN32
if (Py_SetProgramName == NULL ||
PySys_SetArgv == NULL ||
Py_SetPythonHome == NULL ||
Py_Initialize == NULL ||
Py_Finalize == NULL ||
PyEval_InitThreads == NULL ||
PyEval_AcquireLock == NULL ||
PyEval_ReleaseLock == NULL ||
PyRun_SimpleString == NULL ||
PyErr_Print == NULL ||
Py_XDECREF == NULL ||
PyImport_ImportModule == NULL ||
PyObject_SetAttrString == NULL ||
PyObject_GetAttrString == NULL ||
Py_BuildValue == NULL ||
PyObject_CallFunction == NULL) {
// Couldn't get all of the needed Python functions for some reason.
cerr << "Py_SetProgramName = " << Py_SetProgramName << "\n"
<< "PySys_SetArgv = " << PySys_SetArgv << "\n"
<< "Py_SetPythonHome = " << Py_SetPythonHome << "\n"
<< "Py_Initialize = " << Py_Initialize << "\n"
<< "Py_Finalize = " << Py_Finalize << "\n"
<< "PyEval_InitThreads = " << PyEval_InitThreads << "\n"
<< "PyEval_AcquireLock = " << PyEval_AcquireLock << "\n"
<< "PyEval_ReleaseLock = " << PyEval_ReleaseLock << "\n"
<< "PyRun_SimpleString = " << PyRun_SimpleString << "\n"
<< "PyErr_Print = " << PyErr_Print << "\n"
<< "Py_XDECREF = " << Py_XDECREF << "\n"
<< "PyImport_ImportModule = " << PyImport_ImportModule << "\n"
<< "PyObject_SetAttrString = " << PyObject_SetAttrString << "\n"
<< "PyObject_GetAttrString = " << PyObject_GetAttrString << "\n"
<< "Py_BuildValue = " << Py_BuildValue << "\n"
<< "PyObject_CallFunction = " << PyObject_CallFunction << "\n"
<< "\n";
FreeLibrary(_python_module);
_python_module = NULL;
return false;
}
// All right, initialize Python.
Py_SetProgramName((char *)_program_name.c_str());
Py_Initialize();
Py_SetPythonHome((char *)_root_dir.c_str());
PySys_SetArgv(_py_argc, _py_argv);
// Set sys.path appropriately.
PyObject *sys = PyImport_ImportModule("sys");
if (sys == NULL) {
PyErr_Print();
return false;
}
PyObject *path = Py_BuildValue("[s]", _root_dir.c_str());
PyObject_SetAttrString(sys, "path", path);
Py_XDECREF(path);
Py_XDECREF(sys);
// Now load runappmf.pyd.
PyObject *runappmf = PyImport_ImportModule("runappmf");
if (runappmf == NULL) {
PyErr_Print();
return false;
}
Py_XDECREF(runappmf);
// And get the pointers to the functions needed within the module.
PyObject *appmf = PyImport_ImportModule("direct.showbase.RunAppMF");
if (appmf == NULL) {
PyErr_Print();
return false;
}
_runPackedApp = PyObject_GetAttrString(appmf, "runPackedApp");
if (_runPackedApp == NULL) {
PyErr_Print();
return false;
}
_setupWindow = PyObject_GetAttrString(appmf, "setupWindow");
if (_setupWindow == NULL) {
PyErr_Print();
return false;
}
_run = PyObject_GetAttrString(appmf, "run");
if (_run == NULL) {
PyErr_Print();
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: P3DPython::tr_thread_run
// Access: Private
// Description: The main function for the sub-thread.
////////////////////////////////////////////////////////////////////
void P3DPython::
tr_thread_run() {
bool valid = true;
if (!tr_init_python()) {
// Couldn't get Python going.
valid = false;
}
if (valid) {
string window_type;
switch (_inst->_window_type) {
case P3D_WT_embedded:
window_type = "embedded";
break;
case P3D_WT_toplevel:
window_type = "toplevel";
break;
case P3D_WT_fullscreen:
window_type = "fullscreen";
break;
case P3D_WT_hidden:
window_type = "hidden";
break;
}
PyObject *result = PyObject_CallFunction
(_setupWindow, "siiiii", window_type.c_str(),
_inst->_win_x, _inst->_win_y,
_inst->_win_width, _inst->_win_height,
#ifdef _WIN32
(int)(_inst->_parent_window._hwnd)
#endif
);
if (result == NULL) {
PyErr_Print();
valid = false;
}
Py_XDECREF(result);
}
if (valid) {
PyObject *result = PyObject_CallFunction(_runPackedApp, "[s]", _inst->get_p3d_filename().c_str());
if (result == NULL) {
PyErr_Print();
valid = false;
}
Py_XDECREF(result);
}
_is_valid = valid;
// Maybe signal the parent that we're ready?
if (valid) {
// Call run(). This function won't return until the p3d app
// exits.
PyObject *result = PyObject_CallFunction(_run, "");
if (result == NULL) {
PyErr_Print();
}
Py_XDECREF(result);
}
// The instance has finished.
P3D_request *request = new P3D_request;
request->_instance = _inst;
request->_request_type = P3D_RT_stop;
_inst->add_request(request);
}
#ifdef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DPython::win_thread_func
// Access: Private, Static
// Description: The Windows flavor of the thread callback function.
////////////////////////////////////////////////////////////////////
DWORD P3DPython::
win_thread_func(LPVOID data) {
((P3DPython *)data)->tr_thread_run();
return 0;
}
#endif

View File

@ -1,125 +0,0 @@
// Filename: p3dPython.h
// Created by: drose (04Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 P3DPYTHON_H
#define P3DPYTHON_H
#include "p3d_plugin_common.h"
////////////////////////////////////////////////////////////////////
// Class : P3DPython
// Description : Corresponds to a single instance of the Python
// interpreter. Since Python is single-threaded and
// global-namespace, there can only be one Python
// instance in a given address space.
//
// Note that, due to Python's "NewInterpreter"
// mechanism, it *might* be possible to have multiple
// virtual interpreters within a single Python instance.
// This will require some work to integrate successfully
// with Panda, though, so it is not currently
// implemented.
////////////////////////////////////////////////////////////////////
class P3DPython {
public:
P3DPython(const string &python_version);
~P3DPython();
INLINE const string &get_python_version() const;
void start_session(P3DSession *session, P3DInstance *inst);
void terminate_session(P3DSession *session);
INLINE int get_num_sessions() const;
INLINE bool is_valid() const;
private:
void spawn_thread();
void join_thread();
private:
// Methods that run only within the sub-thread.
bool tr_init_python();
void tr_thread_run();
#ifdef _WIN32
static DWORD WINAPI win_thread_func(LPVOID data);
#endif
private:
string _python_version;
bool _is_valid;
string _root_dir;
string _program_name;
int _py_argc;
char **_py_argv;
typedef set<P3DSession *> Sessions;
Sessions _sessions;
// Temporary.
P3DInstance *_inst;
#ifdef _WIN32
HMODULE _python_module;
HANDLE _thread;
#endif
typedef struct _object PyObject;
PyObject *_runPackedApp;
PyObject *_setupWindow;
PyObject *_run;
// Pointers to dynamically-loaded Python functions.
typedef void Py_SetProgramName_func(char *name);
typedef void PySys_SetArgv_func(int argc, char **argv);
typedef void Py_SetPythonHome_func(char *name);
typedef void Py_Initialize_func(void);
typedef void Py_Finalize_func(void);
typedef void PyEval_InitThreads_func(void);
typedef void PyEval_AcquireLock_func(void);
typedef void PyEval_ReleaseLock_func(void);
typedef int PyRun_SimpleString_func(const char *command);
typedef void PyErr_Print_func(void);
typedef void Py_XDECREF_func(PyObject *o);
typedef PyObject *PyImport_ImportModule_func(const char *name);
typedef int PyObject_SetAttrString_func(PyObject *o, const char *attr_name, PyObject *v);
typedef PyObject *PyObject_GetAttrString_func(PyObject *o, const char *attr_name);
typedef PyObject *Py_BuildValue_func(const char *format, ...);
typedef PyObject *PyObject_CallFunction_func(PyObject *callable, char *format, ...);
Py_SetProgramName_func *Py_SetProgramName;
PySys_SetArgv_func *PySys_SetArgv;
Py_SetPythonHome_func *Py_SetPythonHome;
Py_Initialize_func *Py_Initialize;
Py_Finalize_func *Py_Finalize;
PyEval_InitThreads_func *PyEval_InitThreads;
PyEval_AcquireLock_func *PyEval_AcquireLock;
PyEval_ReleaseLock_func *PyEval_ReleaseLock;
PyRun_SimpleString_func *PyRun_SimpleString;
PyErr_Print_func *PyErr_Print;
Py_XDECREF_func *Py_XDECREF;
PyImport_ImportModule_func *PyImport_ImportModule;
PyObject_SetAttrString_func *PyObject_SetAttrString;
PyObject_GetAttrString_func *PyObject_GetAttrString;
Py_BuildValue_func *Py_BuildValue;
PyObject_CallFunction_func *PyObject_CallFunction;
};
#include "p3dPython.I"
#endif

View File

@ -0,0 +1,14 @@
// Filename: p3dPythonRun.I
// Created by: drose (05Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,308 @@
// Filename: p3dPythonRun.cxx
// Created by: drose (05Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////
#include "p3dPythonRun.h"
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DPythonRun::
P3DPythonRun(int argc, char *argv[]) {
_read_thread_alive = false;
INIT_LOCK(_commands_lock);
// Open the pipe streams with the input and output handles from the
// parent.
#ifdef _WIN32
HANDLE read = GetStdHandle(STD_INPUT_HANDLE);
HANDLE write = GetStdHandle(STD_OUTPUT_HANDLE);
if (!SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE)) {
cerr << "unable to reset input handle\n";
}
if (!SetStdHandle(STD_OUTPUT_HANDLE, INVALID_HANDLE_VALUE)) {
cerr << "unable to reset input handle\n";
}
_pipe_read.open_read(read);
_pipe_write.open_write(write);
#endif // _WIN32
if (!_pipe_read) {
cerr << "unable to open read pipe\n";
}
if (!_pipe_write) {
cerr << "unable to open write pipe\n";
}
spawn_read_thread();
_program_name = argv[0];
_py_argc = 1;
_py_argv = (char **)malloc(2 * sizeof(char *));
_py_argv[0] = argv[0];
_py_argv[1] = NULL;
// Initialize Python.
Py_SetProgramName((char *)_program_name.c_str());
Py_Initialize();
PySys_SetArgv(_py_argc, _py_argv);
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DPythonRun::
~P3DPythonRun() {
Py_Finalize();
join_read_thread();
DESTROY_LOCK(_commands_lock);
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::run_python
// Access: Public
// Description: Runs the embedded Python process. This method does
// not return until the plugin is ready to exit.
////////////////////////////////////////////////////////////////////
bool P3DPythonRun::
run_python() {
// Now load runappmf.pyd.
PyObject *runappmf = PyImport_ImportModule("runappmf");
if (runappmf == NULL) {
PyErr_Print();
return false;
}
Py_DECREF(runappmf);
// And get the pointers to the functions needed within the module.
PyObject *appmf = PyImport_ImportModule("direct.showbase.RunAppMF");
if (appmf == NULL) {
PyErr_Print();
return false;
}
_runPackedApp = PyObject_GetAttrString(appmf, "runPackedApp");
if (_runPackedApp == NULL) {
PyErr_Print();
return false;
}
_setupWindow = PyObject_GetAttrString(appmf, "setupWindow");
if (_setupWindow == NULL) {
PyErr_Print();
return false;
}
Py_DECREF(appmf);
// Construct a Python wrapper around our check_comm() method.
static PyMethodDef p3dpython_methods[] = {
{"check_comm", P3DPythonRun::py_check_comm, METH_VARARGS,
"Check for communications to and from the plugin host."},
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyObject *p3dpython = Py_InitModule("p3dpython", p3dpython_methods);
if (p3dpython == NULL) {
PyErr_Print();
return false;
}
PyObject *check_comm = PyObject_GetAttrString(p3dpython, "check_comm");
if (check_comm == NULL) {
PyErr_Print();
return false;
}
// Now add check_comm() as a Python task.
PyObject *add_check_comm = PyObject_GetAttrString(appmf, "add_check_comm");
if (add_check_comm == NULL) {
PyErr_Print();
return false;
}
PyObject *task = PyObject_CallFunction
(add_check_comm, "Ol", check_comm, (long)this);
if (task == NULL) {
PyErr_Print();
return false;
}
Py_DECREF(task);
Py_DECREF(add_check_comm);
Py_DECREF(check_comm);
// Finally, get lost in taskMgr.run().
PyObject *taskMgr = PyObject_GetAttrString(appmf, "taskMgr");
if (taskMgr == NULL) {
PyErr_Print();
return false;
}
cerr << "calling run()\n";
PyObject *done = PyObject_CallMethod(taskMgr, "run", "");
if (done == NULL) {
PyErr_Print();
return false;
}
Py_DECREF(done);
cerr << "done calling run()\n";
Py_DECREF(taskMgr);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::handle_command
// Access: Private
// Description: Handles a command received from the plugin host, via
// an XML syntax on the wire.
////////////////////////////////////////////////////////////////////
void P3DPythonRun::
handle_command(TiXmlDocument *doc) {
cerr << "got command: " << *doc << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::check_comm
// Access: Private
// Description: This method is added to the Python task manager (via
// py_check_comm, below) so that it gets a call every
// frame. Its job is to check for commands received
// from, and requests to be delivered to, the plugin
// host in the parent process.
////////////////////////////////////////////////////////////////////
void P3DPythonRun::
check_comm() {
ACQUIRE_LOCK(_commands_lock);
while (!_commands.empty()) {
TiXmlDocument *doc = _commands.front();
_commands.pop_front();
assert(_commands.size() < 10);
RELEASE_LOCK(_commands_lock);
handle_command(doc);
delete doc;
ACQUIRE_LOCK(_commands_lock);
}
RELEASE_LOCK(_commands_lock);
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::py_check_comm
// Access: Private, Static
// Description: This method is added as a Python task function on the
// task manager. It is the Python wrapper around the
// check_comm method.
////////////////////////////////////////////////////////////////////
PyObject *P3DPythonRun::
py_check_comm(PyObject *, PyObject *args) {
long this_int;
PyObject *task;
if (!PyArg_ParseTuple(args, "lO:check_comm", &this_int, &task)) {
return NULL;
}
P3DPythonRun *self = (P3DPythonRun *)(void *)this_int;
self->check_comm();
return PyObject_GetAttrString(task, "cont");
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::spawn_read_thread
// Access: Private
// Description: Starts the read thread. This thread is responsible
// for reading the standard input socket for XML
// commands and storing them in the _commands queue.
////////////////////////////////////////////////////////////////////
void P3DPythonRun::
spawn_read_thread() {
assert(!_read_thread_alive);
_read_thread_alive = true;
#ifdef _WIN32
_read_thread = CreateThread(NULL, 0, &win_rt_thread_run, this, 0, NULL);
#endif
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::join_read_thread
// Access: Private
// Description: Waits for the read thread to stop.
////////////////////////////////////////////////////////////////////
void P3DPythonRun::
join_read_thread() {
cerr << "waiting for thread\n";
_read_thread_alive = false;
#ifdef _WIN32
assert(_read_thread != NULL);
WaitForSingleObject(_read_thread, INFINITE);
CloseHandle(_read_thread);
_read_thread = NULL;
#endif
cerr << "done waiting for thread\n";
}
////////////////////////////////////////////////////////////////////
// Function: P3DPythonRun::rt_thread_run
// Access: Private
// Description: The main function for the read thread.
////////////////////////////////////////////////////////////////////
void P3DPythonRun::
rt_thread_run() {
while (_read_thread_alive) {
TiXmlDocument *doc = new TiXmlDocument;
_pipe_read >> *doc;
if (!_pipe_read || _pipe_read.eof()) {
// Some error on reading. Abort.
cerr << "Error on reading.\n";
return;
}
// Successfully read an XML document. Feed it to the parent.
ACQUIRE_LOCK(_commands_lock);
_commands.push_back(doc);
RELEASE_LOCK(_commands_lock);
}
}
#ifdef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DPython::win_rt_thread_run
// Access: Private, Static
// Description: The Windows flavor of the thread callback function.
////////////////////////////////////////////////////////////////////
DWORD P3DPythonRun::
win_rt_thread_run(LPVOID data) {
((P3DPythonRun *)data)->rt_thread_run();
return 0;
}
#endif
////////////////////////////////////////////////////////////////////
// Function: main
// Description: Starts the program running.
////////////////////////////////////////////////////////////////////
int
main(int argc, char *argv[]) {
P3DPythonRun run(argc, argv);
if (!run.run_python()) {
cerr << "Couldn't initialize Python.\n";
return 1;
}
return 0;
}

View File

@ -0,0 +1,94 @@
// Filename: p3dPythonRun.h
// Created by: drose (05Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 P3DPYTHONRUN_H
#define P3DPYTHONRUN_H
#include <iostream>
#include <string>
#include <deque>
#include <assert.h>
#include <Python.h>
#include <tinyxml.h>
#include "p3d_lock.h"
#include "handleStream.h"
#ifdef _WIN32
#include <windows.h>
#endif
using namespace std;
////////////////////////////////////////////////////////////////////
// Class : P3DPythonRun
// Description : This class is used to run, and communicate with,
// embedded Python in a sub-process. It is compiled and
// launched as a separate executable from the p3d_plugin
// dll, because that's the only way Windows can launch a
// sub-process, and also because it makes it possible to
// compile-time link with the Python dll, instead of
// having to go through the clumsy dynamic-loading
// interface.
//
// Communication is via XML files exchanged via
// anonymous pipes from the parent process. This
// executable is not designed to stand alone.
////////////////////////////////////////////////////////////////////
class P3DPythonRun {
public:
P3DPythonRun(int argc, char *argv[]);
~P3DPythonRun();
bool run_python();
private:
void handle_command(TiXmlDocument *doc);
void check_comm();
static PyObject *py_check_comm(PyObject *, PyObject *args);
void spawn_read_thread();
void join_read_thread();
private:
// This method runs only within the read thread.
void rt_thread_run();
#ifdef _WIN32
static DWORD WINAPI win_rt_thread_run(LPVOID data);
#endif
private:
typedef deque<TiXmlDocument *> Commands;
Commands _commands;
LOCK _commands_lock;
HandleStream _pipe_read;
HandleStream _pipe_write;
bool _read_thread_alive;
#ifdef _WIN32
HANDLE _read_thread;
#endif
string _program_name;
int _py_argc;
char **_py_argv;
PyObject *_runPackedApp;
PyObject *_setupWindow;
};
#include "p3dPythonRun.I"
#endif

View File

@ -15,6 +15,7 @@
#include "p3dSession.h"
#include "p3dInstance.h"
#include "p3dInstanceManager.h"
#include <tinyxml.h>
#include <malloc.h>
@ -31,7 +32,92 @@ P3DSession::
P3DSession(P3DInstance *inst) {
_session_key = inst->get_session_key();
_python_version = inst->get_python_version();
_python = NULL;
_python_root_dir = "C:/p3drun";
string p3dpython = "c:/cygwin/home/drose/player/direct/built/bin/p3dpython.exe";
// Populate the new process' environment.
string env;
// These are the enviroment variables we forward from the current
// environment, if they are set.
const char *keep[] = {
"TEMP", "HOME", "USER",
NULL
};
for (int ki = 0; keep[ki] != NULL; ++ki) {
char *value = getenv(keep[ki]);
if (value != NULL) {
env += keep[ki];
env += "=";
env += value;
env += '\0';
}
}
// Define some new environment variables.
env += "PATH=";
env += _python_root_dir;
env += '\0';
env += "PYTHONPATH=";
env += _python_root_dir;
env += '\0';
// Create a bi-directional pipe to communicate with the sub-process.
#ifdef _WIN32
cerr << "creating pipe\n";
HANDLE orig_stdin = GetStdHandle(STD_INPUT_HANDLE);
HANDLE orig_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
SECURITY_ATTRIBUTES inheritable;
inheritable.nLength = sizeof(inheritable);
inheritable.lpSecurityDescriptor = NULL;
inheritable.bInheritHandle = true;
HANDLE r_to, w_to, r_from, w_from;
// Create the pipe to the process.
if (!CreatePipe(&r_to, &w_to, &inheritable, 0)) {
cerr << "failed to create pipe\n";
} else {
SetStdHandle(STD_INPUT_HANDLE, r_to);
}
// Create the pipe from the process.
if (!CreatePipe(&r_from, &w_from, &inheritable, 0)) {
cerr << "failed to create pipe\n";
} else {
SetStdHandle(STD_OUTPUT_HANDLE, w_from);
}
cerr << "creating process " << p3dpython << "\n";
BOOL result = CreateProcess
(p3dpython.c_str(), NULL, NULL, NULL, TRUE, 0,
/* (void *)env.c_str() */NULL, _python_root_dir.c_str(), NULL, &_p3dpython);
cerr << "result = " << result << "\n";
_started_p3dpython = (result != 0);
if (!_started_p3dpython) {
cerr << "Failed to create process.\n";
} else {
cerr << "Created process: " << _p3dpython.dwProcessId << "\n";
}
CloseHandle(r_to);
CloseHandle(w_from);
SetStdHandle(STD_INPUT_HANDLE, orig_stdin);
SetStdHandle(STD_OUTPUT_HANDLE, orig_stdout);
_pipe_read.open_read(r_from);
_pipe_write.open_write(w_to);
#endif // _WIN32
if (!_pipe_read) {
cerr << "unable to open read pipe\n";
}
if (!_pipe_write) {
cerr << "unable to open write pipe\n";
}
}
////////////////////////////////////////////////////////////////////
@ -42,6 +128,14 @@ P3DSession(P3DInstance *inst) {
////////////////////////////////////////////////////////////////////
P3DSession::
~P3DSession() {
if (_started_p3dpython) {
cerr << "Terminating process.\n";
// Messy. Shouldn't use TerminateProcess unless necessary.
TerminateProcess(_p3dpython.hProcess, 2);
CloseHandle(_p3dpython.hProcess);
CloseHandle(_p3dpython.hThread);
}
}
////////////////////////////////////////////////////////////////////
@ -56,7 +150,6 @@ P3DSession::
////////////////////////////////////////////////////////////////////
void P3DSession::
start_instance(P3DInstance *inst) {
assert(_python == NULL);
assert(inst->_session == NULL);
assert(inst->get_session_key() == _session_key);
assert(inst->get_python_version() == _python_version);
@ -66,10 +159,21 @@ start_instance(P3DInstance *inst) {
assert(inserted);
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
TiXmlDocument doc;
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
TiXmlElement *element = new TiXmlElement("instance");
doc.LinkEndChild(decl);
doc.LinkEndChild(element);
_pipe_write << doc;
/*
P3DPython *python = inst_mgr->start_python(_python_version);
if (python != NULL) {
python->start_session(this, inst);
}
*/
}
////////////////////////////////////////////////////////////////////
@ -81,10 +185,12 @@ start_instance(P3DInstance *inst) {
////////////////////////////////////////////////////////////////////
void P3DSession::
terminate_instance(P3DInstance *inst) {
/*
if (_python != NULL) {
_python->terminate_session(this);
assert(_python == NULL);
}
*/
if (inst->_session == this) {
inst->_session = NULL;

View File

@ -16,6 +16,7 @@
#define P3DSESSION_H
#include "p3d_plugin_common.h"
#include "handleStream.h"
#include <set>
@ -45,12 +46,18 @@ private:
string _session_key;
string _python_version;
P3DPython *_python;
string _python_root_dir;
typedef set<P3DInstance *> Instances;
Instances _instances;
friend class P3DPython;
// Members for communicating with the p3dpython child process.
bool _started_p3dpython;
#ifdef _WIN32
PROCESS_INFORMATION _p3dpython;
#endif
HandleStream _pipe_read;
HandleStream _pipe_write;
};
#include "p3dSession.I"

30
direct/src/plugin/p3d_lock.h Executable file
View File

@ -0,0 +1,30 @@
// Filename: p3d_lock.h
// Created by: drose (05Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 P3D_LOCK_H
#define P3D_LOCK_H
// Provides some simple macros that implement platform-independet
// mutex locks.
#ifdef _WIN32
#define LOCK CRITICAL_SECTION
#define INIT_LOCK(lock) InitializeCriticalSection(&(lock))
#define ACQUIRE_LOCK(lock) EnterCriticalSection(&(lock))
#define RELEASE_LOCK(lock) LeaveCriticalSection(&(lock))
#define DESTROY_LOCK(lock) DeleteCriticalSection(&(lock))
#endif
#endif

View File

@ -15,13 +15,15 @@
#ifndef P3D_PLUGIN_COMMON
#define P3D_PLUGIN_COMMON
// This header file is included by all C++ files in this directory; it
// provides some common symbol declarations.
// This header file is included by all C++ files in this directory
// that contribute to p3d_plugin; provides some common symbol
// declarations.
#define P3D_FUNCTION_PROTOTYPES
#define BUILDING_P3D_PLUGIN
#include "p3d_plugin.h"
#include "p3d_lock.h"
#include <iostream>
#include <string>
@ -31,13 +33,5 @@ using namespace std;
#define INLINE inline
#ifdef _WIN32
#define LOCK CRITICAL_SECTION
#define INIT_LOCK(lock) InitializeCriticalSection(&(lock))
#define ACQUIRE_LOCK(lock) EnterCriticalSection(&(lock))
#define RELEASE_LOCK(lock) LeaveCriticalSection(&(lock))
#define DESTROY_LOCK(lock) DeleteCriticalSection(&(lock))
#endif
#endif

View File

@ -1,5 +1,4 @@
#include "p3d_plugin.cxx"
#include "p3dInstance.cxx"
#include "p3dInstanceManager.cxx"
#include "p3dPython.cxx"
#include "p3dSession.cxx"

View File

@ -10,8 +10,9 @@ Code given out at the 1985 UNIFORUM conference in Dallas.
#include "wingetopt.h"
#include <stdio.h>
#include <string.h>
#define NULL 0
//#define NULL 0
#define EOF (-1)
#define ERR(s, c) if(opterr){\
char errbuf[2];\

View File

@ -15,6 +15,7 @@ import sys
from direct.showbase import VFSImporter
from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, getModelPath
from direct.stdpy import file
from direct.task.TaskManagerGlobal import taskMgr
import os
import __builtin__
@ -144,8 +145,13 @@ def setupWindow(windowType, x, y, width, height, parent):
loadPrcFileData("setupWindow", data)
def run():
taskMgr.run()
def add_check_comm(func, this):
""" This function is provided just a convenience for
p3dPythonRun.cxx. It adds the indicated function to the task
manager with the appropriate parameters for the check_comm
task. """
return taskMgr.add(func, "check_comm", sort = -50, extraArgs = [this],
appendTask = True)
if __name__ == '__main__':
try: