1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BERBERIS_BASE_TRACING_H_
18 #define BERBERIS_BASE_TRACING_H_
19 
20 #include <unistd.h>
21 
22 #include <cstdarg>
23 
24 #include "berberis/base/format_buffer.h"
25 #include "berberis/base/gettid.h"
26 #include "berberis/base/scoped_errno.h"
27 
28 namespace berberis {
29 
30 // TODO(eaeltsin): disable for user builds (NDEBUG doesn't work)!
31 constexpr bool kEnableTracing = true;
32 
33 // Use class static members/functions to keep implementation private but still inline it.
34 class Tracing {
35  public:
36   // ATTENTION: portable code!
37 
Init()38   static void Init() {
39     if (kEnableTracing) InitImpl();
40   }
41 
IsOn()42   static bool IsOn() { return kEnableTracing && IsOnImpl(); }
43 
TraceF(const char * format,...)44   static void __attribute__((__format__(printf, 1, 2))) TraceF(const char* format, ...) {
45     va_list ap;
46     va_start(ap, format);
47     TraceV(format, ap);
48     va_end(ap);
49   }
50 
TraceV(const char * format,va_list ap)51   static void __attribute__((__format__(printf, 1, 0))) TraceV(const char* format, va_list ap) {
52     FormatBufferVaListArgs args(ap);
53     TraceA(format, &args);
54   }
55 
56   template <typename Args>
TraceA(const char * format,Args * args)57   static void TraceA(const char* format, Args* args) {
58     DynamicCStrBuffer buf;
59 
60     FormatBufferImplF(&buf, "%5u %5u ", GetpidSyscall(), GettidSyscall());
61     FormatBufferImpl(&buf, format, args);
62     buf.Put('\n');
63 
64     TraceImpl(buf.Data(), buf.Size());
65   }
66 
67  private:
68   // ATTENTION: platform-specific code!
69 
70   static void InitImpl();
71 
72   // ATTENTION: posix code!
73 
IsOnImpl()74   static bool IsOnImpl() { return fd_ != -1; }
75 
TraceImpl(const char * buf,size_t n)76   static void TraceImpl(const char* buf, size_t n) {
77     ScopedErrno scoped_errno;
78     // Tracing output should always be atomic, there should be no cases when
79     // concurrent tracing threads create mixed messages.
80     // A single 'write' call is intentional. If we are not lucky to output the
81     // whole message or there is an error in one system call, so be it.
82     UNUSED(write(fd_, buf, n));
83   }
84 
85   static int fd_;
86 };
87 
88 }  // namespace berberis
89 
90 // Don't evaluate arguments if tracing is disabled.
91 #define TRACE(...)                              \
92   do {                                          \
93     if (::berberis::Tracing::IsOn()) {          \
94       ::berberis::Tracing::TraceF(__VA_ARGS__); \
95     }                                           \
96   } while (0)
97 
98 #endif  // BERBERIS_BASE_TRACING_H_
99