50a4e509创建于 2012年1月19日历史提交
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "native_client/src/shared/ppapi_proxy/plugin_callback.h"
#include <string.h>
#include "native_client/src/shared/ppapi_proxy/object_serialize.h"
#include "native_client/src/shared/ppapi_proxy/utility.h"
#include "ppapi/c/pp_errors.h"
#include "srpcgen/ppp_rpc.h"

namespace ppapi_proxy {

int32_t MayForceCallback(PP_CompletionCallback callback, int32_t result) {
  if (result == PP_OK_COMPLETIONPENDING)
    return result;

  if (callback.func == NULL ||
      (callback.flags & PP_COMPLETIONCALLBACK_FLAG_OPTIONAL) != 0)
    return result;

  PPBCoreInterface()->CallOnMainThread(0, callback, result);
  return PP_OK_COMPLETIONPENDING;
}

// Initialize static mutex used as critical section for all callback tables.
pthread_mutex_t CompletionCallbackTable::mutex_ = PTHREAD_MUTEX_INITIALIZER;

int32_t CompletionCallbackTable::AddCallback(
    const PP_CompletionCallback& callback,
    void* read_buffer,
    PP_Var* read_var) {
  CallbackTableCriticalSection guard;
  DCHECK (!read_buffer || !read_var);
  if (callback.func == NULL) {
    DebugPrintf("CompletionCallbackTable attempted to add NULL func!!\n");
    return 0;
  }
  int32_t callback_id = next_id_;
  ++next_id_;
  CallbackInfo info = { callback, read_buffer, read_var };
  table_.insert(std::pair<int32_t, CallbackInfo>(callback_id, info));
  return callback_id;
}

int32_t CompletionCallbackTable::AddCallback(
    const PP_CompletionCallback& callback) {
  return AddCallback(callback, NULL, NULL);
}

int32_t CompletionCallbackTable::AddCallback(
    const PP_CompletionCallback& callback,
    void* read_buffer) {
  return AddCallback(callback, read_buffer, NULL);
}

int32_t CompletionCallbackTable::AddCallback(
    const PP_CompletionCallback& callback,
    PP_Var* read_var) {
  return AddCallback(callback, NULL, read_var);
}


PP_CompletionCallback CompletionCallbackTable::RemoveCallback(
    int32_t callback_id, void** read_buffer, PP_Var** read_var) {
  CallbackTableCriticalSection guard;
  CallbackTable::iterator it = table_.find(callback_id);
  DebugPrintf("CompletionCallbackTable::RemoveCallback id: %"NACL_PRId32"\n",
      callback_id);
  if (table_.end() != it) {
    CallbackInfo info = it->second;
    table_.erase(it);
    if (read_buffer != NULL)
      *read_buffer = info.read_buffer;
    if (read_var != NULL)
      *read_var = info.read_var;
    return info.callback;
  }
  *read_buffer = NULL;
  return PP_BlockUntilComplete();
}

}  // namespace ppapi_proxy

// SRPC-abstraction wrapper around a PP_CompletionCallback.
void CompletionCallbackRpcServer::RunCompletionCallback(
    NaClSrpcRpc* rpc,
    NaClSrpcClosure* done,
    // inputs
    int32_t callback_id,
    int32_t result,
    // TODO(polina): use shm for read buffer
    nacl_abi_size_t read_buffer_size, char* read_buffer) {
  NaClSrpcClosureRunner runner(done);
  rpc->result = NACL_SRPC_RESULT_APP_ERROR;

  void* user_buffer;
  PP_Var* user_var;
  PP_CompletionCallback callback =
      ppapi_proxy::CompletionCallbackTable::Get()->RemoveCallback(
          callback_id, &user_buffer, &user_var);
  if (callback.func == NULL) {
    ppapi_proxy::DebugPrintf(
        "CompletionCallbackRpcServer: id of %"NACL_PRId32" is NULL callback!\n",
        callback_id);
    return;
  }

  if (user_buffer != NULL && read_buffer_size > 0)
    memcpy(user_buffer, read_buffer, read_buffer_size);
  else if (user_var != NULL && read_buffer_size > 0)
    ppapi_proxy::DeserializeTo(read_buffer, read_buffer_size, 1, user_var);
  PP_RunCompletionCallback(&callback, result);

  rpc->result = NACL_SRPC_RESULT_OK;
}