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