Coverage for /Syzygy/trace/service/service.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
81.3%2823470.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  //
  15    :  // This file defines the trace::service::Service class which
  16    :  // implements the call trace service RPC interface.
  17    :  //
  18    :  // TODO(rogerm): Use server controlled context handles to refer to the buffers
  19    :  //     across the RPC boundary. The shared memory handle is client controlled
  20    :  //     and not necessarily unique.
  21    :  
  22    :  #include "syzygy/trace/service/service.h"
  23    :  
  24    :  #include "base/bind.h"
  25    :  #include "base/callback.h"
  26    :  #include "base/memory/scoped_ptr.h"
  27    :  #include "base/strings/string_util.h"
  28    :  #include "syzygy/common/align.h"
  29    :  #include "syzygy/common/com_utils.h"
  30    :  #include "syzygy/common/rpc/helpers.h"
  31    :  #include "syzygy/trace/protocol/call_trace_defs.h"
  32    :  #include "syzygy/trace/service/buffer_consumer.h"
  33    :  #include "syzygy/trace/service/session.h"
  34    :  
  35    :  namespace trace {
  36    :  namespace service {
  37    :  
  38    :  const size_t Service::kDefaultBufferSize = 2 * 1024 * 1024;
  39    :  const size_t Service::kDefaultNumIncrementalBuffers = 16;
  40    :  
  41    :  // The choice of this value is not particularly important, but it should be
  42    :  // something that is relatively prime to the number of buffers created per
  43    :  // allocation, and it should represent more memory than our disk bandwidth
  44    :  // can reasonably write in about a second or so, so as to allow sufficient
  45    :  // buffering for smoothing. Assuming 20MB/sec consistent throughput, this
  46    :  // represents about 26 MB, so 1.3 seconds of disk bandwidth.
  47    :  const size_t Service::kDefaultMaxBuffersPendingWrite = 13;
  48    :  
  49    :  Service::Service(BufferConsumerFactory* factory)
  50    :      : num_active_sessions_(0),
  51    :        num_incremental_buffers_(kDefaultNumIncrementalBuffers),
  52    :        buffer_size_in_bytes_(kDefaultBufferSize),
  53    :        max_buffers_pending_write_(kDefaultMaxBuffersPendingWrite),
  54    :        owner_thread_(base::PlatformThread::CurrentId()),
  55    :        buffer_consumer_factory_(factory),
  56    :        a_session_has_closed_(&lock_),
  57    :        rpc_is_initialized_(false),
  58    :        rpc_is_running_(false),
  59    :        rpc_is_non_blocking_(false),
  60  E :        flags_(TRACE_FLAG_BATCH_ENTER) {
  61  E :    DCHECK(factory != NULL);
  62  E :  }
  63    :  
  64  E :  Service::~Service() {
  65  E :    DCHECK_EQ(owner_thread_, base::PlatformThread::CurrentId());
  66  E :    DCHECK(buffer_consumer_factory_ != NULL);
  67    :  
  68  E :    Stop();
  69    :  
  70  E :    DCHECK(sessions_.empty());
  71  E :    DCHECK_EQ(0U, num_active_sessions_);
  72  E :  }
  73    :  
  74  E :  void Service::AddOneActiveSession() {
  75  E :    base::AutoLock auto_lock(lock_);
  76    :  
  77  E :    ++num_active_sessions_;
  78  E :  }
  79    :  
  80  E :  void Service::RemoveOneActiveSession() {
  81    :    {
  82  E :      base::AutoLock auto_lock(lock_);
  83  E :      DCHECK_LT(0u, num_active_sessions_);
  84    :  
  85  E :      --num_active_sessions_;
  86  E :    }
  87    :  
  88  E :    a_session_has_closed_.Signal();
  89  E :  }
  90    :  
  91  E :  bool Service::OpenServiceEvent() {
  92  E :    DCHECK_EQ(owner_thread_, base::PlatformThread::CurrentId());
  93  E :    DCHECK(!service_event_.IsValid());
  94    :  
  95  E :    std::wstring event_name;
  96  E :    ::GetSyzygyCallTraceRpcEventName(instance_id_, &event_name);
  97    :  
  98  E :    service_event_.Set(::CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
  99  E :    if (!service_event_.IsValid()) {
 100  E :      DWORD error = ::GetLastError();
 101  E :      LOG(ERROR) << "Failed to create event: " << ::common::LogWe(error) << ".";
 102  E :      return false;
 103    :    }
 104    :  
 105  E :    return true;
 106  E :  }
 107    :  
 108  E :  bool Service::AcquireServiceMutex() {
 109  E :    DCHECK_EQ(owner_thread_, base::PlatformThread::CurrentId());
 110  E :    DCHECK(!service_mutex_.IsValid());
 111    :  
 112  E :    std::wstring mutex_name;
 113  E :    ::GetSyzygyCallTraceRpcMutexName(instance_id_, &mutex_name);
 114  E :    base::win::ScopedHandle mutex(::CreateMutex(NULL, FALSE, mutex_name.c_str()));
 115  E :    if (!mutex.IsValid()) {
 116  i :      DWORD error = ::GetLastError();
 117  i :      LOG(ERROR) << "Failed to create mutex: " << ::common::LogWe(error) << ".";
 118  i :      return false;
 119    :    }
 120  E :    const DWORD kOneSecondInMs = 1000;
 121    :  
 122  E :    switch (::WaitForSingleObject(mutex.Get(), kOneSecondInMs)) {
 123    :      case WAIT_ABANDONED:
 124  i :        LOG(WARNING) << "Orphaned service mutex found!";
 125    :        // Fall through...
 126    :  
 127    :      case WAIT_OBJECT_0:
 128  E :        VLOG(1) << "Service mutex acquired.";
 129  E :        service_mutex_.Set(mutex.Take());
 130  E :        return true;
 131    :  
 132    :      case WAIT_TIMEOUT:
 133  E :        LOG(ERROR) << "Another instance of the service is running.";
 134  E :        break;
 135    :  
 136    :      default: {
 137  i :        DWORD error = ::GetLastError();
 138  i :        LOG(ERROR) << "Failed to acquire mutex: " << ::common::LogWe(error)
 139    :                   << ".";
 140    :        break;
 141    :      }
 142    :    }
 143  E :    return false;
 144  E :  }
 145    :  
 146  E :  void Service::ReleaseServiceMutex() {
 147  E :    DCHECK_EQ(owner_thread_, base::PlatformThread::CurrentId());
 148    :  
 149  E :    if (service_mutex_.IsValid()) {
 150  E :      ::ReleaseMutex(service_mutex_.Get());
 151  E :      service_mutex_.Close();
 152    :    }
 153  E :  }
 154    :  
 155  E :  bool Service::InitializeRpc()  {
 156  E :    DCHECK_EQ(owner_thread_, base::PlatformThread::CurrentId());
 157    :  
 158  E :    if (rpc_is_initialized_) {
 159  i :      LOG(WARNING) << "The call trace service RPC stack is already initialized.";
 160  i :      return true;
 161    :    }
 162    :  
 163  E :    RPC_STATUS status = RPC_S_OK;
 164    :  
 165    :    // Initialize the RPC protocol we want to use.
 166  E :    std::wstring protocol;
 167  E :    std::wstring endpoint;
 168  E :    ::GetSyzygyCallTraceRpcProtocol(&protocol);
 169  E :    ::GetSyzygyCallTraceRpcEndpoint(instance_id_, &endpoint);
 170    :  
 171  E :    VLOG(1) << "Initializing RPC endpoint '" << endpoint << "' "
 172    :            << "using the '" << protocol << "' protocol.";
 173    :    status = ::RpcServerUseProtseqEp(
 174    :        ::common::rpc::AsRpcWstr(&protocol[0]), RPC_C_LISTEN_MAX_CALLS_DEFAULT,
 175  E :        ::common::rpc::AsRpcWstr(&endpoint[0]), NULL /* Security descriptor. */);
 176  E :    if (status != RPC_S_OK && status != RPC_S_DUPLICATE_ENDPOINT) {
 177  i :      LOG(ERROR) << "Failed to init RPC protocol: " << ::common::LogWe(status)
 178    :                 << ".";
 179  i :      return false;
 180    :    }
 181    :  
 182    :    // Register the server version of the CallTrace interface.
 183  E :    VLOG(1) << "Registering the CallTrace interface.";
 184    :    status = ::RpcServerRegisterIf(
 185  E :        CallTraceService_CallTrace_v1_0_s_ifspec, NULL, NULL);
 186  E :    if (status != RPC_S_OK) {
 187  i :      LOG(ERROR) << "Failed to register CallTrace RPC interface: "
 188    :                 << ::common::LogWe(status) << ".";
 189  i :      return false;
 190    :    }
 191    :  
 192    :    // Register the server version of the CallTraceControl interface.
 193  E :    VLOG(1) << "Registering the CallTraceControl interface.";
 194    :    status = ::RpcServerRegisterIf(
 195  E :        CallTraceService_CallTraceControl_v1_0_s_ifspec, NULL, NULL);
 196  E :    if (status != RPC_S_OK) {
 197  i :      LOG(ERROR) << "Failed to register CallTraceControl RPC interface: "
 198    :                 << ::common::LogWe(status) << ".";
 199  i :      return false;
 200    :    }
 201    :  
 202  E :    rpc_is_initialized_ = true;
 203  E :    return true;
 204  E :  }
 205    :  
 206  E :  bool Service::RunRPC(bool non_blocking) {
 207  E :    VLOG(1) << "Starting the RPC server.";
 208    :  
 209  E :    DCHECK_EQ(owner_thread_, base::PlatformThread::CurrentId());
 210    :  
 211  E :    if (rpc_is_running_) {
 212  i :      LOG(ERROR) << "The RPC server is already running.";
 213  i :      return false;
 214    :    }
 215    :  
 216  E :    rpc_is_running_ = true;
 217  E :    rpc_is_non_blocking_ = non_blocking;
 218    :  
 219    :    RPC_STATUS status = ::RpcServerListen(
 220    :        1,  // Minimum number of handler threads.
 221    :        RPC_C_LISTEN_MAX_CALLS_DEFAULT,
 222  E :        TRUE);
 223    :  
 224  E :    if (status != RPC_S_OK) {
 225  i :      LOG(ERROR) << "Failed to run RPC server: " << ::common::LogWe(status)
 226    :                 << ".";
 227    :    }
 228    :  
 229  E :    if (status == RPC_S_OK) {
 230    :      // Signal that the service is up and running.
 231  E :      DCHECK(service_event_.IsValid());
 232  E :      BOOL success = ::SetEvent(service_event_.Get());
 233  E :      DCHECK_EQ(TRUE, success);
 234    :  
 235    :      // Wait here if we're in blocking mode.
 236  E :      if (!non_blocking) {
 237  E :        VLOG(1) << "Call-trace service is running in blocking mode.";
 238  E :        status = RpcMgmtWaitServerListen();
 239    :  
 240  E :        if (status == RPC_S_OK) {
 241  E :          VLOG(1) << "Call-trace service has finished accepting requests.";
 242  E :        } else {
 243  i :          LOG(ERROR) << "Failed to wait on RPC server: "
 244    :                     << ::common::LogWe(status) << ".";
 245    :        }
 246    :      }
 247    :    }
 248    :  
 249  E :    if (status != RPC_S_OK) {
 250  i :      rpc_is_running_ = false;
 251  i :      rpc_is_non_blocking_ = false;
 252  i :      return false;
 253    :    }
 254    :  
 255  E :    if (rpc_is_non_blocking_)
 256  E :      VLOG(1) << "Call-trace service is running in non-blocking mode.";
 257    :  
 258  E :    return true;
 259  E :  }
 260    :  
 261  E :  void Service::StopRpc() {
 262  E :    if (!rpc_is_running_)
 263  E :      return;
 264    :  
 265    :    // Stop the RPC Server.
 266  E :    base::AutoLock auto_lock(lock_);
 267  E :    if (rpc_is_running_) {
 268  E :      VLOG(1) << "Stopping RPC server.";
 269  E :      RPC_STATUS status = ::RpcMgmtStopServerListening(NULL);
 270  E :      if (status != RPC_S_OK) {
 271  i :        LOG(ERROR) << "Failed to stop the RPC server: "
 272    :                   << ::common::LogWe(status) << ".";
 273    :      }
 274  E :      rpc_is_running_ = false;
 275    :    }
 276  E :  }
 277    :  
 278  E :  void Service::CleanupRpc() {
 279  E :    DCHECK_EQ(owner_thread_, base::PlatformThread::CurrentId());
 280  E :    DCHECK(rpc_is_running_ == false);
 281    :  
 282  E :    RPC_STATUS status = RPC_S_OK;
 283    :  
 284    :    // If we're running in non-blocking mode, then we have to wait for
 285    :    // any in-flight RPC requests to terminate.
 286  E :    if (rpc_is_non_blocking_) {
 287  E :      VLOG(1) << "Waiting for outstanding RPC requests to terminate.";
 288  E :      status = ::RpcMgmtWaitServerListen();
 289  E :      if (status != RPC_S_OK && status != RPC_S_NOT_LISTENING) {
 290  i :        LOG(ERROR) << "Failed wait for RPC server shutdown: "
 291    :                   << ::common::LogWe(status) << ".";
 292    :      }
 293  E :      rpc_is_non_blocking_ = false;
 294    :    }
 295    :  
 296    :    // Unregister the RPC interfaces.
 297  E :    if (rpc_is_initialized_) {
 298  E :      VLOG(1) << "Unregistering RPC interfaces.";
 299  E :      status = ::RpcServerUnregisterIf(NULL, NULL, FALSE);
 300  E :      if (status != RPC_S_OK) {
 301  i :        LOG(ERROR) << "Failed to unregister RPC interfaces: "
 302    :                   << ::common::LogWe(status) << ".";
 303    :      }
 304  E :      rpc_is_initialized_ = false;
 305    :    }
 306  E :  }
 307    :  
 308  E :  bool Service::Start(bool non_blocking) {
 309  E :    LOG(INFO) << "Starting the call-trace service.";
 310    :  
 311  E :    DCHECK_EQ(owner_thread_, base::PlatformThread::CurrentId());
 312    :  
 313  E :    if (!AcquireServiceMutex())
 314  E :      return false;
 315    :  
 316  E :    if (!OpenServiceEvent())
 317  E :      return false;
 318    :  
 319  E :    if (!InitializeRpc()) {
 320  i :      ReleaseServiceMutex();
 321  i :      return false;
 322    :    }
 323    :  
 324  E :    LOG(INFO) << "The call-trace service is running.";
 325    :  
 326  E :    if (!RunRPC(non_blocking))
 327  i :      return false;
 328    :  
 329  E :    LOG(INFO) << "The call-trace service is no longer running.";
 330    :  
 331  E :    return true;
 332  E :  }
 333    :  
 334  E :  bool Service::Stop() {
 335  E :    DCHECK_EQ(owner_thread_, base::PlatformThread::CurrentId());
 336    :  
 337  E :    LOG(INFO) << "Stopping the call-trace service.";
 338    :  
 339  E :    StopRpc();
 340  E :    CleanupRpc();
 341  E :    CloseAllOpenSessions();
 342  E :    ReleaseServiceMutex();
 343    :  
 344    :    // Signal that we've shut down.
 345  E :    if (service_event_.IsValid())
 346  E :      ::ResetEvent(service_event_.Get());
 347    :  
 348  E :    LOG(INFO) << "The call-trace service is stopped.";
 349  E :    return true;
 350  E :  }
 351    :  
 352  E :  bool Service::CloseAllOpenSessions() {
 353  E :    DCHECK_EQ(owner_thread_, base::PlatformThread::CurrentId());
 354  E :    DCHECK(!rpc_is_running_);
 355    :  
 356  E :    VLOG(1) << "Flushing all outstanding buffers.";
 357    :  
 358  E :    SessionMap to_close;
 359    :    {
 360  E :      base::AutoLock auto_lock(lock_);
 361  E :      to_close.swap(sessions_);
 362    :  
 363  E :      DCHECK(sessions_.empty());
 364  E :    }
 365    :  
 366    :    // Tell each session that they are to be closed. This will get them to
 367    :    // flush all outstanding buffers to their respective consumers.
 368  E :    SessionMap::iterator iter = to_close.begin();
 369  E :    for (; iter != to_close.end(); ++iter) {
 370  E :      iter->second->Close();
 371  E :    }
 372    :  
 373    :    // Release the references we hold to the closing sessions.
 374  E :    to_close.clear();
 375    :  
 376    :    // Wait until all pending sessions have closed.
 377    :    {
 378  E :      base::AutoLock auto_lock(lock_);
 379    :  
 380  E :      int pending_sessions = 0;
 381  E :      while ((pending_sessions = num_active_sessions_) != 0) {
 382  E :        VLOG(1) << "There are " << pending_sessions << " pending sessions.";
 383  E :        a_session_has_closed_.Wait();
 384  E :      }
 385  E :    }
 386    :  
 387  E :    return true;
 388  E :  }
 389    :  
 390  E :  Session* Service::CreateSession() {
 391  E :    return new Session(this);
 392  E :  }
 393    :  
 394    :  // RPC entry point.
 395  E :  bool Service::RequestShutdown() {
 396  E :    VLOG(1) << "Requesting a shutdown of the call trace service.";
 397    :  
 398  E :    StopRpc();
 399    :  
 400  E :    return true;
 401  E :  }
 402    :  
 403    :  // RPC entry point.
 404    :  bool Service::CreateSession(handle_t binding,
 405    :                              SessionHandle* session_handle,
 406    :                              CallTraceBuffer* call_trace_buffer,
 407  E :                              unsigned long* flags) {
 408    :    if (binding == NULL || session_handle == NULL || call_trace_buffer == NULL ||
 409  E :        flags == NULL) {
 410  i :      LOG(WARNING) << "Invalid RPC parameters.";
 411  i :      return false;
 412    :    }
 413  E :    const int kVersion = 2;
 414  E :    RPC_CALL_ATTRIBUTES_V2 attribs = { kVersion, RPC_QUERY_CLIENT_PID };
 415  E :    RPC_STATUS status = RpcServerInqCallAttributes(binding, &attribs);
 416  E :    if (status != RPC_S_OK) {
 417  i :      LOG(ERROR) << "Failed to query RPC call attributes: "
 418    :                 << ::common::LogWe(status) << ".";
 419  i :      return false;
 420    :    }
 421    :  
 422  E :    ProcessId client_process_id = reinterpret_cast<ProcessId>(attribs.ClientPID);
 423    :  
 424  E :    VLOG(1) << "Registering client process PID=" << client_process_id << ".";
 425    :  
 426  E :    scoped_refptr<Session> session;
 427  E :    if (!GetNewSession(client_process_id, &session))
 428  i :      return false;
 429    :  
 430  E :    DCHECK(session.get() != NULL);
 431    :  
 432    :    // Request a buffer for the client.
 433  E :    Buffer* client_buffer = NULL;
 434  E :    if (!session->GetNextBuffer(&client_buffer)) {
 435  i :      sessions_.erase(session->client_process_id());
 436  i :      session->Close();
 437  i :      return false;
 438    :    }
 439  E :    DCHECK(client_buffer != NULL);
 440    :  
 441    :    // Copy buffer info into the RPC struct, slicing off the private bits.
 442  E :    *session_handle = reinterpret_cast<SessionHandle>(session.get());
 443  E :    *call_trace_buffer = *client_buffer;
 444  E :    *flags = flags_;
 445    :  
 446  E :    return true;
 447  E :  }
 448    :  
 449    :  // RPC entry point.
 450    :  bool Service::AllocateBuffer(SessionHandle session_handle,
 451  E :                               CallTraceBuffer* call_trace_buffer) {
 452  E :    if (session_handle == NULL || call_trace_buffer == NULL) {
 453  i :      LOG(WARNING) << "Invalid RPC parameters.";
 454  i :      return false;
 455    :    }
 456    :  
 457  E :    scoped_refptr<Session> session;
 458  E :    if (!GetExistingSession(session_handle, &session))
 459  i :      return false;
 460  E :    DCHECK(session.get() != NULL);
 461    :  
 462    :    // Request a buffer for the client.
 463  E :    Buffer* client_buffer = NULL;
 464  E :    if (!session->GetNextBuffer(&client_buffer))
 465  i :      return false;
 466    :  
 467    :    // Copy buffer info into the RPC struct, slicing off the private bits.
 468  E :    DCHECK(client_buffer != NULL);
 469  E :    *call_trace_buffer = *client_buffer;
 470    :  
 471  E :    return true;
 472  E :  }
 473    :  
 474    :  // RPC entry point.
 475    :  bool Service::AllocateLargeBuffer(SessionHandle session_handle,
 476    :                                    size_t minimum_size,
 477  E :                                    CallTraceBuffer* call_trace_buffer) {
 478  E :    if (session_handle == NULL || call_trace_buffer == NULL) {
 479  i :      LOG(WARNING) << "Invalid RPC parameters.";
 480  i :      return false;
 481    :    }
 482    :  
 483  E :    scoped_refptr<Session> session;
 484  E :    if (!GetExistingSession(session_handle, &session))
 485  i :      return false;
 486  E :    DCHECK(session.get() != NULL);
 487    :  
 488    :    // Request a buffer for the client.
 489  E :    Buffer* client_buffer = NULL;
 490  E :    if (!session->GetBuffer(minimum_size, &client_buffer))
 491  i :      return false;
 492    :  
 493    :    // Copy buffer info into the RPC struct, slicing off the private bits.
 494  E :    DCHECK(client_buffer != NULL);
 495  E :    *call_trace_buffer = *client_buffer;
 496    :  
 497  E :    return true;
 498  E :  }
 499    :  
 500    :  // RPC entry point.
 501    :  bool Service::CommitAndExchangeBuffer(SessionHandle session_handle,
 502    :                                        CallTraceBuffer* call_trace_buffer,
 503  E :                                        ExchangeFlag perform_exchange) {
 504  E :    if (session_handle == NULL || call_trace_buffer == NULL) {
 505  i :      LOG(WARNING) << "Invalid RPC parameters.";
 506  i :      return false;
 507    :    }
 508    :  
 509    :    DCHECK(perform_exchange == PERFORM_EXCHANGE ||
 510  E :           perform_exchange == DO_NOT_PERFORM_EXCHANGE);
 511    :  
 512  E :    bool result = true;
 513  E :    scoped_refptr<Session> session;
 514  E :    if (!GetExistingSession(session_handle, &session))
 515  i :      return false;
 516  E :    DCHECK(session.get() != NULL);
 517    :  
 518  E :    Buffer* buffer = NULL;
 519  E :    if (!session->FindBuffer(call_trace_buffer, &buffer))
 520  i :      return false;
 521    :  
 522  E :    DCHECK(buffer != NULL);
 523    :  
 524    :    // We can't say anything about the buffer's state, as it possible that the
 525    :    // session that owns it has already been asked to shutdown, in which case
 526    :    // all of its buffers have already been scheduled for writing and the call
 527    :    // below will be ignored.
 528    :  
 529    :    // Return the buffer to the session. The session will then take care of
 530    :    // scheduling it for writing. Currently, it feeds it right back to us, but
 531    :    // this routing allows the write-queue to be decoupled from the service
 532    :    // more easily in the future.
 533  E :    if (!session->ReturnBuffer(buffer)) {
 534  i :      LOG(ERROR) << "Unable to return buffer to session.";
 535  i :      return false;
 536    :    }
 537    :  
 538  E :    ZeroMemory(call_trace_buffer, sizeof(*call_trace_buffer));
 539    :  
 540  E :    if (perform_exchange == PERFORM_EXCHANGE) {
 541    :      // Request a buffer for the client.
 542  E :      Buffer* client_buffer = NULL;
 543  E :      if (!session->GetNextBuffer(&client_buffer)) {
 544  i :        result = false;
 545  i :      } else {
 546    :        // Copy buffer info into the RPC struct, slicing off the private bits.
 547  E :        DCHECK(client_buffer != NULL);
 548  E :        *call_trace_buffer = *client_buffer;
 549    :      }
 550    :    }
 551    :  
 552  E :    return result;
 553  E :  }
 554    :  
 555    :  // RPC entry-point.
 556  E :  bool Service::CloseSession(SessionHandle* session_handle) {
 557  E :    if (session_handle == NULL || *session_handle == NULL) {
 558  i :      LOG(WARNING) << "Invalid RPC parameters.";
 559  i :      return false;
 560    :    }
 561    :  
 562  E :    scoped_refptr<Session> session;
 563    :    {
 564  E :      base::AutoLock auto_lock(lock_);
 565    :  
 566  E :      if (!GetExistingSessionUnlocked(*session_handle, &session))
 567  i :        return false;
 568    :  
 569  E :      size_t num_erased = sessions_.erase(session->client_process_id());
 570  E :      DCHECK_EQ(1U, num_erased);
 571  E :    }
 572    :  
 573  E :    DCHECK(session.get() != NULL);
 574    :  
 575    :    // Signal that we want the session to close. This will cause it to
 576    :    // schedule all of its outstanding buffers for writing. It will destroy
 577    :    // itself once it's reference count drops to zero.
 578  E :    session->Close();
 579    :  
 580  E :    *session_handle = NULL;
 581    :  
 582  E :    return true;
 583  E :  }
 584    :  
 585    :  bool Service::GetNewSession(ProcessId client_process_id,
 586  E :                              scoped_refptr<Session>* session) {
 587  E :    DCHECK(session != NULL);
 588  E :    *session = NULL;
 589    :  
 590    :    // Create the new session.
 591  E :    scoped_refptr<Session> new_session(CreateSession());
 592  E :    if (new_session.get() == NULL)
 593  i :      return false;
 594    :  
 595    :    // Initialize the session.
 596  E :    if (!new_session->Init(client_process_id))
 597  i :      return false;
 598    :  
 599    :    // Allocate a new buffer consumer.
 600  E :    scoped_refptr<BufferConsumer> consumer;
 601  E :    if (!buffer_consumer_factory_->CreateConsumer(&consumer))
 602  i :      return false;
 603    :  
 604    :    // Open the buffer consumer.
 605  E :    if (!consumer->Open(new_session.get()))
 606  i :      return false;
 607    :  
 608    :    // Hand the buffer consumer over to the session. The session will direct
 609    :    // returned buffers to the consumer.
 610  E :    new_session->set_buffer_consumer(consumer.get());
 611    :  
 612  E :    bool inserted = false;
 613    :    {
 614  E :      base::AutoLock auto_lock(lock_);
 615    :      // Attempt to add the session to the session map.
 616    :      inserted = sessions_.insert(
 617  E :          SessionMap::value_type(client_process_id, new_session)).second;
 618  E :    }
 619    :  
 620  E :    if (inserted == false) {
 621  i :      LOG(ERROR) << "A session already exists for process " << client_process_id
 622    :          << ".";
 623  i :      consumer->Close(new_session.get());
 624  i :      CHECK(new_session->Close());
 625    :  
 626  i :      return false;
 627    :    }
 628    :  
 629    :    // The session map has taken ownership of the session object; release
 630    :    // and return the session pointer.
 631  E :    *session = new_session;
 632    :  
 633  E :    return true;
 634  E :  }
 635    :  
 636    :  bool Service::GetExistingSession(SessionHandle session_handle,
 637  E :                                   scoped_refptr<Session>* session) {
 638  E :    DCHECK(session != NULL);
 639  E :    base::AutoLock auto_lock(lock_);
 640    :  
 641  E :    return GetExistingSessionUnlocked(session_handle, session);
 642  E :  }
 643    :  
 644    :  bool Service::GetExistingSessionUnlocked(SessionHandle session_handle,
 645  E :                                           scoped_refptr<Session>* session) {
 646  E :    DCHECK(session != NULL);
 647  E :    lock_.AssertAcquired();
 648    :  
 649  E :    *session = reinterpret_cast<Session*>(session_handle);
 650    :  
 651    :  #ifndef NDEBUG
 652  E :    if (sessions_.find((*session)->client_process_id()) == sessions_.end()) {
 653  i :      LOG(ERROR) << "No session exists for handle " << session_handle << ".";
 654  i :      *session = static_cast<Session*>(NULL);
 655  i :      return false;
 656    :    }
 657    :  #endif
 658    :  
 659  E :    return true;
 660  E :  }
 661    :  
 662    :  }  // namespace service
 663    :  }  // namespace trace

Coverage information generated Thu Jan 14 17:40:38 2016.