Removed redundant comment
[libcds.git] / src / dllmain.cpp
1 /*
2     This file is a part of libcds - Concurrent Data Structures library
3
4     (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2017
5
6     Source code repo: http://github.com/khizmax/libcds/
7     Download: http://sourceforge.net/projects/libcds/files/
8
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions are met:
11
12     * Redistributions of source code must retain the above copyright notice, this
13       list of conditions and the following disclaimer.
14
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.
18
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.
29 */
30
31 #include <cds/details/defs.h>
32
33 #if CDS_OS_TYPE == CDS_OS_WIN32 || CDS_OS_TYPE == CDS_OS_WIN64 || CDS_OS_TYPE == CDS_OS_MINGW
34
35 #include <cds/os/thread.h>
36
37 // Visual leak detector (see http://vld.codeplex.com/)
38 #if defined(CDS_USE_VLD) && CDS_COMPILER == CDS_COMPILER_MSVC
39 #   ifdef _DEBUG
40 #       include <vld.h>
41 #   endif
42 #endif
43
44 static cds::OS::ThreadId    s_MainThreadId = 0;
45 static HINSTANCE            s_DllInstance = nullptr;
46
47 #if _WIN32_WINNT < 0x0601
48 // For Windows below Windows 7
49
50 #include <cds/os/topology.h>
51 #include <cds/algo/bitop.h>
52
53 static unsigned int     s_nProcessorCount = 1;
54 static unsigned int     s_nProcessorGroupCount = 1;
55
56 static inline void* get_proc_addr( char const* module, char const* func )
57 {
58     HMODULE h = GetModuleHandle( module );
59     if ( !h )
60         return nullptr;
61     return GetProcAddress( h, func );
62 }
63
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;
68
69 static void discover_topology()
70 {
71     // From MSDN: http://msdn.microsoft.com/en-us/library/ms683194%28v=VS.85%29.aspx
72
73     typedef BOOL (WINAPI *LPFN_GLPI)( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
74
75     LPFN_GLPI glpi;
76     bool bDone = false;
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;
84     DWORD byteOffset = 0;
85
86     s_nProcessorCount = 1;
87     s_nProcessorGroupCount = 1;
88
89     glpi = (LPFN_GLPI) get_proc_addr( "kernel32", "GetLogicalProcessorInformation" );
90     if ( glpi == nullptr ) {
91         return;
92     }
93
94     while (!bDone)
95     {
96         DWORD rc = glpi(buffer, &returnLength);
97
98         if (FALSE == rc) {
99             if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
100                 if (buffer)
101                     free(buffer);
102
103                 buffer = reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION>( ::malloc( returnLength ));
104
105                 if ( buffer == nullptr ) {
106                     // allocation failed
107                     return;
108                 }
109             }
110             else {
111                 // System error
112                 // _tprintf(TEXT("\nError %d\n"), GetLastError());
113                 return;
114             }
115         }
116         else
117             bDone = true;
118     }
119
120     ptr = buffer;
121
122     while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength)
123     {
124         switch (ptr->Relationship)
125         {
126         case RelationNumaNode:
127             // Non-NUMA systems report a single record of this type.
128             numaNodeCount++;
129             break;
130
131         case RelationProcessorCore:
132             processorCoreCount++;
133
134             // A hyperthreaded core supplies more than one logical processor.
135             logicalProcessorCount += cds::bitop::SBC( ptr->ProcessorMask );
136             break;
137
138         case RelationCache:
139             break;
140
141         case RelationProcessorPackage:
142             // Logical processors share a physical package.
143             processorPackageCount++;
144             break;
145
146         default:
147             // Unsupported LOGICAL_PROCESSOR_RELATIONSHIP value
148             break;
149         }
150         byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
151         ptr++;
152     }
153
154     s_nProcessorCount = logicalProcessorCount;
155     s_nProcessorGroupCount = numaNodeCount;
156
157     // Build relationship processor -> cell
158     /*
159     s_arrProcessorCellRelationship = new unsigned int[s_nProcessorCount];
160     memset( s_arrProcessorCellRelationship, 0, s_nProcessorCount * sizeof(s_arrProcessorCellRelationship[0]));
161     byteOffset = 0;
162     ptr = buffer;
163     while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength)
164     {
165         switch (ptr->Relationship)
166         {
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;
175                 }
176             }
177             break;
178         }
179         byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
180         ptr++;
181     }
182     */
183
184     free(buffer);
185
186     return;
187 }
188
189 namespace cds { namespace OS { CDS_CXX11_INLINE_NAMESPACE namespace Win32 {
190     unsigned int    topology::processor_count()
191     {
192         return s_nProcessorCount;
193     }
194 }}} // namespace cds::OS::Win32
195
196 #endif  // #if _WIN32_WINNT < 0x0601
197
198 #if _WIN32_WINNT < 0x0600
199 #   include <cds/os/win/topology.h>
200     typedef DWORD (WINAPI * fnGetCurrentProcessorNumber)();
201     static fnGetCurrentProcessorNumber s_fnGetCurrentProcessorNumber;
202
203     static void prepare_current_processor_call()
204     {
205         s_fnGetCurrentProcessorNumber = (fnGetCurrentProcessorNumber) get_proc_addr( "kernel32", "GetCurrentProcessorNumber" );
206         if ( s_fnGetCurrentProcessorNumber == nullptr )
207             s_fnGetCurrentProcessorNumber = (fnGetCurrentProcessorNumber) get_proc_addr( "ntdll", "NtGetCurrentProcessorNumber" );
208     }
209
210     namespace cds { namespace OS { CDS_CXX11_INLINE_NAMESPACE namespace Win32 {
211         unsigned int topology::current_processor()
212         {
213             if ( s_fnGetCurrentProcessorNumber != nullptr )
214                 return s_fnGetCurrentProcessorNumber();
215             return 0;
216         }
217     }}} // namespace cds::OS::Win32
218 #endif
219
220 extern "C" __declspec(dllexport)
221 BOOL WINAPI DllMain(
222                 HINSTANCE hinstDLL,
223                 DWORD fdwReason,
224                 LPVOID /*lpvReserved*/
225 )
226 {
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
232             discover_topology();
233 #endif
234 #   if _WIN32_WINNT < 0x0600
235             prepare_current_processor_call();
236 #endif
237             break;
238
239         case DLL_PROCESS_DETACH:
240 /*
241 #if _WIN32_WINNT < 0x0601
242             if ( s_arrProcessorCellRelationship != nullptr ) {
243                 delete [] s_arrProcessorCellRelationship;
244                 s_arrProcessorCellRelationship = nullptr;
245             }
246 #endif
247 */
248             break;
249     }
250     return TRUE;
251 }
252
253 #endif  // #if CDS_OS_TYPE == CDS_OS_WIN32
254
255