#include "ppapi/thunk/enter.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/stringprintf.h"
#include "base/synchronization/lock.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/shared_impl/ppapi_globals.h"
#include "ppapi/shared_impl/tracked_callback.h"
#include "ppapi/thunk/ppb_instance_api.h"
#include "ppapi/thunk/resource_creation_api.h"
namespace ppapi {
namespace {
bool IsMainThread() {
return
PpapiGlobals::Get()->GetMainThreadMessageLoop()->BelongsToCurrentThread();
}
}
namespace thunk {
namespace subtle {
void AssertLockHeld() {
base::Lock* proxy_lock = PpapiGlobals::Get()->GetProxyLock();
if (proxy_lock)
proxy_lock->AssertAcquired();
}
EnterBase::EnterBase()
: resource_(NULL),
retval_(PP_OK) {
}
EnterBase::EnterBase(PP_Resource resource)
: resource_(GetResource(resource)),
retval_(PP_OK) {
}
EnterBase::EnterBase(PP_Resource resource,
const PP_CompletionCallback& callback)
: resource_(GetResource(resource)),
retval_(PP_OK) {
callback_ = new TrackedCallback(resource_, callback);
}
EnterBase::~EnterBase() {
DCHECK(!callback_);
}
int32_t EnterBase::SetResult(int32_t result) {
if (!callback_) {
NOTREACHED();
retval_ = result;
return result;
}
if (result == PP_OK_COMPLETIONPENDING) {
retval_ = result;
if (callback_->is_blocking()) {
DCHECK(!IsMainThread());
retval_ = callback_->BlockUntilComplete();
} else {
retval_ = result;
}
} else {
if (callback_->is_required()) {
callback_->PostRun(result);
retval_ = PP_OK_COMPLETIONPENDING;
} else {
callback_->MarkAsCompleted();
retval_ = result;
}
}
callback_ = NULL;
return retval_;
}
Resource* EnterBase::GetResource(PP_Resource resource) {
return PpapiGlobals::Get()->GetResourceTracker()->GetResource(resource);
}
void EnterBase::SetStateForCallbackError(bool report_error) {
if (!CallbackIsValid()) {
callback_->MarkAsCompleted();
callback_ = NULL;
retval_ = PP_ERROR_BLOCKS_MAIN_THREAD;
if (report_error) {
std::string message(
"Blocking callbacks are not allowed on the main thread.");
PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR,
std::string(), message);
}
}
}
bool EnterBase::CallbackIsValid() const {
return !callback_ || !callback_->is_blocking() || !IsMainThread();
}
void EnterBase::ClearCallback() {
callback_ = NULL;
}
void EnterBase::SetStateForResourceError(PP_Resource pp_resource,
Resource* resource_base,
void* object,
bool report_error) {
SetStateForCallbackError(report_error);
if (object)
return;
if (callback_ && callback_->is_required()) {
callback_->PostRun(static_cast<int32_t>(PP_ERROR_BADRESOURCE));
callback_ = NULL;
retval_ = PP_OK_COMPLETIONPENDING;
} else {
if (callback_)
callback_->MarkAsCompleted();
callback_ = NULL;
retval_ = PP_ERROR_BADRESOURCE;
}
if (report_error && pp_resource) {
std::string message;
if (resource_base) {
message = base::StringPrintf(
"0x%X is not the correct type for this function.",
pp_resource);
} else {
message = base::StringPrintf(
"0x%X is not a valid resource ID.",
pp_resource);
}
PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR,
std::string(), message);
}
}
void EnterBase::SetStateForFunctionError(PP_Instance pp_instance,
void* object,
bool report_error) {
SetStateForCallbackError(report_error);
if (object)
return;
if (callback_ && callback_->is_required()) {
callback_->PostRun(static_cast<int32_t>(PP_ERROR_BADARGUMENT));
callback_ = NULL;
retval_ = PP_OK_COMPLETIONPENDING;
} else {
if (callback_)
callback_->MarkAsCompleted();
callback_ = NULL;
retval_ = PP_ERROR_BADARGUMENT;
}
if (report_error && pp_instance) {
std::string message;
message = base::StringPrintf(
"0x%X is not a valid instance ID.",
pp_instance);
PpapiGlobals::Get()->BroadcastLogWithSource(0, PP_LOGLEVEL_ERROR,
std::string(), message);
}
}
}
EnterInstance::EnterInstance(PP_Instance instance)
: EnterBase(),
functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) {
SetStateForFunctionError(instance, functions_, true);
}
EnterInstance::EnterInstance(PP_Instance instance,
const PP_CompletionCallback& callback)
: EnterBase(0 , callback),
functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) {
SetStateForFunctionError(instance, functions_, true);
}
EnterInstance::~EnterInstance() {
}
EnterInstanceNoLock::EnterInstanceNoLock(PP_Instance instance)
: EnterBase(),
functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) {
SetStateForFunctionError(instance, functions_, true);
}
EnterInstanceNoLock::EnterInstanceNoLock(
PP_Instance instance,
const PP_CompletionCallback& callback)
: EnterBase(0 , callback),
functions_(PpapiGlobals::Get()->GetInstanceAPI(instance)) {
SetStateForFunctionError(instance, functions_, true);
}
EnterInstanceNoLock::~EnterInstanceNoLock() {
}
EnterResourceCreation::EnterResourceCreation(PP_Instance instance)
: EnterBase(),
functions_(PpapiGlobals::Get()->GetResourceCreationAPI(instance)) {
SetStateForFunctionError(instance, functions_, true);
}
EnterResourceCreation::~EnterResourceCreation() {
}
EnterResourceCreationNoLock::EnterResourceCreationNoLock(PP_Instance instance)
: EnterBase(),
functions_(PpapiGlobals::Get()->GetResourceCreationAPI(instance)) {
SetStateForFunctionError(instance, functions_, true);
}
EnterResourceCreationNoLock::~EnterResourceCreationNoLock() {
}
}
}