Merged branch 'master' of https://github.com/Nemo1369/libcds
[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 // Array of processor - cell relationship
57 // Array size is s_nProcessorCount
58 // s_arrProcessorCellRelationship[i] is the cell (the processor group) number for i-th processor
59 // static unsigned int *   s_arrProcessorCellRelationship = nullptr;
60
61 static void discover_topology()
62 {
63     // From MSDN: http://msdn.microsoft.com/en-us/library/ms683194%28v=VS.85%29.aspx
64
65     typedef BOOL (WINAPI *LPFN_GLPI)( PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
66
67     LPFN_GLPI glpi;
68     bool bDone = false;
69     PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = nullptr;
70     PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = nullptr;
71     DWORD returnLength = 0;
72     DWORD logicalProcessorCount = 0;
73     DWORD numaNodeCount = 0;
74     DWORD processorCoreCount = 0;
75     DWORD processorPackageCount = 0;
76     DWORD byteOffset = 0;
77
78     s_nProcessorCount = 1;
79     s_nProcessorGroupCount = 1;
80
81     glpi = (LPFN_GLPI) GetProcAddress( GetModuleHandle("kernel32"), "GetLogicalProcessorInformation" );
82     if ( glpi == nullptr ) {
83         return;
84     }
85
86     while (!bDone)
87     {
88         DWORD rc = glpi(buffer, &returnLength);
89
90         if (FALSE == rc) {
91             if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
92                 if (buffer)
93                     free(buffer);
94
95                 buffer = reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION>( ::malloc( returnLength ));
96
97                 if ( buffer == nullptr ) {
98                     // allocation failed
99                     return;
100                 }
101             }
102             else {
103                 // System error
104                 // _tprintf(TEXT("\nError %d\n"), GetLastError());
105                 return;
106             }
107         }
108         else
109             bDone = true;
110     }
111
112     ptr = buffer;
113
114     while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength)
115     {
116         switch (ptr->Relationship)
117         {
118         case RelationNumaNode:
119             // Non-NUMA systems report a single record of this type.
120             numaNodeCount++;
121             break;
122
123         case RelationProcessorCore:
124             processorCoreCount++;
125
126             // A hyperthreaded core supplies more than one logical processor.
127             logicalProcessorCount += cds::bitop::SBC( ptr->ProcessorMask );
128             break;
129
130         case RelationCache:
131             break;
132
133         case RelationProcessorPackage:
134             // Logical processors share a physical package.
135             processorPackageCount++;
136             break;
137
138         default:
139             // Unsupported LOGICAL_PROCESSOR_RELATIONSHIP value
140             break;
141         }
142         byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
143         ptr++;
144     }
145
146     s_nProcessorCount = logicalProcessorCount;
147     s_nProcessorGroupCount = numaNodeCount;
148
149     // Build relationship processor -> cell
150     /*
151     s_arrProcessorCellRelationship = new unsigned int[s_nProcessorCount];
152     memset( s_arrProcessorCellRelationship, 0, s_nProcessorCount * sizeof(s_arrProcessorCellRelationship[0]));
153     byteOffset = 0;
154     ptr = buffer;
155     while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength)
156     {
157         switch (ptr->Relationship)
158         {
159         case RelationNumaNode:
160             // Non-NUMA systems report a single record of this type.
161             for ( unsigned int i = 0; i < sizeof(ptr->ProcessorMask) * 8; ++i ) {
162                 if ( ptr->ProcessorMask & (1 << i)) {
163                     assert( i < s_nProcessorCount );
164                     assert( ptr->NumaNode.NodeNumber < s_nProcessorGroupCount );
165                     if ( i < s_nProcessorCount )
166                         s_arrProcessorCellRelationship[i] = ptr->NumaNode.NodeNumber;
167                 }
168             }
169             break;
170         }
171         byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
172         ptr++;
173     }
174     */
175
176     free(buffer);
177
178     return;
179 }
180
181 namespace cds { namespace OS { CDS_CXX11_INLINE_NAMESPACE namespace Win32 {
182     unsigned int    topology::processor_count()
183     {
184         return s_nProcessorCount;
185     }
186 }}} // namespace cds::OS::Win32
187
188 #endif  // #if _WIN32_WINNT < 0x0601
189
190 #if _WIN32_WINNT < 0x0600
191 #   include <cds/os/win/topology.h>
192     typedef DWORD (WINAPI * fnGetCurrentProcessorNumber)();
193     static fnGetCurrentProcessorNumber s_fnGetCurrentProcessorNumber;
194
195     static void prepare_current_processor_call()
196     {
197         s_fnGetCurrentProcessorNumber = (fnGetCurrentProcessorNumber) GetProcAddress( GetModuleHandle("kernel32"), "GetCurrentProcessorNumber" );
198         if ( s_fnGetCurrentProcessorNumber == nullptr )
199             s_fnGetCurrentProcessorNumber = (fnGetCurrentProcessorNumber) GetProcAddress( GetModuleHandle("ntdll"), "NtGetCurrentProcessorNumber" );
200     }
201
202     namespace cds { namespace OS { CDS_CXX11_INLINE_NAMESPACE namespace Win32 {
203         unsigned int topology::current_processor()
204         {
205             if ( s_fnGetCurrentProcessorNumber != nullptr )
206                 return s_fnGetCurrentProcessorNumber();
207             return 0;
208         }
209     }}} // namespace cds::OS::Win32
210 #endif
211
212 extern "C" __declspec(dllexport)
213 BOOL WINAPI DllMain(
214                 HINSTANCE hinstDLL,
215                 DWORD fdwReason,
216                 LPVOID /*lpvReserved*/
217 )
218 {
219     switch ( fdwReason ) {
220         case DLL_PROCESS_ATTACH:
221             s_DllInstance = hinstDLL;
222             s_MainThreadId = cds::OS::get_current_thread_id();
223 #if _WIN32_WINNT < 0x0601
224             discover_topology();
225 #endif
226 #   if _WIN32_WINNT < 0x0600
227             prepare_current_processor_call();
228 #endif
229             break;
230
231         case DLL_PROCESS_DETACH:
232 /*
233 #if _WIN32_WINNT < 0x0601
234             if ( s_arrProcessorCellRelationship != nullptr ) {
235                 delete [] s_arrProcessorCellRelationship;
236                 s_arrProcessorCellRelationship = nullptr;
237             }
238 #endif
239 */
240             break;
241     }
242     return TRUE;
243 }
244
245 #endif  // #if CDS_OS_TYPE == CDS_OS_WIN32
246
247