mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 18:31:55 -04:00
attempts to make windows plugin more stable
This commit is contained in:
parent
850773c4eb
commit
d5b4f7810e
@ -22,8 +22,9 @@
|
||||
fileSpec.cxx fileSpec.h fileSpec.I \
|
||||
find_root_dir.cxx find_root_dir.h \
|
||||
get_tinyxml.h \
|
||||
binaryXml.cxx binaryXml.h \
|
||||
handleStream.cxx handleStream.h handleStream.I \
|
||||
handleStreamBuf.cxx handleStreamBuf.h \
|
||||
handleStreamBuf.cxx handleStreamBuf.h handleStreamBuf.I \
|
||||
mkdir_complete.cxx mkdir_complete.h \
|
||||
p3d_lock.h p3d_plugin.h \
|
||||
p3d_plugin_config.h \
|
||||
@ -98,14 +99,17 @@
|
||||
pipeline:c event:c nativenet:c panda:m
|
||||
|
||||
#define SOURCES \
|
||||
binaryXml.cxx binaryXml.h \
|
||||
handleStream.cxx handleStream.h handleStream.I \
|
||||
handleStreamBuf.cxx handleStreamBuf.h \
|
||||
handleStreamBuf.cxx handleStreamBuf.h handleStreamBuf.I \
|
||||
p3d_lock.h p3d_plugin.h \
|
||||
p3d_plugin_config.h \
|
||||
p3dCInstance.cxx \
|
||||
p3dCInstance.h p3dCInstance.I \
|
||||
p3dPythonRun.cxx p3dPythonRun.h p3dPythonRun.I
|
||||
|
||||
#define WIN_SYS_LIBS user32.lib
|
||||
|
||||
#end bin_target
|
||||
|
||||
#begin static_lib_target
|
||||
|
142
direct/src/plugin/binaryXml.cxx
Normal file
142
direct/src/plugin/binaryXml.cxx
Normal file
@ -0,0 +1,142 @@
|
||||
// Filename: binaryXml.cxx
|
||||
// Created by: drose (13Jul09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "binaryXml.h"
|
||||
#include <sstream>
|
||||
|
||||
// Actually, we haven't implemented the binary I/O for XML files yet.
|
||||
// We just map these directly to the classic formatted I/O for now.
|
||||
|
||||
static const bool debug_xml_output = true;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: write_xml
|
||||
// Description: Writes the indicated TinyXml document to the given
|
||||
// stream.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
write_xml(HandleStream &out, TiXmlDocument *doc, ostream &logfile) {
|
||||
ostringstream strm;
|
||||
strm << *doc;
|
||||
string data = strm.str();
|
||||
|
||||
size_t length = data.length();
|
||||
out.write((char *)&length, sizeof(length));
|
||||
out.write(data.data(), length);
|
||||
out << flush;
|
||||
|
||||
if (debug_xml_output) {
|
||||
logfile << "sent: " << data << "\n" << flush;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: read_xml
|
||||
// Description: Reads a TinyXml document from the given stream, and
|
||||
// returns it. If the document is not yet available,
|
||||
// blocks until it is, or until there is an error
|
||||
// condition on the input.
|
||||
//
|
||||
// The return value is NULL if there is an error, or the
|
||||
// newly-allocated document if it is successfully read.
|
||||
// If not NULL, the document has been allocated with
|
||||
// new, and should be eventually freed by the caller
|
||||
// with delete.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TiXmlDocument *
|
||||
read_xml(HandleStream &in, ostream &logfile) {
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE handle = in.get_handle();
|
||||
|
||||
size_t length;
|
||||
DWORD bytes_read = 0;
|
||||
logfile << "ReadFile\n" << flush;
|
||||
BOOL success = ReadFile(handle, &length, sizeof(length), &bytes_read, NULL);
|
||||
logfile << "done ReadFile\n" << flush;
|
||||
if (!success) {
|
||||
DWORD error = GetLastError();
|
||||
if (error != ERROR_HANDLE_EOF && error != ERROR_BROKEN_PIPE) {
|
||||
logfile << "Error reading " << sizeof(length)
|
||||
<< " bytes, windows error code 0x" << hex
|
||||
<< error << dec << ".\n";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
assert(bytes_read == sizeof(length));
|
||||
|
||||
if (debug_xml_output) {
|
||||
ostringstream logout;
|
||||
logout << "reading " << length << " bytes\n";
|
||||
logfile << logout.str() << flush;
|
||||
}
|
||||
|
||||
char *buffer = new char[length];
|
||||
|
||||
bytes_read = 0;
|
||||
success = ReadFile(handle, buffer, length, &bytes_read, NULL);
|
||||
if (!success) {
|
||||
DWORD error = GetLastError();
|
||||
if (error != ERROR_HANDLE_EOF && error != ERROR_BROKEN_PIPE) {
|
||||
logfile << "Error reading " << length
|
||||
<< " bytes, windows error code 0x" << hex
|
||||
<< error << dec << ".\n";
|
||||
}
|
||||
delete[] buffer;
|
||||
return NULL;
|
||||
}
|
||||
assert(bytes_read == length);
|
||||
|
||||
string data(buffer, length);
|
||||
delete[] buffer;
|
||||
|
||||
#else
|
||||
size_t length;
|
||||
in.read((char *)&length, sizeof(length));
|
||||
if (in.gcount() != sizeof(length)) {
|
||||
logfile << "read " << in.gcount() << " bytes instead of " << sizeof(length)
|
||||
<< "\n";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (debug_xml_output) {
|
||||
ostringstream logout;
|
||||
logout << "reading " << length << " bytes\n";
|
||||
logfile << logout.str() << flush;
|
||||
}
|
||||
|
||||
char *buffer = new char[length];
|
||||
in.read(buffer, length);
|
||||
if (in.gcount() != length) {
|
||||
delete[] buffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string data(buffer, length);
|
||||
delete[] buffer;
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
istringstream strm(data);
|
||||
TiXmlDocument *doc = new TiXmlDocument;
|
||||
strm >> *doc;
|
||||
|
||||
if (debug_xml_output) {
|
||||
ostringstream logout;
|
||||
logout << "received: " << *doc << "\n";
|
||||
logfile << logout.str() << flush;
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
32
direct/src/plugin/binaryXml.h
Normal file
32
direct/src/plugin/binaryXml.h
Normal file
@ -0,0 +1,32 @@
|
||||
// Filename: binaryXml.h
|
||||
// Created by: drose (13Jul09)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 BINARYXML_H
|
||||
#define BINARYXML_H
|
||||
|
||||
#include "get_tinyxml.h"
|
||||
#include "handleStream.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// A pair of functions to input and output the TinyXml constructs on
|
||||
// the indicated streams. We could, of course, use the TinyXml output
|
||||
// operators, but this is a smidge more efficient and gives us more
|
||||
// control.
|
||||
|
||||
void write_xml(HandleStream &out, TiXmlDocument *doc, ostream &logfile);
|
||||
TiXmlDocument *read_xml(HandleStream &in, ostream &logfile);
|
||||
|
||||
#endif
|
@ -14,7 +14,7 @@
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HandleStream::Constructor
|
||||
// Access: Published
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline HandleStream::
|
||||
@ -23,7 +23,7 @@ HandleStream() : iostream(&_buf) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HandleStream::Destructor
|
||||
// Access: Published
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline HandleStream::
|
||||
@ -33,7 +33,7 @@ inline HandleStream::
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HandleStream::open_read
|
||||
// Access: Published
|
||||
// Access: Public
|
||||
// Description: Attempts to open the given handle for input. The
|
||||
// stream may not be simultaneously open for input and
|
||||
// output.
|
||||
@ -49,7 +49,7 @@ open_read(FHandle handle) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HandleStream::open_write
|
||||
// Access: Published
|
||||
// Access: Public
|
||||
// Description: Attempts to open the given handle for output. The
|
||||
// stream may not be simultaneously open for input and
|
||||
// output.
|
||||
@ -65,10 +65,21 @@ open_write(FHandle handle) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HandleStream::close
|
||||
// Access: Published
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline void HandleStream::
|
||||
close() {
|
||||
_buf.close();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HandleStream::get_handle
|
||||
// Access: Public
|
||||
// Description: Returns the handle that was passed to open_read() or
|
||||
// open_write().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline FHandle HandleStream::
|
||||
get_handle() const {
|
||||
return _buf.get_handle();
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ public:
|
||||
inline void open_write(FHandle handle);
|
||||
inline void close();
|
||||
|
||||
inline FHandle get_handle() const;
|
||||
|
||||
private:
|
||||
HandleStreamBuf _buf;
|
||||
};
|
||||
|
@ -12,3 +12,14 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HandleStreamBuf::get_handle
|
||||
// Access: Public
|
||||
// Description: Returns the handle that was passed to open_read() or
|
||||
// open_write().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
inline FHandle HandleStreamBuf::
|
||||
get_handle() const {
|
||||
return _handle;
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ typedef HANDLE FHandle;
|
||||
typedef int FHandle;
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
@ -43,6 +42,8 @@ public:
|
||||
bool is_open_write() const;
|
||||
void close();
|
||||
|
||||
inline FHandle get_handle() const;
|
||||
|
||||
protected:
|
||||
virtual int overflow(int c);
|
||||
virtual int sync();
|
||||
@ -61,4 +62,6 @@ private:
|
||||
char *_buffer;
|
||||
};
|
||||
|
||||
#include "handleStreamBuf.I"
|
||||
|
||||
#endif
|
||||
|
@ -361,6 +361,7 @@ bake_requests() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
add_raw_request(TiXmlDocument *doc) {
|
||||
nout << "add_raw_request " << this << "\n" << flush;
|
||||
ACQUIRE_LOCK(_request_lock);
|
||||
_raw_requests.push_back(doc);
|
||||
_request_pending = true;
|
||||
@ -374,6 +375,7 @@ add_raw_request(TiXmlDocument *doc) {
|
||||
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
|
||||
inst_mgr->signal_request_ready(this);
|
||||
_session->signal_request_ready(this);
|
||||
nout << "done add_raw_request " << this << "\n" << flush;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -640,6 +642,35 @@ request_stop() {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::pump_messages
|
||||
// Access: Public
|
||||
// Description: Windows only: pump the message queue on this
|
||||
// instance's parent window, so that any child-window
|
||||
// operations will be able to continue.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DInstance::
|
||||
pump_messages() {
|
||||
#ifdef _WIN32
|
||||
if (_got_wparams) {
|
||||
HWND hwnd = _wparams.get_parent_window()._hwnd;
|
||||
if (hwnd != NULL) {
|
||||
MSG msg;
|
||||
nout << " peeking " << hwnd << "\n" << flush;
|
||||
|
||||
// It appears to be bad to pump messages for any other
|
||||
// window--Mozilla is apparently not reentrant in this way.
|
||||
if (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE | PM_NOYIELD)) {
|
||||
nout << " pumping " << msg.message << "\n" << flush;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
nout << " done pumping\n" << flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: P3DInstance::make_xml
|
||||
// Access: Public
|
||||
|
@ -82,6 +82,7 @@ public:
|
||||
void start_download(P3DDownload *download);
|
||||
inline bool is_started() const;
|
||||
void request_stop();
|
||||
void pump_messages();
|
||||
|
||||
TiXmlElement *make_xml();
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "p3dPythonRun.h"
|
||||
#include "asyncTaskManager.h"
|
||||
#include "binaryXml.h"
|
||||
|
||||
// There is only one P3DPythonRun object in any given process space.
|
||||
// Makes the statics easier to deal with, and we don't need multiple
|
||||
@ -299,8 +300,7 @@ handle_command(TiXmlDocument *doc) {
|
||||
xresponse->SetAttribute("response_id", want_response_id);
|
||||
doc.LinkEndChild(decl);
|
||||
doc.LinkEndChild(xresponse);
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc << flush;
|
||||
write_xml(_pipe_write, &doc, nout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -473,8 +473,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
|
||||
}
|
||||
|
||||
if (needs_response) {
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc << flush;
|
||||
write_xml(_pipe_write, &doc, nout);
|
||||
}
|
||||
}
|
||||
|
||||
@ -488,6 +487,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DPythonRun::
|
||||
check_comm() {
|
||||
nout << ":" << flush;
|
||||
ACQUIRE_LOCK(_commands_lock);
|
||||
while (!_commands.empty()) {
|
||||
TiXmlDocument *doc = _commands.front();
|
||||
@ -532,7 +532,7 @@ task_check_comm(GenericAsyncTask *task, void *user_data) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TiXmlDocument *P3DPythonRun::
|
||||
wait_script_response(int response_id) {
|
||||
nout << "Waiting script_response " << response_id << "\n";
|
||||
nout << "waiting script_response " << response_id << "\n" << flush;
|
||||
while (true) {
|
||||
ACQUIRE_LOCK(_commands_lock);
|
||||
|
||||
@ -550,7 +550,7 @@ wait_script_response(int response_id) {
|
||||
// This is the response we were waiting for.
|
||||
_commands.erase(ci);
|
||||
RELEASE_LOCK(_commands_lock);
|
||||
nout << "received script_response: " << *doc << "\n" << flush;
|
||||
nout << "got script_response " << unique_id << "\n" << flush;
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
@ -564,6 +564,7 @@ wait_script_response(int response_id) {
|
||||
// This command will be wanting a response. We'd better
|
||||
// honor it right away, or we risk deadlock with the browser
|
||||
// process and the Python process waiting for each other.
|
||||
nout << "honoring response " << want_response_id << "\n" << flush;
|
||||
_commands.erase(ci);
|
||||
RELEASE_LOCK(_commands_lock);
|
||||
handle_command(doc);
|
||||
@ -580,6 +581,27 @@ wait_script_response(int response_id) {
|
||||
|
||||
RELEASE_LOCK(_commands_lock);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Make sure we process the Windows event loop while we're
|
||||
// waiting, or everything that depends on Windows messages will
|
||||
// starve.
|
||||
|
||||
// We appear to be best off with just a single PeekMessage() call
|
||||
// here; the full message pump seems to cause problems.
|
||||
MSG msg;
|
||||
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD);
|
||||
/*
|
||||
if (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE | PM_NOYIELD)) {
|
||||
nout << " pumping " << msg.message << "\n" << flush;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
nout << " done pumping\n" << flush;
|
||||
}
|
||||
*/
|
||||
#endif // _WIN32
|
||||
|
||||
nout << "." << flush;
|
||||
|
||||
// It hasn't shown up yet. Give the sub-thread a chance to
|
||||
// process the input and append it to the queue.
|
||||
Thread::force_yield();
|
||||
@ -648,8 +670,7 @@ py_request_func(PyObject *args) {
|
||||
}
|
||||
|
||||
xrequest->SetAttribute("message", message);
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc << flush;
|
||||
write_xml(_pipe_write, &doc, nout);
|
||||
|
||||
} else if (strcmp(request_type, "script") == 0) {
|
||||
// Meddling with a scripting variable on the browser side.
|
||||
@ -693,8 +714,7 @@ py_request_func(PyObject *args) {
|
||||
xrequest->LinkEndChild(xvalue);
|
||||
}
|
||||
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc << flush;
|
||||
write_xml(_pipe_write, &doc, nout);
|
||||
|
||||
} else if (strcmp(request_type, "drop_p3dobj") == 0) {
|
||||
// Release a particular P3D_object that we were holding a
|
||||
@ -706,8 +726,7 @@ py_request_func(PyObject *args) {
|
||||
nout << "got drop_p3dobj(" << object_id << ")\n" << flush;
|
||||
|
||||
xrequest->SetAttribute("object_id", object_id);
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc << flush;
|
||||
write_xml(_pipe_write, &doc, nout);
|
||||
|
||||
} else {
|
||||
string message = string("Unsupported request type: ") + string(request_type);
|
||||
@ -1150,10 +1169,8 @@ xml_to_pyobj(TiXmlElement *xvalue) {
|
||||
void P3DPythonRun::
|
||||
rt_thread_run() {
|
||||
while (_read_thread_continue) {
|
||||
TiXmlDocument *doc = new TiXmlDocument;
|
||||
|
||||
_pipe_read >> *doc;
|
||||
if (!_pipe_read || _pipe_read.eof()) {
|
||||
TiXmlDocument *doc = read_xml(_pipe_read, nout);
|
||||
if (doc == NULL) {
|
||||
// Some error on reading. Abort.
|
||||
_program_continue = false;
|
||||
return;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "p3dIntObject.h"
|
||||
#include "p3dFloatObject.h"
|
||||
#include "p3dPythonObject.h"
|
||||
#include "binaryXml.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <fcntl.h>
|
||||
@ -94,8 +95,7 @@ shutdown() {
|
||||
xcommand->SetAttribute("cmd", "exit");
|
||||
doc.LinkEndChild(decl);
|
||||
doc.LinkEndChild(xcommand);
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc << flush;
|
||||
write_xml(_pipe_write, &doc, nout);
|
||||
|
||||
// Also close the pipe, to help underscore the point.
|
||||
_pipe_write.close();
|
||||
@ -226,8 +226,7 @@ void P3DSession::
|
||||
send_command(TiXmlDocument *command) {
|
||||
if (_p3dpython_running) {
|
||||
// Python is running. Send the command.
|
||||
nout << "sent: " << *command << "\n" << flush;
|
||||
_pipe_write << *command << flush;
|
||||
write_xml(_pipe_write, command, nout);
|
||||
delete command;
|
||||
} else {
|
||||
// Python not yet running. Queue up the command instead.
|
||||
@ -265,13 +264,14 @@ command_and_response(TiXmlDocument *command) {
|
||||
assert(xcommand != NULL);
|
||||
xcommand->SetAttribute("want_response_id", response_id);
|
||||
|
||||
nout << "sent: " << *command << "\n" << flush;
|
||||
_pipe_write << *command << flush;
|
||||
write_xml(_pipe_write, command, nout);
|
||||
delete command;
|
||||
|
||||
// Now block, waiting for a response to be delivered. We assume
|
||||
// only one thread will be waiting at a time.
|
||||
nout << "waiting for response " << response_id << "\n" << flush;
|
||||
int tick_start = GetTickCount();
|
||||
|
||||
_response_ready.acquire();
|
||||
Responses::iterator ri = _responses.find(response_id);
|
||||
while (ri == _responses.end()) {
|
||||
@ -296,6 +296,7 @@ command_and_response(TiXmlDocument *command) {
|
||||
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
|
||||
P3DInstance *inst = (*ii).second;
|
||||
inst->bake_requests();
|
||||
inst->pump_messages();
|
||||
}
|
||||
_response_ready.acquire();
|
||||
|
||||
@ -312,9 +313,18 @@ command_and_response(TiXmlDocument *command) {
|
||||
// particular, the CreateWindow() call within the subprocess--will
|
||||
// starve, and we could end up with deadlock.
|
||||
|
||||
// A single PeekMessage() seems to be sufficient.
|
||||
MSG msg;
|
||||
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD);
|
||||
/*
|
||||
MSG msg;
|
||||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) {
|
||||
// nout << " pumping " << msg.message << "\n" << flush;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
// nout << " done pumping\n" << flush;
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
// We wait with a timeout, so we can go back and spin the event
|
||||
@ -529,8 +539,7 @@ drop_pyobj(int object_id) {
|
||||
xcommand->SetAttribute("object_id", object_id);
|
||||
doc.LinkEndChild(decl);
|
||||
doc.LinkEndChild(xcommand);
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc << flush;
|
||||
write_xml(_pipe_write, &doc, nout);
|
||||
}
|
||||
}
|
||||
|
||||
@ -657,20 +666,16 @@ start_p3dpython() {
|
||||
xcommand->SetAttribute("session_id", _session_id);
|
||||
doc.LinkEndChild(decl);
|
||||
doc.LinkEndChild(xcommand);
|
||||
nout << "sent: " << doc << "\n" << flush;
|
||||
_pipe_write << doc;
|
||||
write_xml(_pipe_write, &doc, nout);
|
||||
|
||||
// Also feed it any commands we may have queued up from before the
|
||||
// process was started.
|
||||
Commands::iterator ci;
|
||||
for (ci = _commands.begin(); ci != _commands.end(); ++ci) {
|
||||
nout << "sent: " << *(*ci) << "\n" << flush;
|
||||
_pipe_write << *(*ci);
|
||||
write_xml(_pipe_write, (*ci), nout);
|
||||
delete (*ci);
|
||||
}
|
||||
_commands.clear();
|
||||
|
||||
_pipe_write << flush;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -715,10 +720,8 @@ join_read_thread() {
|
||||
void P3DSession::
|
||||
rt_thread_run() {
|
||||
while (_read_thread_continue) {
|
||||
TiXmlDocument *doc = new TiXmlDocument;
|
||||
|
||||
_pipe_read >> *doc;
|
||||
if (!_pipe_read || _pipe_read.eof()) {
|
||||
TiXmlDocument *doc = read_xml(_pipe_read, nout);
|
||||
if (doc == NULL) {
|
||||
// Some error on reading. Abort.
|
||||
rt_terminate();
|
||||
return;
|
||||
@ -727,6 +730,8 @@ rt_thread_run() {
|
||||
// Successfully read an XML document.
|
||||
rt_handle_request(doc);
|
||||
}
|
||||
|
||||
logfile << "Exiting rt_thread_run in " << this << "\n" << flush;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -737,6 +742,7 @@ rt_thread_run() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
rt_handle_request(TiXmlDocument *doc) {
|
||||
nout << "rt_handle_request in " << this << "\n" << flush;
|
||||
TiXmlElement *xresponse = doc->FirstChildElement("response");
|
||||
if (xresponse != (TiXmlElement *)NULL) {
|
||||
int response_id;
|
||||
@ -748,6 +754,7 @@ rt_handle_request(TiXmlDocument *doc) {
|
||||
assert(inserted);
|
||||
_response_ready.notify();
|
||||
_response_ready.release();
|
||||
nout << "done a, rt_handle_request in " << this << "\n" << flush;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -772,6 +779,7 @@ rt_handle_request(TiXmlDocument *doc) {
|
||||
if (doc != NULL) {
|
||||
delete doc;
|
||||
}
|
||||
nout << "done rt_handle_request in " << this << "\n" << flush;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -200,7 +200,14 @@ stop_thread() {
|
||||
// Post a silly message to spin the message loop.
|
||||
PostThreadMessage(_thread_id, WM_USER, 0, 0);
|
||||
|
||||
WaitForSingleObject(_thread, INFINITE);
|
||||
// We can't actually wait for the thread to finish, since there
|
||||
// might a deadlock there: the thread can't finish deleting its
|
||||
// window unless we're pumping the message loop for the parent,
|
||||
// which won't happen if we're sitting here waiting. No worries; we
|
||||
// don't *really* need to wait for the thread.
|
||||
|
||||
// WaitForSingleObject(_thread, INFINITE);
|
||||
|
||||
CloseHandle(_thread);
|
||||
_thread = NULL;
|
||||
}
|
||||
|
@ -23,11 +23,25 @@
|
||||
// Windows case
|
||||
|
||||
// Locks are straightforward.
|
||||
class _lock {
|
||||
public:
|
||||
CRITICAL_SECTION _l;
|
||||
int _count;
|
||||
};
|
||||
|
||||
#define LOCK _lock
|
||||
#define INIT_LOCK(lock) { InitializeCriticalSection(&(lock)._l); (lock)._count = 0; }
|
||||
#define ACQUIRE_LOCK(lock) { EnterCriticalSection(&(lock)._l); ++((lock)._count); if ((lock)._count > 1) { nout << "count = " << (lock)._count << "\n"; } }
|
||||
#define RELEASE_LOCK(lock) { --((lock)._count); LeaveCriticalSection(&(lock)._l); }
|
||||
#define DESTROY_LOCK(lock) DeleteCriticalSection(&(lock)._l)
|
||||
|
||||
/*
|
||||
#define LOCK CRITICAL_SECTION
|
||||
#define INIT_LOCK(lock) InitializeCriticalSection(&(lock))
|
||||
#define ACQUIRE_LOCK(lock) EnterCriticalSection(&(lock))
|
||||
#define RELEASE_LOCK(lock) LeaveCriticalSection(&(lock))
|
||||
#define DESTROY_LOCK(lock) DeleteCriticalSection(&(lock))
|
||||
*/
|
||||
|
||||
// Threads.
|
||||
#define THREAD HANDLE
|
||||
|
@ -62,6 +62,13 @@ extern ofstream logfile;
|
||||
|
||||
#include "load_plugin.h"
|
||||
|
||||
// Uncomment the following to enable use of the PluginThreadAsyncCall
|
||||
// function. (It's commented out for now to assist development of the
|
||||
// case in which this is not available.)
|
||||
#if defined(NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL) && NP_VERSION_MINOR >= NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL
|
||||
#define HAS_PLUGIN_THREAD_ASYNC_CALL 1
|
||||
#endif
|
||||
|
||||
// Appears in startup.cxx.
|
||||
extern NPNetscapeFuncs *browser;
|
||||
|
||||
|
@ -436,31 +436,6 @@ handle_request(P3D_request *request) {
|
||||
P3D_request_finish(request, handled);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPInstance::handle_request_loop
|
||||
// Access: Public, Static
|
||||
// Description: Checks for any new requests from the plugin, and
|
||||
// dispatches them to the appropriate PPInstance. This
|
||||
// function is called only in the main thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PPInstance::
|
||||
handle_request_loop() {
|
||||
if (!is_plugin_loaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
P3D_instance *p3d_inst = P3D_check_request(false);
|
||||
while (p3d_inst != (P3D_instance *)NULL) {
|
||||
P3D_request *request = P3D_instance_get_request(p3d_inst);
|
||||
if (request != (P3D_request *)NULL) {
|
||||
PPInstance *inst = (PPInstance *)(p3d_inst->_user_data);
|
||||
assert(inst != NULL);
|
||||
inst->handle_request(request);
|
||||
}
|
||||
p3d_inst = P3D_check_request(false);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPInstance::handle_event
|
||||
// Access: Public
|
||||
@ -469,8 +444,12 @@ handle_request_loop() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PPInstance::
|
||||
handle_event(void *event) {
|
||||
// This is a good time to check for new requests.
|
||||
#ifndef HAS_PLUGIN_THREAD_ASYNC_CALL
|
||||
// If we can't ask Mozilla to call us back using
|
||||
// NPN_PluginThreadAsyncCall(), then we'll take advantage of the
|
||||
// event loop to do it now.
|
||||
handle_request_loop();
|
||||
#endif
|
||||
|
||||
if (_p3d_inst == NULL) {
|
||||
// Ignore events that come in before we've launched the instance.
|
||||
@ -631,14 +610,24 @@ request_ready(P3D_instance *instance) {
|
||||
// << " thread = " << GetCurrentThreadId()
|
||||
<< "\n" << flush;
|
||||
|
||||
PPInstance *inst = (PPInstance *)(instance->_user_data);
|
||||
assert(inst != NULL);
|
||||
|
||||
#ifdef HAS_PLUGIN_THREAD_ASYNC_CALL
|
||||
// Since we are running at least Gecko 1.9, and we have this very
|
||||
// useful function, let's use it to ask the browser to call us back
|
||||
// in the main thread.
|
||||
browser->pluginthreadasynccall(inst->_npp_instance, browser_sync_callback, NULL);
|
||||
#else // HAS_PLUGIN_THREAD_ASYNC_CALL
|
||||
|
||||
// If we're using an older version of Gecko, we have to do this some
|
||||
// other, OS-dependent way.
|
||||
|
||||
#ifdef _WIN32
|
||||
// Since we might be in a sub-thread at this point, use a Windows
|
||||
// message to forward this event to the main thread.
|
||||
// Use a Windows message to forward this event to the main thread.
|
||||
|
||||
// Get the window handle for the window associated with this
|
||||
// instance.
|
||||
PPInstance *inst = (PPInstance *)(instance->_user_data);
|
||||
assert(inst != NULL);
|
||||
const NPWindow *win = inst->get_window();
|
||||
if (win != NULL && win->type == NPWindowTypeWindow) {
|
||||
PostMessage((HWND)(win->window), WM_USER, 0, 0);
|
||||
@ -656,6 +645,8 @@ request_ready(P3D_instance *instance) {
|
||||
handle_request_loop();
|
||||
#endif // __APPLE__
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // HAS_PLUGIN_THREAD_ASYNC_CALL
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -1101,6 +1092,45 @@ output_np_variant(ostream &out, const NPVariant &result) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPInstance::handle_request_loop
|
||||
// Access: Private, Static
|
||||
// Description: Checks for any new requests from the plugin, and
|
||||
// dispatches them to the appropriate PPInstance. This
|
||||
// function is called only in the main thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PPInstance::
|
||||
handle_request_loop() {
|
||||
if (!is_plugin_loaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
P3D_instance *p3d_inst = P3D_check_request(false);
|
||||
while (p3d_inst != (P3D_instance *)NULL) {
|
||||
P3D_request *request = P3D_instance_get_request(p3d_inst);
|
||||
if (request != (P3D_request *)NULL) {
|
||||
PPInstance *inst = (PPInstance *)(p3d_inst->_user_data);
|
||||
assert(inst != NULL);
|
||||
inst->handle_request(request);
|
||||
}
|
||||
p3d_inst = P3D_check_request(false);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PPInstance::browser_sync_callback
|
||||
// Access: Private, Static
|
||||
// Description: This callback hook is passed to
|
||||
// NPN_PluginThreadAsyncCall() (if that function is
|
||||
// available) to forward a request to the main thread.
|
||||
// The callback is actually called in the main thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PPInstance::
|
||||
browser_sync_callback(void *) {
|
||||
logfile << "browser_sync_callback\n";
|
||||
handle_request_loop();
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -1113,14 +1143,12 @@ output_np_variant(ostream &out, const NPVariant &result) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
LONG PPInstance::
|
||||
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
#ifndef HAS_PLUGIN_THREAD_ASYNC_CALL
|
||||
// Since we're here in the main thread, call handle_request_loop()
|
||||
// to see if there are any new requests to be serviced by the main
|
||||
// thread.
|
||||
|
||||
// This might end up recursing repeatedly into
|
||||
// handle_request_loop(). Not sure if this is bad or not.
|
||||
// *Something* appears to be a little unstable.
|
||||
handle_request_loop();
|
||||
#endif
|
||||
|
||||
switch (msg) {
|
||||
case WM_ERASEBKGND:
|
||||
@ -1129,6 +1157,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
return true;
|
||||
|
||||
case WM_TIMER:
|
||||
case WM_USER:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,6 @@ public:
|
||||
void stream_as_file(NPStream *stream, const char *fname);
|
||||
|
||||
void handle_request(P3D_request *request);
|
||||
static void handle_request_loop();
|
||||
|
||||
void handle_event(void *event);
|
||||
|
||||
@ -78,6 +77,9 @@ private:
|
||||
void create_instance();
|
||||
void send_window();
|
||||
|
||||
static void handle_request_loop();
|
||||
static void browser_sync_callback(void *);
|
||||
|
||||
#ifdef _WIN32
|
||||
static LONG
|
||||
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
|
||||
|
@ -329,7 +329,7 @@ NPP_Print(NPP instance, NPPrint *platformPrint) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int16
|
||||
NPP_HandleEvent(NPP instance, void *event) {
|
||||
// logfile << "HandleEvent\n" << flush;
|
||||
logfile << "HandleEvent\n" << flush;
|
||||
|
||||
PPInstance *inst = (PPInstance *)(instance->pdata);
|
||||
assert(inst != NULL);
|
||||
|
Loading…
x
Reference in New Issue
Block a user