Implement pass-ref semantics for NPObject and NPVariant
This will allow us to get rid of delayed NPN_ReleaseObject.
This commit is contained in:
parent
94593ff660
commit
3791e265ab
|
@ -33,6 +33,7 @@ extern int npclass_add_method_descriptors(rpc_connection_t *connection) attribut
|
|||
// Management of stubs, objects which live on the side that owns the
|
||||
// NPObject and holds a reference to it on behalf of a proxy.
|
||||
extern uint32_t npobject_create_stub(NPObject *npobj) attribute_hidden;
|
||||
extern void npobject_destroy_stub(uint32_t id) attribute_hidden;
|
||||
extern NPObject *npobject_lookup_local(uint32_t id) attribute_hidden;
|
||||
|
||||
// Create a proxy object. The received id must correspond to a live
|
||||
|
@ -41,6 +42,7 @@ extern NPObject *npobject_lookup_local(uint32_t id) attribute_hidden;
|
|||
// its stub.
|
||||
extern NPObject *npobject_create_proxy(uint32_t id) attribute_hidden;
|
||||
extern uint32_t npobject_get_proxy_id(NPObject *npobj) attribute_hidden;
|
||||
extern void npobject_destroy_proxy(NPObject *npobj, bool release_stub);
|
||||
|
||||
struct _NPVariant;
|
||||
extern void npvariant_clear(struct _NPVariant *variant) attribute_hidden;
|
||||
|
|
|
@ -103,14 +103,21 @@ NPObject *npobject_lookup_local(uint32_t id)
|
|||
return stub ? stub->npobject : NULL;
|
||||
}
|
||||
|
||||
static void npobject_destroy_stub(NPObjectStub *stub)
|
||||
static void npobject_destroy_stub_obj(NPObjectStub *stub)
|
||||
{
|
||||
D(bug("npobject_stub: id=0x%x\n", stub->id));
|
||||
D(bug("npobject_destroy_stub: id=0x%x\n", stub->id));
|
||||
g_hash_table_remove(g_stubs, GINT_TO_POINTER(stub->id));
|
||||
NPN_ReleaseObject(stub->npobject);
|
||||
g_free(stub);
|
||||
}
|
||||
|
||||
void npobject_destroy_stub(uint32_t id)
|
||||
{
|
||||
NPObjectStub *stub = npobject_lookup_stub(id);
|
||||
assert(stub != NULL);
|
||||
npobject_destroy_stub_obj(stub);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
/* === NPObject proxies === */
|
||||
/* ====================================================================== */
|
||||
|
@ -154,6 +161,23 @@ uint32_t npobject_get_proxy_id(NPObject *npobj)
|
|||
return proxy->id;
|
||||
}
|
||||
|
||||
static void npclass_invoke_Deallocate(NPObjectProxy *proxy);
|
||||
|
||||
void npobject_destroy_proxy(NPObject *npobj, bool release_stub)
|
||||
{
|
||||
// Unregister the proxy.
|
||||
D(bugiI("npobject_destroy_proxy: npobj=%p, release_stub=%d\n",
|
||||
npobj, release_stub));
|
||||
NPObjectProxy *proxy = npobject_get_proxy(npobj);
|
||||
assert(proxy != NULL);
|
||||
if (release_stub && proxy->is_valid) {
|
||||
npclass_invoke_Deallocate(proxy);
|
||||
g_hash_table_remove(g_proxies, GINT_TO_POINTER(proxy->id));
|
||||
}
|
||||
free(npobj);
|
||||
D(bugiD("npobject_destroy_proxy done\n"));
|
||||
}
|
||||
|
||||
static inline bool is_valid_npobject_proxy(NPObject *npobj)
|
||||
{
|
||||
if (npobj == NULL)
|
||||
|
@ -228,7 +252,7 @@ int npclass_handle_Deallocate(rpc_connection_t *connection)
|
|||
D(bugiI("NPClass:Deallocate: id=0x%x\n", id));
|
||||
NPObjectStub *stub = npobject_lookup_stub(id);
|
||||
if (stub != NULL) {
|
||||
npobject_destroy_stub(stub);
|
||||
npobject_destroy_stub_obj(stub);
|
||||
}
|
||||
D(bugiD("NPClass:Deallocate done\n"));
|
||||
|
||||
|
@ -260,15 +284,7 @@ static void npclass_invoke_Deallocate(NPObjectProxy *proxy)
|
|||
|
||||
void g_NPClass_Deallocate(NPObject *npobj)
|
||||
{
|
||||
// Unregister the proxy.
|
||||
D(bugiI("NPClass::Deallocate: npobj=%p\n", npobj));
|
||||
NPObjectProxy *proxy = npobject_get_proxy(npobj);
|
||||
if (proxy && proxy->is_valid) {
|
||||
npclass_invoke_Deallocate(proxy);
|
||||
g_hash_table_remove(g_proxies, GINT_TO_POINTER(proxy->id));
|
||||
}
|
||||
D(bugiD("NPClass::Deallocate done\n"));
|
||||
free(npobj);
|
||||
npobject_destroy_proxy(npobj, true);
|
||||
}
|
||||
|
||||
// NPClass::Invalidate
|
||||
|
@ -1155,7 +1171,7 @@ static void proxy_deactivate_func(gpointer key, gpointer value, gpointer user_da
|
|||
static void stub_destroy_func(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
NPObjectStub *stub = (NPObjectStub *)value;
|
||||
npobject_destroy_stub(stub);
|
||||
npobject_destroy_stub_obj(stub);
|
||||
}
|
||||
|
||||
void npruntime_deactivate(void)
|
||||
|
|
111
src/npw-rpc.c
111
src/npw-rpc.c
|
@ -1178,19 +1178,38 @@ static int do_recv_NPPrintData(rpc_message_t *message, void *p_value)
|
|||
* Process NPObject objects
|
||||
*/
|
||||
|
||||
static int do_send_NPObject(rpc_message_t *message, void *p_value)
|
||||
static int do_send_NPObject_helper(rpc_message_t *message, void *p_value,
|
||||
bool pass_ref)
|
||||
{
|
||||
uint32_t npobj_id = 0;
|
||||
NPObject *npobj = (NPObject *)p_value;
|
||||
bool release_stub = false;
|
||||
if (npobj) {
|
||||
npobj_id = npobject_get_proxy_id(npobj);
|
||||
if (npobj_id == 0) {
|
||||
// Sending an object on our side. Allocate a stub so the other
|
||||
// side can make a proxy.
|
||||
npobj_id = npobject_create_stub(npobj);
|
||||
if (pass_ref) {
|
||||
// Release our reference; the stub protects the object from
|
||||
// deallocation.
|
||||
NPN_ReleaseObject(npobj);
|
||||
}
|
||||
} else {
|
||||
// This is a proxy for the object on the other side. Just pass
|
||||
// the id along.
|
||||
if (pass_ref) {
|
||||
// As above, we release out reference. If this is not the last
|
||||
// reference, we may just do so. Otherwise, we destroy it, but
|
||||
// do /not/ send the corresponding RPC. That gets merged into
|
||||
// this one.
|
||||
if (npobj->referenceCount == 1) {
|
||||
npobject_destroy_proxy(npobj, false);
|
||||
release_stub = true;
|
||||
} else {
|
||||
NPN_ReleaseObject(npobj);
|
||||
}
|
||||
}
|
||||
}
|
||||
D(bug("sending id 0x%x\n", npobj_id));
|
||||
assert(npobj_id != 0);
|
||||
|
@ -1198,17 +1217,28 @@ static int do_send_NPObject(rpc_message_t *message, void *p_value)
|
|||
int error = rpc_message_send_uint32(message, npobj_id);
|
||||
if (error < 0)
|
||||
return error;
|
||||
// Tell the other side whether or not to destroy the stub.
|
||||
if (pass_ref) {
|
||||
if ((error = rpc_message_send_uint32(message, release_stub)) < 0)
|
||||
return error;
|
||||
}
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_NPObject(rpc_message_t *message, void *p_value)
|
||||
static int do_recv_NPObject_helper(rpc_message_t *message, void *p_value,
|
||||
bool pass_ref)
|
||||
{
|
||||
int error;
|
||||
uint32_t npobj_id;
|
||||
uint32_t release_stub = 0;
|
||||
|
||||
if ((error = rpc_message_recv_uint32(message, &npobj_id)) < 0)
|
||||
return error;
|
||||
if (pass_ref) {
|
||||
if ((error = rpc_message_recv_uint32(message, &release_stub)) < 0)
|
||||
return error;
|
||||
}
|
||||
|
||||
NPObject *npobj = NULL;
|
||||
if (npobj_id) {
|
||||
|
@ -1217,11 +1247,17 @@ static int do_recv_NPObject(rpc_message_t *message, void *p_value)
|
|||
// We got an id of a newly created remote stub. Create a proxy
|
||||
// for it.
|
||||
npobj = npobject_create_proxy(npobj_id);
|
||||
if (release_stub)
|
||||
npw_printf("ERROR: received release_stub for proxy NPObject.\n");
|
||||
} else {
|
||||
// This is an object on our side. Retain it; receiver must
|
||||
// release all received NPObjects.
|
||||
D(bug("local\n"));
|
||||
NPN_RetainObject(npobj);
|
||||
if (release_stub) {
|
||||
// We just retained the object, so it won't be destroyed.
|
||||
npobject_destroy_stub(npobj_id);
|
||||
}
|
||||
}
|
||||
D(bug("recv id 0x%x, obj %p\n", npobj_id, npobj));
|
||||
assert(npobj != NULL);
|
||||
|
@ -1231,6 +1267,26 @@ static int do_recv_NPObject(rpc_message_t *message, void *p_value)
|
|||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_send_NPObject(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
return do_send_NPObject_helper(message, p_value, false);
|
||||
}
|
||||
|
||||
static int do_recv_NPObject(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
return do_recv_NPObject_helper(message, p_value, false);
|
||||
}
|
||||
|
||||
static int do_send_NPObject_pass_ref(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
return do_send_NPObject_helper(message, p_value, true);
|
||||
}
|
||||
|
||||
static int do_recv_NPObject_pass_ref(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
return do_recv_NPObject_helper(message, p_value, true);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process NPIdentifier objects
|
||||
|
@ -1371,7 +1427,8 @@ static int do_recv_NPString(rpc_message_t *message, void *p_value)
|
|||
* Process NPVariant objects
|
||||
*/
|
||||
|
||||
static int do_send_NPVariant(rpc_message_t *message, void *p_value)
|
||||
static int do_send_NPVariant_helper(rpc_message_t *message, void *p_value,
|
||||
bool pass_ref)
|
||||
{
|
||||
NPVariant *variant = (NPVariant *)p_value;
|
||||
if (variant == NULL)
|
||||
|
@ -1403,15 +1460,23 @@ static int do_send_NPVariant(rpc_message_t *message, void *p_value)
|
|||
return error;
|
||||
break;
|
||||
case NPVariantType_Object:
|
||||
if ((error = do_send_NPObject(message, variant->value.objectValue)) < 0)
|
||||
if ((error = do_send_NPObject_helper(message, variant->value.objectValue,
|
||||
pass_ref)) < 0)
|
||||
return error;
|
||||
break;
|
||||
}
|
||||
|
||||
// Clean up local data. If we had an NPObject,
|
||||
// do_send_NPObject_pass_ref took care of it.
|
||||
if (pass_ref && variant->type != NPVariantType_Object) {
|
||||
NPN_ReleaseVariantValue(variant);
|
||||
}
|
||||
|
||||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
|
||||
static int do_recv_NPVariant_helper(rpc_message_t *message, void *p_value,
|
||||
bool pass_ref)
|
||||
{
|
||||
NPVariant *variant = (NPVariant *)p_value;
|
||||
if (variant)
|
||||
|
@ -1451,9 +1516,10 @@ static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
|
|||
return error;
|
||||
break;
|
||||
case NPVariantType_Object:
|
||||
if ((error = do_recv_NPObject(message, &result.value.objectValue)) < 0)
|
||||
if ((error = do_recv_NPObject_helper(message, &result.value.objectValue,
|
||||
pass_ref)) < 0)
|
||||
return error;
|
||||
// NPVariant owns reference from do_recv_NPObject.
|
||||
// NPVariant owns reference from do_recv_NPObject_helper.
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1465,6 +1531,25 @@ static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
|
|||
return RPC_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int do_send_NPVariant(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
return do_send_NPVariant_helper(message, p_value, false);
|
||||
}
|
||||
|
||||
static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
return do_recv_NPVariant_helper(message, p_value, false);
|
||||
}
|
||||
|
||||
static int do_send_NPVariant_pass_ref(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
return do_send_NPVariant_helper(message, p_value, true);
|
||||
}
|
||||
|
||||
static int do_recv_NPVariant_pass_ref(rpc_message_t *message, void *p_value)
|
||||
{
|
||||
return do_recv_NPVariant_helper(message, p_value, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize marshalers for NPAPI types
|
||||
|
@ -1555,6 +1640,12 @@ static const rpc_message_descriptor_t message_descs[] = {
|
|||
do_send_NPObject,
|
||||
do_recv_NPObject
|
||||
},
|
||||
{
|
||||
RPC_TYPE_NP_OBJECT_PASS_REF,
|
||||
sizeof(NPObject *),
|
||||
do_send_NPObject_pass_ref,
|
||||
do_recv_NPObject_pass_ref
|
||||
},
|
||||
{
|
||||
RPC_TYPE_NP_IDENTIFIER,
|
||||
sizeof(NPIdentifier),
|
||||
|
@ -1578,6 +1669,12 @@ static const rpc_message_descriptor_t message_descs[] = {
|
|||
sizeof(NPVariant),
|
||||
do_send_NPVariant,
|
||||
do_recv_NPVariant
|
||||
},
|
||||
{
|
||||
RPC_TYPE_NP_VARIANT_PASS_REF,
|
||||
sizeof(NPVariant),
|
||||
do_send_NPVariant_pass_ref,
|
||||
do_recv_NPVariant_pass_ref
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -131,6 +131,8 @@ enum {
|
|||
RPC_TYPE_NP_STRING, /* 15 */
|
||||
RPC_TYPE_NP_VARIANT,
|
||||
RPC_TYPE_NP_UTF8,
|
||||
RPC_TYPE_NP_OBJECT_PASS_REF,
|
||||
RPC_TYPE_NP_VARIANT_PASS_REF,
|
||||
RPC_TYPE_NPW_PLUGIN_INSTANCE
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue