exit gracefully

This commit is contained in:
David Rose 2009-06-09 01:56:03 +00:00
parent 8c6229ff7f
commit 633eae3ba3
10 changed files with 299 additions and 33 deletions

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

View 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() {
}

View 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

View File

@ -24,6 +24,17 @@ get_p3d_filename() const {
return _p3d_filename; 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 // Function: P3DInstance::get_session_key
// Access: Public // Access: Public

View File

@ -17,6 +17,8 @@
#include <sstream> #include <sstream>
int P3DInstance::_next_instance_id = 0;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: P3DInstance::Constructor // Function: P3DInstance::Constructor
// Access: Public // Access: Public
@ -37,11 +39,13 @@ P3DInstance(P3D_request_ready_func *func,
_win_width(win_width), _win_height(win_height), _win_width(win_width), _win_height(win_height),
_parent_window(parent_window) _parent_window(parent_window)
{ {
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); _instance_id = _next_instance_id;
++_next_instance_id;
INIT_LOCK(_request_lock); INIT_LOCK(_request_lock);
// For the moment, all sessions will be unique. // For the moment, all sessions will be unique.
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
ostringstream strm; ostringstream strm;
strm << inst_mgr->get_unique_session_index(); strm << inst_mgr->get_unique_session_index();
_session_key = strm.str(); _session_key = strm.str();
@ -200,6 +204,7 @@ feed_url_stream(int unique_id,
TiXmlElement *P3DInstance:: TiXmlElement *P3DInstance::
make_xml() { make_xml() {
TiXmlElement *xinstance = new TiXmlElement("instance"); TiXmlElement *xinstance = new TiXmlElement("instance");
xinstance->SetAttribute("id", _instance_id);
xinstance->SetAttribute("p3d_filename", _p3d_filename); xinstance->SetAttribute("p3d_filename", _p3d_filename);
switch (_window_type) { switch (_window_type) {

View File

@ -56,6 +56,7 @@ public:
size_t this_data_size); size_t this_data_size);
inline const string &get_p3d_filename() const; inline const string &get_p3d_filename() const;
inline int get_instance_id() const;
inline const string &get_session_key() const; inline const string &get_session_key() const;
inline const string &get_python_version() const; inline const string &get_python_version() const;
@ -79,6 +80,7 @@ private:
P3D_window_handle _parent_window; P3D_window_handle _parent_window;
Tokens _tokens; Tokens _tokens;
int _instance_id;
string _session_key; string _session_key;
string _python_version; string _python_version;
P3DSession *_session; P3DSession *_session;
@ -87,6 +89,8 @@ private:
typedef deque<P3D_request *> Requests; typedef deque<P3D_request *> Requests;
Requests _pending_requests; Requests _pending_requests;
static int _next_instance_id;
friend class P3DSession; friend class P3DSession;
}; };

View File

@ -21,7 +21,8 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
P3DPythonRun:: P3DPythonRun::
P3DPythonRun(int argc, char *argv[]) { P3DPythonRun(int argc, char *argv[]) {
_read_thread_alive = false; _read_thread_continue = false;
_program_continue = true;
INIT_LOCK(_commands_lock); INIT_LOCK(_commands_lock);
_program_name = argv[0]; _program_name = argv[0];
@ -101,6 +102,11 @@ run_python() {
PyErr_Print(); PyErr_Print();
return false; return false;
} }
_exit = PyObject_GetAttrString(appmf, "exit");
if (_exit == NULL) {
PyErr_Print();
return false;
}
_setupWindow = PyObject_GetAttrString(appmf, "setupWindow"); _setupWindow = PyObject_GetAttrString(appmf, "setupWindow");
if (_setupWindow == NULL) { if (_setupWindow == NULL) {
PyErr_Print(); PyErr_Print();
@ -174,12 +180,27 @@ run_python() {
void P3DPythonRun:: void P3DPythonRun::
handle_command(TiXmlDocument *doc) { handle_command(TiXmlDocument *doc) {
cerr << "got command: " << *doc << "\n"; cerr << "got command: " << *doc << "\n";
TiXmlHandle h(doc); TiXmlElement *xcommand = doc->FirstChildElement("command");
TiXmlElement *xinstance = h.FirstChild("instance").ToElement(); 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) { if (xinstance != (TiXmlElement *)NULL) {
P3DCInstance *inst = new P3DCInstance(xinstance); P3DCInstance *inst = new P3DCInstance(xinstance);
start_instance(inst); 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; delete doc;
ACQUIRE_LOCK(_commands_lock); 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); RELEASE_LOCK(_commands_lock);
} }
@ -236,9 +264,9 @@ py_check_comm(PyObject *, PyObject *args) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void P3DPythonRun:: void P3DPythonRun::
spawn_read_thread() { spawn_read_thread() {
assert(!_read_thread_alive); assert(!_read_thread_continue);
_read_thread_alive = true; _read_thread_continue = true;
#ifdef _WIN32 #ifdef _WIN32
_read_thread = CreateThread(NULL, 0, &win_rt_thread_run, this, 0, NULL); _read_thread = CreateThread(NULL, 0, &win_rt_thread_run, this, 0, NULL);
#endif #endif
@ -252,7 +280,7 @@ spawn_read_thread() {
void P3DPythonRun:: void P3DPythonRun::
join_read_thread() { join_read_thread() {
cerr << "waiting for thread\n"; cerr << "waiting for thread\n";
_read_thread_alive = false; _read_thread_continue = false;
#ifdef _WIN32 #ifdef _WIN32
assert(_read_thread != NULL); assert(_read_thread != NULL);
@ -272,7 +300,7 @@ join_read_thread() {
void P3DPythonRun:: void P3DPythonRun::
start_instance(P3DCInstance *inst) { start_instance(P3DCInstance *inst) {
cerr << "starting instance " << inst->get_p3d_filename() << "\n"; cerr << "starting instance " << inst->get_p3d_filename() << "\n";
_instances.push_back(inst); _instances[inst->get_instance_id()] = inst;
string window_type; string window_type;
switch (inst->_window_type) { switch (inst->_window_type) {
@ -310,6 +338,51 @@ start_instance(P3DCInstance *inst) {
Py_XDECREF(result); 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 // Function: P3DPythonRun::rt_thread_run
// Access: Private // Access: Private
@ -318,13 +391,14 @@ start_instance(P3DCInstance *inst) {
void P3DPythonRun:: void P3DPythonRun::
rt_thread_run() { rt_thread_run() {
cerr << "thread reading.\n"; cerr << "thread reading.\n";
while (_read_thread_alive) { while (_read_thread_continue) {
TiXmlDocument *doc = new TiXmlDocument; TiXmlDocument *doc = new TiXmlDocument;
_pipe_read >> *doc; _pipe_read >> *doc;
if (!_pipe_read || _pipe_read.eof()) { if (!_pipe_read || _pipe_read.eof()) {
// Some error on reading. Abort. // Some error on reading. Abort.
cerr << "Error on reading.\n"; cerr << "Error on reading.\n";
_program_continue = false;
return; return;
} }

View File

@ -18,7 +18,7 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <deque> #include <deque>
#include <vector> #include <map>
#include <assert.h> #include <assert.h>
#include <Python.h> #include <Python.h>
#include <tinyxml.h> #include <tinyxml.h>
@ -63,6 +63,8 @@ private:
void join_read_thread(); void join_read_thread();
void start_instance(P3DCInstance *inst); void start_instance(P3DCInstance *inst);
void terminate_instance(int id);
void terminate_session();
private: private:
// This method runs only within the read thread. // This method runs only within the read thread.
@ -72,7 +74,7 @@ private:
#endif #endif
private: private:
typedef vector<P3DCInstance *> Instances; typedef map<int, P3DCInstance *> Instances;
Instances _instances; Instances _instances;
string _program_name; string _program_name;
@ -80,6 +82,7 @@ private:
char **_py_argv; char **_py_argv;
PyObject *_runPackedApp; PyObject *_runPackedApp;
PyObject *_exit;
PyObject *_setupWindow; PyObject *_setupWindow;
// The remaining members are manipulated by the read thread. // The remaining members are manipulated by the read thread.
@ -90,7 +93,8 @@ private:
HandleStream _pipe_read; HandleStream _pipe_read;
HandleStream _pipe_write; HandleStream _pipe_write;
bool _read_thread_alive; bool _read_thread_continue;
bool _program_continue;
#ifdef _WIN32 #ifdef _WIN32
HANDLE _read_thread; HANDLE _read_thread;
#endif #endif

View File

@ -167,24 +167,17 @@ start_instance(P3DInstance *inst) {
bool inserted = _instances.insert(inst).second; bool inserted = _instances.insert(inst).second;
assert(inserted); assert(inserted);
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
TiXmlDocument doc; TiXmlDocument doc;
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", ""); TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
TiXmlElement *xcommand = new TiXmlElement("command");
xcommand->SetAttribute("cmd", "start_instance");
TiXmlElement *xinstance = inst->make_xml(); TiXmlElement *xinstance = inst->make_xml();
doc.LinkEndChild(decl); doc.LinkEndChild(decl);
doc.LinkEndChild(xinstance); doc.LinkEndChild(xcommand);
xcommand->LinkEndChild(xinstance);
cerr << "sending: " << doc << "\n";
_pipe_write << doc << flush; _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:: void P3DSession::
terminate_instance(P3DInstance *inst) { terminate_instance(P3DInstance *inst) {
/* TiXmlDocument doc;
if (_python != NULL) { TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "", "");
_python->terminate_session(this); TiXmlElement *xcommand = new TiXmlElement("command");
assert(_python == NULL); 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) { if (inst->_session == this) {
inst->_session = NULL; inst->_session = NULL;

View File

@ -153,6 +153,9 @@ def add_check_comm(func, this):
return taskMgr.add(func, "check_comm", sort = -50, extraArgs = [this], return taskMgr.add(func, "check_comm", sort = -50, extraArgs = [this],
appendTask = True) appendTask = True)
def exit():
taskMgr.stop()
if __name__ == '__main__': if __name__ == '__main__':
try: try:
runPackedApp(sys.argv[1:]) runPackedApp(sys.argv[1:])