Pārlūkot izejas kodu

more plugin work

David Rose 16 gadi atpakaļ
vecāks
revīzija
027e5fdc9e

+ 16 - 3
direct/src/plugin/Sources.pp

@@ -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
 

+ 74 - 0
direct/src/plugin/handleStream.I

@@ -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();
+}

+ 15 - 0
direct/src/plugin/handleStream.cxx

@@ -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"

+ 42 - 0
direct/src/plugin/handleStream.h

@@ -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

+ 14 - 0
direct/src/plugin/handleStreamBuf.I

@@ -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."
+//
+////////////////////////////////////////////////////////////////////
+

+ 339 - 0
direct/src/plugin/handleStreamBuf.cxx

@@ -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;
+}

+ 64 - 0
direct/src/plugin/handleStreamBuf.h

@@ -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

+ 3 - 4
direct/src/plugin/p3dInstance.cxx

@@ -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;

+ 0 - 1
direct/src/plugin/p3dInstance.h

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

+ 1 - 43
direct/src/plugin/p3dInstanceManager.cxx

@@ -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

+ 0 - 4
direct/src/plugin/p3dInstanceManager.h

@@ -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.

+ 0 - 49
direct/src/plugin/p3dPython.I

@@ -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;
-}

+ 0 - 372
direct/src/plugin/p3dPython.cxx

@@ -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

+ 0 - 125
direct/src/plugin/p3dPython.h

@@ -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

+ 14 - 0
direct/src/plugin/p3dPythonRun.I

@@ -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."
+//
+////////////////////////////////////////////////////////////////////
+

+ 308 - 0
direct/src/plugin/p3dPythonRun.cxx

@@ -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;
+}

+ 94 - 0
direct/src/plugin/p3dPythonRun.h

@@ -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
+

+ 108 - 2
direct/src/plugin/p3dSession.cxx

@@ -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;

+ 9 - 2
direct/src/plugin/p3dSession.h

@@ -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 - 0
direct/src/plugin/p3d_lock.h

@@ -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
+

+ 4 - 10
direct/src/plugin/p3d_plugin_common.h

@@ -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
 

+ 0 - 1
direct/src/plugin/p3d_plugin_composite1.cxx

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

+ 2 - 1
direct/src/plugin/wingetopt.c

@@ -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];\

+ 8 - 2
direct/src/showbase/RunAppMF.py

@@ -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: