Fixing bug 386773. Add implementation for NPN_PluginThreadAsyncCall(). r=joshmoz@gmail.com, sr=brendan@mozilla.org

This commit is contained in:
jst@mozilla.org 2007-07-11 16:25:45 -07:00
parent fcde0538ee
commit cfb5411441
6 changed files with 213 additions and 19 deletions

View File

@ -37,7 +37,7 @@
/*
* npapi.h $Revision: 3.45 $
* npapi.h $Revision: 3.46 $
* Netscape client plug-in API spec
*/
@ -120,7 +120,7 @@
/*----------------------------------------------------------------------*/
#define NP_VERSION_MAJOR 0
#define NP_VERSION_MINOR 18
#define NP_VERSION_MINOR 19
/* The OS/2 version of Netscape uses RC_DATA to define the
@ -639,18 +639,19 @@ enum NPEventType {
/*
* Version feature information
*/
#define NPVERS_HAS_STREAMOUTPUT 8
#define NPVERS_HAS_NOTIFICATION 9
#define NPVERS_HAS_LIVECONNECT 9
#define NPVERS_WIN16_HAS_LIVECONNECT 9
#define NPVERS_68K_HAS_LIVECONNECT 11
#define NPVERS_HAS_WINDOWLESS 11
#define NPVERS_HAS_XPCONNECT_SCRIPTING 13
#define NPVERS_HAS_NPRUNTIME_SCRIPTING 14
#define NPVERS_HAS_FORM_VALUES 15
#define NPVERS_HAS_POPUPS_ENABLED_STATE 16
#define NPVERS_HAS_RESPONSE_HEADERS 17
#define NPVERS_HAS_NPOBJECT_ENUM 18
#define NPVERS_HAS_STREAMOUTPUT 8
#define NPVERS_HAS_NOTIFICATION 9
#define NPVERS_HAS_LIVECONNECT 9
#define NPVERS_WIN16_HAS_LIVECONNECT 9
#define NPVERS_68K_HAS_LIVECONNECT 11
#define NPVERS_HAS_WINDOWLESS 11
#define NPVERS_HAS_XPCONNECT_SCRIPTING 13
#define NPVERS_HAS_NPRUNTIME_SCRIPTING 14
#define NPVERS_HAS_FORM_VALUES 15
#define NPVERS_HAS_POPUPS_ENABLED_STATE 16
#define NPVERS_HAS_RESPONSE_HEADERS 17
#define NPVERS_HAS_NPOBJECT_ENUM 18
#define NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL 19
/*----------------------------------------------------------------------*/
/* Function Prototypes */
@ -743,6 +744,9 @@ void NP_LOADDS NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion);
void NP_LOADDS NPN_ForceRedraw(NPP instance);
void NP_LOADDS NPN_PushPopupsEnabledState(NPP instance, NPBool enabled);
void NP_LOADDS NPN_PopPopupsEnabledState(NPP instance);
void NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance,
void (*func) (void *),
void *userData);
#ifdef __cplusplus
} /* end extern "C" */

View File

@ -37,7 +37,7 @@
/*
* npupp.h $Revision: 3.24 $
* npupp.h $Revision: 3.25 $
* function call mecahnics needed by platform specific glue code.
*/
@ -484,6 +484,13 @@ typedef bool (* NP_LOADDS NPN_EnumerateUPP)(NPP npp, NPObject *obj, NPIdentifier
#define CallNPN_EnumerateProc(FUNC, ARG1, ARG2, ARG3, ARG4) \
(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))
/* NPN_Enumerate */
typedef void (* NP_LOADDS NPN_PluginThreadAsyncCallUPP)(NPP instance, void (*func)(void *), void *userData);
#define NewNPN_PluginThreadAsyncCallProc(FUNC) \
((NPN_PluginThreadAsyncCallUPP) (FUNC))
#define CallNPN_PluginThreadAsyncCallProc(FUNC, ARG1, ARG2, ARG3) \
(*(FUNC))((ARG1), (ARG2), (ARG3))
/******************************************************************************************
* The actual plugin function table definitions
@ -554,6 +561,7 @@ typedef struct _NPNetscapeFuncs {
NPN_PushPopupsEnabledStateUPP pushpopupsenabledstate;
NPN_PopPopupsEnabledStateUPP poppopupsenabledstate;
NPN_EnumerateUPP enumerate;
NPN_PluginThreadAsyncCallUPP pluginthreadasynccall;
} NPNetscapeFuncs;

View File

@ -40,10 +40,13 @@
#include "prtypes.h"
#include "prmem.h"
#include "prclist.h"
#include "nsAutoLock.h"
#include "ns4xPlugin.h"
#include "ns4xPluginInstance.h"
#include "ns4xPluginStreamListener.h"
#include "nsIServiceManager.h"
#include "nsThreadUtils.h"
#include "nsIMemory.h"
#include "nsIPluginStreamListener.h"
@ -82,6 +85,9 @@
#include "nsJSNPRuntime.h"
static PRLock *sPluginThreadAsyncCallLock = nsnull;
static PRCList sPendingAsyncCalls = PR_INIT_STATIC_CLIST(&sPendingAsyncCalls);
// POST/GET stream type
enum eNPPStreamTypeInternal {
eNPPStreamTypeInternal_Get,
@ -160,6 +166,9 @@ PR_BEGIN_EXTERN_C
static void NP_CALLBACK
_poppopupsenabledstate(NPP npp);
static void NP_CALLBACK
_pluginthreadasynccall(NPP instance, void (*func)(void *), void *userData);
static const char* NP_CALLBACK
_useragent(NPP npp);
@ -375,6 +384,14 @@ ns4xPlugin::CheckClassInitialized(void)
CALLBACKS.poppopupsenabledstate =
NewNPN_PopPopupsEnabledStateProc(FP2TV(_poppopupsenabledstate));
CALLBACKS.pluginthreadasynccall =
NewNPN_PluginThreadAsyncCallProc(FP2TV(_pluginthreadasynccall));
if (!sPluginThreadAsyncCallLock) {
sPluginThreadAsyncCallLock =
nsAutoLock::NewLock("sPluginThreadAsyncCallLock");
}
initialized = TRUE;
NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN callbacks initialized\n"));
@ -2185,4 +2202,151 @@ _poppopupsenabledstate(NPP npp)
inst->PopPopupsEnabledState();
}
class nsPluginThreadRunnable : public nsRunnable,
public PRCList
{
public:
nsPluginThreadRunnable(NPP instance, void (*func)(void *), void *userData);
virtual ~nsPluginThreadRunnable();
NS_IMETHOD Run();
PRBool IsForInstance(NPP instance)
{
return (mInstance == instance);
}
void Invalidate()
{
mFunc = nsnull;
}
PRBool IsValid()
{
return (mFunc != nsnull);
}
private:
NPP mInstance;
void (*mFunc)(void *);
void *mUserData;
};
nsPluginThreadRunnable::nsPluginThreadRunnable(NPP instance,
void (*func)(void *),
void *userData)
: mInstance(instance), mFunc(func), mUserData(userData)
{
if (!sPluginThreadAsyncCallLock) {
// Failed to create lock, not much we can do here then...
mFunc = nsnull;
return;
}
PR_INIT_CLIST(this);
{
nsAutoLock lock(sPluginThreadAsyncCallLock);
ns4xPluginInstance *inst = (ns4xPluginInstance *)instance->ndata;
if (!inst || !inst->IsStarted()) {
// The plugin was stopped, ignore this async call.
mFunc = nsnull;
return;
}
PR_APPEND_LINK(this, &sPendingAsyncCalls);
}
}
nsPluginThreadRunnable::~nsPluginThreadRunnable()
{
if (!sPluginThreadAsyncCallLock) {
return;
}
{
nsAutoLock lock(sPluginThreadAsyncCallLock);
PR_REMOVE_LINK(this);
}
}
NS_IMETHODIMP
nsPluginThreadRunnable::Run()
{
if (mFunc) {
NS_TRY_SAFE_CALL_VOID(mFunc(mUserData), nsnull, nsnull);
}
return NS_OK;
}
void NP_CALLBACK
_pluginthreadasynccall(NPP instance, void (*func)(void *), void *userData)
{
nsRefPtr<nsPluginThreadRunnable> evt =
new nsPluginThreadRunnable(instance, func, userData);
if (evt && evt->IsValid()) {
NS_DispatchToMainThread(evt);
}
}
void
OnPluginDestroy(NPP instance)
{
if (!sPluginThreadAsyncCallLock) {
return;
}
{
nsAutoLock lock(sPluginThreadAsyncCallLock);
if (PR_CLIST_IS_EMPTY(&sPendingAsyncCalls)) {
return;
}
nsPluginThreadRunnable *r =
(nsPluginThreadRunnable *)PR_LIST_HEAD(&sPendingAsyncCalls);
do {
if (r->IsForInstance(instance)) {
r->Invalidate();
}
r = (nsPluginThreadRunnable *)PR_NEXT_LINK(r);
} while (r != &sPendingAsyncCalls);
}
}
void
OnShutdown()
{
NS_ASSERTION(PR_CLIST_IS_EMPTY(&sPendingAsyncCalls),
"Pending async plugin call list not cleaned up!");
if (sPluginThreadAsyncCallLock) {
nsAutoLock::DestroyLock(sPluginThreadAsyncCallLock);
}
}
void
EnterAsyncPluginThreadCallLock()
{
if (sPluginThreadAsyncCallLock) {
PR_Lock(sPluginThreadAsyncCallLock);
}
}
void
ExitAsyncPluginThreadCallLock()
{
if (sPluginThreadAsyncCallLock) {
PR_Unlock(sPluginThreadAsyncCallLock);
}
}
NPP NPPStack::sCurrentNPP = nsnull;

View File

@ -253,6 +253,17 @@ PeekException();
void
PopException();
void
OnPluginDestroy(NPP instance);
void
OnShutdown();
void
EnterAsyncPluginThreadCallLock();
void
ExitAsyncPluginThreadCallLock();
class NPPStack
{
public:

View File

@ -869,8 +869,8 @@ NS_IMETHODIMP ns4xPluginInstance::Start(void)
if(mStarted)
return NS_OK;
else
return InitializePlugin(mPeer);
return InitializePlugin(mPeer);
}
@ -900,6 +900,14 @@ NS_IMETHODIMP ns4xPluginInstance::Stop(void)
if(!mStarted)
return NS_OK;
// Make sure we lock while we're writing to mStarted after we've
// started as other threads might be checking that inside a lock.
EnterAsyncPluginThreadCallLock();
mStarted = PR_FALSE;
ExitAsyncPluginThreadCallLock();
OnPluginDestroy(&fNPP);
if (fCallbacks->destroy == NULL)
return NS_ERROR_FAILURE; // XXX right error?
@ -925,8 +933,6 @@ NS_IMETHODIMP ns4xPluginInstance::Stop(void)
NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("NPP Destroy called: this=%p, npp=%p, return=%d\n", this, &fNPP, error));
mStarted = PR_FALSE;
nsJSNPRuntime::OnPluginDestroy(&fNPP);
if(error != NPERR_NO_ERROR)

View File

@ -6355,6 +6355,7 @@ NS_IMETHODIMP nsPluginHostImpl::Observe(nsISupports *aSubject,
{
if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic))
{
OnShutdown();
Destroy();
UnloadUnusedLibraries();
sInst->Release();