mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 01:07:51 -04:00
exit gracefully
This commit is contained in:
parent
8c6229ff7f
commit
633eae3ba3
36
direct/src/plugin/p3dCInstance.I
Executable file
36
direct/src/plugin/p3dCInstance.I
Executable file
@ -0,0 +1,36 @@
|
||||
// Filename: p3dCInstance.I
|
||||
// Created by: drose (08Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: P3DCInstance::get_p3d_filename
|
||||
// Access: Public
|
||||
// Description: Returns the p3d filename that was passed to the
|
||||
// constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline const string &P3DCInstance::
|
||||
get_p3d_filename() const {
|
||||
return _p3d_filename;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DCInstance::get_instance_id
|
||||
// Access: Public
|
||||
// Description: Returns a unique integer for each instance in the
|
||||
// system.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline int P3DCInstance::
|
||||
get_instance_id() const {
|
||||
return _instance_id;
|
||||
}
|
70
direct/src/plugin/p3dCInstance.cxx
Executable file
70
direct/src/plugin/p3dCInstance.cxx
Executable file
@ -0,0 +1,70 @@
|
||||
// Filename: p3dCInstance.cxx
|
||||
// Created by: drose (08Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "p3dCInstance.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DCInstance::Constructor
|
||||
// Access: Public
|
||||
// Description: Constructs a new Instance from an XML description.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DCInstance::
|
||||
P3DCInstance(TiXmlElement *xinstance) :
|
||||
_func(NULL),
|
||||
_window_type(P3D_WT_toplevel),
|
||||
_win_x(0), _win_y(0),
|
||||
_win_width(0), _win_height(0)
|
||||
{
|
||||
xinstance->Attribute("id", &_instance_id);
|
||||
|
||||
const char *p3d_filename = xinstance->Attribute("p3d_filename");
|
||||
if (p3d_filename != NULL) {
|
||||
_p3d_filename = p3d_filename;
|
||||
}
|
||||
|
||||
const char *window_type = xinstance->Attribute("window_type");
|
||||
if (window_type != NULL) {
|
||||
if (strcmp(window_type, "embedded") == 0) {
|
||||
_window_type = P3D_WT_embedded;
|
||||
} else if (strcmp(window_type, "toplevel") == 0) {
|
||||
_window_type = P3D_WT_toplevel;
|
||||
} else if (strcmp(window_type, "fullscreen") == 0) {
|
||||
_window_type = P3D_WT_fullscreen;
|
||||
} else if (strcmp(window_type, "hidden") == 0) {
|
||||
_window_type = P3D_WT_hidden;
|
||||
}
|
||||
}
|
||||
|
||||
xinstance->Attribute("win_x", &_win_x);
|
||||
xinstance->Attribute("win_y", &_win_y);
|
||||
xinstance->Attribute("win_width", &_win_width);
|
||||
xinstance->Attribute("win_height", &_win_height);
|
||||
|
||||
#ifdef _WIN32
|
||||
int hwnd;
|
||||
if (xinstance->Attribute("parent_hwnd", &hwnd)) {
|
||||
_parent_window._hwnd = (HWND)hwnd;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DCInstance::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DCInstance::
|
||||
~P3DCInstance() {
|
||||
}
|
62
direct/src/plugin/p3dCInstance.h
Executable file
62
direct/src/plugin/p3dCInstance.h
Executable file
@ -0,0 +1,62 @@
|
||||
// Filename: p3dCInstance.h
|
||||
// Created by: drose (08Jun09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 P3DCINSTANCE_H
|
||||
#define P3DCINSTANCE_H
|
||||
|
||||
#include "p3d_plugin.h"
|
||||
|
||||
#include <vector>
|
||||
#include <tinyxml.h>
|
||||
|
||||
class P3DSession;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : P3DCInstance
|
||||
// Description : This is an instance of a Panda3D window, as seen in
|
||||
// the parent-level process.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class P3DCInstance : public P3D_instance {
|
||||
public:
|
||||
P3DCInstance(TiXmlElement *xinstance);
|
||||
~P3DCInstance();
|
||||
|
||||
inline const string &get_p3d_filename() const;
|
||||
inline int get_instance_id() const;
|
||||
|
||||
private:
|
||||
class Token {
|
||||
public:
|
||||
string _keyword;
|
||||
string _value;
|
||||
};
|
||||
typedef vector<Token> Tokens;
|
||||
|
||||
P3D_request_ready_func *_func;
|
||||
string _p3d_filename;
|
||||
P3D_window_type _window_type;
|
||||
int _win_x, _win_y;
|
||||
int _win_width, _win_height;
|
||||
P3D_window_handle _parent_window;
|
||||
|
||||
Tokens _tokens;
|
||||
|
||||
int _instance_id;
|
||||
|
||||
friend class P3DPythonRun;
|
||||
};
|
||||
|
||||
#include "p3dCInstance.I"
|
||||
|
||||
#endif
|
@ -24,6 +24,17 @@ get_p3d_filename() const {
|
||||
return _p3d_filename;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::get_instance_id
|
||||
// Access: Public
|
||||
// Description: Returns a unique integer for each instance in the
|
||||
// system.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline int P3DInstance::
|
||||
get_instance_id() const {
|
||||
return _instance_id;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::get_session_key
|
||||
// Access: Public
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
int P3DInstance::_next_instance_id = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::Constructor
|
||||
// Access: Public
|
||||
@ -37,11 +39,13 @@ P3DInstance(P3D_request_ready_func *func,
|
||||
_win_width(win_width), _win_height(win_height),
|
||||
_parent_window(parent_window)
|
||||
{
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
_instance_id = _next_instance_id;
|
||||
++_next_instance_id;
|
||||
|
||||
INIT_LOCK(_request_lock);
|
||||
|
||||
// For the moment, all sessions will be unique.
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
ostringstream strm;
|
||||
strm << inst_mgr->get_unique_session_index();
|
||||
_session_key = strm.str();
|
||||
@ -200,6 +204,7 @@ feed_url_stream(int unique_id,
|
||||
TiXmlElement *P3DInstance::
|
||||
make_xml() {
|
||||
TiXmlElement *xinstance = new TiXmlElement("instance");
|
||||
xinstance->SetAttribute("id", _instance_id);
|
||||
xinstance->SetAttribute("p3d_filename", _p3d_filename);
|
||||
|
||||
switch (_window_type) {
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
size_t this_data_size);
|
||||
|
||||
inline const string &get_p3d_filename() const;
|
||||
inline int get_instance_id() const;
|
||||
inline const string &get_session_key() const;
|
||||
inline const string &get_python_version() const;
|
||||
|
||||
@ -79,6 +80,7 @@ private:
|
||||
P3D_window_handle _parent_window;
|
||||
Tokens _tokens;
|
||||
|
||||
int _instance_id;
|
||||
string _session_key;
|
||||
string _python_version;
|
||||
P3DSession *_session;
|
||||
@ -87,6 +89,8 @@ private:
|
||||
typedef deque<P3D_request *> Requests;
|
||||
Requests _pending_requests;
|
||||
|
||||
static int _next_instance_id;
|
||||
|
||||
friend class P3DSession;
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,8 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
P3DPythonRun::
|
||||
P3DPythonRun(int argc, char *argv[]) {
|
||||
_read_thread_alive = false;
|
||||
_read_thread_continue = false;
|
||||
_program_continue = true;
|
||||
INIT_LOCK(_commands_lock);
|
||||
|
||||
_program_name = argv[0];
|
||||
@ -101,6 +102,11 @@ run_python() {
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
_exit = PyObject_GetAttrString(appmf, "exit");
|
||||
if (_exit == NULL) {
|
||||
PyErr_Print();
|
||||
return false;
|
||||
}
|
||||
_setupWindow = PyObject_GetAttrString(appmf, "setupWindow");
|
||||
if (_setupWindow == NULL) {
|
||||
PyErr_Print();
|
||||
@ -174,12 +180,27 @@ run_python() {
|
||||
void P3DPythonRun::
|
||||
handle_command(TiXmlDocument *doc) {
|
||||
cerr << "got command: " << *doc << "\n";
|
||||
TiXmlHandle h(doc);
|
||||
TiXmlElement *xinstance = h.FirstChild("instance").ToElement();
|
||||
if (xinstance != (TiXmlElement *)NULL) {
|
||||
P3DCInstance *inst = new P3DCInstance(xinstance);
|
||||
start_instance(inst);
|
||||
}
|
||||
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
||||
if (xcommand != NULL) {
|
||||
const char *cmd = xcommand->Attribute("cmd");
|
||||
if (cmd != NULL) {
|
||||
if (strcmp(cmd, "start_instance") == 0) {
|
||||
TiXmlElement *xinstance = xcommand->FirstChildElement("instance");
|
||||
if (xinstance != (TiXmlElement *)NULL) {
|
||||
P3DCInstance *inst = new P3DCInstance(xinstance);
|
||||
start_instance(inst);
|
||||
}
|
||||
} else if (strcmp(cmd, "terminate_instance") == 0) {
|
||||
int id;
|
||||
if (xcommand->Attribute("id", &id)) {
|
||||
terminate_instance(id);
|
||||
}
|
||||
|
||||
} else {
|
||||
cerr << "Unhandled command " << cmd << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -203,6 +224,13 @@ check_comm() {
|
||||
delete doc;
|
||||
ACQUIRE_LOCK(_commands_lock);
|
||||
}
|
||||
|
||||
if (!_program_continue) {
|
||||
// The low-level thread detected an error, for instance pipe
|
||||
// closed. We should exit gracefully.
|
||||
terminate_session();
|
||||
}
|
||||
|
||||
RELEASE_LOCK(_commands_lock);
|
||||
}
|
||||
|
||||
@ -236,9 +264,9 @@ py_check_comm(PyObject *, PyObject *args) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPythonRun::
|
||||
spawn_read_thread() {
|
||||
assert(!_read_thread_alive);
|
||||
assert(!_read_thread_continue);
|
||||
|
||||
_read_thread_alive = true;
|
||||
_read_thread_continue = true;
|
||||
#ifdef _WIN32
|
||||
_read_thread = CreateThread(NULL, 0, &win_rt_thread_run, this, 0, NULL);
|
||||
#endif
|
||||
@ -252,7 +280,7 @@ spawn_read_thread() {
|
||||
void P3DPythonRun::
|
||||
join_read_thread() {
|
||||
cerr << "waiting for thread\n";
|
||||
_read_thread_alive = false;
|
||||
_read_thread_continue = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
assert(_read_thread != NULL);
|
||||
@ -272,7 +300,7 @@ join_read_thread() {
|
||||
void P3DPythonRun::
|
||||
start_instance(P3DCInstance *inst) {
|
||||
cerr << "starting instance " << inst->get_p3d_filename() << "\n";
|
||||
_instances.push_back(inst);
|
||||
_instances[inst->get_instance_id()] = inst;
|
||||
|
||||
string window_type;
|
||||
switch (inst->_window_type) {
|
||||
@ -310,6 +338,51 @@ start_instance(P3DCInstance *inst) {
|
||||
Py_XDECREF(result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPythonRun::terminate_instance
|
||||
// Access: Private
|
||||
// Description: Stops the instance with the indicated id.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPythonRun::
|
||||
terminate_instance(int id) {
|
||||
Instances::iterator ii = _instances.find(id);
|
||||
if (ii == _instances.end()) {
|
||||
cerr << "Can't stop instance " << id << ": not started.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
P3DCInstance *inst = (*ii).second;
|
||||
_instances.erase(ii);
|
||||
delete inst;
|
||||
|
||||
// TODO: we don't currently have any way to stop just one instance
|
||||
// of a multi-instance session. We could maybe close its window or
|
||||
// something.
|
||||
terminate_session();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPythonRun::terminate_session
|
||||
// Access: Private
|
||||
// Description: Stops all currently-running instances.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPythonRun::
|
||||
terminate_session() {
|
||||
Instances::iterator ii;
|
||||
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||
P3DCInstance *inst = (*ii).second;
|
||||
delete inst;
|
||||
}
|
||||
_instances.clear();
|
||||
|
||||
PyObject *result = PyObject_CallFunction(_exit, "");
|
||||
if (result == NULL) {
|
||||
PyErr_Print();
|
||||
}
|
||||
Py_XDECREF(result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DPythonRun::rt_thread_run
|
||||
// Access: Private
|
||||
@ -318,13 +391,14 @@ start_instance(P3DCInstance *inst) {
|
||||
void P3DPythonRun::
|
||||
rt_thread_run() {
|
||||
cerr << "thread reading.\n";
|
||||
while (_read_thread_alive) {
|
||||
while (_read_thread_continue) {
|
||||
TiXmlDocument *doc = new TiXmlDocument;
|
||||
|
||||
_pipe_read >> *doc;
|
||||
if (!_pipe_read || _pipe_read.eof()) {
|
||||
// Some error on reading. Abort.
|
||||
cerr << "Error on reading.\n";
|
||||
_program_continue = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <assert.h>
|
||||
#include <Python.h>
|
||||
#include <tinyxml.h>
|
||||
@ -63,6 +63,8 @@ private:
|
||||
void join_read_thread();
|
||||
|
||||
void start_instance(P3DCInstance *inst);
|
||||
void terminate_instance(int id);
|
||||
void terminate_session();
|
||||
|
||||
private:
|
||||
// This method runs only within the read thread.
|
||||
@ -72,7 +74,7 @@ private:
|
||||
#endif
|
||||
|
||||
private:
|
||||
typedef vector<P3DCInstance *> Instances;
|
||||
typedef map<int, P3DCInstance *> Instances;
|
||||
Instances _instances;
|
||||
|
||||
string _program_name;
|
||||
@ -80,6 +82,7 @@ private:
|
||||
char **_py_argv;
|
||||
|
||||
PyObject *_runPackedApp;
|
||||
PyObject *_exit;
|
||||
PyObject *_setupWindow;
|
||||
|
||||
// The remaining members are manipulated by the read thread.
|
||||
@ -90,7 +93,8 @@ private:
|
||||
HandleStream _pipe_read;
|
||||
HandleStream _pipe_write;
|
||||
|
||||
bool _read_thread_alive;
|
||||
bool _read_thread_continue;
|
||||
bool _program_continue;
|
||||
#ifdef _WIN32
|
||||
HANDLE _read_thread;
|
||||
#endif
|
||||
|
@ -167,24 +167,17 @@ start_instance(P3DInstance *inst) {
|
||||
bool inserted = _instances.insert(inst).second;
|
||||
assert(inserted);
|
||||
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
|
||||
TiXmlDocument doc;
|
||||
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
|
||||
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||
xcommand->SetAttribute("cmd", "start_instance");
|
||||
TiXmlElement *xinstance = inst->make_xml();
|
||||
|
||||
doc.LinkEndChild(decl);
|
||||
doc.LinkEndChild(xinstance);
|
||||
doc.LinkEndChild(xcommand);
|
||||
xcommand->LinkEndChild(xinstance);
|
||||
|
||||
cerr << "sending: " << doc << "\n";
|
||||
_pipe_write << doc << flush;
|
||||
|
||||
/*
|
||||
P3DPython *python = inst_mgr->start_python(_python_version);
|
||||
if (python != NULL) {
|
||||
python->start_session(this, inst);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -196,12 +189,16 @@ start_instance(P3DInstance *inst) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
terminate_instance(P3DInstance *inst) {
|
||||
/*
|
||||
if (_python != NULL) {
|
||||
_python->terminate_session(this);
|
||||
assert(_python == NULL);
|
||||
}
|
||||
*/
|
||||
TiXmlDocument doc;
|
||||
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
|
||||
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||
xcommand->SetAttribute("cmd", "terminate_instance");
|
||||
xcommand->SetAttribute("id", inst->get_instance_id());
|
||||
|
||||
doc.LinkEndChild(decl);
|
||||
doc.LinkEndChild(xcommand);
|
||||
|
||||
_pipe_write << doc << flush;
|
||||
|
||||
if (inst->_session == this) {
|
||||
inst->_session = NULL;
|
||||
|
@ -153,6 +153,9 @@ def add_check_comm(func, this):
|
||||
return taskMgr.add(func, "check_comm", sort = -50, extraArgs = [this],
|
||||
appendTask = True)
|
||||
|
||||
def exit():
|
||||
taskMgr.stop()
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
runPackedApp(sys.argv[1:])
|
||||
|
Loading…
x
Reference in New Issue
Block a user