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::Session class, which manages
16 : // the trace file and buffers for a given client of the call trace service.
17 :
18 : #ifndef SYZYGY_TRACE_SERVICE_SESSION_H_
19 : #define SYZYGY_TRACE_SERVICE_SESSION_H_
20 :
21 : #include <list>
22 : #include <map>
23 :
24 : #include "base/basictypes.h"
25 : #include "base/process.h"
26 : #include "base/files/file_path.h"
27 : #include "base/memory/ref_counted.h"
28 : #include "base/memory/scoped_ptr.h"
29 : #include "base/synchronization/condition_variable.h"
30 : #include "base/synchronization/lock.h"
31 : #include "base/win/scoped_handle.h"
32 : #include "syzygy/trace/service/buffer_consumer.h"
33 : #include "syzygy/trace/service/buffer_pool.h"
34 : #include "syzygy/trace/service/process_info.h"
35 :
36 : namespace trace {
37 : namespace service {
38 :
39 : // Forward declaration.
40 : class Service;
41 :
42 : // Holds all of the data associated with a given client session.
43 : // Note that this class it not internally thread safe. It is expected
44 : // that the CallTraceService will ensure that access to a given instance
45 : // of this class is synchronized.
46 : class Session : public base::RefCountedThreadSafe<Session> {
47 : public:
48 : typedef base::ProcessId ProcessId;
49 :
50 : explicit Session(Service* call_trace_service);
51 :
52 : public:
53 : // Initialize this session object.
54 : bool Init(ProcessId client_process_id);
55 :
56 : // Close the session. The causes the session to flush all of its outstanding
57 : // buffers to the write queue.
58 : bool Close();
59 :
60 : // Get the next available buffer for use by a client. The session retains
61 : // ownership of the buffer object, it MUST not be deleted by the caller. This
62 : // may cause new buffers to be allocated if there are no free buffers
63 : // available.
64 : // @param buffer will be populated with a pointer to the buffer to be provided
65 : // to the client.
66 : // @returns true on success, false otherwise.
67 : bool GetNextBuffer(Buffer** buffer);
68 :
69 : // Gets a buffer with a size at least as big as that requested. If the size
70 : // is consistent with the common buffer pool, this will be satisfied from
71 : // there. Otherwise, it will result in a specific allocation. The buffer
72 : // should be returned/recycled in the normal way. Buffers requested in this
73 : // method are not specifically subject to throttling and thus should only be
74 : // called for large and long lifespan uses.
75 : // @param minimum_size the minimum size of the buffer.
76 : // @param buffer will be populated with a pointer to the buffer to be provided
77 : // to the client.
78 : // @returns true on success, false otherwise.
79 : bool GetBuffer(size_t minimum_size, Buffer** out_buffer);
80 :
81 : // Returns a full buffer back to the session. After being returned here the
82 : // session will ensure the buffer gets written to disk before being returned
83 : // to service.
84 : // @param buffer the full buffer to return.
85 : // @returns true on success, false otherwise.
86 : bool ReturnBuffer(Buffer* buffer);
87 :
88 : // Returns a buffer to the pool of available buffers to be handed out to
89 : // clients. This is to be called by the write queue thread after the buffer
90 : // has been written to disk.
91 : // @param buffer the full buffer to recycle.
92 : // @returns true on success, false otherwise.
93 : bool RecycleBuffer(Buffer* buffer);
94 :
95 : // Locates the local record of the given call trace buffer. The session
96 : // retains ownership of the buffer object, it MUST not be deleted by the
97 : // caller.
98 : bool FindBuffer(::CallTraceBuffer* call_trace_buffer,
99 : Buffer** client_buffer);
100 :
101 : // Returns the process id of the client process.
102 E : ProcessId client_process_id() const { return client_.process_id; }
103 :
104 : // Returns the process information about this session's client.
105 E : const ProcessInfo& client_info() const { return client_; }
106 :
107 : // Get the buffer consumer for this session.
108 E : BufferConsumer* buffer_consumer() { return buffer_consumer_; }
109 :
110 : // Set the buffer consumer for this session.
111 E : void set_buffer_consumer(BufferConsumer* consumer) {
112 E : DCHECK(consumer != NULL);
113 E : DCHECK(buffer_consumer_.get() == NULL);
114 E : buffer_consumer_ = consumer;
115 E : }
116 :
117 : protected:
118 : friend class base::RefCountedThreadSafe<Session>;
119 : virtual ~Session();
120 :
121 : // @name Testing seams. These are basically events which will be called,
122 : // providing places for unittests to set some hooks.
123 : // @{
124 i : virtual void OnWaitingForBufferToBeRecycled() { }
125 :
126 E : virtual void OnDestroySingletonBuffer(Buffer* buffer) { }
127 :
128 : // Initialize process information for @p process_id.
129 : // @param process_id the process we want to capture information for.
130 : // @param client the record where we store the captured info.
131 : // @returns true on success.
132 : // @note does detailed logging on failure.
133 : virtual bool InitializeProcessInfo(ProcessId process_id,
134 : ProcessInfo* client);
135 :
136 : // Copy a shared memory segment handle to the client process.
137 : // @param client_process_handle a valid handle to the client process.
138 : // @param local_handle the locally valid handle that's to be duplicated.
139 : // @param client_copy on success returns the copied handle.
140 : // @returns true on success.
141 : // @note does detailed logging on failure.
142 : virtual bool CopyBufferHandleToClient(HANDLE client_process_handle,
143 : HANDLE local_handle,
144 : HANDLE* client_copy);
145 :
146 : // @}
147 :
148 : typedef Buffer::BufferState BufferState;
149 : typedef std::list<BufferPool*> SharedMemoryBufferCollection;
150 :
151 : // Allocates num_buffers shared client buffers, each of size
152 : // buffer_size and adds them to the free list.
153 : // @param num_nuffers the number of buffers to allocate.
154 : // @param buffer_size the size of each buffer to be allocated.
155 : // @param pool a pointer to the pool of allocated buffers.
156 : // @returns true on success, false otherwise.
157 : // @pre Under lock_.
158 : bool AllocateBufferPool(
159 : size_t num_buffers, size_t buffer_size, BufferPool** out_pool);
160 :
161 : // Allocates num_buffers shared client buffers, each of size
162 : // buffer_size and adds them to the free list.
163 : // @param num_nuffers the number of buffers to allocate.
164 : // @param buffer_size the size of each buffer to be allocated.
165 : // @returns true on success, false otherwise.
166 : // @pre Under lock_.
167 : // @note this is virtual to provide a testing seam.
168 : virtual bool AllocateBuffers(size_t num_buffers, size_t buffer_size);
169 :
170 : // Allocates a buffer for immediate use, not releasing it to the common buffer
171 : // pool and signaling its availability.
172 : // @param minimum_size the minimum size of the buffer.
173 : // @param out_buffer will be set to point to the newly allocated buffer.
174 : // @pre Under lock_.
175 : // @pre minimum_size must be bigger than the common buffer allocation size.
176 : bool AllocateBufferForImmediateUse(size_t minimum_size, Buffer** out_buffer);
177 :
178 : // A private implementation of GetNextBuffer, but which assumes the lock has
179 : // already been acquired.
180 : // @param buffer will be populated with a pointer to the buffer to be provided
181 : // to the client.
182 : // @returns true on success, false otherwise.
183 : // @pre Under lock_.
184 : bool GetNextBufferUnlocked(Buffer** buffer);
185 :
186 : // Destroys the given buffer, and its containing pool. The buffer must be the
187 : // only buffer in its pool, and must be in the pending write state. This is
188 : // meant for destroying singleton buffers that have been allocated with
189 : // custom sizes. We don't want to return them to the general pool.
190 : // @param buffer the buffer whose pool is to be destroyed.
191 : // @returns true on success, false otherwise.
192 : // @pre buffer is in the 'pending write' state. It should already have been
193 : // written but not yet transitioned.
194 : // @pre buffer is a singleton. That is, is part of a pool that contains only
195 : // a single buffer.
196 : bool DestroySingletonBuffer(Buffer* buffer);
197 :
198 : // Transitions the buffer to the given state. This only updates the buffer's
199 : // internal state and buffer_state_counts_, but not buffers_available_.
200 : // DCHECKs on any attempted invalid state changes.
201 : // @param new_state the new state to be applied to the buffer.
202 : // @param buffer the buffer to have its state changed.
203 : // @pre Under lock_.
204 : void ChangeBufferState(BufferState new_state, Buffer* buffer);
205 :
206 : // Gets (creating if needed) a buffer and populates it with a
207 : // TRACE_PROCESS_ENDED event. This is called by Close(), which is called
208 : // when the process owning this session disconnects (at its death).
209 : // @param buffer receives a pointer to the buffer that is used.
210 : // @returns true on success, false otherwise.
211 : // @pre Under lock_.
212 : bool CreateProcessEndedEvent(Buffer** buffer);
213 :
214 : // Returns true if the buffer book-keeping is self-consistent.
215 : // @pre Under lock_.
216 : bool BufferBookkeepingIsConsistent() const;
217 :
218 : // The call trace service this session lives in. We do not own this
219 : // object.
220 : Service* const call_trace_service_;
221 :
222 : // The process information for the client to which the session belongs.
223 : ProcessInfo client_;
224 :
225 : // All shared memory buffers allocated for this session.
226 : SharedMemoryBufferCollection shared_memory_buffers_; // Under lock_.
227 :
228 : // This is the set of buffers that we currently own.
229 : typedef std::map<Buffer::ID, Buffer*> BufferMap;
230 : BufferMap buffers_; // Under lock_.
231 :
232 : // State summary.
233 : size_t buffer_state_counts_[Buffer::kBufferStateMax]; // Under lock_.
234 :
235 : // The consumer responsible for processing this sessions buffers. The
236 : // lifetime of this object is managed by the call trace service.
237 : scoped_refptr<BufferConsumer> buffer_consumer_;
238 :
239 : // Buffers available to give to the clients.
240 : typedef std::deque<Buffer*> BufferQueue;
241 : BufferQueue buffers_available_; // Under lock_.
242 :
243 : // Tracks whether this session is in the process of shutting down.
244 : bool is_closing_; // Under lock_.
245 :
246 : // This is used to count the number of GetNextBuffer requests that are
247 : // currently applying back-pressure. There can only be as many of them as
248 : // there are buffers to be recycled until we fall below the back-pressure cap.
249 : size_t buffer_requests_waiting_for_recycle_; // Under lock_.
250 :
251 : // This condition variable is used to indicate that a buffer is available.
252 : base::ConditionVariable buffer_is_available_; // Under lock_.
253 :
254 : // This is currently only used to allocate unique IDs to buffers allocated
255 : // after the session closes.
256 : // TODO(rogerm): extend this to all buffers.
257 : size_t buffer_id_; // Under lock_.
258 :
259 : // This lock protects any access to the internals related to buffers and their
260 : // state.
261 : base::Lock lock_;
262 :
263 : // Tracks whether or not invalid input errors have already been logged.
264 : // When an error of this type occurs, there will typically be numerous
265 : // follow-on occurrences that we don't want to log.
266 : bool input_error_already_logged_; // Under lock_.
267 :
268 : private:
269 : DISALLOW_COPY_AND_ASSIGN(Session);
270 : };
271 :
272 : } // namespace service
273 : } // namespace trace
274 :
275 : #endif // SYZYGY_TRACE_SERVICE_SESSION_H_
|