OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 | 5 |
6 #ifndef BASE_DEBUG_TRACE_EVENT_IMPL_H_ | 6 #ifndef BASE_DEBUG_TRACE_EVENT_IMPL_H_ |
7 #define BASE_DEBUG_TRACE_EVENT_IMPL_H_ | 7 #define BASE_DEBUG_TRACE_EVENT_IMPL_H_ |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
59 long long as_int; | 59 long long as_int; |
60 double as_double; | 60 double as_double; |
61 const void* as_pointer; | 61 const void* as_pointer; |
62 const char* as_string; | 62 const char* as_string; |
63 }; | 63 }; |
64 | 64 |
65 TraceEvent(); | 65 TraceEvent(); |
66 TraceEvent(int thread_id, | 66 TraceEvent(int thread_id, |
67 TimeTicks timestamp, | 67 TimeTicks timestamp, |
68 char phase, | 68 char phase, |
69 const unsigned char* category_enabled, | 69 const unsigned char* category_group_enabled, |
70 const char* name, | 70 const char* name, |
71 unsigned long long id, | 71 unsigned long long id, |
72 int num_args, | 72 int num_args, |
73 const char** arg_names, | 73 const char** arg_names, |
74 const unsigned char* arg_types, | 74 const unsigned char* arg_types, |
75 const unsigned long long* arg_values, | 75 const unsigned long long* arg_values, |
76 unsigned char flags); | 76 unsigned char flags); |
77 ~TraceEvent(); | 77 ~TraceEvent(); |
78 | 78 |
79 // Serialize event data to JSON | 79 // Serialize event data to JSON |
80 static void AppendEventsAsJSON(const std::vector<TraceEvent>& events, | 80 static void AppendEventsAsJSON(const std::vector<TraceEvent>& events, |
81 size_t start, | 81 size_t start, |
82 size_t count, | 82 size_t count, |
83 std::string* out); | 83 std::string* out); |
84 void AppendAsJSON(std::string* out) const; | 84 void AppendAsJSON(std::string* out) const; |
85 | 85 |
86 static void AppendValueAsJSON(unsigned char type, | 86 static void AppendValueAsJSON(unsigned char type, |
87 TraceValue value, | 87 TraceValue value, |
88 std::string* out); | 88 std::string* out); |
89 | 89 |
90 TimeTicks timestamp() const { return timestamp_; } | 90 TimeTicks timestamp() const { return timestamp_; } |
91 | 91 |
92 // Exposed for unittesting: | 92 // Exposed for unittesting: |
93 | 93 |
94 const base::RefCountedString* parameter_copy_storage() const { | 94 const base::RefCountedString* parameter_copy_storage() const { |
95 return parameter_copy_storage_.get(); | 95 return parameter_copy_storage_.get(); |
96 } | 96 } |
97 | 97 |
98 const unsigned char* category_enabled() const { return category_enabled_; } | 98 const unsigned char* category_group_enabled() const { |
99 return category_group_enabled_; | |
100 } | |
101 | |
99 const char* name() const { return name_; } | 102 const char* name() const { return name_; } |
100 | 103 |
101 private: | 104 private: |
102 // Note: these are ordered by size (largest first) for optimal packing. | 105 // Note: these are ordered by size (largest first) for optimal packing. |
103 TimeTicks timestamp_; | 106 TimeTicks timestamp_; |
104 // id_ can be used to store phase-specific data. | 107 // id_ can be used to store phase-specific data. |
105 unsigned long long id_; | 108 unsigned long long id_; |
106 TraceValue arg_values_[kTraceMaxNumArgs]; | 109 TraceValue arg_values_[kTraceMaxNumArgs]; |
107 const char* arg_names_[kTraceMaxNumArgs]; | 110 const char* arg_names_[kTraceMaxNumArgs]; |
108 const unsigned char* category_enabled_; | 111 const unsigned char* category_group_enabled_; |
109 const char* name_; | 112 const char* name_; |
110 scoped_refptr<base::RefCountedString> parameter_copy_storage_; | 113 scoped_refptr<base::RefCountedString> parameter_copy_storage_; |
111 int thread_id_; | 114 int thread_id_; |
112 char phase_; | 115 char phase_; |
113 unsigned char flags_; | 116 unsigned char flags_; |
114 unsigned char arg_types_[kTraceMaxNumArgs]; | 117 unsigned char arg_types_[kTraceMaxNumArgs]; |
115 }; | 118 }; |
116 | 119 |
120 class BASE_EXPORT CategoryFilter { | |
121 // The default category filter, used when none is provided. | |
122 // Allows all categories through, except if they end in the suffix 'Debug' or | |
123 // 'Test'. | |
124 static const char* kDefaultCategoryFilterString; | |
125 | |
126 public: | |
127 // Constructs the default category filter. This is equivalent to | |
128 // CategoryFilter(CategoryFilter::kDefaultCategoryFilterString); | |
129 CategoryFilter(); | |
130 | |
131 // |filter_string| is a comma-delimited list of category wildcards. | |
132 // A category can have an optional '-' prefix to make it an excluded category. | |
133 // All the same rules apply above, so for example, having both included and | |
134 // excluded categories in the same list would not be supported. | |
135 // | |
136 // Example: CategoryFilter"test_MyTest*"); | |
137 // Example: CategoryFilter("test_MyTest*,test_OtherStuff"); | |
138 // Example: CategoryFilter("-excluded_category1,-excluded_category2"); | |
139 // Example: CategoryFilter("-*,webkit"); would disable everything but webkit. | |
140 // Example: CategoryFilter("-webkit"); would enable everything but webkit. | |
141 CategoryFilter(const std::string& filter_string); | |
dsinclair
2013/03/12 21:27:24
explicit CategoryFilter(const std::string& filter_
rterrazas
2013/03/20 08:48:49
Done.
| |
142 | |
143 CategoryFilter(const CategoryFilter& cf) | |
dsinclair
2013/03/12 21:27:24
The chromium style is to avoid overloading functio
rterrazas
2013/03/20 08:48:49
Like, reads better that way. Done.
| |
144 : included_(cf.included_), | |
145 excluded_(cf.excluded_) { | |
146 } | |
147 | |
148 CategoryFilter& operator=(const CategoryFilter& rhs) { | |
149 if (this == &rhs) | |
150 return *this; | |
151 | |
152 included_ = rhs.included_; | |
153 excluded_ = rhs.excluded_; | |
154 return *this; | |
155 } | |
156 | |
157 // Writes the string representation of the CategoryFilter. This is a comma | |
158 // separated string, similar in nature to the one used to determine | |
159 // enabled/disabled category patterns, except here there is an arbitrary | |
160 // order, included categories go first, then excluded categories. Excluded | |
161 // categories are distinguished from included categories by the prefix '-'. | |
162 std::string ToString() const; | |
163 | |
164 // Determines whether category group would be enabled or | |
165 // disabled by this filter. | |
dsinclair
2013/03/12 21:27:24
disabled by this category filter.
On first readin
rterrazas
2013/03/20 08:48:49
Done.
| |
166 bool IsCategoryGroupEnabled(const char* category_group) const; | |
167 | |
168 // Merges nested_filter with the current CategoryFilter | |
169 void Merge(const CategoryFilter& nested_filter); | |
170 | |
171 // Determines whether or not we have explicitly allowed category patterns. | |
172 bool HasAllowedPatterns() const; | |
173 | |
174 // Clears both included/excluded pattern lists. This would be equivalent to | |
175 // creating a CategoryFilter with an empty string, through the constructor. | |
176 // i.e: CategoryFilter(""). | |
177 // | |
178 // When using an empty filter, all categories are considered included as we | |
179 // are not excluding anything. | |
180 void Clear(); | |
181 | |
182 private: | |
183 void Initialize(const std::string& filter_string); | |
184 void WriteString(std::string* out, bool included) const; | |
185 | |
186 std::vector<std::string> included_; | |
187 std::vector<std::string> excluded_; | |
188 | |
189 }; | |
117 | 190 |
118 // TraceResultBuffer collects and converts trace fragments returned by TraceLog | 191 // TraceResultBuffer collects and converts trace fragments returned by TraceLog |
119 // to JSON output. | 192 // to JSON output. |
120 class BASE_EXPORT TraceResultBuffer { | 193 class BASE_EXPORT TraceResultBuffer { |
121 public: | 194 public: |
122 typedef base::Callback<void(const std::string&)> OutputCallback; | 195 typedef base::Callback<void(const std::string&)> OutputCallback; |
123 | 196 |
124 // If you don't need to stream JSON chunks out efficiently, and just want to | 197 // If you don't need to stream JSON chunks out efficiently, and just want to |
125 // get a complete JSON string after calling Finish, use this struct to collect | 198 // get a complete JSON string after calling Finish, use this struct to collect |
126 // JSON trace output. | 199 // JSON trace output. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 // Enable the sampling profiler. | 251 // Enable the sampling profiler. |
179 ENABLE_SAMPLING = 1 << 1, | 252 ENABLE_SAMPLING = 1 << 1, |
180 }; | 253 }; |
181 | 254 |
182 static TraceLog* GetInstance(); | 255 static TraceLog* GetInstance(); |
183 | 256 |
184 // Convert the given string to trace options. Defaults to RECORD_UNTIL_FULL if | 257 // Convert the given string to trace options. Defaults to RECORD_UNTIL_FULL if |
185 // the string does not provide valid options. | 258 // the string does not provide valid options. |
186 static Options TraceOptionsFromString(const std::string& str); | 259 static Options TraceOptionsFromString(const std::string& str); |
187 | 260 |
188 // Get set of known categories. This can change as new code paths are reached. | 261 // Get set of known category groups. This can change as new code paths are |
189 // The known categories are inserted into |categories|. | 262 // reached. The known category groups are inserted into |category_groups|. |
190 void GetKnownCategories(std::vector<std::string>* categories); | 263 void GetKnownCategoryGroups(std::vector<std::string>* category_groups); |
191 | 264 |
192 // Enable tracing for provided list of categories. If tracing is already | 265 // Retrieves the current filter used to enable categories. Only |
193 // enabled, this method does nothing -- changing categories during trace is | |
194 // not supported. | |
195 // If both included_categories and excluded_categories are empty, | |
196 // all categories are traced. | |
197 // Else if included_categories is non-empty, only those are traced. | |
198 // Else if excluded_categories is non-empty, everything but those are traced. | |
199 // Wildcards * and ? are supported (see MatchPattern in string_util.h). | |
200 void SetEnabled(const std::vector<std::string>& included_categories, | |
201 const std::vector<std::string>& excluded_categories, | |
202 Options options); | |
203 | |
204 // |categories| is a comma-delimited list of category wildcards. | |
205 // A category can have an optional '-' prefix to make it an excluded category. | |
206 // All the same rules apply above, so for example, having both included and | |
207 // excluded categories in the same list would not be supported. | |
208 // | |
209 // Example: SetEnabled("test_MyTest*"); | |
210 // Example: SetEnabled("test_MyTest*,test_OtherStuff"); | |
211 // Example: SetEnabled("-excluded_category1,-excluded_category2"); | |
212 void SetEnabled(const std::string& categories, Options options); | |
213 | |
214 // Retieves the categories set via a prior call to SetEnabled(). Only | |
215 // meaningful if |IsEnabled()| is true. | 266 // meaningful if |IsEnabled()| is true. |
216 void GetEnabledTraceCategories(std::vector<std::string>* included_out, | 267 const CategoryFilter& GetCurrentCategoryFilter(); |
217 std::vector<std::string>* excluded_out); | |
218 | 268 |
219 Options trace_options() const { return trace_options_; } | 269 Options trace_options() const { return trace_options_; } |
220 | 270 |
271 // Enables tracing. See CategoryFilter comments for details | |
272 // on how to control what categories will be traced. | |
273 void SetEnabled(const CategoryFilter& category_filter, Options options); | |
274 | |
221 // Disable tracing for all categories. | 275 // Disable tracing for all categories. |
222 void SetDisabled(); | 276 void SetDisabled(); |
223 // Helper method to enable/disable tracing for all categories. | |
224 void SetEnabled(bool enabled, Options options); | |
225 bool IsEnabled() { return !!enable_count_; } | 277 bool IsEnabled() { return !!enable_count_; } |
226 | 278 |
227 #if defined(OS_ANDROID) | 279 #if defined(OS_ANDROID) |
228 void StartATrace(); | 280 void StartATrace(); |
229 void StopATrace(); | 281 void StopATrace(); |
230 #endif | 282 #endif |
231 | 283 |
232 // Enabled state listeners give a callback when tracing is enabled or | 284 // Enabled state listeners give a callback when tracing is enabled or |
233 // disabled. This can be used to tie into other library's tracing systems | 285 // disabled. This can be used to tie into other library's tracing systems |
234 // on-demand. | 286 // on-demand. |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
276 | 328 |
277 // Flush all collected events to the given output callback. The callback will | 329 // Flush all collected events to the given output callback. The callback will |
278 // be called one or more times with IPC-bite-size chunks. The string format is | 330 // be called one or more times with IPC-bite-size chunks. The string format is |
279 // undefined. Use TraceResultBuffer to convert one or more trace strings to | 331 // undefined. Use TraceResultBuffer to convert one or more trace strings to |
280 // JSON. | 332 // JSON. |
281 typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&)> | 333 typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&)> |
282 OutputCallback; | 334 OutputCallback; |
283 void Flush(const OutputCallback& cb); | 335 void Flush(const OutputCallback& cb); |
284 | 336 |
285 // Called by TRACE_EVENT* macros, don't call this directly. | 337 // Called by TRACE_EVENT* macros, don't call this directly. |
286 static const unsigned char* GetCategoryEnabled(const char* name); | 338 // The name parameter is a category group for example: |
287 static const char* GetCategoryName(const unsigned char* category_enabled); | 339 // TRACE_EVENT0("renderer,webkit", "WebViewImpl::HandleInputEvent") |
340 static const unsigned char* GetCategoryGroupEnabled(const char* name); | |
341 static const char* GetCategoryGroupName( | |
342 const unsigned char* category_group_enabled); | |
288 | 343 |
289 // Called by TRACE_EVENT* macros, don't call this directly. | 344 // Called by TRACE_EVENT* macros, don't call this directly. |
290 // If |copy| is set, |name|, |arg_name1| and |arg_name2| will be deep copied | 345 // If |copy| is set, |name|, |arg_name1| and |arg_name2| will be deep copied |
291 // into the event; see "Memory scoping note" and TRACE_EVENT_COPY_XXX above. | 346 // into the event; see "Memory scoping note" and TRACE_EVENT_COPY_XXX above. |
292 void AddTraceEvent(char phase, | 347 void AddTraceEvent(char phase, |
293 const unsigned char* category_enabled, | 348 const unsigned char* category_group_enabled, |
294 const char* name, | 349 const char* category_group, |
295 unsigned long long id, | 350 unsigned long long id, |
296 int num_args, | 351 int num_args, |
297 const char** arg_names, | 352 const char** arg_names, |
298 const unsigned char* arg_types, | 353 const unsigned char* arg_types, |
299 const unsigned long long* arg_values, | 354 const unsigned long long* arg_values, |
300 unsigned char flags); | 355 unsigned char flags); |
301 void AddTraceEventWithThreadIdAndTimestamp( | 356 void AddTraceEventWithThreadIdAndTimestamp( |
302 char phase, | 357 char phase, |
303 const unsigned char* category_enabled, | 358 const unsigned char* category_enabled, |
304 const char* name, | 359 const char* name, |
305 unsigned long long id, | 360 unsigned long long id, |
306 int thread_id, | 361 int thread_id, |
307 const TimeTicks& timestamp, | 362 const TimeTicks& timestamp, |
308 int num_args, | 363 int num_args, |
309 const char** arg_names, | 364 const char** arg_names, |
310 const unsigned char* arg_types, | 365 const unsigned char* arg_types, |
311 const unsigned long long* arg_values, | 366 const unsigned long long* arg_values, |
312 unsigned char flags); | 367 unsigned char flags); |
313 static void AddTraceEventEtw(char phase, | 368 static void AddTraceEventEtw(char phase, |
314 const char* name, | 369 const char* category_group, |
315 const void* id, | 370 const void* id, |
316 const char* extra); | 371 const char* extra); |
317 static void AddTraceEventEtw(char phase, | 372 static void AddTraceEventEtw(char phase, |
318 const char* name, | 373 const char* category_group, |
319 const void* id, | 374 const void* id, |
320 const std::string& extra); | 375 const std::string& extra); |
321 | 376 |
322 // For every matching event, a notification will be fired. NOTE: the | 377 // For every matching event, a notification will be fired. NOTE: the |
323 // notification will fire for each matching event that has already occurred | 378 // notification will fire for each matching event that has already occurred |
324 // since tracing was started (including before tracing if the process was | 379 // since tracing was started (including before tracing if the process was |
325 // started with tracing turned on). | 380 // started with tracing turned on). |
326 void SetWatchEvent(const std::string& category_name, | 381 void SetWatchEvent(const std::string& category_name, |
327 const std::string& event_name); | 382 const std::string& event_name); |
328 // Cancel the watch event. If tracing is enabled, this may race with the | 383 // Cancel the watch event. If tracing is enabled, this may race with the |
(...skipping 19 matching lines...) Expand all Loading... | |
348 return logged_events_[index]; | 403 return logged_events_[index]; |
349 } | 404 } |
350 | 405 |
351 void SetProcessID(int process_id); | 406 void SetProcessID(int process_id); |
352 | 407 |
353 // Allow setting an offset between the current TimeTicks time and the time | 408 // Allow setting an offset between the current TimeTicks time and the time |
354 // that should be reported. | 409 // that should be reported. |
355 void SetTimeOffset(TimeDelta offset); | 410 void SetTimeOffset(TimeDelta offset); |
356 | 411 |
357 private: | 412 private: |
413 | |
358 // This allows constructor and destructor to be private and usable only | 414 // This allows constructor and destructor to be private and usable only |
359 // by the Singleton class. | 415 // by the Singleton class. |
360 friend struct StaticMemorySingletonTraits<TraceLog>; | 416 friend struct StaticMemorySingletonTraits<TraceLog>; |
361 | 417 |
362 // The pointer returned from GetCategoryEnabledInternal() points to a value | 418 // Enable/disable each category group based on the current category_filter_. |
363 // with zero or more of the following bits. Used in this class only. | 419 // If the category group contains a category that matches an included category |
420 // pattern, that category group will be enabled. | |
421 void EnableIncludedCategoryGroups(); | |
422 void EnableIncludedCategoryGroup(int category_index); | |
423 | |
424 // The pointer returned from GetCategoryGroupEnabledInternal() points to a | |
425 // value with zero or more of the following bits. Used in this class only. | |
364 // The TRACE_EVENT macros should only use the value as a bool. | 426 // The TRACE_EVENT macros should only use the value as a bool. |
365 enum CategoryEnabledFlags { | 427 enum CategoryEnabledFlags { |
366 // Normal enabled flag for categories enabled with Enable(). | 428 // Normal enabled flag for categories enabled with Enable(). |
367 CATEGORY_ENABLED = 1 << 0, | 429 CATEGORY_ENABLED = 1 << 0, |
368 // On Android if ATrace is enabled, all categories will have this bit. | 430 // On Android if ATrace is enabled, all categories will have this bit. |
369 // Not used on other platforms. | 431 // Not used on other platforms. |
370 ATRACE_ENABLED = 1 << 1 | 432 ATRACE_ENABLED = 1 << 1 |
371 }; | 433 }; |
372 | 434 |
373 // Helper class for managing notification_thread_count_ and running | 435 // Helper class for managing notification_thread_count_ and running |
(...skipping 14 matching lines...) Expand all Loading... | |
388 inline void SendNotificationIfAny(); | 450 inline void SendNotificationIfAny(); |
389 | 451 |
390 private: | 452 private: |
391 TraceLog* trace_log_; | 453 TraceLog* trace_log_; |
392 NotificationCallback callback_copy_; | 454 NotificationCallback callback_copy_; |
393 int notification_; | 455 int notification_; |
394 }; | 456 }; |
395 | 457 |
396 TraceLog(); | 458 TraceLog(); |
397 ~TraceLog(); | 459 ~TraceLog(); |
398 const unsigned char* GetCategoryEnabledInternal(const char* name); | 460 const unsigned char* GetCategoryGroupEnabledInternal(const char* name); |
399 void AddThreadNameMetadataEvents(); | 461 void AddThreadNameMetadataEvents(); |
400 | 462 |
401 #if defined(OS_ANDROID) | 463 #if defined(OS_ANDROID) |
402 void SendToATrace(char phase, | 464 void SendToATrace(char phase, |
403 const char* category, | 465 const char* category_group, |
404 const char* name, | 466 const char* name, |
405 int num_args, | 467 int num_args, |
406 const char** arg_names, | 468 const char** arg_names, |
407 const unsigned char* arg_types, | 469 const unsigned char* arg_types, |
408 const unsigned long long* arg_values); | 470 const unsigned long long* arg_values); |
409 static void ApplyATraceEnabledFlag(unsigned char* category_enabled); | 471 static void ApplyATraceEnabledFlag(unsigned char* category_group_enabled); |
410 #endif | 472 #endif |
411 | 473 |
412 // TODO(nduca): switch to per-thread trace buffers to reduce thread | 474 // TODO(nduca): switch to per-thread trace buffers to reduce thread |
413 // synchronization. | 475 // synchronization. |
414 // This lock protects TraceLog member accesses from arbitrary threads. | 476 // This lock protects TraceLog member accesses from arbitrary threads. |
415 Lock lock_; | 477 Lock lock_; |
416 int enable_count_; | 478 int enable_count_; |
417 NotificationCallback notification_callback_; | 479 NotificationCallback notification_callback_; |
418 EventCallback event_callback_; | 480 EventCallback event_callback_; |
419 std::vector<TraceEvent> logged_events_; | 481 std::vector<TraceEvent> logged_events_; |
420 std::vector<std::string> included_categories_; | 482 CategoryFilter category_filter_; |
421 std::vector<std::string> excluded_categories_; | |
422 bool dispatching_to_observer_list_; | 483 bool dispatching_to_observer_list_; |
423 ObserverList<EnabledStateChangedObserver> enabled_state_observer_list_; | 484 ObserverList<EnabledStateChangedObserver> enabled_state_observer_list_; |
424 | 485 |
425 base::hash_map<int, std::string> thread_names_; | 486 base::hash_map<int, std::string> thread_names_; |
426 | 487 |
427 // XORed with TraceID to make it unlikely to collide with other processes. | 488 // XORed with TraceID to make it unlikely to collide with other processes. |
428 unsigned long long process_id_hash_; | 489 unsigned long long process_id_hash_; |
429 | 490 |
430 int process_id_; | 491 int process_id_; |
431 | 492 |
432 TimeDelta time_offset_; | 493 TimeDelta time_offset_; |
433 | 494 |
434 // Allow tests to wake up when certain events occur. | 495 // Allow tests to wake up when certain events occur. |
435 const unsigned char* watch_category_; | 496 const unsigned char* watch_category_; |
436 std::string watch_event_name_; | 497 std::string watch_event_name_; |
437 | 498 |
438 Options trace_options_; | 499 Options trace_options_; |
439 | 500 |
440 // Sampling thread handles. | 501 // Sampling thread handles. |
441 scoped_ptr<TraceSamplingThread> sampling_thread_; | 502 scoped_ptr<TraceSamplingThread> sampling_thread_; |
442 PlatformThreadHandle sampling_thread_handle_; | 503 PlatformThreadHandle sampling_thread_handle_; |
443 | 504 |
444 DISALLOW_COPY_AND_ASSIGN(TraceLog); | 505 DISALLOW_COPY_AND_ASSIGN(TraceLog); |
445 }; | 506 }; |
446 | 507 |
447 } // namespace debug | 508 } // namespace debug |
448 } // namespace base | 509 } // namespace base |
449 | 510 |
450 #endif // BASE_DEBUG_TRACE_EVENT_IMPL_H_ | 511 #endif // BASE_DEBUG_TRACE_EVENT_IMPL_H_ |
OLD | NEW |