p3dPythonRun.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Filename: p3dPythonRun.h
  2. // Created by: drose (05Jun09)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) Carnegie Mellon University. All rights reserved.
  8. //
  9. // All use of this software is subject to the terms of the revised BSD
  10. // license. You should have received a copy of this license along
  11. // with this source code in a file named "LICENSE."
  12. //
  13. ////////////////////////////////////////////////////////////////////
  14. #ifndef P3DPYTHONRUN_H
  15. #define P3DPYTHONRUN_H
  16. #include "pandabase.h"
  17. #ifdef _WIN32
  18. #define WIN32_LEAN_AND_MEAN
  19. #include <windows.h>
  20. #endif
  21. #include "p3d_lock.h"
  22. #include "handleStream.h"
  23. #include "p3dCInstance.h"
  24. #include "pythonTask.h"
  25. #include "pmap.h"
  26. #include "pdeque.h"
  27. #include "pmutex.h"
  28. #include "get_tinyxml.h"
  29. #include "filename.h"
  30. #include <Python.h>
  31. // Python 2.5 adds Py_ssize_t; earlier versions don't have it.
  32. #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
  33. typedef int Py_ssize_t;
  34. #define PY_SSIZE_T_MAX INT_MAX
  35. #define PY_SSIZE_T_MIN INT_MIN
  36. #endif
  37. using namespace std;
  38. ////////////////////////////////////////////////////////////////////
  39. // Class : P3DPythonRun
  40. // Description : This class is used to run, and communicate with,
  41. // embedded Python in a sub-process. It is compiled and
  42. // launched as a separate executable from the p3d_plugin
  43. // dll, because that's the only way Windows can launch a
  44. // sub-process, and also because it makes it possible to
  45. // compile-time link with Panda and Python, instead of
  46. // having to go through the clumsy dynamic-loading
  47. // interface.
  48. //
  49. // Communication is via XML files exchanged via
  50. // anonymous pipes from the parent process. This isn't
  51. // terribly eficient, of course, but it's easy; and it's
  52. // a fairly low-bandwidth channel so efficiency is not
  53. // paramount.
  54. //
  55. // This executable is not designed to stand alone; it is
  56. // designed to be invoked only by p3d_plugin.
  57. ////////////////////////////////////////////////////////////////////
  58. class P3DPythonRun {
  59. public:
  60. P3DPythonRun(int argc, char *argv[]);
  61. ~P3DPythonRun();
  62. bool run_python();
  63. private:
  64. void handle_command(TiXmlDocument *doc);
  65. void handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
  66. int want_response_id);
  67. void handle_script_response_command(TiXmlElement *xcommand);
  68. void check_comm();
  69. static PyObject *st_check_comm(PyObject *, PyObject *args);
  70. TiXmlDocument *wait_script_response(int response_id);
  71. PyObject *py_request_func(PyObject *args);
  72. static PyObject *st_request_func(PyObject *, PyObject *args);
  73. void spawn_read_thread();
  74. void join_read_thread();
  75. void start_instance(P3DCInstance *inst, TiXmlElement *xinstance);
  76. void terminate_instance(int id);
  77. void set_instance_info(P3DCInstance *inst, TiXmlElement *xinstance);
  78. void add_package_info(P3DCInstance *inst, TiXmlElement *xpackage);
  79. void set_p3d_filename(P3DCInstance *inst, TiXmlElement *xfparams);
  80. void setup_window(int id, TiXmlElement *xwparams);
  81. void setup_window(P3DCInstance *inst, TiXmlElement *xwparams);
  82. void terminate_session();
  83. private:
  84. TiXmlElement *pyobj_to_xml(PyObject *value);
  85. PyObject *xml_to_pyobj(TiXmlElement *xvalue);
  86. private:
  87. // This method runs only within the read thread.
  88. THREAD_CALLBACK_DECLARATION(P3DPythonRun, rt_thread_run);
  89. void rt_thread_run();
  90. private:
  91. typedef pmap<int, P3DCInstance *> Instances;
  92. Instances _instances;
  93. int _session_id;
  94. string _program_name;
  95. Filename _archive_file;
  96. int _py_argc;
  97. char **_py_argv;
  98. PyObject *_runner;
  99. PyObject *_undefined_object_class;
  100. PyObject *_undefined;
  101. PyObject *_concrete_struct_class;
  102. PyObject *_browser_object_class;
  103. PyObject *_taskMgr;
  104. PT(PythonTask) _check_comm_task;
  105. // This map keeps track of the PyObject pointers we have delivered
  106. // to the parent process. We have to hold the reference count on
  107. // each of these until the parent process tells us it's safe to
  108. // release them.
  109. typedef pmap<int, PyObject *> SentObjects;
  110. SentObjects _sent_objects;
  111. int _next_sent_id;
  112. typedef pdeque<TiXmlDocument *> Commands;
  113. // This is a special queue of responses extracted from the _commands
  114. // queue, below. It's protected by the Panda mutex.
  115. Commands _responses;
  116. Mutex _responses_lock;
  117. // The remaining members are manipulated by the read thread.
  118. Commands _commands;
  119. // This has to be an actual OS LOCK instead of Panda's Mutex,
  120. // because we have to use a true thread here, not one of Panda's
  121. // simple threads.
  122. LOCK _commands_lock;
  123. HandleStream _pipe_read;
  124. HandleStream _pipe_write;
  125. bool _read_thread_continue;
  126. bool _program_continue;
  127. THREAD _read_thread;
  128. public:
  129. static P3DPythonRun *_global_ptr;
  130. };
  131. #include "p3dPythonRun.I"
  132. #endif