diff options
Diffstat (limited to 'sandbox/src/sharedmem_ipc_client.cc')
-rw-r--r-- | sandbox/src/sharedmem_ipc_client.cc | 152 |
1 files changed, 0 insertions, 152 deletions
diff --git a/sandbox/src/sharedmem_ipc_client.cc b/sandbox/src/sharedmem_ipc_client.cc deleted file mode 100644 index 30c03b9..0000000 --- a/sandbox/src/sharedmem_ipc_client.cc +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) 2006-2008 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 <string.h> -#include "sandbox/src/sharedmem_ipc_client.h" -#include "sandbox/src/sandbox.h" -#include "sandbox/src/crosscall_client.h" -#include "sandbox/src/crosscall_params.h" -#include "base/logging.h" - -namespace sandbox { - -// Get the base of the data buffer of the channel; this is where the input -// parameters get serialized. Since they get serialized directly into the -// channel we avoid one copy. -void* SharedMemIPCClient::GetBuffer() { - bool failure = false; - size_t ix = LockFreeChannel(&failure); - if (failure) { - return NULL; - } - return reinterpret_cast<char*>(control_) + - control_->channels[ix].channel_base; -} - -// If we need to cancel an IPC before issuing DoCall -// our client should call FreeBuffer with the same pointer -// returned by GetBuffer. -void SharedMemIPCClient::FreeBuffer(void* buffer) { - size_t num = ChannelIndexFromBuffer(buffer); - ChannelControl* channel = control_->channels; - LONG result = ::InterlockedExchange(&channel[num].state, kFreeChannel); - DCHECK(kFreeChannel != result); - result; -} - -// The constructor simply casts the shared memory to the internal -// structures. This is a cheap step that is why this IPC object can -// and should be constructed per call. -SharedMemIPCClient::SharedMemIPCClient(void* shared_mem) - : control_(reinterpret_cast<IPCControl*>(shared_mem)) { - first_base_ = reinterpret_cast<char*>(shared_mem) + - control_->channels[0].channel_base; - // There must be at least one channel. - DCHECK(0 != control_->channels_count); -} - -// Do the IPC. At this point the channel should have already been -// filled with the serialized input parameters. -// We follow the pattern explained in the header file. -ResultCode SharedMemIPCClient::DoCall(CrossCallParams* params, - CrossCallReturn* answer) { - if (!control_->server_alive) - return SBOX_ERROR_CHANNEL_ERROR; - - size_t num = ChannelIndexFromBuffer(params->GetBuffer()); - ChannelControl* channel = control_->channels; - // Note that the IPC tag goes outside the buffer as well inside - // the buffer. This should enable the server to prioritize based on - // IPC tags without having to de-serialize the entire message. - channel[num].ipc_tag = params->GetTag(); - - // Wait for the server to service this IPC call. After kIPCWaitTimeOut1 - // we check if the server_alive mutex was abandoned which will indicate - // that the server has died. - - // While the atomic signaling and waiting is not a requirement, it - // is nice because we save a trip to kernel. - DWORD wait = ::SignalObjectAndWait(channel[num].ping_event, - channel[num].pong_event, - kIPCWaitTimeOut1, FALSE); - if (WAIT_TIMEOUT == wait) { - // The server is taking too long. Enter a loop were we check if the - // server_alive mutex has been abandoned which would signal a server crash - // or else we keep waiting for a response. - while (true) { - wait = ::WaitForSingleObject(control_->server_alive, 0); - if (WAIT_TIMEOUT == wait) { - // Server seems still alive. We already signaled so here we just wait. - wait = ::WaitForSingleObject(channel[num].pong_event, kIPCWaitTimeOut1); - if (WAIT_OBJECT_0 == wait) { - // The server took a long time but responded. - break; - } else if (WAIT_TIMEOUT == wait) { - continue; - } else { - return SBOX_ERROR_CHANNEL_ERROR; - } - } else { - // The server has crashed and windows has signaled the mutex as - // abandoned. - ::InterlockedExchange(&channel[num].state, kAbandonnedChannel); - control_->server_alive = 0; - return SBOX_ERROR_CHANNEL_ERROR; - } - } - } else if (WAIT_OBJECT_0 != wait) { - // Probably the server crashed before the kIPCWaitTimeOut1 occurred. - return SBOX_ERROR_CHANNEL_ERROR; - } - - // The server has returned an answer, copy it and free the channel. - memcpy(answer, params->GetCallReturn(), sizeof(CrossCallReturn)); - - // Return the IPC state It can indicate that while the IPC has - // completed some error in the Broker has caused to not return valid - // results. - return answer->call_outcome; -} - -// Locking a channel is a simple as looping over all the channels -// looking for one that is has state = kFreeChannel and atomically -// swapping it to kBusyChannel. -// If there is no free channel, then we must back off so some other -// thread makes progress and frees a channel. To back off we sleep. -size_t SharedMemIPCClient::LockFreeChannel(bool* severe_failure) { - if (0 == control_->channels_count) { - *severe_failure = true; - return 0; - } - ChannelControl* channel = control_->channels; - do { - for (size_t ix = 0; ix != control_->channels_count; ++ix) { - if (kFreeChannel == ::InterlockedCompareExchange(&channel[ix].state, - kBusyChannel, - kFreeChannel)) { - *severe_failure = false; - return ix; - } - } - // We did not find any available channel, maybe the server is dead. - DWORD wait = ::WaitForSingleObject(control_->server_alive, - kIPCWaitTimeOut2); - if (WAIT_TIMEOUT != wait) { - // The server is dead and we outlive it enough to get in trouble. - *severe_failure = true; - return 0; - } - } - while (true); -} - -// Find out which channel we are from the pointer returned by GetBuffer. -size_t SharedMemIPCClient::ChannelIndexFromBuffer(const void* buffer) { - ptrdiff_t d = reinterpret_cast<const char*>(buffer) - first_base_; - size_t num = d/kIPCChannelSize; - DCHECK(num < control_->channels_count); - return (num); -} - -} // namespace sandbox |