Browse Source

more plugin work

David Rose 16 years ago
parent
commit
027e5fdc9e

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

@@ -3,24 +3,25 @@
 #define BUILD_DIRECTORY $[HAVE_P3D_PLUGIN]
 #define BUILD_DIRECTORY $[HAVE_P3D_PLUGIN]
 
 
 #begin lib_target
 #begin lib_target
+  #define USE_PACKAGES tinyxml
   #define TARGET p3d_plugin
   #define TARGET p3d_plugin
 
 
   #define COMBINED_SOURCES \
   #define COMBINED_SOURCES \
     $[TARGET]_composite1.cxx
     $[TARGET]_composite1.cxx
 
 
   #define SOURCES \
   #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 \
     p3d_plugin_common.h \
     p3dInstance.h p3dInstance.I \
     p3dInstance.h p3dInstance.I \
     p3dInstanceManager.h p3dInstanceManager.I \
     p3dInstanceManager.h p3dInstanceManager.I \
-    p3dPython.h p3dPython.I \
     p3dSession.h p3dSession.I
     p3dSession.h p3dSession.I
 
 
   #define INCLUDED_SOURCES \
   #define INCLUDED_SOURCES \
     p3d_plugin.cxx \
     p3d_plugin.cxx \
     p3dInstance.cxx \
     p3dInstance.cxx \
     p3dInstanceManager.cxx \
     p3dInstanceManager.cxx \
-    p3dPython.cxx \
     p3dSession.cxx
     p3dSession.cxx
 
 
   #define INSTALL_HEADERS \
   #define INSTALL_HEADERS \
