more plugin work
This commit is contained in:
parent
be2883308b
commit
027e5fdc9e
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
|
|
@ -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."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ private:
|
|||
Requests _pending_requests;
|
||||
|
||||
friend class P3DSession;
|
||||
friend class P3DPython;
|
||||
};
|
||||
|
||||
#include "p3dInstance.I"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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."
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "p3d_plugin.cxx"
|
||||
#include "p3dInstance.cxx"
|
||||
#include "p3dInstanceManager.cxx"
|
||||
#include "p3dPython.cxx"
|
||||
#include "p3dSession.cxx"
|
||||
|
|
|
|||
|
|
@ -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];\
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue