// Copyright 2014 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 "mojo/system/platform_handle_dispatcher.h"
#include <algorithm>
#include "base/logging.h"
namespace mojo {
namespace system {
namespace {
const size_t kInvalidPlatformHandleIndex = static_cast<size_t>(-1);
struct SerializedPlatformHandleDispatcher {
size_t platform_handle_index; // (Or |kInvalidPlatformHandleIndex|.)
};
} // namespace
PlatformHandleDispatcher::PlatformHandleDispatcher(
embedder::ScopedPlatformHandle platform_handle)
: platform_handle_(platform_handle.Pass()) {
}
embedder::ScopedPlatformHandle PlatformHandleDispatcher::PassPlatformHandle() {
base::AutoLock locker(lock());
return platform_handle_.Pass();
}
Dispatcher::Type PlatformHandleDispatcher::GetType() const {
return kTypePlatformHandle;
}
// static
scoped_refptr<PlatformHandleDispatcher> PlatformHandleDispatcher::Deserialize(
Channel* channel,
const void* source,
size_t size,
embedder::PlatformHandleVector* platform_handles) {
if (size != sizeof(SerializedPlatformHandleDispatcher)) {
LOG(ERROR) << "Invalid serialized platform handle dispatcher (bad size)";
return scoped_refptr<PlatformHandleDispatcher>();
}
const SerializedPlatformHandleDispatcher* serialization =
static_cast<const SerializedPlatformHandleDispatcher*>(source);
size_t platform_handle_index = serialization->platform_handle_index;
// Starts off invalid, which is what we want.
embedder::PlatformHandle platform_handle;
if (platform_handle_index != kInvalidPlatformHandleIndex) {
if (!platform_handles ||
platform_handle_index >= platform_handles->size()) {
LOG(ERROR)
<< "Invalid serialized platform handle dispatcher (missing handles)";
return scoped_refptr<PlatformHandleDispatcher>();
}
// We take ownership of the handle, so we have to invalidate the one in
// |platform_handles|.
std::swap(platform_handle, (*platform_handles)[platform_handle_index]);
}
return scoped_refptr<PlatformHandleDispatcher>(new PlatformHandleDispatcher(
embedder::ScopedPlatformHandle(platform_handle)));
}
PlatformHandleDispatcher::~PlatformHandleDispatcher() {
}
void PlatformHandleDispatcher::CloseImplNoLock() {
lock().AssertAcquired();
platform_handle_.reset();
}
scoped_refptr<Dispatcher>
PlatformHandleDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() {
lock().AssertAcquired();
return scoped_refptr<Dispatcher>(
new PlatformHandleDispatcher(platform_handle_.Pass()));
}
void PlatformHandleDispatcher::StartSerializeImplNoLock(
Channel* /*channel*/,
size_t* max_size,
size_t* max_platform_handles) {
DCHECK(HasOneRef()); // Only one ref => no need to take the lock.
*max_size = sizeof(SerializedPlatformHandleDispatcher);
*max_platform_handles = 1;
}
bool PlatformHandleDispatcher::EndSerializeAndCloseImplNoLock(
Channel* /*channel*/,
void* destination,
size_t* actual_size,
embedder::PlatformHandleVector* platform_handles) {
DCHECK(HasOneRef()); // Only one ref => no need to take the lock.
SerializedPlatformHandleDispatcher* serialization =
static_cast<SerializedPlatformHandleDispatcher*>(destination);
if (platform_handle_.is_valid()) {
serialization->platform_handle_index = platform_handles->size();
platform_handles->push_back(platform_handle_.release());
} else {
serialization->platform_handle_index = kInvalidPlatformHandleIndex;
}
*actual_size = sizeof(SerializedPlatformHandleDispatcher);
return true;
}
HandleSignalsState
PlatformHandleDispatcher::GetHandleSignalsStateNoLock() const {
return HandleSignalsState();
}
} // namespace system
} // namespace mojo