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
|