2 This file is a part of libcds - Concurrent Data Structures library
4 (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
6 Source code repo: http://github.com/khizmax/libcds/
7 Download: http://sourceforge.net/projects/libcds/files/
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice, this
13 list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 this list of conditions and the following disclaimer in the documentation
17 and/or other materials provided with the distribution.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <cds/details/defs.h>
33 #if CDS_OS_TYPE == CDS_OS_WIN32 || CDS_OS_TYPE == CDS_OS_WIN64 || CDS_OS_TYPE == CDS_OS_MINGW
35 #include <cds/os/thread.h>
37 // Visual leak detector (see http://vld.codeplex.com/)
38 #if defined(CDS_USE_VLD) && CDS_COMPILER == CDS_COMPILER_MSVC
44 static cds::OS::ThreadId s_MainThreadId = 0;
45 static HINSTANCE s_DllInstance = nullptr;
47 #if _WIN32_WINNT < 0x0601
48 // For Windows below Windows 7
50 #include <cds/os/topology.h>
51 #include <cds/algo/bitop.h>
53 static unsigned int s_nProcessorCount = 1;
54 static unsigned int s_nProcessorGroupCount = 1;
56 static inline void* get_proc_addr( char const* module, char const* func )
58 HMODULE h = GetModuleHandle( module );
61 return GetProcAddress( h, func );
64 // Array of processor - cell relationship
65 // Array size is s_nProcessorCount
66 // s_arrProcessorCellRelationship[i] is the cell (the processor group) number for i-th processor
67 // static unsigned int * s_arrProcessorCellRelationship = nullptr;
69 static void discover_topology()
71 // From MSDN: http://msdn.microsoft.com/en-us/library/ms683194%28v=VS.85%29.aspx
73 typedef BOOL (WINAPI *LPFN_GLPI)( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
77 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = nullptr;
78 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = nullptr;
79 DWORD returnLength = 0;
80 DWORD logicalProcessorCount = 0;
81 DWORD numaNodeCount = 0;
82 DWORD processorCoreCount = 0;
83 DWORD processorPackageCount = 0;
86 s_nProcessorCount = 1;
87 s_nProcessorGroupCount = 1;
89 glpi = (LPFN_GLPI) get_proc_addr( "kernel32", "GetLogicalProcessorInformation" );
90 if ( glpi == nullptr ) {
96 DWORD rc = glpi(buffer, &returnLength);
99 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
103 buffer = reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION>( ::malloc( returnLength ));
105 if ( buffer == nullptr ) {
112 // _tprintf(TEXT("\nError %d\n"), GetLastError());
122 while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength)
124 switch (ptr->Relationship)
126 case RelationNumaNode:
127 // Non-NUMA systems report a single record of this type.
131 case RelationProcessorCore:
132 processorCoreCount++;
134 // A hyperthreaded core supplies more than one logical processor.
135 logicalProcessorCount += cds::bitop::SBC( ptr->ProcessorMask );
141 case RelationProcessorPackage:
142 // Logical processors share a physical package.
143 processorPackageCount++;
147 // Unsupported LOGICAL_PROCESSOR_RELATIONSHIP value
150 byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
154 s_nProcessorCount = logicalProcessorCount;
155 s_nProcessorGroupCount = numaNodeCount;
157 // Build relationship processor -> cell
159 s_arrProcessorCellRelationship = new unsigned int[s_nProcessorCount];
160 memset( s_arrProcessorCellRelationship, 0, s_nProcessorCount * sizeof(s_arrProcessorCellRelationship[0]));
163 while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength)
165 switch (ptr->Relationship)
167 case RelationNumaNode:
168 // Non-NUMA systems report a single record of this type.
169 for ( unsigned int i = 0; i < sizeof(ptr->ProcessorMask) * 8; ++i ) {
170 if ( ptr->ProcessorMask & (1 << i)) {
171 assert( i < s_nProcessorCount );
172 assert( ptr->NumaNode.NodeNumber < s_nProcessorGroupCount );
173 if ( i < s_nProcessorCount )
174 s_arrProcessorCellRelationship[i] = ptr->NumaNode.NodeNumber;
179 byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
189 namespace cds { namespace OS { inline namespace Win32 {
190 unsigned int topology::processor_count()
192 return s_nProcessorCount;
194 }}} // namespace cds::OS::Win32
196 #endif // #if _WIN32_WINNT < 0x0601
198 #if _WIN32_WINNT < 0x0600
199 # include <cds/os/win/topology.h>
200 typedef DWORD (WINAPI * fnGetCurrentProcessorNumber)();
201 static fnGetCurrentProcessorNumber s_fnGetCurrentProcessorNumber;
203 static void prepare_current_processor_call()
205 s_fnGetCurrentProcessorNumber = (fnGetCurrentProcessorNumber) get_proc_addr( "kernel32", "GetCurrentProcessorNumber" );
206 if ( s_fnGetCurrentProcessorNumber == nullptr )
207 s_fnGetCurrentProcessorNumber = (fnGetCurrentProcessorNumber) get_proc_addr( "ntdll", "NtGetCurrentProcessorNumber" );
210 namespace cds { namespace OS { inline namespace Win32 {
211 unsigned int topology::current_processor()
213 if ( s_fnGetCurrentProcessorNumber != nullptr )
214 return s_fnGetCurrentProcessorNumber();
217 }}} // namespace cds::OS::Win32
220 extern "C" __declspec(dllexport)
224 LPVOID /*lpvReserved*/
227 switch ( fdwReason ) {
228 case DLL_PROCESS_ATTACH:
229 s_DllInstance = hinstDLL;
230 s_MainThreadId = cds::OS::get_current_thread_id();
231 #if _WIN32_WINNT < 0x0601
234 # if _WIN32_WINNT < 0x0600
235 prepare_current_processor_call();
239 case DLL_PROCESS_DETACH:
241 #if _WIN32_WINNT < 0x0601
242 if ( s_arrProcessorCellRelationship != nullptr ) {
243 delete [] s_arrProcessorCellRelationship;
244 s_arrProcessorCellRelationship = nullptr;
253 #endif // #if CDS_OS_TYPE == CDS_OS_WIN32