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