1 /*
2     Copyright (c) 2005-2021 Intel Corporation
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 // Source file for miscellaneous entities that are infrequently referenced by
18 // an executing program.
19 
20 #include "oneapi/tbb/detail/_exception.h"
21 #include "oneapi/tbb/detail/_machine.h"
22 
23 #include "oneapi/tbb/version.h"
24 
25 #include "misc.h"
26 #include "governor.h"
27 #include "assert_impl.h" // Out-of-line TBB assertion handling routines are instantiated here.
28 #include "concurrent_monitor_mutex.h"
29 
30 #include <cstdio>
31 #include <cstdlib>
32 #include <stdexcept>
33 #include <cstring>
34 #include <cstdarg>
35 
36 #if _WIN32||_WIN64
37 #include <windows.h>
38 #endif
39 
40 #if !_WIN32
41 #include <unistd.h> // sysconf(_SC_PAGESIZE)
42 #endif
43 
44 namespace tbb {
45 namespace detail {
46 namespace r1 {
47 
48 //------------------------------------------------------------------------
49 // governor data
50 //------------------------------------------------------------------------
51 cpu_features_type governor::cpu_features;
52 
53 //------------------------------------------------------------------------
54 // concurrent_monitor_mutex data
55 //------------------------------------------------------------------------
56 #if !__TBB_USE_FUTEX
57 std::mutex concurrent_monitor_mutex::my_init_mutex;
58 #endif
59 
60 
DefaultSystemPageSize()61 size_t DefaultSystemPageSize() {
62 #if _WIN32
63     SYSTEM_INFO si;
64     GetSystemInfo(&si);
65     return si.dwPageSize;
66 #else
67     return sysconf(_SC_PAGESIZE);
68 #endif
69 }
70 
71 /** The leading "\0" is here so that applying "strings" to the binary delivers a clean result. */
72 static const char VersionString[] = "\0" TBB_VERSION_STRINGS;
73 
74 static bool PrintVersionFlag = false;
75 
PrintVersion()76 void PrintVersion() {
77     PrintVersionFlag = true;
78     std::fputs(VersionString+1,stderr);
79 }
80 
PrintExtraVersionInfo(const char * category,const char * format,...)81 void PrintExtraVersionInfo( const char* category, const char* format, ... ) {
82     if( PrintVersionFlag ) {
83         char str[1024]; std::memset(str, 0, 1024);
84         va_list args; va_start(args, format);
85         // Note: correct vsnprintf definition obtained from tbb_assert_impl.h
86         std::vsnprintf( str, 1024-1, format, args);
87         va_end(args);
88         std::fprintf(stderr, "oneTBB: %s\t%s\n", category, str );
89     }
90 }
91 
92 //! check for transaction support.
93 #if _MSC_VER
94 #include <intrin.h> // for __cpuid
95 #endif
96 
97 #if __TBB_x86_32 || __TBB_x86_64
check_cpuid(int leaf,int sub_leaf,int registers[4])98 void check_cpuid(int leaf, int sub_leaf, int registers[4]) {
99 #if _MSC_VER
100     __cpuidex(registers, leaf, sub_leaf);
101 #else
102     int reg_eax = 0;
103     int reg_ebx = 0;
104     int reg_ecx = 0;
105     int reg_edx = 0;
106 #if __TBB_x86_32 && __PIC__
107     // On 32-bit systems with position-independent code GCC fails to work around the stuff in EBX
108     // register. We help it using backup and restore.
109     __asm__("mov %%ebx, %%esi\n\t"
110             "cpuid\n\t"
111             "xchg %%ebx, %%esi"
112             : "=a"(reg_eax), "=S"(reg_ebx), "=c"(reg_ecx), "=d"(reg_edx)
113             : "0"(leaf), "2"(sub_leaf) // read value from eax and ecx
114     );
115 #else
116     __asm__("cpuid"
117             : "=a"(reg_eax), "=b"(reg_ebx), "=c"(reg_ecx), "=d"(reg_edx)
118             : "0"(leaf), "2"(sub_leaf) // read value from eax and ecx
119     );
120 #endif
121     registers[0] = reg_eax;
122     registers[1] = reg_ebx;
123     registers[2] = reg_ecx;
124     registers[3] = reg_edx;
125 #endif
126 }
127 #endif
128 
detect_cpu_features(cpu_features_type & cpu_features)129 void detect_cpu_features(cpu_features_type& cpu_features) {
130     suppress_unused_warning(cpu_features);
131 #if __TBB_x86_32 || __TBB_x86_64
132     const int rtm_ebx_mask = 1 << 11;
133     const int waitpkg_ecx_mask = 1 << 5;
134     int registers[4] = {0};
135 
136     // Check RTM and WAITPKG
137     check_cpuid(7, 0, registers);
138     cpu_features.rtm_enabled = (registers[1] & rtm_ebx_mask) != 0;
139     cpu_features.waitpkg_enabled = (registers[2] & waitpkg_ecx_mask) != 0;
140 #endif /* (__TBB_x86_32 || __TBB_x86_64) */
141 }
142 
143 } // namespace r1
144 } // namespace detail
145 } // namespace tbb
146