@@ -28,6 +29,18 @@
 
 
 #end lib_target
 #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
 #begin bin_target
   #define TARGET panda3d
   #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)
   _parent_window(parent_window)
 {
 {
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  cerr << "creating instance\n";
 
 
   INIT_LOCK(_request_lock);
   INIT_LOCK(_request_lock);
 
 
-  // For the moment, all sessions will be shared.
-  /*
+  // For the moment, all sessions will be unique.
   ostringstream strm;
   ostringstream strm;
   strm << inst_mgr->get_unique_session_index();
   strm << inst_mgr->get_unique_session_index();
   _session_key = strm.str();
   _session_key = strm.str();
-  */
-  _session_key = "common";
+
   _python_version = "python24";
   _python_version = "python24";
 
 
   _session = NULL;
   _session = NULL;

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

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

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

@@ -15,7 +15,6 @@
 #include "p3dInstanceManager.h"
 #include "p3dInstanceManager.h"
 #include "p3dInstance.h"
 #include "p3dInstance.h"
 #include "p3dSession.h"
 #include "p3dSession.h"
-#include "p3dPython.h"
 
 
 P3DInstanceManager *P3DInstanceManager::_global_ptr;
 P3DInstanceManager *P3DInstanceManager::_global_ptr;
 
 
@@ -26,8 +25,8 @@ P3DInstanceManager *P3DInstanceManager::_global_ptr;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 P3DInstanceManager::
 P3DInstanceManager::
 P3DInstanceManager() {
 P3DInstanceManager() {
+  cerr << "creating instance manager\n";
   _unique_session_index = 0;
   _unique_session_index = 0;
-  _current_python = NULL;
 
 
   _request_seq = 0;
   _request_seq = 0;
 #ifdef _WIN32
 #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
 //     Function: P3DInstanceManager::get_unique_session_index
 //       Access: Public
 //       Access: Public

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

@@ -22,7 +22,6 @@
 
 
 class P3DInstance;
 class P3DInstance;
 class P3DSession;
 class P3DSession;
-class P3DPython;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : P3DInstanceManager
 //       Class : P3DInstanceManager
@@ -52,8 +51,6 @@ public:
   P3DInstance *check_request();
   P3DInstance *check_request();
   void wait_request();
   void wait_request();
 
 
-  P3DPython *start_python(const string &python_version);
-
   INLINE int get_num_instances() const;
   INLINE int get_num_instances() const;
 
 
   INLINE const string &get_dll_filename() const;
   INLINE const string &get_dll_filename() const;
@@ -73,7 +70,6 @@ private:
   typedef map<string, P3DSession *> Sessions;
   typedef map<string, P3DSession *> Sessions;
   Sessions _sessions;
   Sessions _sessions;
 
 
-  P3DPython *_current_python;
   int _unique_session_index;
   int _unique_session_index;
 
 
   // Implements a condition-var like behavior.
   // 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 "p3dSession.h"
 #include "p3dInstance.h"
 #include "p3dInstance.h"
 #include "p3dInstanceManager.h"
 #include "p3dInstanceManager.h"
+#include <tinyxml.h>
 
 
 #include <malloc.h>
 #include <malloc.h>
 
 
@@ -31,7 +32,92 @@ P3DSession::
 P3DSession(P3DInstance *inst) {
 P3DSession(P3DInstance *inst) {
   _session_key = inst->get_session_key();
   _session_key = inst->get_session_key();
   _python_version = inst->get_python_version();
   _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::
 ~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::
 void P3DSession::
 start_instance(P3DInstance *inst) {
 start_instance(P3DInstance *inst) {
-  assert(_python == NULL);
   assert(inst->_session == NULL);
   assert(inst->_session == NULL);
   assert(inst->get_session_key() == _session_key);
   assert(inst->get_session_key() == _session_key);
   assert(inst->get_python_version() == _python_version);
   assert(inst->get_python_version() == _python_version);
@@ -66,10 +159,21 @@ start_instance(P3DInstance *inst) {
   assert(inserted);
   assert(inserted);
 
 
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   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);
   P3DPython *python = inst_mgr->start_python(_python_version);
   if (python != NULL) {
   if (python != NULL) {
     python->start_session(this, inst);
     python->start_session(this, inst);
   }
   }
+  */
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -81,10 +185,12 @@ start_instance(P3DInstance *inst) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DSession::
 void P3DSession::
 terminate_instance(P3DInstance *inst) {
 terminate_instance(P3DInstance *inst) {
+  /*
   if (_python != NULL) {
   if (_python != NULL) {
     _python->terminate_session(this);
     _python->terminate_session(this);
     assert(_python == NULL);
     assert(_python == NULL);
   }
   }
+  */
 
 
   if (inst->_session == this) {
   if (inst->_session == this) {
     inst->_session = NULL;
     inst->_session = NULL;

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

@@ -16,6 +16,7 @@
 #define P3DSESSION_H
 #define P3DSESSION_H
 
 
 #include "p3d_plugin_common.h"
 #include "p3d_plugin_common.h"
+#include "handleStream.h"
 
 
 #include <set>
 #include <set>
 
 
@@ -45,12 +46,18 @@ private:
   string _session_key;
   string _session_key;
   string _python_version;
   string _python_version;
 
 
-  P3DPython *_python;
+  string _python_root_dir;
 
 
   typedef set<P3DInstance *> Instances;
   typedef set<P3DInstance *> Instances;
   Instances _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"
 #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
 #ifndef P3D_PLUGIN_COMMON
 #define 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 P3D_FUNCTION_PROTOTYPES
 #define BUILDING_P3D_PLUGIN
 #define BUILDING_P3D_PLUGIN
 
 
 #include "p3d_plugin.h"
 #include "p3d_plugin.h"
+#include "p3d_lock.h"
 
 
 #include <iostream>
 #include <iostream>
 #include <string>
 #include <string>
@@ -31,13 +33,5 @@ using namespace std;
 
 
 #define INLINE inline
 #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
 #endif
 
 

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

@@ -1,5 +1,4 @@
 #include "p3d_plugin.cxx"
 #include "p3d_plugin.cxx"
 #include "p3dInstance.cxx"
 #include "p3dInstance.cxx"
 #include "p3dInstanceManager.cxx"
 #include "p3dInstanceManager.cxx"
-#include "p3dPython.cxx"
 #include "p3dSession.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 "wingetopt.h"
 #include <stdio.h>
 #include <stdio.h>
+#include <string.h>
 
 
-#define NULL	0
+//#define NULL	0
 #define EOF	(-1)
 #define EOF	(-1)
 #define ERR(s, c)	if(opterr){\
 #define ERR(s, c)	if(opterr){\
 	char errbuf[2];\
 	char errbuf[2];\

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

@@ -15,6 +15,7 @@ import sys
 from direct.showbase import VFSImporter
 from direct.showbase import VFSImporter
 from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, getModelPath
 from pandac.PandaModules import VirtualFileSystem, Filename, Multifile, loadPrcFileData, getModelPath
 from direct.stdpy import file
 from direct.stdpy import file
+from direct.task.TaskManagerGlobal import taskMgr
 import os
 import os
 import __builtin__
 import __builtin__
 
 
@@ -144,8 +145,13 @@ def setupWindow(windowType, x, y, width, height, parent):
 
 
     loadPrcFileData("setupWindow", data)
     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__':
 if __name__ == '__main__':
     try:
     try: