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

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

Coverage information generated Fri Jul 29 11:00:21 2016.