256 lines
8.8 KiB
C++
256 lines
8.8 KiB
C++
// Filename: p3dInstanceManager.cxx
|
|
// Created by: drose (29May09)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 "p3dInstanceManager.h"
|
|
#include "p3dInstance.h"
|
|
#include "p3dSession.h"
|
|
#include "p3dPython.h"
|
|
|
|
P3DInstanceManager *P3DInstanceManager::_global_ptr;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DInstanceManager::Constructor
|
|
// Access: Private
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
P3DInstanceManager::
|
|
P3DInstanceManager() {
|
|
_unique_session_index = 0;
|
|
_current_python = NULL;
|
|
|
|
_request_seq = 0;
|
|
#ifdef _WIN32
|
|
_request_ready = CreateEvent(NULL, false, false, NULL);
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DInstanceManager::Destructor
|
|
// Access: Private
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
P3DInstanceManager::
|
|
~P3DInstanceManager() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DInstanceManager::initialize
|
|
// Access: Public
|
|
// Description: Called by the host at application startup, this
|
|
// receives the name of the DLL that contains this code
|
|
// (for patching purposes). It returns true if the DLL
|
|
// is successfully initialized, false if it should be
|
|
// immediately shut down and redownloaded.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool P3DInstanceManager::
|
|
initialize(const string &config_xml, const string &dll_filename) {
|
|
_dll_filename = dll_filename;
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DInstanceManager::create_instance
|
|
// Access: Public
|
|
// Description: Returns a newly-allocated P3DInstance with the
|
|
// indicated startup information.
|
|
////////////////////////////////////////////////////////////////////
|
|
P3DInstance *P3DInstanceManager::
|
|
create_instance(P3D_request_ready_func *func,
|
|
const string &p3d_filename,
|
|
P3D_window_type window_type,
|
|
int win_x, int win_y,
|
|
int win_width, int win_height,
|
|
P3D_window_handle parent_window,
|
|
const P3D_token *tokens[], size_t tokens_size) {
|
|
P3DInstance *inst = new P3DInstance(func, p3d_filename,
|
|
window_type, win_x, win_y,
|
|
win_width, win_height, parent_window,
|
|
tokens, tokens_size);
|
|
_instances.insert(inst);
|
|
|
|
P3DSession *session;
|
|
Sessions::iterator si = _sessions.find(inst->get_session_key());
|
|
if (si == _sessions.end()) {
|
|
session = new P3DSession(inst);
|
|
bool inserted = _sessions.insert(Sessions::value_type(session->get_session_key(), session)).second;
|
|
assert(inserted);
|
|
} else {
|
|
session = (*si).second;
|
|
}
|
|
|
|
session->start_instance(inst);
|
|
|
|
return inst;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DInstanceManager::finish_instance
|
|
// Access: Public
|
|
// Description: Terminates and removes a previously-returned
|
|
// instance.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DInstanceManager::
|
|
finish_instance(P3DInstance *inst) {
|
|
Instances::iterator ii;
|
|
ii = _instances.find(inst);
|
|
assert(ii != _instances.end());
|
|
_instances.erase(ii);
|
|
|
|
Sessions::iterator si = _sessions.find(inst->get_session_key());
|
|
assert(si != _sessions.end());
|
|
P3DSession *session = (*si).second;
|
|
session->terminate_instance(inst);
|
|
|
|
// If that was the last instance in this session, terminate the
|
|
// session.
|
|
if (session->get_num_instances() == 0) {
|
|
_sessions.erase(session->get_session_key());
|
|
delete session;
|
|
}
|
|
|
|
delete inst;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DInstanceManager::check_request
|
|
// Access: Public
|
|
// Description: If a request is currently pending on any instance,
|
|
// returns its pointer. Otherwise, returns NULL.
|
|
////////////////////////////////////////////////////////////////////
|
|
P3DInstance *P3DInstanceManager::
|
|
check_request() {
|
|
Instances::iterator ii;
|
|
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
|
P3DInstance *inst = (*ii);
|
|
if (inst->has_request()) {
|
|
return inst;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DInstanceManager::wait_request
|
|
// Access: Public
|
|
// Description: Does not return until a request is pending on some
|
|
// instance, or until no instances remain. Use
|
|
// check_request to retrieve the pending request. Due
|
|
// to the possibility of race conditions, it is possible
|
|
// for this function to return when there is in fact no
|
|
// request pending (another thread may have extracted
|
|
// the request first).
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DInstanceManager::
|
|
wait_request() {
|
|
int seq = _request_seq;
|
|
|
|
while (true) {
|
|
if (_instances.empty()) {
|
|
return;
|
|
}
|
|
if (check_request() != (P3DInstance *)NULL) {
|
|
return;
|
|
}
|
|
|
|
// No pending requests; go to sleep.
|
|
if (seq == _request_seq) {
|
|
WaitForSingleObject(_request_ready, INFINITE);
|
|
}
|
|
seq = _request_seq;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// 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
|
|
// Description: Returns a number used to uniquify the session_key for
|
|
// different instances. This number is guaranteed to be
|
|
// different at each call.
|
|
////////////////////////////////////////////////////////////////////
|
|
int P3DInstanceManager::
|
|
get_unique_session_index() {
|
|
++_unique_session_index;
|
|
return _unique_session_index;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DInstanceManager::signal_request_ready
|
|
// Access: Public
|
|
// Description: May be called in any thread to indicate that a new
|
|
// P3D_request is available in some instance. This will
|
|
// wake up a sleeping wait_request() call, if any.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DInstanceManager::
|
|
signal_request_ready() {
|
|
++_request_seq;
|
|
#ifdef _WIN32
|
|
SetEvent(_request_ready);
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DInstanceManager::get_global_ptr
|
|
// Access: Public, Static
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
P3DInstanceManager *P3DInstanceManager::
|
|
get_global_ptr() {
|
|
if (_global_ptr == NULL) {
|
|
_global_ptr = new P3DInstanceManager;
|
|
}
|
|
return _global_ptr;
|
|
}
|