1c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev/*
2c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * Copyright (C) Texas Instruments - http://www.ti.com/
3c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev *
4c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * Licensed under the Apache License, Version 2.0 (the "License");
5c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * you may not use this file except in compliance with the License.
6c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * You may obtain a copy of the License at
7c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev *
8c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev *      http://www.apache.org/licenses/LICENSE-2.0
9c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev *
10c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * Unless required by applicable law or agreed to in writing, software
11c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * distributed under the License is distributed on an "AS IS" BASIS,
12c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * See the License for the specific language governing permissions and
14c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * limitations under the License.
15c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev */
16c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
17c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev#ifndef DEBUG_UTILS_H
18c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev#define DEBUG_UTILS_H
19c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
20f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#include <android/log.h>
21f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#include <utils/threads.h>
22f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#include <utils/Vector.h>
23c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
24c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
25c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
26c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
27f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsnamespace Ti {
28f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
29f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
30f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
31f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
32f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons// use 2 space characters for call stack indent
33f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsstatic const int kFunctionLoggerIndentSize = 2;
34f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
35f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
36f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
37f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
38f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonstemplate <int Size = kFunctionLoggerIndentSize>
39f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsclass IndentString
40f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
41f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonspublic:
42f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    IndentString(int length);
43f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
44f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    const char * string() const;
45f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
46f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsprivate:
47f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    int calculateOffset(int length) const;
48f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
49f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsprivate:
50f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    const int mOffset;
51f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons};
52f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
53f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
54f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
55f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
56f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsclass Debug
57f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
58f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonspublic:
59f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    static Debug * instance();
60f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
61f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    int offsetForCurrentThread();
62f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    void log(int priority, const char * format, ...);
63f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
64f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsprivate:
65f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    class ThreadInfo
66f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {
67f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    public:
68f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        ThreadInfo() :
69f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            threadId(0), callOffset(0)
70f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        {}
71f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
72f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        volatile int32_t threadId;
73f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        int callOffset;
74f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    };
75f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
76f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    class Data : public android::RefBase
77f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {
78f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    public:
79f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        android::Vector<ThreadInfo*> threads;
80f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    };
81f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
82f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsprivate:
83f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // called from FunctionLogger
84f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    void increaseOffsetForCurrentThread();
85f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    void decreaseOffsetForCurrentThread();
86f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
87f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsprivate:
88f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    Debug();
89f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
90f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    void grow();
91f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    ThreadInfo * registerThread(Data * data, int32_t threadId);
92f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    ThreadInfo * findCurrentThreadInfo();
93f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    void addOffsetForCurrentThread(int offset);
94f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
95f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsprivate:
96f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    static Debug sInstance;
97f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
98f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    mutable android::Mutex mMutex;
99f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    android::sp<Data> mData;
100f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
101f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    friend class FunctionLogger;
102f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons};
103f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
104f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
105f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
106f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
107f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsclass FunctionLogger
108f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
109f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonspublic:
110f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    FunctionLogger(const char * file, int line, const char * function);
111f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    ~FunctionLogger();
112f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
113f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    void setExitLine(int line);
114f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
115f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsprivate:
116f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    const char * const mFile;
117f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    const int mLine;
118f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    const char * const mFunction;
119f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    const void * const mThreadId;
120f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    int mExitLine;
121f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons};
122f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
123f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
124f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
125f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
126f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#ifdef TI_UTILS_FUNCTION_LOGGER_ENABLE
127f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#   define LOG_FUNCTION_NAME Ti::FunctionLogger __function_logger_instance(__FILE__, __LINE__, __FUNCTION__);
128f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#   define LOG_FUNCTION_NAME_EXIT __function_logger_instance.setExitLine(__LINE__);
129f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#else
130f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#   define LOG_FUNCTION_NAME int __function_logger_instance;
131f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#   define LOG_FUNCTION_NAME_EXIT (void*)__function_logger_instance;
132f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#endif
133f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
134f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#ifdef TI_UTILS_DEBUG_USE_TIMESTAMPS
135f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // truncate timestamp to 1000 seconds to fit into 6 characters
136f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#   define TI_UTILS_DEBUG_TIMESTAMP_TOKEN "[%06d] "
137f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#   define TI_UTILS_DEBUG_TIMESTAMP_VARIABLE static_cast<int>(nanoseconds_to_milliseconds(systemTime()) % 1000000),
138f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#else
139f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#   define TI_UTILS_DEBUG_TIMESTAMP_TOKEN
140f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#   define TI_UTILS_DEBUG_TIMESTAMP_VARIABLE
141f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#endif
142f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
143f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
144f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
145f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
146f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGV_FULL(priority, file, line, function, format, ...)       \
147f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    do                                                                        \
148f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {                                                                         \
149f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        Ti::Debug * const debug = Ti::Debug::instance();                      \
150f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        debug->log(priority, format,                                          \
151f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                TI_UTILS_DEBUG_TIMESTAMP_VARIABLE                             \
152f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                reinterpret_cast<int>(androidGetThreadId()),                  \
153f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                Ti::IndentString<>(debug->offsetForCurrentThread()).string(), \
154f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                file, line, function, __VA_ARGS__);                           \
155f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    } while (0)
156f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
157f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGV(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_VERBOSE, __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s  %s:%d %s - " __VA_ARGS__, "")
158f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGD(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_DEBUG,   __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s  %s:%d %s - " __VA_ARGS__, "")
159f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGI(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_INFO,    __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s  %s:%d %s - " __VA_ARGS__, "")
160f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGW(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_WARN,    __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s  %s:%d %s - " __VA_ARGS__, "")
161f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGE(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_ERROR,   __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s  %s:%d %s - " __VA_ARGS__, "")
162f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGF(...) DBGUTILS_LOGV_FULL(ANDROID_LOG_FATAL,   __FILE__, __LINE__, __FUNCTION__, TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s  %s:%d %s - " __VA_ARGS__, "")
163f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
164f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGVA DBGUTILS_LOGV
165f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGVB DBGUTILS_LOGV
166f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
167f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGDA DBGUTILS_LOGD
168f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGDB DBGUTILS_LOGD
169f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
170f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGEA DBGUTILS_LOGE
171f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_LOGEB DBGUTILS_LOGE
172f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
173f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons// asserts
174f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define _DBGUTILS_PLAIN_ASSERT(condition)                              \
175f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    do                                                                 \
176f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {                                                                  \
177f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        if ( !(condition) )                                            \
178f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        {                                                              \
179f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            __android_log_print(ANDROID_LOG_FATAL, "Ti::Debug",        \
180f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                    "Condition failed: " #condition);                  \
181f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            __android_log_print(ANDROID_LOG_FATAL, "Ti::Debug",        \
182f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                    "Aborting process...");                            \
183f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            abort();                                                   \
184f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        }                                                              \
185f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    } while (0)
186f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
187f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define _DBGUTILS_PLAIN_ASSERT_X(condition, ...)                       \
188f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    do                                                                 \
189f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {                                                                  \
190f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        if ( !(condition) )                                            \
191f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        {                                                              \
192f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            __android_log_print(ANDROID_LOG_FATAL, "Ti::Debug",        \
193f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                    "Condition failed: " #condition ": " __VA_ARGS__); \
194f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            __android_log_print(ANDROID_LOG_FATAL, "Ti::Debug",        \
195f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                    "Aborting process...");                            \
196f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            abort();                                                   \
197f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        }                                                              \
198f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    } while (0)
199f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
200f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_ASSERT(condition)                                           \
201f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    do                                                                       \
202f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {                                                                        \
203f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        if ( !(condition) )                                                  \
204f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        {                                                                    \
205f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            DBGUTILS_LOGF("Condition failed: " #condition);                  \
206f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            DBGUTILS_LOGF("Aborting process...");                            \
207f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            abort();                                                         \
208f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        }                                                                    \
209f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    } while (0)
210c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
211f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#define DBGUTILS_ASSERT_X(condition, ...)                                    \
212f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    do                                                                       \
213f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {                                                                        \
214f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        if ( !(condition) )                                                  \
215f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        {                                                                    \
216f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            DBGUTILS_LOGF("Condition failed: " #condition ": " __VA_ARGS__); \
217f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            DBGUTILS_LOGF("Aborting process...");                            \
218f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            abort();                                                         \
219f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        }                                                                    \
220f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    } while (0)
221f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
222f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
223f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
224f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
225f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsstatic const int kIndentStringMaxLength = 128;
226f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
227f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonstemplate <int Size>
228f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline int IndentString<Size>::calculateOffset(const int length) const
229f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
230f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    const int offset = kIndentStringMaxLength - length*Size;
231f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    return offset < 0 ? 0 : offset;
232f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
233f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
234f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonstemplate <int Size>
235f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline IndentString<Size>::IndentString(const int length) :
236f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    mOffset(calculateOffset(length))
237f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{}
238f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
239f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonstemplate <int Size>
240f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline const char * IndentString<Size>::string() const
241f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
242f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    extern const char sIndentStringBuffer[];
243f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    return sIndentStringBuffer + mOffset;
244f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
245f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
246f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
247f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
248f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
249f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline Debug * Debug::instance()
250f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{ return &sInstance; }
251f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
252f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
253f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline Debug::ThreadInfo * Debug::findCurrentThreadInfo()
254f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
255f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // retain reference to threads data
256f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    android::sp<Data> data = mData;
257f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
258f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // iterate over threads to locate thread id,
259f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // this is safe from race conditions because each thread
260f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // is able to modify only his own ThreadInfo structure
261f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    const int32_t threadId = reinterpret_cast<int32_t>(androidGetThreadId());
262f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    const int size = int(data->threads.size());
263f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    for ( int i = 0; i < size; ++i )
264f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {
265f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        ThreadInfo * const threadInfo = data->threads.itemAt(i);
266f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        if ( threadInfo->threadId == threadId )
267f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            return threadInfo;
268f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    }
269f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
270f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // this thread has not been registered yet,
271f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // try to fing empty thread info slot
272f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    while ( true )
273f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {
274f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        ThreadInfo * const threadInfo = registerThread(data.get(), threadId);
275f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        if ( threadInfo )
276f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            return threadInfo;
277f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
278f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        // failed registering thread, because all slots are occupied
279f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        // grow the data and try again
280f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        grow();
281f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
282f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        data = mData;
283f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    }
284f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
285f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // should never reach here
286f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    _DBGUTILS_PLAIN_ASSERT(false);
287f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    return 0;
288f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
289f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
290f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
291f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline void Debug::addOffsetForCurrentThread(const int offset)
292f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
293f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if ( offset == 0 )
294f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        return;
295f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
296f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    ThreadInfo * const threadInfo = findCurrentThreadInfo();
297f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    _DBGUTILS_PLAIN_ASSERT(threadInfo);
298f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
299f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    threadInfo->callOffset += offset;
300f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
301f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if ( threadInfo->callOffset == 0 )
302f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {
303f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        // thread call stack has dropped to zero, unregister it
304f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        android_atomic_acquire_store(0, &threadInfo->threadId);
305f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    }
306f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
307f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
308f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
309f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline int Debug::offsetForCurrentThread()
310f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
311f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#ifdef TI_UTILS_FUNCTION_LOGGER_ENABLE
312f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    ThreadInfo * const threadInfo = findCurrentThreadInfo();
313f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    _DBGUTILS_PLAIN_ASSERT(threadInfo);
314f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
315f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    return threadInfo->callOffset;
316f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#else
317f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    return 0;
318f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#endif
319f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
320f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
321f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
322f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline void Debug::increaseOffsetForCurrentThread()
323f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
324f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#ifdef TI_UTILS_FUNCTION_LOGGER_ENABLE
325f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    addOffsetForCurrentThread(1);
326f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#endif
327f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
328f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
329f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
330f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline void Debug::decreaseOffsetForCurrentThread()
331f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
332f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#ifdef TI_UTILS_FUNCTION_LOGGER_ENABLE
333f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    addOffsetForCurrentThread(-1);
334f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#endif
335f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
336f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
337f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
338f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline void Debug::log(const int priority, const char * const format, ...)
339f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
340f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    va_list args;
341f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    va_start(args, format);
342f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    __android_log_vprint(priority, LOG_TAG, format, args);
343f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    va_end(args);
344f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
345f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
346f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
347f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
348f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
349f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline FunctionLogger::FunctionLogger(const char * const file, const int line, const char * const function) :
350f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    mFile(file), mLine(line), mFunction(function), mThreadId(androidGetThreadId()), mExitLine(-1)
351f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
352f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    Debug * const debug = Debug::instance();
353f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    debug->increaseOffsetForCurrentThread();
354f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    android_printLog(ANDROID_LOG_DEBUG, LOG_TAG,
355f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s+ %s:%d %s - ENTER",
356f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            TI_UTILS_DEBUG_TIMESTAMP_VARIABLE
357f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            (int)mThreadId, IndentString<>(debug->offsetForCurrentThread()).string(),
358f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            mFile, mLine, mFunction);
359f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
360f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
361f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
362f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline FunctionLogger::~FunctionLogger()
363f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
364f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    Debug * const debug = Debug::instance();
365f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    android_printLog(ANDROID_LOG_DEBUG, LOG_TAG,
366f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s- %s:%d %s - EXIT",
367f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            TI_UTILS_DEBUG_TIMESTAMP_VARIABLE
368f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            (int)mThreadId, IndentString<>(debug->offsetForCurrentThread()).string(),
369f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            mFile, mExitLine == -1 ? mLine : mExitLine, mFunction);
370f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    debug->decreaseOffsetForCurrentThread();
371f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
372f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
373f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
374f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsinline void FunctionLogger::setExitLine(const int line)
375f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
376f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if ( mExitLine != -1 )
377f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    {
378f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        Debug * const debug = Debug::instance();
379f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        android_printLog(ANDROID_LOG_DEBUG, LOG_TAG,
380f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                TI_UTILS_DEBUG_TIMESTAMP_TOKEN "(%x) %s  %s:%d %s - Double function exit trace detected. Previous: %d",
381f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                TI_UTILS_DEBUG_TIMESTAMP_VARIABLE
382f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                (int)mThreadId, IndentString<>(debug->offsetForCurrentThread()).string(),
383f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                mFile, line, mFunction, mExitLine);
384f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    }
385f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
386f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    mExitLine = line;
387f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
388f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
389f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
390f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
391f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
392f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons} // namespace Ti
393f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
394f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
395f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
396f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
397f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons#endif //DEBUG_UTILS_H
398