Browse Source

exit gracefully

David Rose 16 years ago
parent
commit
633eae3ba3

+ 36 - 0
direct/src/plugin/p3dCInstance.I

@@ -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 - 0
direct/src/plugin/p3dCInstance.cxx

@@ -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 - 0
direct/src/plugin/p3dCInstance.h

@@ -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

+ 11 - 0
direct/src/plugin/p3dInstance.I

@@ -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

+ 6 - 1
direct/src/plugin/p3dInstance.cxx

@@ -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) {

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

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

+ 86 - 12
direct/src/plugin/p3dPythonRun.cxx

@@ -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 *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;
     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;
     }
     }
 
 

+ 7 - 3
direct/src/plugin/p3dPythonRun.h

@@ -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

+ 14 - 17
direct/src/plugin/p3dSession.cxx

@@ -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) {
-  /*
-  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) {
   if (inst->_session == this) {
     inst->_session = NULL;
     inst->_session = NULL;

+ 3 - 0
direct/src/showbase/RunAppMF.py

@@ -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:])