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
|