Replace GCC specific __thread with C++ 11 keyword thread_local
[platform/core/uifw/dali-core.git] / dali / internal / common / mutex-impl.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
18 // HEADER
19 #include <dali/internal/common/mutex-impl.h>
20
21
22 #ifdef LOCK_BACKTRACE_ENABLED
23 // EXTERNAL INCLUDES
24 #include <cstdlib>
25 #include <execinfo.h>
26
27 // INTERNAL INCLUDES
28 #include <dali/public-api/common/dali-common.h>
29 #include <dali/integration-api/debug.h>
30
31 #endif // LOCK_BACKTRACE_ENABLED
32
33 // INTERNAL INCLUDES
34 #include <dali/integration-api/debug.h>
35
36 namespace Dali
37 {
38 #ifdef LOCK_BACKTRACE_ENABLED
39 extern std::string Demangle( const char* symbol );
40 #endif // LOCK_BACKTRACE_ENABLED
41
42 namespace Internal
43 {
44
45 namespace Mutex
46 {
47
48 namespace
49 {
50 #ifdef LOCK_BACKTRACE_ENABLED
51
52 // Constants
53 const unsigned int MAX_NUM_STACK_FRAMES = 4;
54 const unsigned int MAX_LOCK_SUPPORT = 5;
55
56 struct BackTraceInfo
57 {
58   void * frameArray[ MAX_NUM_STACK_FRAMES ]; ///< Stores the frame array where the lock occurred
59   int size;                                  ///< Number of frames in the frame array (can be less than MAX_NUM_STACK_FRAMES)
60 };
61
62 thread_local BackTraceInfo gBackTraceInfo[ MAX_LOCK_SUPPORT ]; ///< Thread local storage for the backtrace of the locks
63
64 #endif // LOCK_BACKTRACE_ENABLED
65
66 thread_local unsigned int gThreadLockCount = 0; ///< Thread local storage for the backtrace of the locks
67 } // unnamed namespace
68
69 void Lock( pthread_mutex_t* mutex )
70 {
71   ++gThreadLockCount;
72
73 #ifdef LOCK_BACKTRACE_ENABLED
74
75   if( gThreadLockCount <= MAX_LOCK_SUPPORT )
76   {
77     // Store the frame array for this lock
78     int backTraceIndex = gThreadLockCount - 1;
79     gBackTraceInfo[ backTraceIndex ].size = backtrace( gBackTraceInfo[ backTraceIndex ].frameArray, MAX_NUM_STACK_FRAMES );
80   }
81   else
82   {
83     DALI_LOG_ERROR( "Reached Maximum lock backtrace support. Previous Locks:\n" );
84   }
85
86   // If we've got more than one lock, then show a warning with a backtrace for all locks that we currently hold
87   if( gThreadLockCount > 1 )
88   {
89     for( unsigned int i = 0; ( i < gThreadLockCount ) && ( i < MAX_LOCK_SUPPORT ); ++i )
90     {
91       DALI_LOG_WARNING( "[Lock %d]\n", i+1 );
92       char** symbols = backtrace_symbols( gBackTraceInfo[ i ].frameArray, gBackTraceInfo[ i ].size );
93       for( int j = 1; j < gBackTraceInfo[ i ].size; ++j )
94       {
95         std::string demangled_symbol = Demangle( symbols[ j ] );
96         DALI_LOG_WARNING( "  [%02d] %s\n", j, demangled_symbol.c_str() );
97       }
98       free(symbols);
99     }
100     DALI_LOG_WARNING( "====================================\n" );
101   }
102
103 #else
104
105   // TODO: Uncomment when locks held per thread at any given time are 1
106   //DALI_ASSERT_DEBUG( gThreadLockCount == 1 );
107
108 #endif // LOCK_BACKTRACE_ENABLED
109
110   if( pthread_mutex_lock( mutex ) )
111   {
112     DALI_LOG_ERROR( "Error calling pthread_mutex_lock\n" );
113   }
114 }
115
116 void Unlock( pthread_mutex_t* mutex )
117 {
118   if( pthread_mutex_unlock( mutex ) )
119   {
120     DALI_LOG_ERROR( "Error calling pthread_mutex_unlock\n" );
121   }
122   --gThreadLockCount;
123 }
124
125 } // namespace Mutex
126
127 } // namespace Internal
128
129 } // namespace Dali