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