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 declares the trace::service::Service class which implements
16 : // the call trace service RPC interface.
17 :
18 : #ifndef SYZYGY_TRACE_SERVICE_SERVICE_H_
19 : #define SYZYGY_TRACE_SERVICE_SERVICE_H_
20 :
21 : #include <map>
22 :
23 : #include "base/files/file_path.h"
24 : #include "base/memory/ref_counted.h"
25 : #include "base/process/process.h"
26 : #include "base/strings/string_piece.h"
27 : #include "base/synchronization/condition_variable.h"
28 : #include "base/threading/platform_thread.h"
29 : #include "base/threading/thread.h"
30 : #include "syzygy/trace/rpc/call_trace_rpc.h"
31 :
32 : namespace trace {
33 : namespace service {
34 :
35 : // Forward declarations.
36 : class BufferConsumerFactory;
37 : class Session;
38 :
39 : // Implements the CallTraceService interface (see "call_trace_rpc.idl".
40 : // For the most basic usage:
41 : //
42 : // trace::service::Service::Instance().Start(false);
43 : //
44 : // This will access and launch a static instance of the service using a
45 : // default configuration. Specifying false, as in the above example,
46 : // will cause the call to be blocking; the call will not return until
47 : // the service is shutdown via the RequestShutdown() method. Specifying
48 : // true for the parameter to Start() will cause the Start() method to
49 : // return immediately, running the service in the background.
50 : //
51 : // Some mechanism to trigger a call to RequestShutdown() should be
52 : // provided to the operator of the service; for example, a signal handler
53 : // on SIGINT and/or SIGTERM, an event listening listening for a shutdown
54 : // Message, an IO loop waiting on a socket or Event, etc. The service
55 : // can also stopped remotely via an RPC call to CallTraceControl::Stop().
56 : class Service {
57 : public:
58 : typedef base::ProcessId ProcessId;
59 :
60 : // Flag passed to CommitAndExchangeBuffer() to determine whether or
61 : // not a fresh buffer should be returned to the client.
62 : enum ExchangeFlag {
63 : DO_NOT_PERFORM_EXCHANGE,
64 : PERFORM_EXCHANGE
65 : };
66 :
67 : // Construct a new call trace Service instance. The service will use the
68 : // given @p factory to construct buffer consumers for new sessions. The
69 : // service instance does NOT take ownership of the @p factory, which must
70 : // exist at least until the service instance is destroyed.
71 : explicit Service(BufferConsumerFactory* factory);
72 : ~Service();
73 :
74 : // The default number of buffers to allocate when expanding the buffer
75 : // pool allocated for a given client session.
76 : static const size_t kDefaultNumIncrementalBuffers;
77 :
78 : // The default size (in bytes) for each call trace buffer.
79 : static const size_t kDefaultBufferSize;
80 :
81 : // The default maximum number of buffers pending write that a session should
82 : // allow before beginning to force writes.
83 : static const size_t kDefaultMaxBuffersPendingWrite;
84 :
85 : // Set the id for this instance.
86 E : void set_instance_id(const base::StringPiece16& id) {
87 E : DCHECK(!is_running());
88 E : instance_id_.assign(id.begin(), id.end());
89 E : }
90 :
91 : // Set the trace flags that get communicated to clients on session creation.
92 : // The flags value should be bitmask composed of the values from the
93 : // TraceEventType enumeration (see call_trace_defs.h).
94 : //
95 : // @note TRACE_FLAG_BATCH_ENTER is mutually exclusive with all other flags.
96 : // If TRACE_FLAG_BATCH_ENTER is set, all other flags will be ignored.
97 i : void set_flags(uint32_t flags) { flags_ = flags; }
98 :
99 : // Set the number of buffers by which to grow a sessions
100 : // buffer pool.
101 E : void set_num_incremental_buffers(size_t n) {
102 E : num_incremental_buffers_ = n;
103 E : }
104 :
105 : // Set the number of bytes comprising each buffer in a
106 : // sessions buffer pool.
107 E : void set_buffer_size_in_bytes(size_t n) {
108 E : buffer_size_in_bytes_ = n;
109 E : }
110 :
111 : // Sets the maximum number of buffers pending write that a session should
112 : // allow before starting to force buffer writes.
113 : // @param n the max number of buffers pending write to allow.
114 E : void set_max_buffers_pending_write(size_t n) {
115 E : DCHECK_LT(0u, n);
116 E : max_buffers_pending_write_ = n;
117 E : }
118 :
119 : // @returns the number of new buffers to be created per allocation.
120 E : size_t num_incremental_buffers() const { return num_incremental_buffers_; }
121 :
122 : // @returns the size (in bytes) of new buffers to be allocated.
123 E : size_t buffer_size_in_bytes() const { return buffer_size_in_bytes_; }
124 :
125 : // @returns the maximum number of buffers that sessions should allow to be
126 : // pending writes prior to starting to force them.
127 E : size_t max_buffers_pending_write() const {
128 E : return max_buffers_pending_write_;
129 E : }
130 :
131 : // Returns true if any of the service's subsystems are running.
132 E : bool is_running() const {
133 E : return rpc_is_running_ || num_active_sessions_ > 0;
134 E : }
135 :
136 : // Begin accepting and handling RPC invocations. This method is not
137 : // generally callable by clients of the service; it may only be called
138 : // by the thread which created the service.
139 : //
140 : // The request handlers will be run on a thread pool owned by the RPC
141 : // runtime. If the non_blocking parameter is true, the call to Start()
142 : // will return immediately, allowing the owning thread to perform other
143 : // work while the service runs in the background. If non_blocking is
144 : // false, then the call to Start() will only return when the service
145 : // receives a shutdown request (via the RequestShutdown() method).
146 : //
147 : // Following the receipt of a shutdown request, it is the responsibility of
148 : // the thread which owns the service to call Stop() on the service, which
149 : // will take care of concluding any in-flight requests and flushing all
150 : // outstanding call trace buffers to disk.
151 : bool Start(bool non_blocking);
152 :
153 : // Completely shutdown the service. This method is not generally callable
154 : // by clients of the service; it may only be called by the thread which
155 : // created, and subsequently started, the service.
156 : //
157 : // Following the receipt of a shutdown request, it is the responsibility of
158 : // the thread which owns the service to call Stop() on the service, which
159 : // will take care of concluding any in-flight requests and flushing all
160 : // outstanding call trace buffers to disk.
161 : //
162 : // This is a blocking call, it will return after all outstanding requests
163 : // have been handled, all call trace buffers have been flushed, all
164 : // sessions have been closed, and all session resources deallocated.
165 : bool Stop();
166 :
167 : // RPC implementation of CallTraceControl::Stop().
168 : // See call_trace_rpc.idl for further info.
169 : bool RequestShutdown();
170 :
171 : // RPC implementation of CallTraceService::CreateSession().
172 : // See call_trace_rpc.idl for further info.
173 : bool CreateSession(handle_t binding,
174 : SessionHandle* session_handle,
175 : CallTraceBuffer* call_trace_buffer,
176 : unsigned long* flags);
177 :
178 : // RPC implementation of CallTraceService::AllocateBuffer().
179 : // See call_trace_rpc.idl for further info.
180 : bool AllocateBuffer(SessionHandle session_handle,
181 : CallTraceBuffer* call_trace_buffer);
182 :
183 : // RPC implementation of CallTraceService::AllocateLargeBuffer().
184 : // See call_trace_rpc.idl for further info.
185 : bool AllocateLargeBuffer(SessionHandle session_handle,
186 : size_t minimum_size,
187 : CallTraceBuffer* call_trace_buffer);
188 :
189 : // RPC implementation of both CallTraceService::ExchangeBuffer()
190 : // and CallTraceService::ReturnBuffer(). See call_trace_rpc.idl
191 : // for further info.
192 : bool CommitAndExchangeBuffer(SessionHandle session_handle,
193 : CallTraceBuffer* call_trace_buffer,
194 : ExchangeFlag perform_exchange);
195 :
196 : // RPC implementation of CallTraceService::CloseSession().
197 : // See call_trace_rpc.idl for further info.
198 : bool CloseSession(SessionHandle* session_handle);
199 :
200 : // Decrement the active session count.
201 : // @see num_active_sessions_
202 : void RemoveOneActiveSession();
203 :
204 : // Increment the active session count.
205 : // @see num_active_sessions_.
206 : void AddOneActiveSession();
207 :
208 : // These are protected for unittesting.
209 : protected:
210 :
211 : // @name RPC Server Management Functions.
212 : // These functions, unless otherwise noted, are single threaded and must
213 : // all be called from the thread that created this instance.
214 : // @{
215 : bool OpenServiceEvent();
216 : bool AcquireServiceMutex();
217 : void ReleaseServiceMutex();
218 : bool InitializeRpc();
219 : bool RunRPC(bool non_blocking);
220 :
221 : // This function is thread-safe.
222 : void StopRpc();
223 : void CleanupRpc();
224 : // @}
225 :
226 : // Creates a new session, returning true on success. On failure, the value
227 : // of *session will be NULL; otherwise it will contain a Session reference.
228 : bool GetNewSession(ProcessId client_process_id,
229 : scoped_refptr<Session>* session);
230 :
231 : // Looks up an existing session, returning true on success. On failure,
232 : // the value of *session will be NULL; otherwise it will contain a
233 : // Session reference.
234 : bool GetExistingSession(SessionHandle session_handle,
235 : scoped_refptr<Session>* session);
236 : // Looks up an existing session, returning true on success. On failure,
237 : // the value of *session will be NULL; otherwise it will contain a
238 : // Session reference.
239 : bool GetExistingSessionUnlocked(SessionHandle session_handle,
240 : scoped_refptr<Session>* session);
241 :
242 : // Closes all open sessions. This call blocks until all sessions have been
243 : // shutdown and have finished flushing their buffers.
244 : bool CloseAllOpenSessions();
245 :
246 : // Session factory. This is virtual for testing purposes.
247 : virtual Session* CreateSession();
248 :
249 : // Protects concurrent access to the internals, except for write-queue
250 : // related internals.
251 : base::Lock lock_;
252 :
253 : // The collection of open trace sessions. This is the collection of sessions
254 : // for which the service is currently accepting requests. Once a session is
255 : // closed, it is removed from this collection, but may still be active for
256 : // some time as it's trace buffers are consumed. See num_active_sessions_.
257 : typedef std::map<ProcessId, scoped_refptr<Session>> SessionMap;
258 : SessionMap sessions_; // Under lock_.
259 :
260 : // A count of the number of active sessions currently managed by this service.
261 : // This includes both open sessions and closed sessions which have not yet
262 : // finished flushing their buffers.
263 : size_t num_active_sessions_; // Under lock_.
264 :
265 : // The instance id to use when running this service instance.
266 : std::wstring instance_id_;
267 :
268 : // The number of buffers to allocate with each increment.
269 : size_t num_incremental_buffers_;
270 :
271 : // The number of bytes in each buffer.
272 : size_t buffer_size_in_bytes_;
273 :
274 : // The maximum number of buffers that a session should have pending write.
275 : size_t max_buffers_pending_write_;
276 :
277 : // Handle to the thread that owns/created this call trace service instance.
278 : base::PlatformThreadId owner_thread_;
279 :
280 : // The source factory for buffer consumer objects.
281 : BufferConsumerFactory* buffer_consumer_factory_;
282 :
283 : // Used to wait for all sessions to be closed on service shutdown.
284 : base::ConditionVariable a_session_has_closed_; // Under lock_.
285 :
286 : // Used to detect whether multiple instances of the service are running
287 : // against the service endpoint.
288 : base::win::ScopedHandle service_mutex_;
289 :
290 : // Signaled once the service has successfully initialized.
291 : base::win::ScopedHandle service_event_;
292 :
293 : // Flags denoting the state of the RPC server.
294 : bool rpc_is_initialized_;
295 : // TODO(rogerm): Access to this flag is inconsistent, but it seems the
296 : // transition from true to false will always take place under lock_.
297 : bool rpc_is_running_; // Under lock_.
298 : bool rpc_is_non_blocking_;
299 :
300 : // Flags informing the client of what trace events the service would like
301 : // to receive.
302 : uint32_t flags_;
303 :
304 : private:
305 : DISALLOW_COPY_AND_ASSIGN(Service);
306 : };
307 :
308 : } // namespace service
309 : } // namespace trace
310 :
311 : #endif // SYZYGY_TRACE_SERVICE_SERVICE_H_
|