1 /*============================================================================
2   KWSys - Kitware System Library
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4 
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7 
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 
13 #if defined(_WIN32)
14 # define NOMINMAX // use our min,max
15 # if !defined(_WIN32_WINNT) && !(defined(_MSC_VER) && _MSC_VER < 1300)
16 #  define _WIN32_WINNT 0x0501
17 # endif
18 # include <winsock.h> // WSADATA, include before sys/types.h
19 #endif
20 
21 #if (defined(__GNUC__) || defined(__PGI)) && !defined(_GNU_SOURCE)
22 # define _GNU_SOURCE
23 #endif
24 
25 // TODO:
26 // We need an alternative implementation for many functions in this file
27 // when USE_ASM_INSTRUCTIONS gets defined as 0.
28 //
29 // Consider using these on Win32/Win64 for some of them:
30 //
31 // IsProcessorFeaturePresent
32 // http://msdn.microsoft.com/en-us/library/ms724482(VS.85).aspx
33 //
34 // GetProcessMemoryInfo
35 // http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx
36 
37 #include "kwsysPrivate.h"
38 #include KWSYS_HEADER(stl/string)
39 #include KWSYS_HEADER(stl/vector)
40 #include KWSYS_HEADER(ios/iosfwd)
41 #include KWSYS_HEADER(SystemInformation.hxx)
42 #include KWSYS_HEADER(Process.h)
43 #include KWSYS_HEADER(ios/iostream)
44 #include KWSYS_HEADER(ios/sstream)
45 #include KWSYS_HEADER(ios/fstream)
46 
47 // Work-around CMake dependency scanning limitation.  This must
48 // duplicate the above list of headers.
49 #if 0
50 # include "SystemInformation.hxx.in"
51 # include "Process.h.in"
52 # include "Configure.hxx.in"
53 # include "kwsys_stl.hxx.in"
54 # include "kwsys_stl_vector.in"
55 # include "kwsys_stl_iosfwd.in"
56 # include "kwsys_ios_sstream.h.in"
57 # include "kwsys_ios_iostream.h.in"
58 # include "kwsys_ios_fstream.h.in"
59 #endif
60 
61 #if defined(_WIN32)
62 # include <windows.h>
63 # if defined(_MSC_VER) && _MSC_VER >= 1800
64 #  define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
65 # endif
66 # include <errno.h>
67 # if defined(KWSYS_SYS_HAS_PSAPI)
68 #  include <psapi.h>
69 # endif
70 # if !defined(siginfo_t)
71 typedef int siginfo_t;
72 # endif
73 #else
74 # include <sys/types.h>
75 # include <sys/time.h>
76 # include <sys/utsname.h> // int uname(struct utsname *buf);
77 # include <sys/resource.h> // getrlimit
78 # include <unistd.h>
79 # include <signal.h>
80 # include <fcntl.h>
81 # include <errno.h> // extern int errno;
82 #endif
83 
84 #ifdef __FreeBSD__
85 # include <sys/sysctl.h>
86 # include <fenv.h>
87 # include <sys/socket.h>
88 # include <netdb.h>
89 # include <netinet/in.h>
90 # if defined(KWSYS_SYS_HAS_IFADDRS_H)
91 #  include <ifaddrs.h>
92 #  define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
93 # endif
94 #endif
95 
96 #if defined(__OpenBSD__) || defined(__NetBSD__)
97 # include <sys/param.h>
98 # include <sys/sysctl.h>
99 #endif
100 
101 #if defined(KWSYS_SYS_HAS_MACHINE_CPU_H)
102 # include <machine/cpu.h>
103 #endif
104 
105 #if defined(__DragonFly__)
106 # include <sys/sysctl.h>
107 #endif
108 
109 #ifdef __APPLE__
110 # include <sys/sysctl.h>
111 # include <mach/vm_statistics.h>
112 # include <mach/host_info.h>
113 # include <mach/mach.h>
114 # include <mach/mach_types.h>
115 # include <fenv.h>
116 # include <sys/socket.h>
117 # include <netdb.h>
118 # include <netinet/in.h>
119 # if defined(KWSYS_SYS_HAS_IFADDRS_H)
120 #  include <ifaddrs.h>
121 #  define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
122 # endif
123 # if !(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__-0 >= 1050)
124 #  undef KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE
125 # endif
126 #endif
127 
128 #ifdef __linux
129 # include <fenv.h>
130 # include <sys/socket.h>
131 # include <netdb.h>
132 # include <netinet/in.h>
133 # if defined(KWSYS_SYS_HAS_IFADDRS_H)
134 #  include <ifaddrs.h>
135 #  if !defined(__LSB_VERSION__) /* LSB has no getifaddrs */
136 #   define KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN
137 #  endif
138 # endif
139 # if defined(KWSYS_CXX_HAS_RLIMIT64)
140 typedef struct rlimit64 ResourceLimitType;
141 #  define GetResourceLimit getrlimit64
142 # else
143 typedef struct rlimit ResourceLimitType;
144 #  define GetResourceLimit getrlimit
145 # endif
146 #elif defined( __hpux )
147 # include <sys/param.h>
148 # include <sys/pstat.h>
149 # if defined(KWSYS_SYS_HAS_MPCTL_H)
150 #  include <sys/mpctl.h>
151 # endif
152 #endif
153 
154 #ifdef __HAIKU__
155 # include <OS.h>
156 #endif
157 
158 #if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
159 # include <execinfo.h>
160 # if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
161 #  include <cxxabi.h>
162 # endif
163 # if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
164 #  include <dlfcn.h>
165 # endif
166 #else
167 # undef KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE
168 # undef KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP
169 #endif
170 
171 #include <memory.h>
172 #include <stdlib.h>
173 #include <stdio.h>
174 #include <string.h>
175 #include <ctype.h> // int isdigit(int c);
176 
177 #if defined(KWSYS_USE_LONG_LONG)
178 # if defined(KWSYS_IOS_HAS_OSTREAM_LONG_LONG)
179 #  define iostreamLongLong(x) (x)
180 # else
181 #  define iostreamLongLong(x) ((long)x)
182 # endif
183 #elif defined(KWSYS_USE___INT64)
184 # if defined(KWSYS_IOS_HAS_OSTREAM___INT64)
185 #  define iostreamLongLong(x) (x)
186 # else
187 #  define iostreamLongLong(x) ((long)x)
188 # endif
189 #else
190 # error "No Long Long"
191 #endif
192 
193 #if defined(KWSYS_CXX_HAS_ATOLL)
194 # define atoLongLong atoll
195 #else
196 # if defined(KWSYS_CXX_HAS__ATOI64)
197 #  define atoLongLong _atoi64
198 # elif defined(KWSYS_CXX_HAS_ATOL)
199 #  define atoLongLong atol
200 # else
201 #  define atoLongLong atoi
202 # endif
203 #endif
204 
205 #if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_WIN64)
206 #define USE_ASM_INSTRUCTIONS 1
207 #else
208 #define USE_ASM_INSTRUCTIONS 0
209 #endif
210 
211 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
212 #include <intrin.h>
213 #define USE_CPUID_INTRINSICS 1
214 #else
215 #define USE_CPUID_INTRINSICS 0
216 #endif
217 
218 #if USE_ASM_INSTRUCTIONS || USE_CPUID_INTRINSICS || defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
219 # define USE_CPUID 1
220 #else
221 # define USE_CPUID 0
222 #endif
223 
224 #if USE_CPUID
225 
226 #define CPUID_AWARE_COMPILER
227 
228 /**
229  * call CPUID instruction
230  *
231  * Will return false if the instruction failed.
232  */
call_cpuid(int select,int result[4])233 static bool call_cpuid(int select, int result[4])
234 {
235 #if USE_CPUID_INTRINSICS
236   __cpuid(result, select);
237   return true;
238 #else
239   int tmp[4];
240 #if defined(_MSC_VER)
241   // Use SEH to determine CPUID presence
242   __try {
243     _asm {
244 #ifdef CPUID_AWARE_COMPILER
245       ; we must push/pop the registers <<CPUID>> writes to, as the
246       ; optimiser does not know about <<CPUID>>, and so does not expect
247       ; these registers to change.
248       push eax
249       push ebx
250       push ecx
251       push edx
252 #endif
253       ; <<CPUID>>
254       mov eax, select
255 #ifdef CPUID_AWARE_COMPILER
256       cpuid
257 #else
258       _asm _emit 0x0f
259       _asm _emit 0xa2
260 #endif
261       mov tmp[0 * TYPE int], eax
262       mov tmp[1 * TYPE int], ebx
263       mov tmp[2 * TYPE int], ecx
264       mov tmp[3 * TYPE int], edx
265 
266 #ifdef CPUID_AWARE_COMPILER
267       pop edx
268       pop ecx
269       pop ebx
270       pop eax
271 #endif
272       }
273     }
274   __except(1)
275     {
276     return false;
277     }
278 
279     memcpy(result, tmp, sizeof(tmp));
280 #elif defined(KWSYS_CXX_HAS_BORLAND_ASM_CPUID)
281   unsigned int a, b, c, d;
282   __asm {
283     mov EAX, select;
284     cpuid
285     mov a, EAX;
286     mov b, EBX;
287     mov c, ECX;
288     mov d, EDX;
289   }
290 
291   result[0] = a;
292   result[1] = b;
293   result[2] = c;
294   result[3] = d;
295 #endif
296 
297   // The cpuid instruction succeeded.
298   return true;
299 #endif
300 }
301 #endif
302 
303 
304 namespace KWSYS_NAMESPACE
305 {
306 template<typename T>
min(T a,T b)307 T min(T a, T b){ return a<b ? a : b; }
308 
309 extern "C" { typedef void (*SigAction)(int,siginfo_t*,void*); }
310 
311 //  Define SystemInformationImplementation class
312 typedef  void (*DELAY_FUNC)(unsigned int uiMS);
313 
314 class SystemInformationImplementation
315 {
316 public:
317   typedef SystemInformation::LongLong LongLong;
318   SystemInformationImplementation ();
319   ~SystemInformationImplementation ();
320 
321   const char * GetVendorString();
322   const char * GetVendorID();
323   kwsys_stl::string GetTypeID();
324   kwsys_stl::string GetFamilyID();
325   kwsys_stl::string GetModelID();
326   kwsys_stl::string GetModelName();
327   kwsys_stl::string GetSteppingCode();
328   const char * GetExtendedProcessorName();
329   const char * GetProcessorSerialNumber();
330   int GetProcessorCacheSize();
331   unsigned int GetLogicalProcessorsPerPhysical();
332   float GetProcessorClockFrequency();
333   int GetProcessorAPICID();
334   int GetProcessorCacheXSize(long int);
335   bool DoesCPUSupportFeature(long int);
336 
337   const char * GetOSName();
338   const char * GetHostname();
339   int GetFullyQualifiedDomainName(kwsys_stl::string &fqdn);
340   const char * GetOSRelease();
341   const char * GetOSVersion();
342   const char * GetOSPlatform();
343 
344   bool Is64Bits();
345 
346   unsigned int GetNumberOfLogicalCPU(); // per physical cpu
347   unsigned int GetNumberOfPhysicalCPU();
348 
349   bool DoesCPUSupportCPUID();
350 
351   // Retrieve memory information in megabyte.
352   size_t GetTotalVirtualMemory();
353   size_t GetAvailableVirtualMemory();
354   size_t GetTotalPhysicalMemory();
355   size_t GetAvailablePhysicalMemory();
356 
357   LongLong GetProcessId();
358 
359   // Retrieve memory information in kib
360   LongLong GetHostMemoryTotal();
361   LongLong GetHostMemoryAvailable(const char *envVarName);
362   LongLong GetHostMemoryUsed();
363 
364   LongLong GetProcMemoryAvailable(
365         const char *hostLimitEnvVarName,
366         const char *procLimitEnvVarName);
367   LongLong GetProcMemoryUsed();
368 
369   // enable/disable stack trace signal handler.
370   static
371   void SetStackTraceOnError(int enable);
372 
373   // get current stack
374   static
375   kwsys_stl::string GetProgramStack(int firstFrame, int wholePath);
376 
377   /** Run the different checks */
378   void RunCPUCheck();
379   void RunOSCheck();
380   void RunMemoryCheck();
381 
382 public:
383   typedef struct tagID
384     {
385     int Type;
386     int Family;
387     int Model;
388     int Revision;
389     int ExtendedFamily;
390     int ExtendedModel;
391     kwsys_stl::string ProcessorName;
392     kwsys_stl::string Vendor;
393     kwsys_stl::string SerialNumber;
394     kwsys_stl::string ModelName;
395     } ID;
396 
397   typedef struct tagCPUPowerManagement
398     {
399     bool HasVoltageID;
400     bool HasFrequencyID;
401     bool HasTempSenseDiode;
402     } CPUPowerManagement;
403 
404   typedef struct tagCPUExtendedFeatures
405     {
406     bool Has3DNow;
407     bool Has3DNowPlus;
408     bool SupportsMP;
409     bool HasMMXPlus;
410     bool HasSSEMMX;
411     bool SupportsHyperthreading;
412     unsigned int LogicalProcessorsPerPhysical;
413     int APIC_ID;
414     CPUPowerManagement PowerManagement;
415     } CPUExtendedFeatures;
416 
417   typedef struct CPUtagFeatures
418     {
419     bool HasFPU;
420     bool HasTSC;
421     bool HasMMX;
422     bool HasSSE;
423     bool HasSSEFP;
424     bool HasSSE2;
425     bool HasIA64;
426     bool HasAPIC;
427     bool HasCMOV;
428     bool HasMTRR;
429     bool HasACPI;
430     bool HasSerial;
431     bool HasThermal;
432     int CPUSpeed;
433     int L1CacheSize;
434     int L2CacheSize;
435     int L3CacheSize;
436     CPUExtendedFeatures ExtendedFeatures;
437     } CPUFeatures;
438 
439   enum Manufacturer
440     {
441     AMD, Intel, NSC, UMC, Cyrix, NexGen, IDT, Rise, Transmeta, Sun, IBM,
442     Motorola, HP, UnknownManufacturer
443     };
444 
445 protected:
446   // Functions.
447   bool RetrieveCPUFeatures();
448   bool RetrieveCPUIdentity();
449   bool RetrieveCPUCacheDetails();
450   bool RetrieveClassicalCPUCacheDetails();
451   bool RetrieveCPUClockSpeed();
452   bool RetrieveClassicalCPUClockSpeed();
453   bool RetrieveCPUExtendedLevelSupport(int);
454   bool RetrieveExtendedCPUFeatures();
455   bool RetrieveProcessorSerialNumber();
456   bool RetrieveCPUPowerManagement();
457   bool RetrieveClassicalCPUIdentity();
458   bool RetrieveExtendedCPUIdentity();
459 
460   Manufacturer  ChipManufacturer;
461   CPUFeatures   Features;
462   ID            ChipID;
463   float         CPUSpeedInMHz;
464   unsigned int  NumberOfLogicalCPU;
465   unsigned int  NumberOfPhysicalCPU;
466 
467   int CPUCount();
468   unsigned char LogicalCPUPerPhysicalCPU();
469   unsigned char GetAPICId();
470   bool IsHyperThreadingSupported();
471   static LongLong GetCyclesDifference(DELAY_FUNC, unsigned int);
472 
473   // For Linux and Cygwin, /proc/cpuinfo formats are slightly different
474   bool RetreiveInformationFromCpuInfoFile();
475   kwsys_stl::string ExtractValueFromCpuInfoFile(kwsys_stl::string buffer,
476                                           const char* word, size_t init=0);
477 
478   bool QueryLinuxMemory();
479   bool QueryCygwinMemory();
480 
481   static void Delay (unsigned int);
482   static void DelayOverhead (unsigned int);
483 
484   void FindManufacturer(const kwsys_stl::string &family = "");
485 
486   // For Mac
487   bool ParseSysCtl();
488   int CallSwVers(const char *arg, kwsys_stl::string &ver);
489   void TrimNewline(kwsys_stl::string&);
490   kwsys_stl::string ExtractValueFromSysCtl(const char* word);
491   kwsys_stl::string SysCtlBuffer;
492 
493   // For Solaris
494   bool QuerySolarisMemory();
495   bool QuerySolarisProcessor();
496   kwsys_stl::string ParseValueFromKStat(const char* arguments);
497   kwsys_stl::string RunProcess(kwsys_stl::vector<const char*> args);
498 
499   //For Haiku OS
500   bool QueryHaikuInfo();
501 
502   //For QNX
503   bool QueryQNXMemory();
504   bool QueryQNXProcessor();
505 
506   //For OpenBSD, FreeBSD, NetBSD, DragonFly
507   bool QueryBSDMemory();
508   bool QueryBSDProcessor();
509 
510   //For HP-UX
511   bool QueryHPUXMemory();
512   bool QueryHPUXProcessor();
513 
514   //For Microsoft Windows
515   bool QueryWindowsMemory();
516 
517   //For AIX
518   bool QueryAIXMemory();
519 
520   bool QueryProcessorBySysconf();
521   bool QueryProcessor();
522 
523   // Evaluate the memory information.
524   bool QueryMemoryBySysconf();
525   bool QueryMemory();
526   size_t TotalVirtualMemory;
527   size_t AvailableVirtualMemory;
528   size_t TotalPhysicalMemory;
529   size_t AvailablePhysicalMemory;
530 
531   size_t CurrentPositionInFile;
532 
533   // Operating System information
534   bool QueryOSInformation();
535   kwsys_stl::string OSName;
536   kwsys_stl::string Hostname;
537   kwsys_stl::string OSRelease;
538   kwsys_stl::string OSVersion;
539   kwsys_stl::string OSPlatform;
540 };
541 
542 
SystemInformation()543 SystemInformation::SystemInformation()
544 {
545   this->Implementation = new SystemInformationImplementation;
546 }
547 
~SystemInformation()548 SystemInformation::~SystemInformation()
549 {
550   delete this->Implementation;
551 }
552 
GetVendorString()553 const char * SystemInformation::GetVendorString()
554 {
555   return this->Implementation->GetVendorString();
556 }
557 
GetVendorID()558 const char * SystemInformation::GetVendorID()
559 {
560   return this->Implementation->GetVendorID();
561 }
562 
GetTypeID()563 kwsys_stl::string SystemInformation::GetTypeID()
564 {
565   return this->Implementation->GetTypeID();
566 }
567 
GetFamilyID()568 kwsys_stl::string SystemInformation::GetFamilyID()
569 {
570   return this->Implementation->GetFamilyID();
571 }
572 
GetModelID()573 kwsys_stl::string SystemInformation::GetModelID()
574 {
575   return this->Implementation->GetModelID();
576 }
577 
GetModelName()578 kwsys_stl::string SystemInformation::GetModelName()
579 {
580   return this->Implementation->GetModelName();
581 }
582 
GetSteppingCode()583 kwsys_stl::string SystemInformation::GetSteppingCode()
584 {
585   return this->Implementation->GetSteppingCode();
586 }
587 
GetExtendedProcessorName()588 const char * SystemInformation::GetExtendedProcessorName()
589 {
590   return this->Implementation->GetExtendedProcessorName();
591 }
592 
GetProcessorSerialNumber()593 const char * SystemInformation::GetProcessorSerialNumber()
594 {
595   return this->Implementation->GetProcessorSerialNumber();
596 }
597 
GetProcessorCacheSize()598 int SystemInformation::GetProcessorCacheSize()
599 {
600   return this->Implementation->GetProcessorCacheSize();
601 }
602 
GetLogicalProcessorsPerPhysical()603 unsigned int SystemInformation::GetLogicalProcessorsPerPhysical()
604 {
605   return this->Implementation->GetLogicalProcessorsPerPhysical();
606 }
607 
GetProcessorClockFrequency()608 float SystemInformation::GetProcessorClockFrequency()
609 {
610   return this->Implementation->GetProcessorClockFrequency();
611 }
612 
GetProcessorAPICID()613 int SystemInformation::GetProcessorAPICID()
614 {
615   return this->Implementation->GetProcessorAPICID();
616 }
617 
GetProcessorCacheXSize(long int l)618 int SystemInformation::GetProcessorCacheXSize(long int l)
619 {
620   return this->Implementation->GetProcessorCacheXSize(l);
621 }
622 
DoesCPUSupportFeature(long int i)623 bool SystemInformation::DoesCPUSupportFeature(long int i)
624 {
625   return this->Implementation->DoesCPUSupportFeature(i);
626 }
627 
GetCPUDescription()628 kwsys_stl::string SystemInformation::GetCPUDescription()
629 {
630   kwsys_ios::ostringstream oss;
631   oss
632     << this->GetNumberOfPhysicalCPU()
633     << " core ";
634   if (this->GetModelName().empty())
635     {
636     oss
637       << this->GetProcessorClockFrequency()
638       << " MHz "
639       << this->GetVendorString()
640       << " "
641       << this->GetExtendedProcessorName();
642     }
643   else
644     {
645     oss << this->GetModelName();
646     }
647 
648   // remove extra spaces
649   kwsys_stl::string tmp=oss.str();
650   size_t pos;
651   while( (pos=tmp.find("  "))!=kwsys_stl::string::npos)
652     {
653     tmp.replace(pos,2," ");
654     }
655 
656   return tmp;
657 }
658 
GetOSName()659 const char * SystemInformation::GetOSName()
660 {
661   return this->Implementation->GetOSName();
662 }
663 
GetHostname()664 const char * SystemInformation::GetHostname()
665 {
666   return this->Implementation->GetHostname();
667 }
668 
GetFullyQualifiedDomainName()669 kwsys_stl::string SystemInformation::GetFullyQualifiedDomainName()
670 {
671   kwsys_stl::string fqdn;
672   this->Implementation->GetFullyQualifiedDomainName(fqdn);
673   return fqdn;
674 }
675 
GetOSRelease()676 const char * SystemInformation::GetOSRelease()
677 {
678   return this->Implementation->GetOSRelease();
679 }
680 
GetOSVersion()681 const char * SystemInformation::GetOSVersion()
682 {
683   return this->Implementation->GetOSVersion();
684 }
685 
GetOSPlatform()686 const char * SystemInformation::GetOSPlatform()
687 {
688   return this->Implementation->GetOSPlatform();
689 }
690 
GetOSIsWindows()691 int SystemInformation::GetOSIsWindows()
692 {
693 #if defined(_WIN32)
694   return 1;
695 #else
696   return 0;
697 #endif
698 }
699 
GetOSIsLinux()700 int SystemInformation::GetOSIsLinux()
701 {
702 #if defined(__linux)
703   return 1;
704 #else
705   return 0;
706 #endif
707 }
708 
GetOSIsApple()709 int SystemInformation::GetOSIsApple()
710 {
711 #if defined(__APPLE__)
712   return 1;
713 #else
714   return 0;
715 #endif
716 }
717 
GetOSDescription()718 kwsys_stl::string SystemInformation::GetOSDescription()
719 {
720   kwsys_ios::ostringstream oss;
721   oss
722     << this->GetOSName()
723     << " "
724     << this->GetOSRelease()
725     << " "
726     << this->GetOSVersion();
727 
728   return oss.str();
729 }
730 
Is64Bits()731 bool SystemInformation::Is64Bits()
732 {
733   return this->Implementation->Is64Bits();
734 }
735 
GetNumberOfLogicalCPU()736 unsigned int SystemInformation::GetNumberOfLogicalCPU() // per physical cpu
737 {
738   return this->Implementation->GetNumberOfLogicalCPU();
739 }
740 
GetNumberOfPhysicalCPU()741 unsigned int SystemInformation::GetNumberOfPhysicalCPU()
742 {
743   return this->Implementation->GetNumberOfPhysicalCPU();
744 }
745 
DoesCPUSupportCPUID()746 bool SystemInformation::DoesCPUSupportCPUID()
747 {
748   return this->Implementation->DoesCPUSupportCPUID();
749 }
750 
751 // Retrieve memory information in megabyte.
GetTotalVirtualMemory()752 size_t SystemInformation::GetTotalVirtualMemory()
753 {
754   return this->Implementation->GetTotalVirtualMemory();
755 }
756 
GetAvailableVirtualMemory()757 size_t SystemInformation::GetAvailableVirtualMemory()
758 {
759   return this->Implementation->GetAvailableVirtualMemory();
760 }
761 
GetTotalPhysicalMemory()762 size_t SystemInformation::GetTotalPhysicalMemory()
763 {
764   return this->Implementation->GetTotalPhysicalMemory();
765 }
766 
GetAvailablePhysicalMemory()767 size_t SystemInformation::GetAvailablePhysicalMemory()
768 {
769   return this->Implementation->GetAvailablePhysicalMemory();
770 }
771 
GetMemoryDescription(const char * hostLimitEnvVarName,const char * procLimitEnvVarName)772 kwsys_stl::string SystemInformation::GetMemoryDescription(
773       const char *hostLimitEnvVarName,
774       const char *procLimitEnvVarName)
775 {
776   kwsys_ios::ostringstream oss;
777   oss
778     << "Host Total: "
779     << iostreamLongLong(this->GetHostMemoryTotal())
780     << " KiB, Host Available: "
781     << iostreamLongLong(this->GetHostMemoryAvailable(hostLimitEnvVarName))
782     << " KiB, Process Available: "
783     << iostreamLongLong(
784          this->GetProcMemoryAvailable(hostLimitEnvVarName,procLimitEnvVarName))
785     << " KiB";
786   return oss.str();
787 }
788 
789 // host memory info in units of KiB.
GetHostMemoryTotal()790 SystemInformation::LongLong SystemInformation::GetHostMemoryTotal()
791 {
792   return this->Implementation->GetHostMemoryTotal();
793 }
794 
795 SystemInformation::LongLong
GetHostMemoryAvailable(const char * hostLimitEnvVarName)796 SystemInformation::GetHostMemoryAvailable(const char *hostLimitEnvVarName)
797 {
798   return this->Implementation->GetHostMemoryAvailable(hostLimitEnvVarName);
799 }
800 
GetHostMemoryUsed()801 SystemInformation::LongLong SystemInformation::GetHostMemoryUsed()
802 {
803   return this->Implementation->GetHostMemoryUsed();
804 }
805 
806 // process memory info in units of KiB.
807 SystemInformation::LongLong
GetProcMemoryAvailable(const char * hostLimitEnvVarName,const char * procLimitEnvVarName)808 SystemInformation::GetProcMemoryAvailable(
809         const char *hostLimitEnvVarName,
810         const char *procLimitEnvVarName)
811 {
812   return this->Implementation->GetProcMemoryAvailable(
813           hostLimitEnvVarName,
814           procLimitEnvVarName);
815 }
816 
GetProcMemoryUsed()817 SystemInformation::LongLong SystemInformation::GetProcMemoryUsed()
818 {
819   return this->Implementation->GetProcMemoryUsed();
820 }
821 
GetProcessId()822 SystemInformation::LongLong SystemInformation::GetProcessId()
823 {
824   return this->Implementation->GetProcessId();
825 }
826 
SetStackTraceOnError(int enable)827 void SystemInformation::SetStackTraceOnError(int enable)
828 {
829   SystemInformationImplementation::SetStackTraceOnError(enable);
830 }
831 
GetProgramStack(int firstFrame,int wholePath)832 kwsys_stl::string SystemInformation::GetProgramStack(int firstFrame, int wholePath)
833 {
834   return SystemInformationImplementation::GetProgramStack(firstFrame, wholePath);
835 }
836 
837 /** Run the different checks */
RunCPUCheck()838 void SystemInformation::RunCPUCheck()
839 {
840   this->Implementation->RunCPUCheck();
841 }
842 
RunOSCheck()843 void SystemInformation::RunOSCheck()
844 {
845   this->Implementation->RunOSCheck();
846 }
847 
RunMemoryCheck()848 void SystemInformation::RunMemoryCheck()
849 {
850   this->Implementation->RunMemoryCheck();
851 }
852 
853 
854 // --------------------------------------------------------------
855 // SystemInformationImplementation starts here
856 
857 #define STORE_TLBCACHE_INFO(x,y)  x = (x < y) ? y : x
858 #define TLBCACHE_INFO_UNITS      (15)
859 #define CLASSICAL_CPU_FREQ_LOOP    10000000
860 #define RDTSC_INSTRUCTION      _asm _emit 0x0f _asm _emit 0x31
861 
862 #define MMX_FEATURE            0x00000001
863 #define MMX_PLUS_FEATURE       0x00000002
864 #define SSE_FEATURE            0x00000004
865 #define SSE2_FEATURE           0x00000008
866 #define AMD_3DNOW_FEATURE      0x00000010
867 #define AMD_3DNOW_PLUS_FEATURE 0x00000020
868 #define IA64_FEATURE           0x00000040
869 #define MP_CAPABLE             0x00000080
870 #define HYPERTHREAD_FEATURE    0x00000100
871 #define SERIALNUMBER_FEATURE   0x00000200
872 #define APIC_FEATURE           0x00000400
873 #define SSE_FP_FEATURE         0x00000800
874 #define SSE_MMX_FEATURE        0x00001000
875 #define CMOV_FEATURE           0x00002000
876 #define MTRR_FEATURE           0x00004000
877 #define L1CACHE_FEATURE        0x00008000
878 #define L2CACHE_FEATURE        0x00010000
879 #define L3CACHE_FEATURE        0x00020000
880 #define ACPI_FEATURE           0x00040000
881 #define THERMALMONITOR_FEATURE 0x00080000
882 #define TEMPSENSEDIODE_FEATURE 0x00100000
883 #define FREQUENCYID_FEATURE    0x00200000
884 #define VOLTAGEID_FREQUENCY    0x00400000
885 
886 // Status Flag
887 #define HT_NOT_CAPABLE           0
888 #define HT_ENABLED               1
889 #define HT_DISABLED              2
890 #define HT_SUPPORTED_NOT_ENABLED 3
891 #define HT_CANNOT_DETECT         4
892 
893 // EDX[28]  Bit 28 is set if HT is supported
894 #define HT_BIT             0x10000000
895 
896 // EAX[11:8] Bit 8-11 contains family processor ID.
897 #define FAMILY_ID          0x0F00
898 #define PENTIUM4_ID        0x0F00
899 // EAX[23:20] Bit 20-23 contains extended family processor ID
900 #define EXT_FAMILY_ID      0x0F00000
901 // EBX[23:16] Bit 16-23 in ebx contains the number of logical
902 #define NUM_LOGICAL_BITS   0x00FF0000
903 // processors per physical processor when execute cpuid with
904 // eax set to 1
905 // EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
906 #define INITIAL_APIC_ID_BITS  0xFF000000
907 // initial APIC ID for the processor this code is running on.
908 // Default value = 0xff if HT is not supported
909 
910 // Hide implementation details in an anonymous namespace.
911 namespace {
912 // *****************************************************************************
913 #if defined(__linux) || defined(__APPLE__)
LoadLines(FILE * file,kwsys_stl::vector<kwsys_stl::string> & lines)914 int LoadLines(
915       FILE *file,
916       kwsys_stl::vector<kwsys_stl::string> &lines)
917 {
918   // Load each line in the given file into a the vector.
919   int nRead=0;
920   const int bufSize=1024;
921   char buf[bufSize]={'\0'};
922   while (!feof(file) && !ferror(file))
923     {
924     errno=0;
925     if (fgets(buf,bufSize,file) == 0)
926       {
927       if (ferror(file) && (errno==EINTR))
928         {
929         clearerr(file);
930         }
931       continue;
932       }
933     char *pBuf=buf;
934     while(*pBuf)
935       {
936       if (*pBuf=='\n') *pBuf='\0';
937       pBuf+=1;
938       }
939     lines.push_back(buf);
940     ++nRead;
941     }
942   if (ferror(file))
943     {
944     return 0;
945     }
946   return nRead;
947 }
948 
949 # if defined(__linux)
950 // *****************************************************************************
LoadLines(const char * fileName,kwsys_stl::vector<kwsys_stl::string> & lines)951 int LoadLines(
952       const char *fileName,
953       kwsys_stl::vector<kwsys_stl::string> &lines)
954 {
955   FILE *file=fopen(fileName,"r");
956   if (file==0)
957     {
958     return 0;
959     }
960   int nRead=LoadLines(file,lines);
961   fclose(file);
962   return nRead;
963 }
964 # endif
965 
966 // ****************************************************************************
967 template<typename T>
NameValue(kwsys_stl::vector<kwsys_stl::string> & lines,kwsys_stl::string name,T & value)968 int NameValue(
969       kwsys_stl::vector<kwsys_stl::string> &lines,
970       kwsys_stl::string name, T &value)
971 {
972   size_t nLines=lines.size();
973   for (size_t i=0; i<nLines; ++i)
974     {
975     size_t at=lines[i].find(name);
976     if (at==kwsys_stl::string::npos)
977       {
978       continue;
979       }
980     kwsys_ios::istringstream is(lines[i].substr(at+name.size()));
981     is >> value;
982     return 0;
983     }
984   return -1;
985 }
986 #endif
987 
988 #if defined(__linux)
989 // ****************************************************************************
990 template<typename T>
GetFieldsFromFile(const char * fileName,const char ** fieldNames,T * values)991 int GetFieldsFromFile(
992       const char *fileName,
993       const char **fieldNames,
994       T *values)
995 {
996   kwsys_stl::vector<kwsys_stl::string> fields;
997   if (!LoadLines(fileName,fields))
998     {
999     return -1;
1000     }
1001   int i=0;
1002   while (fieldNames[i]!=NULL)
1003     {
1004     int ierr=NameValue(fields,fieldNames[i],values[i]);
1005     if (ierr)
1006       {
1007       return -(i+2);
1008       }
1009     i+=1;
1010     }
1011   return 0;
1012 }
1013 
1014 // ****************************************************************************
1015 template<typename T>
GetFieldFromFile(const char * fileName,const char * fieldName,T & value)1016 int GetFieldFromFile(
1017       const char *fileName,
1018       const char *fieldName,
1019       T &value)
1020 {
1021   const char *fieldNames[2]={fieldName,NULL};
1022   T values[1]={T(0)};
1023   int ierr=GetFieldsFromFile(fileName,fieldNames,values);
1024   if (ierr)
1025     {
1026     return ierr;
1027     }
1028   value=values[0];
1029   return 0;
1030 }
1031 #endif
1032 
1033 // ****************************************************************************
1034 #if defined(__APPLE__)
1035 template<typename T>
GetFieldsFromCommand(const char * command,const char ** fieldNames,T * values)1036 int GetFieldsFromCommand(
1037       const char *command,
1038       const char **fieldNames,
1039       T *values)
1040 {
1041   FILE *file=popen(command,"r");
1042   if (file==0)
1043     {
1044     return -1;
1045     }
1046   kwsys_stl::vector<kwsys_stl::string> fields;
1047   int nl=LoadLines(file,fields);
1048   pclose(file);
1049   if (nl==0)
1050     {
1051     return -1;
1052     }
1053   int i=0;
1054   while (fieldNames[i]!=NULL)
1055     {
1056     int ierr=NameValue(fields,fieldNames[i],values[i]);
1057     if (ierr)
1058       {
1059       return -(i+2);
1060       }
1061     i+=1;
1062     }
1063   return 0;
1064 }
1065 #endif
1066 
1067 // ****************************************************************************
1068 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
StacktraceSignalHandler(int sigNo,siginfo_t * sigInfo,void *)1069 void StacktraceSignalHandler(
1070       int sigNo,
1071       siginfo_t *sigInfo,
1072       void * /*sigContext*/)
1073 {
1074 #if defined(__linux) || defined(__APPLE__)
1075   kwsys_ios::ostringstream oss;
1076   oss
1077      << kwsys_ios::endl
1078      << "=========================================================" << kwsys_ios::endl
1079      << "Process id " << getpid() << " ";
1080   switch (sigNo)
1081     {
1082     case SIGINT:
1083       oss << "Caught SIGINT";
1084       break;
1085 
1086     case SIGTERM:
1087       oss << "Caught SIGTERM";
1088       break;
1089 
1090     case SIGABRT:
1091       oss << "Caught SIGABRT";
1092       break;
1093 
1094     case SIGFPE:
1095       oss
1096         << "Caught SIGFPE at "
1097         << (sigInfo->si_addr==0?"0x":"")
1098         << sigInfo->si_addr
1099         <<  " ";
1100       switch (sigInfo->si_code)
1101         {
1102 # if defined(FPE_INTDIV)
1103         case FPE_INTDIV:
1104           oss << "integer division by zero";
1105           break;
1106 # endif
1107 
1108 # if defined(FPE_INTOVF)
1109         case FPE_INTOVF:
1110           oss << "integer overflow";
1111           break;
1112 # endif
1113 
1114         case FPE_FLTDIV:
1115           oss << "floating point divide by zero";
1116           break;
1117 
1118         case FPE_FLTOVF:
1119           oss << "floating point overflow";
1120           break;
1121 
1122         case FPE_FLTUND:
1123           oss << "floating point underflow";
1124           break;
1125 
1126         case FPE_FLTRES:
1127           oss << "floating point inexact result";
1128           break;
1129 
1130         case FPE_FLTINV:
1131           oss << "floating point invalid operation";
1132           break;
1133 
1134 #if defined(FPE_FLTSUB)
1135         case FPE_FLTSUB:
1136           oss << "floating point subscript out of range";
1137           break;
1138 #endif
1139 
1140         default:
1141           oss << "code " << sigInfo->si_code;
1142           break;
1143         }
1144       break;
1145 
1146     case SIGSEGV:
1147       oss
1148         << "Caught SIGSEGV at "
1149         << (sigInfo->si_addr==0?"0x":"")
1150         << sigInfo->si_addr
1151         <<  " ";
1152       switch (sigInfo->si_code)
1153         {
1154         case SEGV_MAPERR:
1155           oss << "address not mapped to object";
1156           break;
1157 
1158         case SEGV_ACCERR:
1159           oss << "invalid permission for mapped object";
1160           break;
1161 
1162         default:
1163           oss << "code " << sigInfo->si_code;
1164           break;
1165         }
1166       break;
1167 
1168     case SIGBUS:
1169       oss
1170         << "Caught SIGBUS at "
1171         << (sigInfo->si_addr==0?"0x":"")
1172         << sigInfo->si_addr
1173         <<  " ";
1174       switch (sigInfo->si_code)
1175         {
1176         case BUS_ADRALN:
1177           oss << "invalid address alignment";
1178           break;
1179 
1180 # if defined(BUS_ADRERR)
1181         case BUS_ADRERR:
1182           oss << "nonexistent physical address";
1183           break;
1184 # endif
1185 
1186 # if defined(BUS_OBJERR)
1187         case BUS_OBJERR:
1188           oss << "object-specific hardware error";
1189           break;
1190 # endif
1191 
1192 # if defined(BUS_MCEERR_AR)
1193         case BUS_MCEERR_AR:
1194           oss << "Hardware memory error consumed on a machine check; action required.";
1195           break;
1196 # endif
1197 
1198 # if defined(BUS_MCEERR_AO)
1199         case BUS_MCEERR_AO:
1200           oss << "Hardware memory error detected in process but not consumed; action optional.";
1201           break;
1202 # endif
1203 
1204         default:
1205           oss << "code " << sigInfo->si_code;
1206           break;
1207         }
1208       break;
1209 
1210     case SIGILL:
1211       oss
1212         << "Caught SIGILL at "
1213         << (sigInfo->si_addr==0?"0x":"")
1214         << sigInfo->si_addr
1215         <<  " ";
1216       switch (sigInfo->si_code)
1217         {
1218         case ILL_ILLOPC:
1219           oss << "illegal opcode";
1220           break;
1221 
1222 # if defined(ILL_ILLOPN)
1223         case ILL_ILLOPN:
1224           oss << "illegal operand";
1225           break;
1226 # endif
1227 
1228 # if defined(ILL_ILLADR)
1229         case ILL_ILLADR:
1230           oss << "illegal addressing mode.";
1231           break;
1232 # endif
1233 
1234         case ILL_ILLTRP:
1235           oss << "illegal trap";
1236 
1237         case ILL_PRVOPC:
1238           oss << "privileged opcode";
1239           break;
1240 
1241 # if defined(ILL_PRVREG)
1242         case ILL_PRVREG:
1243           oss << "privileged register";
1244           break;
1245 # endif
1246 
1247 # if defined(ILL_COPROC)
1248         case ILL_COPROC:
1249           oss << "co-processor error";
1250           break;
1251 # endif
1252 
1253 # if defined(ILL_BADSTK)
1254         case ILL_BADSTK:
1255           oss << "internal stack error";
1256           break;
1257 # endif
1258 
1259         default:
1260           oss << "code " << sigInfo->si_code;
1261           break;
1262         }
1263       break;
1264 
1265     default:
1266       oss << "Caught " << sigNo << " code " << sigInfo->si_code;
1267       break;
1268     }
1269   oss
1270     << kwsys_ios::endl
1271     << "Program Stack:" << kwsys_ios::endl
1272     << SystemInformationImplementation::GetProgramStack(2,0)
1273     << "=========================================================" << kwsys_ios::endl;
1274   kwsys_ios::cerr << oss.str() << kwsys_ios::endl;
1275 
1276   // restore the previously registered handlers
1277   // and abort
1278   SystemInformationImplementation::SetStackTraceOnError(0);
1279   abort();
1280 #else
1281   // avoid warning C4100
1282   (void)sigNo;
1283   (void)sigInfo;
1284 #endif
1285 }
1286 #endif
1287 
1288 #if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
1289 #define safes(_arg)((_arg)?(_arg):"???")
1290 
1291 // Description:
1292 // A container for symbol properties. Each instance
1293 // must be Initialized.
1294 class SymbolProperties
1295 {
1296 public:
1297   SymbolProperties();
1298 
1299   // Description:
1300   // The SymbolProperties instance must be initialized by
1301   // passing a stack address.
1302   void Initialize(void *address);
1303 
1304   // Description:
1305   // Get the symbol's stack address.
GetAddress() const1306   void *GetAddress() const { return this->Address; }
1307 
1308   // Description:
1309   // If not set paths will be removed. eg, from a binary
1310   // or source file.
SetReportPath(int rp)1311   void SetReportPath(int rp){ this->ReportPath=rp; }
1312 
1313   // Description:
1314   // Set/Get the name of the binary file that the symbol
1315   // is found in.
SetBinary(const char * binary)1316   void SetBinary(const char *binary)
1317     { this->Binary=safes(binary); }
1318 
1319   kwsys_stl::string GetBinary() const;
1320 
1321   // Description:
1322   // Set the name of the function that the symbol is found in.
1323   // If c++ demangling is supported it will be demangled.
SetFunction(const char * function)1324   void SetFunction(const char *function)
1325     { this->Function=this->Demangle(function); }
1326 
GetFunction() const1327   kwsys_stl::string GetFunction() const
1328     { return this->Function; }
1329 
1330   // Description:
1331   // Set/Get the name of the source file where the symbol
1332   // is defined.
SetSourceFile(const char * sourcefile)1333   void SetSourceFile(const char *sourcefile)
1334     { this->SourceFile=safes(sourcefile); }
1335 
GetSourceFile() const1336   kwsys_stl::string GetSourceFile() const
1337     { return this->GetFileName(this->SourceFile); }
1338 
1339   // Description:
1340   // Set/Get the line number where the symbol is defined
SetLineNumber(long linenumber)1341   void SetLineNumber(long linenumber){ this->LineNumber=linenumber; }
GetLineNumber() const1342   long GetLineNumber() const { return this->LineNumber; }
1343 
1344   // Description:
1345   // Set the address where the biinary image is mapped
1346   // into memory.
SetBinaryBaseAddress(void * address)1347   void SetBinaryBaseAddress(void *address)
1348     { this->BinaryBaseAddress=address; }
1349 
1350 private:
GetRealAddress() const1351   void *GetRealAddress() const
1352     { return (void*)((char*)this->Address-(char*)this->BinaryBaseAddress); }
1353 
1354   kwsys_stl::string GetFileName(const kwsys_stl::string &path) const;
1355   kwsys_stl::string Demangle(const char *symbol) const;
1356 
1357 private:
1358   kwsys_stl::string Binary;
1359   void *BinaryBaseAddress;
1360   void *Address;
1361   kwsys_stl::string SourceFile;
1362   kwsys_stl::string Function;
1363   long LineNumber;
1364   int ReportPath;
1365 };
1366 
1367 // --------------------------------------------------------------------------
operator <<(kwsys_ios::ostream & os,const SymbolProperties & sp)1368 kwsys_ios::ostream &operator<<(
1369       kwsys_ios::ostream &os,
1370       const SymbolProperties &sp)
1371 {
1372 #if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
1373   os
1374     << kwsys_ios::hex << sp.GetAddress() << " : "
1375     << sp.GetFunction()
1376     << " [(" << sp.GetBinary() << ") "
1377     << sp.GetSourceFile() << ":"
1378     << kwsys_ios::dec << sp.GetLineNumber() << "]";
1379 #elif defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
1380   void *addr = sp.GetAddress();
1381   char **syminfo = backtrace_symbols(&addr,1);
1382   os << safes(syminfo[0]);
1383   free(syminfo);
1384 #else
1385   (void)os;
1386   (void)sp;
1387 #endif
1388   return os;
1389 }
1390 
1391 // --------------------------------------------------------------------------
SymbolProperties()1392 SymbolProperties::SymbolProperties()
1393 {
1394   // not using an initializer list
1395   // to avoid some PGI compiler warnings
1396   this->SetBinary("???");
1397   this->SetBinaryBaseAddress(NULL);
1398   this->Address = NULL;
1399   this->SetSourceFile("???");
1400   this->SetFunction("???");
1401   this->SetLineNumber(-1);
1402   this->SetReportPath(0);
1403   // avoid PGI compiler warnings
1404   this->GetRealAddress();
1405   this->GetFunction();
1406   this->GetSourceFile();
1407   this->GetLineNumber();
1408 }
1409 
1410 // --------------------------------------------------------------------------
GetFileName(const kwsys_stl::string & path) const1411 kwsys_stl::string SymbolProperties::GetFileName(const kwsys_stl::string &path) const
1412 {
1413   kwsys_stl::string file(path);
1414   if (!this->ReportPath)
1415     {
1416     size_t at = file.rfind("/");
1417     if (at!=kwsys_stl::string::npos)
1418       {
1419       file = file.substr(at+1,kwsys_stl::string::npos);
1420       }
1421     }
1422   return file;
1423 }
1424 
1425 // --------------------------------------------------------------------------
GetBinary() const1426 kwsys_stl::string SymbolProperties::GetBinary() const
1427 {
1428 // only linux has proc fs
1429 #if defined(__linux__)
1430   if (this->Binary=="/proc/self/exe")
1431     {
1432     kwsys_stl::string binary;
1433     char buf[1024]={'\0'};
1434     ssize_t ll=0;
1435     if ((ll=readlink("/proc/self/exe",buf,1024))>0)
1436       {
1437       buf[ll]='\0';
1438       binary=buf;
1439       }
1440     else
1441       {
1442       binary="/proc/self/exe";
1443       }
1444     return this->GetFileName(binary);
1445     }
1446 #endif
1447   return this->GetFileName(this->Binary);
1448 }
1449 
1450 // --------------------------------------------------------------------------
Demangle(const char * symbol) const1451 kwsys_stl::string SymbolProperties::Demangle(const char *symbol) const
1452 {
1453   kwsys_stl::string result = safes(symbol);
1454 #if defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
1455   int status = 0;
1456   size_t bufferLen = 1024;
1457   char *buffer = (char*)malloc(1024);
1458   char *demangledSymbol =
1459     abi::__cxa_demangle(symbol, buffer, &bufferLen, &status);
1460   if (!status)
1461     {
1462     result = demangledSymbol;
1463     }
1464   free(buffer);
1465 #else
1466   (void)symbol;
1467 #endif
1468   return result;
1469 }
1470 
1471 // --------------------------------------------------------------------------
Initialize(void * address)1472 void SymbolProperties::Initialize(void *address)
1473 {
1474   this->Address = address;
1475 #if defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
1476   // first fallback option can demangle c++ functions
1477   Dl_info info;
1478   int ierr=dladdr(this->Address,&info);
1479   if (ierr && info.dli_sname && info.dli_saddr)
1480     {
1481     this->SetBinary(info.dli_fname);
1482     this->SetFunction(info.dli_sname);
1483     }
1484 #else
1485   // second fallback use builtin backtrace_symbols
1486   // to decode the bactrace.
1487 #endif
1488 }
1489 #endif // don't define this class if we're not using it
1490 
1491 } // anonymous namespace
1492 
1493 
SystemInformationImplementation()1494 SystemInformationImplementation::SystemInformationImplementation()
1495 {
1496   this->TotalVirtualMemory = 0;
1497   this->AvailableVirtualMemory = 0;
1498   this->TotalPhysicalMemory = 0;
1499   this->AvailablePhysicalMemory = 0;
1500   this->CurrentPositionInFile = 0;
1501   this->ChipManufacturer = UnknownManufacturer;
1502   memset(&this->Features, 0, sizeof(CPUFeatures));
1503   this->ChipID.Type = 0;
1504   this->ChipID.Family = 0;
1505   this->ChipID.Model = 0;
1506   this->ChipID.Revision = 0;
1507   this->ChipID.ExtendedFamily = 0;
1508   this->ChipID.ExtendedModel = 0;
1509   this->CPUSpeedInMHz = 0;
1510   this->NumberOfLogicalCPU = 0;
1511   this->NumberOfPhysicalCPU = 0;
1512   this->OSName = "";
1513   this->Hostname = "";
1514   this->OSRelease = "";
1515   this->OSVersion = "";
1516   this->OSPlatform = "";
1517 }
1518 
~SystemInformationImplementation()1519 SystemInformationImplementation::~SystemInformationImplementation()
1520 {
1521 }
1522 
RunCPUCheck()1523 void SystemInformationImplementation::RunCPUCheck()
1524 {
1525 #ifdef WIN32
1526   // Check to see if this processor supports CPUID.
1527   bool supportsCPUID = DoesCPUSupportCPUID();
1528 
1529   if (supportsCPUID)
1530     {
1531     // Retrieve the CPU details.
1532     RetrieveCPUIdentity();
1533     this->FindManufacturer();
1534     RetrieveCPUFeatures();
1535     }
1536 
1537   // These two may be called without support for the CPUID instruction.
1538   // (But if the instruction is there, they should be called *after*
1539   // the above call to RetrieveCPUIdentity... that's why the two if
1540   // blocks exist with the same "if (supportsCPUID)" logic...
1541   //
1542   if (!RetrieveCPUClockSpeed())
1543     {
1544     RetrieveClassicalCPUClockSpeed();
1545     }
1546 
1547   if (supportsCPUID)
1548     {
1549     // Retrieve cache information.
1550     if (!RetrieveCPUCacheDetails())
1551       {
1552       RetrieveClassicalCPUCacheDetails();
1553       }
1554 
1555     // Retrieve the extended CPU details.
1556     if (!RetrieveExtendedCPUIdentity())
1557       {
1558       RetrieveClassicalCPUIdentity();
1559       }
1560 
1561     RetrieveExtendedCPUFeatures();
1562     RetrieveCPUPowerManagement();
1563 
1564     // Now attempt to retrieve the serial number (if possible).
1565     RetrieveProcessorSerialNumber();
1566     }
1567 
1568   this->CPUCount();
1569 
1570 #elif defined(__APPLE__)
1571   this->ParseSysCtl();
1572 #elif defined (__SVR4) && defined (__sun)
1573   this->QuerySolarisProcessor();
1574 #elif defined(__HAIKU__)
1575   this->QueryHaikuInfo();
1576 #elif defined(__QNX__)
1577   this->QueryQNXProcessor();
1578 #elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
1579   this->QueryBSDProcessor();
1580 #elif defined(__hpux)
1581   this->QueryHPUXProcessor();
1582 #elif defined(__linux) || defined(__CYGWIN__)
1583   this->RetreiveInformationFromCpuInfoFile();
1584 #else
1585   this->QueryProcessor();
1586 #endif
1587 }
1588 
RunOSCheck()1589 void SystemInformationImplementation::RunOSCheck()
1590 {
1591   this->QueryOSInformation();
1592 }
1593 
RunMemoryCheck()1594 void SystemInformationImplementation::RunMemoryCheck()
1595 {
1596 #if defined(__APPLE__)
1597   this->ParseSysCtl();
1598 #elif defined (__SVR4) && defined (__sun)
1599   this->QuerySolarisMemory();
1600 #elif defined(__HAIKU__)
1601   this->QueryHaikuInfo();
1602 #elif defined(__QNX__)
1603   this->QueryQNXMemory();
1604 #elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
1605   this->QueryBSDMemory();
1606 #elif defined(__CYGWIN__)
1607   this->QueryCygwinMemory();
1608 #elif defined(_WIN32)
1609   this->QueryWindowsMemory();
1610 #elif defined(__hpux)
1611   this->QueryHPUXMemory();
1612 #elif defined(__linux)
1613   this->QueryLinuxMemory();
1614 #elif defined(_AIX)
1615   this->QueryAIXMemory();
1616 #else
1617   this->QueryMemory();
1618 #endif
1619 }
1620 
1621 /** Get the vendor string */
GetVendorString()1622 const char * SystemInformationImplementation::GetVendorString()
1623 {
1624   return this->ChipID.Vendor.c_str();
1625 }
1626 
1627 /** Get the OS Name */
GetOSName()1628 const char * SystemInformationImplementation::GetOSName()
1629 {
1630   return this->OSName.c_str();
1631 }
1632 
1633 /** Get the hostname */
GetHostname()1634 const char* SystemInformationImplementation::GetHostname()
1635 {
1636   if (this->Hostname.empty())
1637     {
1638     this->Hostname="localhost";
1639 #if defined(_WIN32)
1640     WORD wVersionRequested;
1641     WSADATA wsaData;
1642     char name[255];
1643     wVersionRequested = MAKEWORD(2,0);
1644     if ( WSAStartup( wVersionRequested, &wsaData ) == 0 )
1645       {
1646       gethostname(name,sizeof(name));
1647       WSACleanup( );
1648       }
1649     this->Hostname = name;
1650 #else
1651     struct utsname unameInfo;
1652     int errorFlag = uname(&unameInfo);
1653     if(errorFlag == 0)
1654       {
1655       this->Hostname = unameInfo.nodename;
1656       }
1657 #endif
1658     }
1659   return this->Hostname.c_str();
1660 }
1661 
1662 /** Get the FQDN */
GetFullyQualifiedDomainName(kwsys_stl::string & fqdn)1663 int SystemInformationImplementation::GetFullyQualifiedDomainName(
1664       kwsys_stl::string &fqdn)
1665 {
1666   // in the event of absolute failure return localhost.
1667   fqdn="localhost";
1668 
1669 #if defined(_WIN32)
1670   int ierr;
1671   // TODO - a more robust implementation for windows, see comments
1672   // in unix implementation.
1673   WSADATA wsaData;
1674   WORD ver=MAKEWORD(2,0);
1675   ierr=WSAStartup(ver,&wsaData);
1676   if (ierr)
1677     {
1678     return -1;
1679     }
1680 
1681   char base[256]={'\0'};
1682   ierr=gethostname(base,256);
1683   if (ierr)
1684     {
1685     WSACleanup();
1686     return -2;
1687     }
1688   fqdn=base;
1689 
1690   HOSTENT *hent=gethostbyname(base);
1691   if (hent)
1692     {
1693     fqdn=hent->h_name;
1694     }
1695 
1696   WSACleanup();
1697   return 0;
1698 
1699 #elif defined(KWSYS_SYSTEMINFORMATION_IMPLEMENT_FQDN)
1700   // gethostname typical returns an alias for loopback interface
1701   // we want the fully qualified domain name. Because there are
1702   // any number of interfaces on this system we look for the
1703   // first of these that contains the name returned by gethostname
1704   // and is longer. failing that we return gethostname and indicate
1705   // with a failure code. Return of a failure code is not necessarilly
1706   // an indication of an error. for instance gethostname may return
1707   // the fully qualified domain name, or there may not be one if the
1708   // system lives on a private network such as in the case of a cluster
1709   // node.
1710 
1711   int ierr=0;
1712   char base[NI_MAXHOST];
1713   ierr=gethostname(base,NI_MAXHOST);
1714   if (ierr)
1715     {
1716     return -1;
1717     }
1718   size_t baseSize=strlen(base);
1719   fqdn=base;
1720 
1721   struct ifaddrs *ifas;
1722   struct ifaddrs *ifa;
1723   ierr=getifaddrs(&ifas);
1724   if (ierr)
1725     {
1726     return -2;
1727     }
1728 
1729   for (ifa=ifas; ifa!=NULL; ifa=ifa->ifa_next)
1730     {
1731     int fam = ifa->ifa_addr? ifa->ifa_addr->sa_family : -1;
1732     if ((fam==AF_INET) || (fam==AF_INET6))
1733       {
1734       char host[NI_MAXHOST]={'\0'};
1735 
1736       const size_t addrlen
1737         = (fam==AF_INET?sizeof(struct sockaddr_in):sizeof(struct sockaddr_in6));
1738 
1739       ierr=getnameinfo(
1740             ifa->ifa_addr,
1741             static_cast<socklen_t>(addrlen),
1742             host,
1743             NI_MAXHOST,
1744             NULL,
1745             0,
1746             NI_NAMEREQD);
1747       if (ierr)
1748         {
1749         // don't report the failure now since we may succeed on another
1750         // interface. If all attempts fail then return the failure code.
1751         ierr=-3;
1752         continue;
1753         }
1754 
1755       kwsys_stl::string candidate=host;
1756       if ((candidate.find(base)!=kwsys_stl::string::npos) && baseSize<candidate.size())
1757         {
1758         // success, stop now.
1759         ierr=0;
1760         fqdn=candidate;
1761         break;
1762         }
1763       }
1764     }
1765   freeifaddrs(ifas);
1766 
1767   return ierr;
1768 #else
1769   /* TODO: Implement on more platforms.  */
1770   fqdn=this->GetHostname();
1771   return -1;
1772 #endif
1773 }
1774 
1775 /** Get the OS release */
GetOSRelease()1776 const char* SystemInformationImplementation::GetOSRelease()
1777 {
1778   return this->OSRelease.c_str();
1779 }
1780 
1781 /** Get the OS version */
GetOSVersion()1782 const char* SystemInformationImplementation::GetOSVersion()
1783 {
1784   return this->OSVersion.c_str();
1785 }
1786 
1787 /** Get the OS platform */
GetOSPlatform()1788 const char* SystemInformationImplementation::GetOSPlatform()
1789 {
1790   return this->OSPlatform.c_str();
1791 }
1792 
1793 /** Get the vendor ID */
GetVendorID()1794 const char * SystemInformationImplementation::GetVendorID()
1795 {
1796   // Return the vendor ID.
1797   switch (this->ChipManufacturer)
1798     {
1799     case Intel:
1800       return "Intel Corporation";
1801     case AMD:
1802       return "Advanced Micro Devices";
1803     case NSC:
1804       return "National Semiconductor";
1805     case Cyrix:
1806       return "Cyrix Corp., VIA Inc.";
1807     case NexGen:
1808       return "NexGen Inc., Advanced Micro Devices";
1809     case IDT:
1810       return "IDT\\Centaur, Via Inc.";
1811     case UMC:
1812       return "United Microelectronics Corp.";
1813     case Rise:
1814       return "Rise";
1815     case Transmeta:
1816       return "Transmeta";
1817     case Sun:
1818       return "Sun Microelectronics";
1819     case IBM:
1820       return "IBM";
1821     case Motorola:
1822       return "Motorola";
1823     case HP:
1824       return "Hewlett-Packard";
1825     default:
1826       return "Unknown Manufacturer";
1827     }
1828 }
1829 
1830 /** Return the type ID of the CPU */
GetTypeID()1831 kwsys_stl::string SystemInformationImplementation::GetTypeID()
1832 {
1833   kwsys_ios::ostringstream str;
1834   str << this->ChipID.Type;
1835   return str.str();
1836 }
1837 
1838 /** Return the family of the CPU present */
GetFamilyID()1839 kwsys_stl::string SystemInformationImplementation::GetFamilyID()
1840 {
1841   kwsys_ios::ostringstream str;
1842   str << this->ChipID.Family;
1843   return str.str();
1844 }
1845 
1846 // Return the model of CPU present */
GetModelID()1847 kwsys_stl::string SystemInformationImplementation::GetModelID()
1848 {
1849   kwsys_ios::ostringstream str;
1850   str << this->ChipID.Model;
1851   return str.str();
1852 }
1853 
1854 // Return the model name of CPU present */
GetModelName()1855 kwsys_stl::string SystemInformationImplementation::GetModelName()
1856 {
1857   return this->ChipID.ModelName;
1858 }
1859 
1860 /** Return the stepping code of the CPU present. */
GetSteppingCode()1861 kwsys_stl::string SystemInformationImplementation::GetSteppingCode()
1862 {
1863   kwsys_ios::ostringstream str;
1864   str << this->ChipID.Revision;
1865   return str.str();
1866 }
1867 
1868 /** Return the stepping code of the CPU present. */
GetExtendedProcessorName()1869 const char * SystemInformationImplementation::GetExtendedProcessorName()
1870 {
1871   return this->ChipID.ProcessorName.c_str();
1872 }
1873 
1874 /** Return the serial number of the processor
1875  *  in hexadecimal: xxxx-xxxx-xxxx-xxxx-xxxx-xxxx. */
GetProcessorSerialNumber()1876 const char * SystemInformationImplementation::GetProcessorSerialNumber()
1877 {
1878   return this->ChipID.SerialNumber.c_str();
1879 }
1880 
1881 /** Return the logical processors per physical */
GetLogicalProcessorsPerPhysical()1882 unsigned int SystemInformationImplementation::GetLogicalProcessorsPerPhysical()
1883 {
1884   return this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical;
1885 }
1886 
1887 /** Return the processor clock frequency. */
GetProcessorClockFrequency()1888 float SystemInformationImplementation::GetProcessorClockFrequency()
1889 {
1890   return this->CPUSpeedInMHz;
1891 }
1892 
1893 /**  Return the APIC ID. */
GetProcessorAPICID()1894 int SystemInformationImplementation::GetProcessorAPICID()
1895 {
1896   return this->Features.ExtendedFeatures.APIC_ID;
1897 }
1898 
1899 /** Return the L1 cache size. */
GetProcessorCacheSize()1900 int SystemInformationImplementation::GetProcessorCacheSize()
1901 {
1902   return this->Features.L1CacheSize;
1903 }
1904 
1905 /** Return the chosen cache size. */
GetProcessorCacheXSize(long int dwCacheID)1906 int SystemInformationImplementation::GetProcessorCacheXSize(long int dwCacheID)
1907 {
1908   switch (dwCacheID)
1909     {
1910     case L1CACHE_FEATURE:
1911       return this->Features.L1CacheSize;
1912     case L2CACHE_FEATURE:
1913       return this->Features.L2CacheSize;
1914     case L3CACHE_FEATURE:
1915       return this->Features.L3CacheSize;
1916     }
1917   return -1;
1918 }
1919 
1920 
DoesCPUSupportFeature(long int dwFeature)1921 bool SystemInformationImplementation::DoesCPUSupportFeature(long int dwFeature)
1922 {
1923   bool bHasFeature = false;
1924 
1925   // Check for MMX instructions.
1926   if (((dwFeature & MMX_FEATURE) != 0) && this->Features.HasMMX) bHasFeature = true;
1927 
1928   // Check for MMX+ instructions.
1929   if (((dwFeature & MMX_PLUS_FEATURE) != 0) && this->Features.ExtendedFeatures.HasMMXPlus) bHasFeature = true;
1930 
1931   // Check for SSE FP instructions.
1932   if (((dwFeature & SSE_FEATURE) != 0) && this->Features.HasSSE) bHasFeature = true;
1933 
1934   // Check for SSE FP instructions.
1935   if (((dwFeature & SSE_FP_FEATURE) != 0) && this->Features.HasSSEFP) bHasFeature = true;
1936 
1937   // Check for SSE MMX instructions.
1938   if (((dwFeature & SSE_MMX_FEATURE) != 0) && this->Features.ExtendedFeatures.HasSSEMMX) bHasFeature = true;
1939 
1940   // Check for SSE2 instructions.
1941   if (((dwFeature & SSE2_FEATURE) != 0) && this->Features.HasSSE2) bHasFeature = true;
1942 
1943   // Check for 3DNow! instructions.
1944   if (((dwFeature & AMD_3DNOW_FEATURE) != 0) && this->Features.ExtendedFeatures.Has3DNow) bHasFeature = true;
1945 
1946   // Check for 3DNow+ instructions.
1947   if (((dwFeature & AMD_3DNOW_PLUS_FEATURE) != 0) && this->Features.ExtendedFeatures.Has3DNowPlus) bHasFeature = true;
1948 
1949   // Check for IA64 instructions.
1950   if (((dwFeature & IA64_FEATURE) != 0) && this->Features.HasIA64) bHasFeature = true;
1951 
1952   // Check for MP capable.
1953   if (((dwFeature & MP_CAPABLE) != 0) && this->Features.ExtendedFeatures.SupportsMP) bHasFeature = true;
1954 
1955   // Check for a serial number for the processor.
1956   if (((dwFeature & SERIALNUMBER_FEATURE) != 0) && this->Features.HasSerial) bHasFeature = true;
1957 
1958   // Check for a local APIC in the processor.
1959   if (((dwFeature & APIC_FEATURE) != 0) && this->Features.HasAPIC) bHasFeature = true;
1960 
1961   // Check for CMOV instructions.
1962   if (((dwFeature & CMOV_FEATURE) != 0) && this->Features.HasCMOV) bHasFeature = true;
1963 
1964   // Check for MTRR instructions.
1965   if (((dwFeature & MTRR_FEATURE) != 0) && this->Features.HasMTRR) bHasFeature = true;
1966 
1967   // Check for L1 cache size.
1968   if (((dwFeature & L1CACHE_FEATURE) != 0) && (this->Features.L1CacheSize != -1)) bHasFeature = true;
1969 
1970   // Check for L2 cache size.
1971   if (((dwFeature & L2CACHE_FEATURE) != 0) && (this->Features.L2CacheSize != -1)) bHasFeature = true;
1972 
1973   // Check for L3 cache size.
1974   if (((dwFeature & L3CACHE_FEATURE) != 0) && (this->Features.L3CacheSize != -1)) bHasFeature = true;
1975 
1976   // Check for ACPI capability.
1977   if (((dwFeature & ACPI_FEATURE) != 0) && this->Features.HasACPI) bHasFeature = true;
1978 
1979   // Check for thermal monitor support.
1980   if (((dwFeature & THERMALMONITOR_FEATURE) != 0) && this->Features.HasThermal) bHasFeature = true;
1981 
1982   // Check for temperature sensing diode support.
1983   if (((dwFeature & TEMPSENSEDIODE_FEATURE) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode) bHasFeature = true;
1984 
1985   // Check for frequency ID support.
1986   if (((dwFeature & FREQUENCYID_FEATURE) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID) bHasFeature = true;
1987 
1988   // Check for voltage ID support.
1989   if (((dwFeature & VOLTAGEID_FREQUENCY) != 0) && this->Features.ExtendedFeatures.PowerManagement.HasVoltageID) bHasFeature = true;
1990 
1991   return bHasFeature;
1992 }
1993 
1994 
Delay(unsigned int uiMS)1995 void SystemInformationImplementation::Delay(unsigned int uiMS)
1996 {
1997 #ifdef WIN32
1998   LARGE_INTEGER Frequency, StartCounter, EndCounter;
1999   __int64 x;
2000 
2001   // Get the frequency of the high performance counter.
2002   if (!QueryPerformanceFrequency (&Frequency)) return;
2003   x = Frequency.QuadPart / 1000 * uiMS;
2004 
2005   // Get the starting position of the counter.
2006   QueryPerformanceCounter (&StartCounter);
2007 
2008   do {
2009     // Get the ending position of the counter.
2010     QueryPerformanceCounter (&EndCounter);
2011     } while (EndCounter.QuadPart - StartCounter.QuadPart < x);
2012 #endif
2013   (void)uiMS;
2014 }
2015 
2016 
DoesCPUSupportCPUID()2017 bool SystemInformationImplementation::DoesCPUSupportCPUID()
2018 {
2019 #if USE_CPUID
2020   int dummy[4] = { 0, 0, 0, 0 };
2021 
2022 #if USE_ASM_INSTRUCTIONS
2023   return call_cpuid(0, dummy);
2024 #else
2025   call_cpuid(0, dummy);
2026   return dummy[0] || dummy[1] || dummy[2] || dummy[3];
2027 #endif
2028 #else
2029   // Assume no cpuid instruction.
2030   return false;
2031 #endif
2032 }
2033 
2034 
RetrieveCPUFeatures()2035 bool SystemInformationImplementation::RetrieveCPUFeatures()
2036 {
2037 #if USE_CPUID
2038   int cpuinfo[4] = { 0, 0, 0, 0 };
2039 
2040   if (!call_cpuid(1, cpuinfo))
2041     {
2042     return false;
2043     }
2044 
2045   // Retrieve the features of CPU present.
2046   this->Features.HasFPU =     ((cpuinfo[3] & 0x00000001) != 0);    // FPU Present --> Bit 0
2047   this->Features.HasTSC =     ((cpuinfo[3] & 0x00000010) != 0);    // TSC Present --> Bit 4
2048   this->Features.HasAPIC =    ((cpuinfo[3] & 0x00000200) != 0);    // APIC Present --> Bit 9
2049   this->Features.HasMTRR =    ((cpuinfo[3] & 0x00001000) != 0);    // MTRR Present --> Bit 12
2050   this->Features.HasCMOV =    ((cpuinfo[3] & 0x00008000) != 0);    // CMOV Present --> Bit 15
2051   this->Features.HasSerial =  ((cpuinfo[3] & 0x00040000) != 0);    // Serial Present --> Bit 18
2052   this->Features.HasACPI =    ((cpuinfo[3] & 0x00400000) != 0);    // ACPI Capable --> Bit 22
2053   this->Features.HasMMX =     ((cpuinfo[3] & 0x00800000) != 0);    // MMX Present --> Bit 23
2054   this->Features.HasSSE =     ((cpuinfo[3] & 0x02000000) != 0);    // SSE Present --> Bit 25
2055   this->Features.HasSSE2 =    ((cpuinfo[3] & 0x04000000) != 0);    // SSE2 Present --> Bit 26
2056   this->Features.HasThermal = ((cpuinfo[3] & 0x20000000) != 0);    // Thermal Monitor Present --> Bit 29
2057   this->Features.HasIA64 =    ((cpuinfo[3] & 0x40000000) != 0);    // IA64 Present --> Bit 30
2058 
2059 #if USE_ASM_INSTRUCTIONS
2060   // Retrieve extended SSE capabilities if SSE is available.
2061   if (this->Features.HasSSE) {
2062 
2063     // Attempt to __try some SSE FP instructions.
2064     __try
2065       {
2066       // Perform: orps xmm0, xmm0
2067       _asm
2068         {
2069         _emit 0x0f
2070         _emit 0x56
2071         _emit 0xc0
2072         }
2073 
2074       // SSE FP capable processor.
2075       this->Features.HasSSEFP = true;
2076       }
2077     __except(1)
2078       {
2079       // bad instruction - processor or OS cannot handle SSE FP.
2080       this->Features.HasSSEFP = false;
2081       }
2082     }
2083   else
2084     {
2085     // Set the advanced SSE capabilities to not available.
2086     this->Features.HasSSEFP = false;
2087     }
2088 #else
2089   this->Features.HasSSEFP = false;
2090 #endif
2091 
2092   // Retrieve Intel specific extended features.
2093   if (this->ChipManufacturer == Intel)
2094     {
2095     this->Features.ExtendedFeatures.SupportsHyperthreading =  ((cpuinfo[3] &  0x10000000) != 0);  // Intel specific: Hyperthreading --> Bit 28
2096     this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical = (this->Features.ExtendedFeatures.SupportsHyperthreading) ? ((cpuinfo[1] & 0x00FF0000) >> 16) : 1;
2097 
2098     if ((this->Features.ExtendedFeatures.SupportsHyperthreading) && (this->Features.HasAPIC))
2099       {
2100       // Retrieve APIC information if there is one present.
2101       this->Features.ExtendedFeatures.APIC_ID = ((cpuinfo[1] & 0xFF000000) >> 24);
2102       }
2103     }
2104 
2105   return true;
2106 
2107 #else
2108   return false;
2109 #endif
2110 }
2111 
2112 
2113 /** Find the manufacturer given the vendor id */
FindManufacturer(const kwsys_stl::string & family)2114 void SystemInformationImplementation::FindManufacturer(const kwsys_stl::string& family)
2115 {
2116   if (this->ChipID.Vendor == "GenuineIntel")       this->ChipManufacturer = Intel;        // Intel Corp.
2117   else if (this->ChipID.Vendor == "UMC UMC UMC ")  this->ChipManufacturer = UMC;          // United Microelectronics Corp.
2118   else if (this->ChipID.Vendor == "AuthenticAMD")  this->ChipManufacturer = AMD;          // Advanced Micro Devices
2119   else if (this->ChipID.Vendor == "AMD ISBETTER")  this->ChipManufacturer = AMD;          // Advanced Micro Devices (1994)
2120   else if (this->ChipID.Vendor == "CyrixInstead")  this->ChipManufacturer = Cyrix;        // Cyrix Corp., VIA Inc.
2121   else if (this->ChipID.Vendor == "NexGenDriven")  this->ChipManufacturer = NexGen;        // NexGen Inc. (now AMD)
2122   else if (this->ChipID.Vendor == "CentaurHauls")  this->ChipManufacturer = IDT;          // IDT/Centaur (now VIA)
2123   else if (this->ChipID.Vendor == "RiseRiseRise")  this->ChipManufacturer = Rise;        // Rise
2124   else if (this->ChipID.Vendor == "GenuineTMx86")  this->ChipManufacturer = Transmeta;      // Transmeta
2125   else if (this->ChipID.Vendor == "TransmetaCPU")  this->ChipManufacturer = Transmeta;      // Transmeta
2126   else if (this->ChipID.Vendor == "Geode By NSC")  this->ChipManufacturer = NSC;          // National Semiconductor
2127   else if (this->ChipID.Vendor == "Sun")           this->ChipManufacturer = Sun;          // Sun Microelectronics
2128   else if (this->ChipID.Vendor == "IBM")           this->ChipManufacturer = IBM;          // IBM Microelectronics
2129   else if (this->ChipID.Vendor == "Hewlett-Packard") this->ChipManufacturer = HP;         // Hewlett-Packard
2130   else if (this->ChipID.Vendor == "Motorola")      this->ChipManufacturer = Motorola;          // Motorola Microelectronics
2131   else if (family.substr(0, 7) == "PA-RISC")       this->ChipManufacturer = HP;           // Hewlett-Packard
2132   else                                             this->ChipManufacturer = UnknownManufacturer;  // Unknown manufacturer
2133 }
2134 
2135 
2136 /** */
RetrieveCPUIdentity()2137 bool SystemInformationImplementation::RetrieveCPUIdentity()
2138 {
2139 #if USE_CPUID
2140   int localCPUVendor[4];
2141   int localCPUSignature[4];
2142 
2143   if (!call_cpuid(0, localCPUVendor))
2144     {
2145     return false;
2146     }
2147   if (!call_cpuid(1, localCPUSignature))
2148     {
2149     return false;
2150     }
2151 
2152   // Process the returned information.
2153   //    ; eax = 0 --> eax: maximum value of CPUID instruction.
2154   //    ;        ebx: part 1 of 3; CPU signature.
2155   //    ;        edx: part 2 of 3; CPU signature.
2156   //    ;        ecx: part 3 of 3; CPU signature.
2157   char vbuf[13];
2158   memcpy (&(vbuf[0]), &(localCPUVendor[1]), sizeof (int));
2159   memcpy (&(vbuf[4]), &(localCPUVendor[3]), sizeof (int));
2160   memcpy (&(vbuf[8]), &(localCPUVendor[2]), sizeof (int));
2161   vbuf[12] = '\0';
2162   this->ChipID.Vendor = vbuf;
2163 
2164   // Retrieve the family of CPU present.
2165   //    ; eax = 1 --> eax: CPU ID - bits 31..16 - unused, bits 15..12 - type, bits 11..8 - family, bits 7..4 - model, bits 3..0 - mask revision
2166   //    ;        ebx: 31..24 - default APIC ID, 23..16 - logical processor ID, 15..8 - CFLUSH chunk size , 7..0 - brand ID
2167   //    ;        edx: CPU feature flags
2168   this->ChipID.ExtendedFamily = ((localCPUSignature[0] & 0x0FF00000) >> 20);  // Bits 27..20 Used
2169   this->ChipID.ExtendedModel =  ((localCPUSignature[0] & 0x000F0000) >> 16);  // Bits 19..16 Used
2170   this->ChipID.Type =           ((localCPUSignature[0] & 0x0000F000) >> 12);  // Bits 15..12 Used
2171   this->ChipID.Family =         ((localCPUSignature[0] & 0x00000F00) >> 8);    // Bits 11..8 Used
2172   this->ChipID.Model =          ((localCPUSignature[0] & 0x000000F0) >> 4);    // Bits 7..4 Used
2173   this->ChipID.Revision =       ((localCPUSignature[0] & 0x0000000F) >> 0);    // Bits 3..0 Used
2174 
2175   return true;
2176 
2177 #else
2178   return false;
2179 #endif
2180 }
2181 
2182 
2183 /** */
RetrieveCPUCacheDetails()2184 bool SystemInformationImplementation::RetrieveCPUCacheDetails()
2185 {
2186 #if USE_CPUID
2187   int L1Cache[4] = { 0, 0, 0, 0 };
2188   int L2Cache[4] = { 0, 0, 0, 0 };
2189 
2190   // Check to see if what we are about to do is supported...
2191   if (RetrieveCPUExtendedLevelSupport (0x80000005))
2192     {
2193     if (!call_cpuid(0x80000005, L1Cache))
2194       {
2195       return false;
2196       }
2197     // Save the L1 data cache size (in KB) from ecx: bits 31..24 as well as data cache size from edx: bits 31..24.
2198     this->Features.L1CacheSize = ((L1Cache[2] & 0xFF000000) >> 24);
2199     this->Features.L1CacheSize += ((L1Cache[3] & 0xFF000000) >> 24);
2200     }
2201   else
2202     {
2203     // Store -1 to indicate the cache could not be queried.
2204     this->Features.L1CacheSize = -1;
2205     }
2206 
2207   // Check to see if what we are about to do is supported...
2208   if (RetrieveCPUExtendedLevelSupport (0x80000006))
2209     {
2210     if (!call_cpuid(0x80000006, L2Cache))
2211       {
2212       return false;
2213       }
2214     // Save the L2 unified cache size (in KB) from ecx: bits 31..16.
2215     this->Features.L2CacheSize = ((L2Cache[2] & 0xFFFF0000) >> 16);
2216     }
2217   else
2218     {
2219     // Store -1 to indicate the cache could not be queried.
2220     this->Features.L2CacheSize = -1;
2221     }
2222 
2223   // Define L3 as being not present as we cannot test for it.
2224   this->Features.L3CacheSize = -1;
2225 
2226 #endif
2227 
2228   // Return failure if we cannot detect either cache with this method.
2229   return ((this->Features.L1CacheSize == -1) && (this->Features.L2CacheSize == -1)) ? false : true;
2230 }
2231 
2232 
2233 /** */
RetrieveClassicalCPUCacheDetails()2234 bool SystemInformationImplementation::RetrieveClassicalCPUCacheDetails()
2235 {
2236 #if USE_CPUID
2237   int TLBCode = -1, TLBData = -1, L1Code = -1, L1Data = -1, L1Trace = -1, L2Unified = -1, L3Unified = -1;
2238   int TLBCacheData[4] = { 0, 0, 0, 0 };
2239   int TLBPassCounter = 0;
2240   int TLBCacheUnit = 0;
2241 
2242 
2243   do {
2244     if (!call_cpuid(2, TLBCacheData))
2245       {
2246       return false;
2247       }
2248 
2249     int bob = ((TLBCacheData[0] & 0x00FF0000) >> 16);
2250     (void)bob;
2251     // Process the returned TLB and cache information.
2252     for (int nCounter = 0; nCounter < TLBCACHE_INFO_UNITS; nCounter ++)
2253       {
2254       // First of all - decide which unit we are dealing with.
2255       switch (nCounter)
2256         {
2257         // eax: bits 8..15 : bits 16..23 : bits 24..31
2258         case 0: TLBCacheUnit = ((TLBCacheData[0] & 0x0000FF00) >> 8); break;
2259         case 1: TLBCacheUnit = ((TLBCacheData[0] & 0x00FF0000) >> 16); break;
2260         case 2: TLBCacheUnit = ((TLBCacheData[0] & 0xFF000000) >> 24); break;
2261 
2262         // ebx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
2263         case 3: TLBCacheUnit = ((TLBCacheData[1] & 0x000000FF) >> 0); break;
2264         case 4: TLBCacheUnit = ((TLBCacheData[1] & 0x0000FF00) >> 8); break;
2265         case 5: TLBCacheUnit = ((TLBCacheData[1] & 0x00FF0000) >> 16); break;
2266         case 6: TLBCacheUnit = ((TLBCacheData[1] & 0xFF000000) >> 24); break;
2267 
2268         // ecx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
2269         case 7: TLBCacheUnit = ((TLBCacheData[2] & 0x000000FF) >> 0); break;
2270         case 8: TLBCacheUnit = ((TLBCacheData[2] & 0x0000FF00) >> 8); break;
2271         case 9: TLBCacheUnit = ((TLBCacheData[2] & 0x00FF0000) >> 16); break;
2272         case 10: TLBCacheUnit = ((TLBCacheData[2] & 0xFF000000) >> 24); break;
2273 
2274         // edx: bits 0..7 : bits 8..15 : bits 16..23 : bits 24..31
2275         case 11: TLBCacheUnit = ((TLBCacheData[3] & 0x000000FF) >> 0); break;
2276         case 12: TLBCacheUnit = ((TLBCacheData[3] & 0x0000FF00) >> 8); break;
2277         case 13: TLBCacheUnit = ((TLBCacheData[3] & 0x00FF0000) >> 16); break;
2278         case 14: TLBCacheUnit = ((TLBCacheData[3] & 0xFF000000) >> 24); break;
2279 
2280         // Default case - an error has occured.
2281         default: return false;
2282         }
2283 
2284       // Now process the resulting unit to see what it means....
2285       switch (TLBCacheUnit)
2286         {
2287         case 0x00: break;
2288         case 0x01: STORE_TLBCACHE_INFO (TLBCode, 4); break;
2289         case 0x02: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
2290         case 0x03: STORE_TLBCACHE_INFO (TLBData, 4); break;
2291         case 0x04: STORE_TLBCACHE_INFO (TLBData, 4096); break;
2292         case 0x06: STORE_TLBCACHE_INFO (L1Code, 8); break;
2293         case 0x08: STORE_TLBCACHE_INFO (L1Code, 16); break;
2294         case 0x0a: STORE_TLBCACHE_INFO (L1Data, 8); break;
2295         case 0x0c: STORE_TLBCACHE_INFO (L1Data, 16); break;
2296         case 0x10: STORE_TLBCACHE_INFO (L1Data, 16); break;      // <-- FIXME: IA-64 Only
2297         case 0x15: STORE_TLBCACHE_INFO (L1Code, 16); break;      // <-- FIXME: IA-64 Only
2298         case 0x1a: STORE_TLBCACHE_INFO (L2Unified, 96); break;    // <-- FIXME: IA-64 Only
2299         case 0x22: STORE_TLBCACHE_INFO (L3Unified, 512); break;
2300         case 0x23: STORE_TLBCACHE_INFO (L3Unified, 1024); break;
2301         case 0x25: STORE_TLBCACHE_INFO (L3Unified, 2048); break;
2302         case 0x29: STORE_TLBCACHE_INFO (L3Unified, 4096); break;
2303         case 0x39: STORE_TLBCACHE_INFO (L2Unified, 128); break;
2304         case 0x3c: STORE_TLBCACHE_INFO (L2Unified, 256); break;
2305         case 0x40: STORE_TLBCACHE_INFO (L2Unified, 0); break;    // <-- FIXME: No integrated L2 cache (P6 core) or L3 cache (P4 core).
2306         case 0x41: STORE_TLBCACHE_INFO (L2Unified, 128); break;
2307         case 0x42: STORE_TLBCACHE_INFO (L2Unified, 256); break;
2308         case 0x43: STORE_TLBCACHE_INFO (L2Unified, 512); break;
2309         case 0x44: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
2310         case 0x45: STORE_TLBCACHE_INFO (L2Unified, 2048); break;
2311         case 0x50: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
2312         case 0x51: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
2313         case 0x52: STORE_TLBCACHE_INFO (TLBCode, 4096); break;
2314         case 0x5b: STORE_TLBCACHE_INFO (TLBData, 4096); break;
2315         case 0x5c: STORE_TLBCACHE_INFO (TLBData, 4096); break;
2316         case 0x5d: STORE_TLBCACHE_INFO (TLBData, 4096); break;
2317         case 0x66: STORE_TLBCACHE_INFO (L1Data, 8); break;
2318         case 0x67: STORE_TLBCACHE_INFO (L1Data, 16); break;
2319         case 0x68: STORE_TLBCACHE_INFO (L1Data, 32); break;
2320         case 0x70: STORE_TLBCACHE_INFO (L1Trace, 12); break;
2321         case 0x71: STORE_TLBCACHE_INFO (L1Trace, 16); break;
2322         case 0x72: STORE_TLBCACHE_INFO (L1Trace, 32); break;
2323         case 0x77: STORE_TLBCACHE_INFO (L1Code, 16); break;      // <-- FIXME: IA-64 Only
2324         case 0x79: STORE_TLBCACHE_INFO (L2Unified, 128); break;
2325         case 0x7a: STORE_TLBCACHE_INFO (L2Unified, 256); break;
2326         case 0x7b: STORE_TLBCACHE_INFO (L2Unified, 512); break;
2327         case 0x7c: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
2328         case 0x7e: STORE_TLBCACHE_INFO (L2Unified, 256); break;
2329         case 0x81: STORE_TLBCACHE_INFO (L2Unified, 128); break;
2330         case 0x82: STORE_TLBCACHE_INFO (L2Unified, 256); break;
2331         case 0x83: STORE_TLBCACHE_INFO (L2Unified, 512); break;
2332         case 0x84: STORE_TLBCACHE_INFO (L2Unified, 1024); break;
2333         case 0x85: STORE_TLBCACHE_INFO (L2Unified, 2048); break;
2334         case 0x88: STORE_TLBCACHE_INFO (L3Unified, 2048); break;  // <-- FIXME: IA-64 Only
2335         case 0x89: STORE_TLBCACHE_INFO (L3Unified, 4096); break;  // <-- FIXME: IA-64 Only
2336         case 0x8a: STORE_TLBCACHE_INFO (L3Unified, 8192); break;  // <-- FIXME: IA-64 Only
2337         case 0x8d: STORE_TLBCACHE_INFO (L3Unified, 3096); break;  // <-- FIXME: IA-64 Only
2338         case 0x90: STORE_TLBCACHE_INFO (TLBCode, 262144); break;  // <-- FIXME: IA-64 Only
2339         case 0x96: STORE_TLBCACHE_INFO (TLBCode, 262144); break;  // <-- FIXME: IA-64 Only
2340         case 0x9b: STORE_TLBCACHE_INFO (TLBCode, 262144); break;  // <-- FIXME: IA-64 Only
2341 
2342         // Default case - an error has occured.
2343         default: return false;
2344         }
2345       }
2346 
2347     // Increment the TLB pass counter.
2348     TLBPassCounter ++;
2349     } while ((TLBCacheData[0] & 0x000000FF) > TLBPassCounter);
2350 
2351   // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
2352   if ((L1Code == -1) && (L1Data == -1) && (L1Trace == -1))
2353     {
2354     this->Features.L1CacheSize = -1;
2355     }
2356   else if ((L1Code == -1) && (L1Data == -1) && (L1Trace != -1))
2357     {
2358     this->Features.L1CacheSize = L1Trace;
2359     }
2360   else if ((L1Code != -1) && (L1Data == -1))
2361     {
2362     this->Features.L1CacheSize = L1Code;
2363     }
2364   else if ((L1Code == -1) && (L1Data != -1))
2365     {
2366     this->Features.L1CacheSize = L1Data;
2367     }
2368   else if ((L1Code != -1) && (L1Data != -1))
2369     {
2370     this->Features.L1CacheSize = L1Code + L1Data;
2371     }
2372   else
2373     {
2374     this->Features.L1CacheSize = -1;
2375     }
2376 
2377   // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
2378   if (L2Unified == -1)
2379     {
2380     this->Features.L2CacheSize = -1;
2381     }
2382   else
2383     {
2384     this->Features.L2CacheSize = L2Unified;
2385     }
2386 
2387   // Ok - we now have the maximum TLB, L1, L2, and L3 sizes...
2388   if (L3Unified == -1)
2389     {
2390     this->Features.L3CacheSize = -1;
2391     }
2392   else
2393     {
2394     this->Features.L3CacheSize = L3Unified;
2395     }
2396 
2397   return true;
2398 
2399 #else
2400   return false;
2401 #endif
2402 }
2403 
2404 
2405 /** */
RetrieveCPUClockSpeed()2406 bool SystemInformationImplementation::RetrieveCPUClockSpeed()
2407 {
2408   bool retrieved = false;
2409 
2410 #if defined(_WIN32)
2411   unsigned int uiRepetitions = 1;
2412   unsigned int uiMSecPerRepetition = 50;
2413   __int64  i64Total = 0;
2414   __int64 i64Overhead = 0;
2415 
2416   // Check if the TSC implementation works at all
2417   if (this->Features.HasTSC &&
2418       GetCyclesDifference(SystemInformationImplementation::Delay,
2419                           uiMSecPerRepetition) > 0)
2420     {
2421     for (unsigned int nCounter = 0; nCounter < uiRepetitions; nCounter ++)
2422       {
2423       i64Total += GetCyclesDifference (SystemInformationImplementation::Delay,
2424                                        uiMSecPerRepetition);
2425       i64Overhead +=
2426         GetCyclesDifference (SystemInformationImplementation::DelayOverhead,
2427                              uiMSecPerRepetition);
2428       }
2429 
2430     // Calculate the MHz speed.
2431     i64Total -= i64Overhead;
2432     i64Total /= uiRepetitions;
2433     i64Total /= uiMSecPerRepetition;
2434     i64Total /= 1000;
2435 
2436     // Save the CPU speed.
2437     this->CPUSpeedInMHz = (float) i64Total;
2438 
2439     retrieved = true;
2440     }
2441 
2442   // If RDTSC is not supported, we fallback to trying to read this value
2443   // from the registry:
2444   if (!retrieved)
2445     {
2446     HKEY hKey = NULL;
2447     LONG err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2448       L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0,
2449       KEY_READ, &hKey);
2450 
2451     if (ERROR_SUCCESS == err)
2452       {
2453       DWORD dwType = 0;
2454       DWORD data = 0;
2455       DWORD dwSize = sizeof(DWORD);
2456 
2457       err = RegQueryValueExW(hKey, L"~MHz", 0,
2458         &dwType, (LPBYTE) &data, &dwSize);
2459 
2460       if (ERROR_SUCCESS == err)
2461         {
2462         this->CPUSpeedInMHz = (float) data;
2463         retrieved = true;
2464         }
2465 
2466       RegCloseKey(hKey);
2467       hKey = NULL;
2468       }
2469     }
2470 #endif
2471 
2472   return retrieved;
2473 }
2474 
2475 
2476 /** */
RetrieveClassicalCPUClockSpeed()2477 bool SystemInformationImplementation::RetrieveClassicalCPUClockSpeed()
2478 {
2479 #if USE_ASM_INSTRUCTIONS
2480   LARGE_INTEGER liStart, liEnd, liCountsPerSecond;
2481   double dFrequency, dDifference;
2482 
2483   // Attempt to get a starting tick count.
2484   QueryPerformanceCounter (&liStart);
2485 
2486   __try
2487     {
2488     _asm
2489       {
2490       mov eax, 0x80000000
2491       mov ebx, CLASSICAL_CPU_FREQ_LOOP
2492       Timer_Loop:
2493       bsf ecx,eax
2494       dec ebx
2495       jnz Timer_Loop
2496       }
2497     }
2498   __except(1)
2499     {
2500     return false;
2501     }
2502 
2503   // Attempt to get a starting tick count.
2504   QueryPerformanceCounter (&liEnd);
2505 
2506   // Get the difference...  NB: This is in seconds....
2507   QueryPerformanceFrequency (&liCountsPerSecond);
2508   dDifference = (((double) liEnd.QuadPart - (double) liStart.QuadPart) / (double) liCountsPerSecond.QuadPart);
2509 
2510   // Calculate the clock speed.
2511   if (this->ChipID.Family == 3)
2512     {
2513     // 80386 processors....  Loop time is 115 cycles!
2514     dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 115) / dDifference) / 1000000);
2515     }
2516   else if (this->ChipID.Family == 4)
2517     {
2518     // 80486 processors....  Loop time is 47 cycles!
2519     dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 47) / dDifference) / 1000000);
2520     }
2521   else if (this->ChipID.Family == 5)
2522     {
2523     // Pentium processors....  Loop time is 43 cycles!
2524     dFrequency = (((CLASSICAL_CPU_FREQ_LOOP * 43) / dDifference) / 1000000);
2525     }
2526 
2527   // Save the clock speed.
2528   this->Features.CPUSpeed = (int) dFrequency;
2529 
2530   return true;
2531 
2532 #else
2533   return false;
2534 #endif
2535 }
2536 
2537 
2538 /** */
RetrieveCPUExtendedLevelSupport(int CPULevelToCheck)2539 bool SystemInformationImplementation::RetrieveCPUExtendedLevelSupport(int CPULevelToCheck)
2540 {
2541   int cpuinfo[4] = { 0, 0, 0, 0 };
2542 
2543   // The extended CPUID is supported by various vendors starting with the following CPU models:
2544   //
2545   //    Manufacturer & Chip Name      |    Family     Model    Revision
2546   //
2547   //    AMD K6, K6-2                  |       5       6      x
2548   //    Cyrix GXm, Cyrix III "Joshua" |       5       4      x
2549   //    IDT C6-2                      |       5       8      x
2550   //    VIA Cyrix III                 |       6       5      x
2551   //    Transmeta Crusoe              |       5       x      x
2552   //    Intel Pentium 4               |       f       x      x
2553   //
2554 
2555   // We check to see if a supported processor is present...
2556   if (this->ChipManufacturer == AMD)
2557     {
2558     if (this->ChipID.Family < 5) return false;
2559     if ((this->ChipID.Family == 5) && (this->ChipID.Model < 6)) return false;
2560     }
2561   else if (this->ChipManufacturer == Cyrix)
2562     {
2563     if (this->ChipID.Family < 5) return false;
2564     if ((this->ChipID.Family == 5) && (this->ChipID.Model < 4)) return false;
2565     if ((this->ChipID.Family == 6) && (this->ChipID.Model < 5)) return false;
2566     }
2567   else if (this->ChipManufacturer == IDT)
2568     {
2569     if (this->ChipID.Family < 5) return false;
2570     if ((this->ChipID.Family == 5) && (this->ChipID.Model < 8)) return false;
2571     }
2572   else if (this->ChipManufacturer == Transmeta)
2573     {
2574     if (this->ChipID.Family < 5) return false;
2575     }
2576   else if (this->ChipManufacturer == Intel)
2577     {
2578     if (this->ChipID.Family < 0xf)
2579       {
2580       return false;
2581       }
2582     }
2583 
2584 #if USE_CPUID
2585   if (!call_cpuid(0x80000000, cpuinfo))
2586     {
2587     return false;
2588     }
2589 #endif
2590 
2591   // Now we have to check the level wanted vs level returned...
2592   int nLevelWanted = (CPULevelToCheck & 0x7FFFFFFF);
2593   int nLevelReturn = (cpuinfo[0] & 0x7FFFFFFF);
2594 
2595   // Check to see if the level provided is supported...
2596   if (nLevelWanted > nLevelReturn)
2597     {
2598     return false;
2599     }
2600 
2601   return true;
2602 }
2603 
2604 
2605 /** */
RetrieveExtendedCPUFeatures()2606 bool SystemInformationImplementation::RetrieveExtendedCPUFeatures()
2607 {
2608 
2609   // Check that we are not using an Intel processor as it does not support this.
2610   if (this->ChipManufacturer == Intel)
2611     {
2612     return false;
2613     }
2614 
2615   // Check to see if what we are about to do is supported...
2616   if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000001)))
2617     {
2618     return false;
2619     }
2620 
2621 #if USE_CPUID
2622   int localCPUExtendedFeatures[4] = { 0, 0, 0, 0 };
2623 
2624   if (!call_cpuid(0x80000001, localCPUExtendedFeatures))
2625     {
2626     return false;
2627     }
2628 
2629   // Retrieve the extended features of CPU present.
2630   this->Features.ExtendedFeatures.Has3DNow =     ((localCPUExtendedFeatures[3] & 0x80000000) != 0);  // 3DNow Present --> Bit 31.
2631   this->Features.ExtendedFeatures.Has3DNowPlus = ((localCPUExtendedFeatures[3] & 0x40000000) != 0);  // 3DNow+ Present -- > Bit 30.
2632   this->Features.ExtendedFeatures.HasSSEMMX =    ((localCPUExtendedFeatures[3] & 0x00400000) != 0);  // SSE MMX Present --> Bit 22.
2633   this->Features.ExtendedFeatures.SupportsMP =   ((localCPUExtendedFeatures[3] & 0x00080000) != 0);  // MP Capable -- > Bit 19.
2634 
2635   // Retrieve AMD specific extended features.
2636   if (this->ChipManufacturer == AMD)
2637     {
2638     this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures[3] & 0x00400000) != 0);  // AMD specific: MMX-SSE --> Bit 22
2639     }
2640 
2641   // Retrieve Cyrix specific extended features.
2642   if (this->ChipManufacturer == Cyrix)
2643     {
2644     this->Features.ExtendedFeatures.HasMMXPlus = ((localCPUExtendedFeatures[3] & 0x01000000) != 0);  // Cyrix specific: Extended MMX --> Bit 24
2645     }
2646 
2647   return true;
2648 
2649 #else
2650   return false;
2651 #endif
2652 }
2653 
2654 
2655 /** */
RetrieveProcessorSerialNumber()2656 bool SystemInformationImplementation::RetrieveProcessorSerialNumber()
2657 {
2658   // Check to see if the processor supports the processor serial number.
2659   if (!this->Features.HasSerial)
2660     {
2661     return false;
2662     }
2663 
2664 #if USE_CPUID
2665   int SerialNumber[4];
2666 
2667   if (!call_cpuid(3, SerialNumber))
2668     {
2669     return false;
2670     }
2671 
2672   // Process the returned information.
2673   //    ; eax = 3 --> ebx: top 32 bits are the processor signature bits --> NB: Transmeta only ?!?
2674   //    ;        ecx: middle 32 bits are the processor signature bits
2675   //    ;        edx: bottom 32 bits are the processor signature bits
2676   char sn[128];
2677   sprintf (sn, "%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x",
2678        ((SerialNumber[1] & 0xff000000) >> 24),
2679        ((SerialNumber[1] & 0x00ff0000) >> 16),
2680        ((SerialNumber[1] & 0x0000ff00) >> 8),
2681        ((SerialNumber[1] & 0x000000ff) >> 0),
2682        ((SerialNumber[2] & 0xff000000) >> 24),
2683        ((SerialNumber[2] & 0x00ff0000) >> 16),
2684        ((SerialNumber[2] & 0x0000ff00) >> 8),
2685        ((SerialNumber[2] & 0x000000ff) >> 0),
2686        ((SerialNumber[3] & 0xff000000) >> 24),
2687        ((SerialNumber[3] & 0x00ff0000) >> 16),
2688        ((SerialNumber[3] & 0x0000ff00) >> 8),
2689        ((SerialNumber[3] & 0x000000ff) >> 0));
2690   this->ChipID.SerialNumber = sn;
2691   return true;
2692 
2693 #else
2694   return false;
2695 #endif
2696 }
2697 
2698 
2699 /** */
RetrieveCPUPowerManagement()2700 bool SystemInformationImplementation::RetrieveCPUPowerManagement()
2701 {
2702   // Check to see if what we are about to do is supported...
2703   if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000007)))
2704     {
2705     this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID = false;
2706     this->Features.ExtendedFeatures.PowerManagement.HasVoltageID = false;
2707     this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode = false;
2708     return false;
2709     }
2710 
2711 #if USE_CPUID
2712   int localCPUPowerManagement[4] = { 0, 0, 0, 0 };
2713 
2714   if (!call_cpuid(0x80000007, localCPUPowerManagement))
2715     {
2716     return false;
2717     }
2718 
2719   // Check for the power management capabilities of the CPU.
2720   this->Features.ExtendedFeatures.PowerManagement.HasTempSenseDiode =  ((localCPUPowerManagement[3] & 0x00000001) != 0);
2721   this->Features.ExtendedFeatures.PowerManagement.HasFrequencyID =     ((localCPUPowerManagement[3] & 0x00000002) != 0);
2722   this->Features.ExtendedFeatures.PowerManagement.HasVoltageID =       ((localCPUPowerManagement[3] & 0x00000004) != 0);
2723 
2724   return true;
2725 
2726 #else
2727   return false;
2728 #endif
2729 }
2730 
2731 #if USE_CPUID
2732 // Used only in USE_CPUID implementation below.
SystemInformationStripLeadingSpace(kwsys_stl::string & str)2733 static void SystemInformationStripLeadingSpace(kwsys_stl::string& str)
2734 {
2735   // Because some manufacturers have leading white space - we have to post-process the name.
2736   kwsys_stl::string::size_type pos = str.find_first_not_of(" ");
2737   if(pos != kwsys_stl::string::npos)
2738     {
2739     str = str.substr(pos);
2740     }
2741 }
2742 #endif
2743 
2744 /** */
RetrieveExtendedCPUIdentity()2745 bool SystemInformationImplementation::RetrieveExtendedCPUIdentity()
2746 {
2747   // Check to see if what we are about to do is supported...
2748   if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000002)))
2749     return false;
2750   if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000003)))
2751     return false;
2752   if (!RetrieveCPUExtendedLevelSupport(static_cast<int>(0x80000004)))
2753     return false;
2754 
2755 #if USE_CPUID
2756   int CPUExtendedIdentity[12];
2757 
2758   if (!call_cpuid(0x80000002, CPUExtendedIdentity))
2759     {
2760     return false;
2761     }
2762   if (!call_cpuid(0x80000003, CPUExtendedIdentity + 4))
2763     {
2764     return false;
2765     }
2766   if (!call_cpuid(0x80000004, CPUExtendedIdentity + 8))
2767     {
2768     return false;
2769     }
2770 
2771   // Process the returned information.
2772   char nbuf[49];
2773   memcpy (&(nbuf[0]), &(CPUExtendedIdentity[0]), sizeof (int));
2774   memcpy (&(nbuf[4]), &(CPUExtendedIdentity[1]), sizeof (int));
2775   memcpy (&(nbuf[8]), &(CPUExtendedIdentity[2]), sizeof (int));
2776   memcpy (&(nbuf[12]), &(CPUExtendedIdentity[3]), sizeof (int));
2777   memcpy (&(nbuf[16]), &(CPUExtendedIdentity[4]), sizeof (int));
2778   memcpy (&(nbuf[20]), &(CPUExtendedIdentity[5]), sizeof (int));
2779   memcpy (&(nbuf[24]), &(CPUExtendedIdentity[6]), sizeof (int));
2780   memcpy (&(nbuf[28]), &(CPUExtendedIdentity[7]), sizeof (int));
2781   memcpy (&(nbuf[32]), &(CPUExtendedIdentity[8]), sizeof (int));
2782   memcpy (&(nbuf[36]), &(CPUExtendedIdentity[9]), sizeof (int));
2783   memcpy (&(nbuf[40]), &(CPUExtendedIdentity[10]), sizeof (int));
2784   memcpy (&(nbuf[44]), &(CPUExtendedIdentity[11]), sizeof (int));
2785   nbuf[48] = '\0';
2786   this->ChipID.ProcessorName = nbuf;
2787   this->ChipID.ModelName = nbuf;
2788 
2789   // Because some manufacturers have leading white space - we have to post-process the name.
2790   SystemInformationStripLeadingSpace(this->ChipID.ProcessorName);
2791   return true;
2792 #else
2793   return false;
2794 #endif
2795 }
2796 
2797 
2798 /** */
RetrieveClassicalCPUIdentity()2799 bool SystemInformationImplementation::RetrieveClassicalCPUIdentity()
2800 {
2801   // Start by decided which manufacturer we are using....
2802   switch (this->ChipManufacturer)
2803     {
2804     case Intel:
2805       // Check the family / model / revision to determine the CPU ID.
2806       switch (this->ChipID.Family) {
2807         case 3:
2808           this->ChipID.ProcessorName =  "Newer i80386 family";
2809           break;
2810         case 4:
2811           switch (this->ChipID.Model) {
2812             case 0: this->ChipID.ProcessorName = "i80486DX-25/33"; break;
2813             case 1: this->ChipID.ProcessorName = "i80486DX-50"; break;
2814             case 2: this->ChipID.ProcessorName = "i80486SX"; break;
2815             case 3: this->ChipID.ProcessorName = "i80486DX2"; break;
2816             case 4: this->ChipID.ProcessorName = "i80486SL"; break;
2817             case 5: this->ChipID.ProcessorName = "i80486SX2"; break;
2818             case 7: this->ChipID.ProcessorName = "i80486DX2 WriteBack"; break;
2819             case 8: this->ChipID.ProcessorName = "i80486DX4"; break;
2820             case 9: this->ChipID.ProcessorName = "i80486DX4 WriteBack"; break;
2821             default: this->ChipID.ProcessorName = "Unknown 80486 family"; return false;
2822             }
2823           break;
2824         case 5:
2825           switch (this->ChipID.Model)
2826             {
2827             case 0: this->ChipID.ProcessorName = "P5 A-Step"; break;
2828             case 1: this->ChipID.ProcessorName = "P5"; break;
2829             case 2: this->ChipID.ProcessorName = "P54C"; break;
2830             case 3: this->ChipID.ProcessorName = "P24T OverDrive"; break;
2831             case 4: this->ChipID.ProcessorName = "P55C"; break;
2832             case 7: this->ChipID.ProcessorName = "P54C"; break;
2833             case 8: this->ChipID.ProcessorName = "P55C (0.25micron)"; break;
2834             default: this->ChipID.ProcessorName = "Unknown Pentium family"; return false;
2835             }
2836           break;
2837         case 6:
2838           switch (this->ChipID.Model)
2839             {
2840             case 0: this->ChipID.ProcessorName = "P6 A-Step"; break;
2841             case 1: this->ChipID.ProcessorName = "P6"; break;
2842             case 3: this->ChipID.ProcessorName = "Pentium II (0.28 micron)"; break;
2843             case 5: this->ChipID.ProcessorName = "Pentium II (0.25 micron)"; break;
2844             case 6: this->ChipID.ProcessorName = "Pentium II With On-Die L2 Cache"; break;
2845             case 7: this->ChipID.ProcessorName = "Pentium III (0.25 micron)"; break;
2846             case 8: this->ChipID.ProcessorName = "Pentium III (0.18 micron) With 256 KB On-Die L2 Cache "; break;
2847             case 0xa: this->ChipID.ProcessorName = "Pentium III (0.18 micron) With 1 Or 2 MB On-Die L2 Cache "; break;
2848             case 0xb: this->ChipID.ProcessorName = "Pentium III (0.13 micron) With 256 Or 512 KB On-Die L2 Cache "; break;
2849             case 23: this->ChipID.ProcessorName =  "Intel(R) Core(TM)2 Duo CPU     T9500  @ 2.60GHz"; break;
2850             default: this->ChipID.ProcessorName = "Unknown P6 family"; return false;
2851             }
2852           break;
2853         case 7:
2854           this->ChipID.ProcessorName = "Intel Merced (IA-64)";
2855           break;
2856         case 0xf:
2857           // Check the extended family bits...
2858           switch (this->ChipID.ExtendedFamily)
2859             {
2860             case 0:
2861               switch (this->ChipID.Model)
2862                 {
2863                 case 0: this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; break;
2864                 case 1: this->ChipID.ProcessorName = "Pentium IV (0.18 micron)"; break;
2865                 case 2: this->ChipID.ProcessorName = "Pentium IV (0.13 micron)"; break;
2866                 default: this->ChipID.ProcessorName = "Unknown Pentium 4 family"; return false;
2867                 }
2868               break;
2869             case 1:
2870               this->ChipID.ProcessorName = "Intel McKinley (IA-64)";
2871               break;
2872             default:
2873               this->ChipID.ProcessorName = "Pentium";
2874             }
2875           break;
2876         default:
2877           this->ChipID.ProcessorName = "Unknown Intel family";
2878           return false;
2879         }
2880       break;
2881 
2882     case AMD:
2883       // Check the family / model / revision to determine the CPU ID.
2884       switch (this->ChipID.Family)
2885         {
2886         case 4:
2887           switch (this->ChipID.Model)
2888             {
2889             case 3: this->ChipID.ProcessorName = "80486DX2"; break;
2890             case 7: this->ChipID.ProcessorName = "80486DX2 WriteBack"; break;
2891             case 8: this->ChipID.ProcessorName = "80486DX4"; break;
2892             case 9: this->ChipID.ProcessorName = "80486DX4 WriteBack"; break;
2893             case 0xe: this->ChipID.ProcessorName = "5x86"; break;
2894             case 0xf: this->ChipID.ProcessorName = "5x86WB"; break;
2895             default: this->ChipID.ProcessorName = "Unknown 80486 family"; return false;
2896             }
2897           break;
2898         case 5:
2899           switch (this->ChipID.Model)
2900             {
2901             case 0: this->ChipID.ProcessorName = "SSA5 (PR75, PR90 =  PR100)"; break;
2902             case 1: this->ChipID.ProcessorName = "5k86 (PR120 =  PR133)"; break;
2903             case 2: this->ChipID.ProcessorName = "5k86 (PR166)"; break;
2904             case 3: this->ChipID.ProcessorName = "5k86 (PR200)"; break;
2905             case 6: this->ChipID.ProcessorName = "K6 (0.30 micron)"; break;
2906             case 7: this->ChipID.ProcessorName = "K6 (0.25 micron)"; break;
2907             case 8: this->ChipID.ProcessorName = "K6-2"; break;
2908             case 9: this->ChipID.ProcessorName = "K6-III"; break;
2909             case 0xd: this->ChipID.ProcessorName = "K6-2+ or K6-III+ (0.18 micron)"; break;
2910             default: this->ChipID.ProcessorName = "Unknown 80586 family"; return false;
2911             }
2912           break;
2913         case 6:
2914           switch (this->ChipID.Model)
2915             {
2916             case 1: this->ChipID.ProcessorName = "Athlon- (0.25 micron)"; break;
2917             case 2: this->ChipID.ProcessorName = "Athlon- (0.18 micron)"; break;
2918             case 3: this->ChipID.ProcessorName = "Duron- (SF core)"; break;
2919             case 4: this->ChipID.ProcessorName = "Athlon- (Thunderbird core)"; break;
2920             case 6: this->ChipID.ProcessorName = "Athlon- (Palomino core)"; break;
2921             case 7: this->ChipID.ProcessorName = "Duron- (Morgan core)"; break;
2922             case 8:
2923               if (this->Features.ExtendedFeatures.SupportsMP)
2924                 this->ChipID.ProcessorName = "Athlon - MP (Thoroughbred core)";
2925               else this->ChipID.ProcessorName = "Athlon - XP (Thoroughbred core)";
2926               break;
2927             default: this->ChipID.ProcessorName = "Unknown K7 family"; return false;
2928             }
2929           break;
2930         default:
2931           this->ChipID.ProcessorName = "Unknown AMD family";
2932           return false;
2933         }
2934       break;
2935 
2936     case Transmeta:
2937       switch (this->ChipID.Family)
2938         {
2939         case 5:
2940           switch (this->ChipID.Model)
2941             {
2942             case 4: this->ChipID.ProcessorName = "Crusoe TM3x00 and TM5x00"; break;
2943             default: this->ChipID.ProcessorName = "Unknown Crusoe family"; return false;
2944             }
2945           break;
2946         default:
2947           this->ChipID.ProcessorName = "Unknown Transmeta family";
2948           return false;
2949         }
2950       break;
2951 
2952     case Rise:
2953       switch (this->ChipID.Family)
2954         {
2955         case 5:
2956           switch (this->ChipID.Model)
2957             {
2958             case 0: this->ChipID.ProcessorName = "mP6 (0.25 micron)"; break;
2959             case 2: this->ChipID.ProcessorName = "mP6 (0.18 micron)"; break;
2960             default: this->ChipID.ProcessorName = "Unknown Rise family"; return false;
2961             }
2962           break;
2963         default:
2964           this->ChipID.ProcessorName = "Unknown Rise family";
2965           return false;
2966         }
2967       break;
2968 
2969     case UMC:
2970       switch (this->ChipID.Family)
2971         {
2972         case 4:
2973           switch (this->ChipID.Model)
2974             {
2975             case 1: this->ChipID.ProcessorName = "U5D"; break;
2976             case 2: this->ChipID.ProcessorName = "U5S"; break;
2977             default: this->ChipID.ProcessorName = "Unknown UMC family"; return false;
2978             }
2979           break;
2980         default:
2981           this->ChipID.ProcessorName = "Unknown UMC family";
2982           return false;
2983         }
2984       break;
2985 
2986     case IDT:
2987       switch (this->ChipID.Family)
2988         {
2989         case 5:
2990           switch (this->ChipID.Model)
2991             {
2992             case 4: this->ChipID.ProcessorName = "C6"; break;
2993             case 8: this->ChipID.ProcessorName = "C2"; break;
2994             case 9: this->ChipID.ProcessorName = "C3"; break;
2995             default: this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; return false;
2996             }
2997           break;
2998         case 6:
2999           switch (this->ChipID.Model)
3000             {
3001             case 6: this->ChipID.ProcessorName = "VIA Cyrix III - Samuel"; break;
3002             default: this->ChipID.ProcessorName = "Unknown IDT\\Centaur family"; return false;
3003             }
3004           break;
3005         default:
3006           this->ChipID.ProcessorName = "Unknown IDT\\Centaur family";
3007           return false;
3008         }
3009       break;
3010 
3011     case Cyrix:
3012       switch (this->ChipID.Family)
3013         {
3014         case 4:
3015           switch (this->ChipID.Model)
3016             {
3017             case 4: this->ChipID.ProcessorName = "MediaGX GX =  GXm"; break;
3018             case 9: this->ChipID.ProcessorName = "5x86"; break;
3019             default: this->ChipID.ProcessorName = "Unknown Cx5x86 family"; return false;
3020             }
3021           break;
3022         case 5:
3023           switch (this->ChipID.Model)
3024             {
3025             case 2: this->ChipID.ProcessorName = "Cx6x86"; break;
3026             case 4: this->ChipID.ProcessorName = "MediaGX GXm"; break;
3027             default: this->ChipID.ProcessorName = "Unknown Cx6x86 family"; return false;
3028             }
3029           break;
3030         case 6:
3031           switch (this->ChipID.Model)
3032             {
3033             case 0: this->ChipID.ProcessorName = "6x86MX"; break;
3034             case 5: this->ChipID.ProcessorName = "Cyrix M2 Core"; break;
3035             case 6: this->ChipID.ProcessorName = "WinChip C5A Core"; break;
3036             case 7: this->ChipID.ProcessorName = "WinChip C5B\\C5C Core"; break;
3037             case 8: this->ChipID.ProcessorName = "WinChip C5C-T Core"; break;
3038             default: this->ChipID.ProcessorName = "Unknown 6x86MX\\Cyrix III family"; return false;
3039             }
3040           break;
3041         default:
3042           this->ChipID.ProcessorName = "Unknown Cyrix family";
3043           return false;
3044         }
3045       break;
3046 
3047     case NexGen:
3048       switch (this->ChipID.Family)
3049         {
3050         case 5:
3051           switch (this->ChipID.Model)
3052             {
3053             case 0: this->ChipID.ProcessorName = "Nx586 or Nx586FPU"; break;
3054             default: this->ChipID.ProcessorName = "Unknown NexGen family"; return false;
3055             }
3056           break;
3057         default:
3058           this->ChipID.ProcessorName = "Unknown NexGen family";
3059           return false;
3060         }
3061       break;
3062 
3063     case NSC:
3064       this->ChipID.ProcessorName = "Cx486SLC \\ DLC \\ Cx486S A-Step";
3065       break;
3066     default:
3067       this->ChipID.ProcessorName = "Unknown family"; // We cannot identify the processor.
3068       return false;
3069     }
3070 
3071   return true;
3072 }
3073 
3074 
3075 /** Extract a value from the CPUInfo file */
ExtractValueFromCpuInfoFile(kwsys_stl::string buffer,const char * word,size_t init)3076 kwsys_stl::string SystemInformationImplementation::ExtractValueFromCpuInfoFile(kwsys_stl::string buffer,const char* word,size_t init)
3077 {
3078   size_t pos = buffer.find(word,init);
3079   if(pos != buffer.npos)
3080     {
3081     this->CurrentPositionInFile = pos;
3082     pos = buffer.find(":",pos);
3083     size_t pos2 = buffer.find("\n",pos);
3084     if(pos!=buffer.npos && pos2!=buffer.npos)
3085       {
3086       // It may happen that the beginning matches, but this is still not the requested key.
3087       // An example is looking for "cpu" when "cpu family" comes first. So we check that
3088       // we have only spaces from here to pos, otherwise we search again.
3089       for(size_t i=this->CurrentPositionInFile+strlen(word); i < pos; ++i)
3090         {
3091         if(buffer[i] != ' ' && buffer[i] != '\t')
3092           {
3093           return this->ExtractValueFromCpuInfoFile(buffer, word, pos2);
3094           }
3095         }
3096       return buffer.substr(pos+2,pos2-pos-2);
3097       }
3098     }
3099   this->CurrentPositionInFile = buffer.npos;
3100   return "";
3101 }
3102 
3103 /** Query for the cpu status */
RetreiveInformationFromCpuInfoFile()3104 bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile()
3105 {
3106   this->NumberOfLogicalCPU = 0;
3107   this->NumberOfPhysicalCPU = 0;
3108   kwsys_stl::string buffer;
3109 
3110   FILE *fd = fopen("/proc/cpuinfo", "r" );
3111   if ( !fd )
3112     {
3113     kwsys_ios::cout << "Problem opening /proc/cpuinfo" << kwsys_ios::endl;
3114     return false;
3115     }
3116 
3117   size_t fileSize = 0;
3118   while(!feof(fd))
3119     {
3120     buffer += static_cast<char>(fgetc(fd));
3121     fileSize++;
3122     }
3123   fclose( fd );
3124   buffer.resize(fileSize-2);
3125   // Number of logical CPUs (combination of multiple processors, multi-core
3126   // and hyperthreading)
3127   size_t pos = buffer.find("processor\t");
3128   while(pos != buffer.npos)
3129     {
3130     this->NumberOfLogicalCPU++;
3131     pos = buffer.find("processor\t",pos+1);
3132     }
3133 
3134 #ifdef __linux
3135   // Find the largest physical id.
3136   int maxId = -1;
3137   kwsys_stl::string idc =
3138                        this->ExtractValueFromCpuInfoFile(buffer,"physical id");
3139   while(this->CurrentPositionInFile != buffer.npos)
3140     {
3141       int id = atoi(idc.c_str());
3142       if(id > maxId)
3143       {
3144        maxId=id;
3145       }
3146     idc = this->ExtractValueFromCpuInfoFile(buffer,"physical id",
3147                                             this->CurrentPositionInFile+1);
3148     }
3149   // Physical ids returned by Linux don't distinguish cores.
3150   // We want to record the total number of cores in this->NumberOfPhysicalCPU
3151   // (checking only the first proc)
3152   kwsys_stl::string cores =
3153                         this->ExtractValueFromCpuInfoFile(buffer,"cpu cores");
3154   int numberOfCoresPerCPU=atoi(cores.c_str());
3155   if (maxId > 0)
3156     {
3157     this->NumberOfPhysicalCPU=static_cast<unsigned int>(
3158       numberOfCoresPerCPU*(maxId+1));
3159     }
3160   else
3161     {
3162     // Linux Sparc: get cpu count
3163     this->NumberOfPhysicalCPU=
3164             atoi(this->ExtractValueFromCpuInfoFile(buffer,"ncpus active").c_str());
3165     }
3166 
3167 #else // __CYGWIN__
3168   // does not have "physical id" entries, neither "cpu cores"
3169   // this has to be fixed for hyper-threading.
3170   kwsys_stl::string cpucount =
3171     this->ExtractValueFromCpuInfoFile(buffer,"cpu count");
3172   this->NumberOfPhysicalCPU=
3173     this->NumberOfLogicalCPU = atoi(cpucount.c_str());
3174 #endif
3175   // gotta have one, and if this is 0 then we get a / by 0n
3176   // better to have a bad answer than a crash
3177   if(this->NumberOfPhysicalCPU <= 0)
3178     {
3179     this->NumberOfPhysicalCPU = 1;
3180     }
3181   // LogicalProcessorsPerPhysical>1 => hyperthreading.
3182   this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical=
3183       this->NumberOfLogicalCPU/this->NumberOfPhysicalCPU;
3184 
3185   // CPU speed (checking only the first processor)
3186   kwsys_stl::string CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer,"cpu MHz");
3187   if(!CPUSpeed.empty())
3188     {
3189     this->CPUSpeedInMHz = static_cast<float>(atof(CPUSpeed.c_str()));
3190     }
3191 #ifdef __linux
3192   else
3193     {
3194     // Linux Sparc: CPU speed is in Hz and encoded in hexadecimal
3195     CPUSpeed = this->ExtractValueFromCpuInfoFile(buffer,"Cpu0ClkTck");
3196     this->CPUSpeedInMHz = static_cast<float>(
3197                                  strtoull(CPUSpeed.c_str(),0,16))/1000000.0f;
3198     }
3199 #endif
3200 
3201   // Chip family
3202   kwsys_stl::string familyStr =
3203     this->ExtractValueFromCpuInfoFile(buffer,"cpu family");
3204   if(familyStr.empty())
3205     {
3206     familyStr = this->ExtractValueFromCpuInfoFile(buffer,"CPU architecture");
3207     }
3208   this->ChipID.Family = atoi(familyStr.c_str());
3209 
3210   // Chip Vendor
3211   this->ChipID.Vendor = this->ExtractValueFromCpuInfoFile(buffer,"vendor_id");
3212   this->FindManufacturer(familyStr);
3213 
3214   // second try for setting family
3215   if (this->ChipID.Family == 0 && this->ChipManufacturer == HP)
3216     {
3217     if (familyStr == "PA-RISC 1.1a")
3218       this->ChipID.Family = 0x11a;
3219     else if (familyStr == "PA-RISC 2.0")
3220       this->ChipID.Family = 0x200;
3221     // If you really get CMake to work on a machine not belonging to
3222     // any of those families I owe you a dinner if you get it to
3223     // contribute nightly builds regularly.
3224     }
3225 
3226   // Chip Model
3227   this->ChipID.Model = atoi(this->ExtractValueFromCpuInfoFile(buffer,"model").c_str());
3228   if(!this->RetrieveClassicalCPUIdentity())
3229     {
3230     // Some platforms (e.g. PA-RISC) tell us their CPU name here.
3231     // Note: x86 does not.
3232     kwsys_stl::string cpuname = this->ExtractValueFromCpuInfoFile(buffer,"cpu");
3233     if(!cpuname.empty())
3234       {
3235       this->ChipID.ProcessorName = cpuname;
3236       }
3237     }
3238 
3239   // Chip revision
3240   kwsys_stl::string cpurev = this->ExtractValueFromCpuInfoFile(buffer,"stepping");
3241   if(cpurev.empty())
3242     {
3243     cpurev = this->ExtractValueFromCpuInfoFile(buffer,"CPU revision");
3244     }
3245   this->ChipID.Revision = atoi(cpurev.c_str());
3246 
3247   // Chip Model Name
3248   this->ChipID.ModelName = this->ExtractValueFromCpuInfoFile(buffer,"model name").c_str();
3249 
3250   // L1 Cache size
3251   // Different architectures may show different names for the caches.
3252   // Sum up everything we find.
3253   kwsys_stl::vector<const char*> cachename;
3254   cachename.clear();
3255 
3256   cachename.push_back("cache size"); // e.g. x86
3257   cachename.push_back("I-cache"); // e.g. PA-RISC
3258   cachename.push_back("D-cache"); // e.g. PA-RISC
3259 
3260   this->Features.L1CacheSize = 0;
3261   for (size_t index = 0; index < cachename.size(); index ++)
3262     {
3263     kwsys_stl::string cacheSize = this->ExtractValueFromCpuInfoFile(buffer,cachename[index]);
3264     if (!cacheSize.empty())
3265       {
3266       pos = cacheSize.find(" KB");
3267       if(pos!=cacheSize.npos)
3268         {
3269         cacheSize = cacheSize.substr(0,pos);
3270         }
3271       this->Features.L1CacheSize += atoi(cacheSize.c_str());
3272       }
3273     }
3274 
3275   // processor feature flags (probably x86 specific)
3276   kwsys_stl::string cpuflags = this->ExtractValueFromCpuInfoFile(buffer,"flags");
3277   if(!cpurev.empty())
3278     {
3279     // now we can match every flags as space + flag + space
3280     cpuflags = " " + cpuflags + " ";
3281     if ((cpuflags.find(" fpu ")!=kwsys_stl::string::npos))
3282       {
3283       this->Features.HasFPU = true;
3284       }
3285     if ((cpuflags.find(" tsc ")!=kwsys_stl::string::npos))
3286       {
3287       this->Features.HasTSC = true;
3288       }
3289     if ((cpuflags.find(" mmx ")!=kwsys_stl::string::npos))
3290       {
3291       this->Features.HasMMX = true;
3292       }
3293     if ((cpuflags.find(" sse ")!=kwsys_stl::string::npos))
3294       {
3295       this->Features.HasSSE = true;
3296       }
3297     if ((cpuflags.find(" sse2 ")!=kwsys_stl::string::npos))
3298       {
3299       this->Features.HasSSE2 = true;
3300       }
3301     if ((cpuflags.find(" apic ")!=kwsys_stl::string::npos))
3302       {
3303       this->Features.HasAPIC = true;
3304       }
3305     if ((cpuflags.find(" cmov ")!=kwsys_stl::string::npos))
3306       {
3307       this->Features.HasCMOV = true;
3308       }
3309     if ((cpuflags.find(" mtrr ")!=kwsys_stl::string::npos))
3310       {
3311       this->Features.HasMTRR = true;
3312       }
3313     if ((cpuflags.find(" acpi ")!=kwsys_stl::string::npos))
3314       {
3315       this->Features.HasACPI = true;
3316       }
3317     if ((cpuflags.find(" 3dnow ")!=kwsys_stl::string::npos))
3318       {
3319       this->Features.ExtendedFeatures.Has3DNow = true;
3320       }
3321     }
3322 
3323   return true;
3324 }
3325 
QueryProcessorBySysconf()3326 bool SystemInformationImplementation::QueryProcessorBySysconf()
3327 {
3328 #if defined(_SC_NPROC_ONLN) && !defined(_SC_NPROCESSORS_ONLN)
3329 // IRIX names this slightly different
3330 # define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
3331 #endif
3332 
3333 #ifdef _SC_NPROCESSORS_ONLN
3334   long c = sysconf(_SC_NPROCESSORS_ONLN);
3335   if (c <= 0)
3336     {
3337     return false;
3338     }
3339 
3340   this->NumberOfPhysicalCPU = static_cast<unsigned int>(c);
3341   this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
3342 
3343   return true;
3344 #else
3345   return false;
3346 #endif
3347 }
3348 
QueryProcessor()3349 bool SystemInformationImplementation::QueryProcessor()
3350 {
3351   return this->QueryProcessorBySysconf();
3352 }
3353 
3354 /**
3355 Get total system RAM in units of KiB.
3356 */
3357 SystemInformation::LongLong
GetHostMemoryTotal()3358 SystemInformationImplementation::GetHostMemoryTotal()
3359 {
3360 #if defined(_WIN32)
3361 # if defined(_MSC_VER) && _MSC_VER < 1300
3362   MEMORYSTATUS stat;
3363   stat.dwLength = sizeof(stat);
3364   GlobalMemoryStatus(&stat);
3365   return stat.dwTotalPhys/1024;
3366 # else
3367   MEMORYSTATUSEX statex;
3368   statex.dwLength=sizeof(statex);
3369   GlobalMemoryStatusEx(&statex);
3370   return statex.ullTotalPhys/1024;
3371 # endif
3372 #elif defined(__linux)
3373   SystemInformation::LongLong memTotal=0;
3374   int ierr=GetFieldFromFile("/proc/meminfo","MemTotal:",memTotal);
3375   if (ierr)
3376     {
3377     return -1;
3378     }
3379   return memTotal;
3380 #elif defined(__APPLE__)
3381   uint64_t mem;
3382   size_t len = sizeof(mem);
3383   int ierr=sysctlbyname("hw.memsize", &mem, &len, NULL, 0);
3384   if (ierr)
3385     {
3386     return -1;
3387     }
3388   return mem/1024;
3389 #else
3390   return 0;
3391 #endif
3392 }
3393 
3394 /**
3395 Get total system RAM in units of KiB. This may differ from the
3396 host total if a host-wide resource limit is applied.
3397 */
3398 SystemInformation::LongLong
GetHostMemoryAvailable(const char * hostLimitEnvVarName)3399 SystemInformationImplementation::GetHostMemoryAvailable(const char *hostLimitEnvVarName)
3400 {
3401   SystemInformation::LongLong memTotal=this->GetHostMemoryTotal();
3402 
3403   // the following mechanism is provided for systems that
3404   // apply resource limits across groups of processes.
3405   // this is of use on certain SMP systems (eg. SGI UV)
3406   // where the host has a large amount of ram but a given user's
3407   // access to it is severly restricted. The system will
3408   // apply a limit across a set of processes. Units are in KiB.
3409   if (hostLimitEnvVarName)
3410     {
3411     const char *hostLimitEnvVarValue=getenv(hostLimitEnvVarName);
3412     if (hostLimitEnvVarValue)
3413       {
3414       SystemInformation::LongLong hostLimit=atoLongLong(hostLimitEnvVarValue);
3415       if (hostLimit>0)
3416         {
3417         memTotal=min(hostLimit,memTotal);
3418         }
3419       }
3420     }
3421 
3422   return memTotal;
3423 }
3424 
3425 /**
3426 Get total system RAM in units of KiB. This may differ from the
3427 host total if a per-process resource limit is applied.
3428 */
3429 SystemInformation::LongLong
GetProcMemoryAvailable(const char * hostLimitEnvVarName,const char * procLimitEnvVarName)3430 SystemInformationImplementation::GetProcMemoryAvailable(
3431         const char *hostLimitEnvVarName,
3432         const char *procLimitEnvVarName)
3433 {
3434   SystemInformation::LongLong memAvail
3435     = this->GetHostMemoryAvailable(hostLimitEnvVarName);
3436 
3437   // the following mechanism is provide for systems where rlimits
3438   // are not employed. Units are in KiB.
3439   if (procLimitEnvVarName)
3440     {
3441     const char *procLimitEnvVarValue=getenv(procLimitEnvVarName);
3442     if (procLimitEnvVarValue)
3443       {
3444       SystemInformation::LongLong procLimit=atoLongLong(procLimitEnvVarValue);
3445       if (procLimit>0)
3446         {
3447         memAvail=min(procLimit,memAvail);
3448         }
3449       }
3450     }
3451 
3452 #if defined(__linux)
3453   int ierr;
3454   ResourceLimitType rlim;
3455   ierr=GetResourceLimit(RLIMIT_DATA,&rlim);
3456   if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY))
3457     {
3458     memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail);
3459     }
3460 
3461   ierr=GetResourceLimit(RLIMIT_AS,&rlim);
3462   if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY))
3463     {
3464     memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail);
3465     }
3466 #elif defined(__APPLE__)
3467   struct rlimit rlim;
3468   int ierr;
3469   ierr=getrlimit(RLIMIT_DATA,&rlim);
3470   if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY))
3471     {
3472     memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail);
3473     }
3474 
3475   ierr=getrlimit(RLIMIT_RSS,&rlim);
3476   if ((ierr==0) && (rlim.rlim_cur != RLIM_INFINITY))
3477     {
3478     memAvail=min((SystemInformation::LongLong)rlim.rlim_cur/1024,memAvail);
3479     }
3480 #endif
3481 
3482   return memAvail;
3483 }
3484 
3485 /**
3486 Get RAM used by all processes in the host, in units of KiB.
3487 */
3488 SystemInformation::LongLong
GetHostMemoryUsed()3489 SystemInformationImplementation::GetHostMemoryUsed()
3490 {
3491 #if defined(_WIN32)
3492 # if defined(_MSC_VER) && _MSC_VER < 1300
3493   MEMORYSTATUS stat;
3494   stat.dwLength = sizeof(stat);
3495   GlobalMemoryStatus(&stat);
3496   return (stat.dwTotalPhys - stat.dwAvailPhys)/1024;
3497 # else
3498   MEMORYSTATUSEX statex;
3499   statex.dwLength=sizeof(statex);
3500   GlobalMemoryStatusEx(&statex);
3501   return (statex.ullTotalPhys - statex.ullAvailPhys)/1024;
3502 # endif
3503 #elif defined(__linux)
3504   const char *names[3]={"MemTotal:","MemFree:",NULL};
3505   SystemInformation::LongLong values[2]={SystemInformation::LongLong(0)};
3506   int ierr=GetFieldsFromFile("/proc/meminfo",names,values);
3507   if (ierr)
3508     {
3509     return ierr;
3510     }
3511   SystemInformation::LongLong &memTotal=values[0];
3512   SystemInformation::LongLong &memFree=values[1];
3513   return memTotal - memFree;
3514 #elif defined(__APPLE__)
3515   SystemInformation::LongLong psz=getpagesize();
3516   if (psz<1)
3517     {
3518     return -1;
3519     }
3520   const char *names[4]={"Pages active:","Pages inactive:","Pages wired down:",NULL};
3521   SystemInformation::LongLong values[3]={SystemInformation::LongLong(0)};
3522   int ierr=GetFieldsFromCommand("vm_stat", names, values);
3523   if (ierr)
3524     {
3525     return -1;
3526     }
3527   SystemInformation::LongLong &vmActive=values[0];
3528   SystemInformation::LongLong &vmInactive=values[1];
3529   SystemInformation::LongLong &vmWired=values[2];
3530   return ((vmActive+vmInactive+vmWired)*psz)/1024;
3531 #else
3532   return 0;
3533 #endif
3534 }
3535 
3536 /**
3537 Get system RAM used by the process associated with the given
3538 process id in units of KiB.
3539 */
3540 SystemInformation::LongLong
GetProcMemoryUsed()3541 SystemInformationImplementation::GetProcMemoryUsed()
3542 {
3543 #if defined(_WIN32) && defined(KWSYS_SYS_HAS_PSAPI)
3544   long pid=GetCurrentProcessId();
3545   HANDLE hProc;
3546   hProc=OpenProcess(
3547       PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
3548       false,
3549       pid);
3550   if (hProc==0)
3551     {
3552     return -1;
3553     }
3554   PROCESS_MEMORY_COUNTERS pmc;
3555   int ok=GetProcessMemoryInfo(hProc,&pmc,sizeof(pmc));
3556   CloseHandle(hProc);
3557   if (!ok)
3558     {
3559     return -2;
3560     }
3561   return pmc.WorkingSetSize/1024;
3562 #elif defined(__linux)
3563   SystemInformation::LongLong memUsed=0;
3564   int ierr=GetFieldFromFile("/proc/self/status","VmRSS:",memUsed);
3565   if (ierr)
3566     {
3567     return -1;
3568     }
3569   return memUsed;
3570 #elif defined(__APPLE__)
3571   SystemInformation::LongLong memUsed=0;
3572   pid_t pid=getpid();
3573   kwsys_ios::ostringstream oss;
3574   oss << "ps -o rss= -p " << pid;
3575   FILE *file=popen(oss.str().c_str(),"r");
3576   if (file==0)
3577     {
3578     return -1;
3579     }
3580   oss.str("");
3581   while (!feof(file) && !ferror(file))
3582     {
3583     char buf[256]={'\0'};
3584     errno=0;
3585     size_t nRead=fread(buf,1,256,file);
3586     if (ferror(file) && (errno==EINTR))
3587       {
3588       clearerr(file);
3589       }
3590     if (nRead) oss << buf;
3591     }
3592   int ierr=ferror(file);
3593   pclose(file);
3594   if (ierr)
3595     {
3596     return -2;
3597     }
3598   kwsys_ios::istringstream iss(oss.str());
3599   iss >> memUsed;
3600   return memUsed;
3601 #else
3602   return 0;
3603 #endif
3604 }
3605 
3606 /**
3607 Get the process id of the running process.
3608 */
3609 SystemInformation::LongLong
GetProcessId()3610 SystemInformationImplementation::GetProcessId()
3611 {
3612 #if defined(_WIN32)
3613   return GetCurrentProcessId();
3614 #elif defined(__linux) || defined(__APPLE__)
3615   return getpid();
3616 #else
3617   return -1;
3618 #endif
3619 }
3620 
3621 /**
3622 return current program stack in a string
3623 demangle cxx symbols if possible.
3624 */
GetProgramStack(int firstFrame,int wholePath)3625 kwsys_stl::string SystemInformationImplementation::GetProgramStack(
3626       int firstFrame,
3627       int wholePath)
3628 {
3629   kwsys_stl::string programStack = ""
3630 #if !defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
3631     "WARNING: The stack could not be examined "
3632     "because backtrace is not supported.\n"
3633 #elif !defined(KWSYS_SYSTEMINFORMATION_HAS_DEBUG_BUILD)
3634     "WARNING: The stack trace will not use advanced "
3635     "capabilities because this is a release build.\n"
3636 #else
3637 # if !defined(KWSYS_SYSTEMINFORMATION_HAS_SYMBOL_LOOKUP)
3638     "WARNING: Function names will not be demangled because "
3639     "dladdr is not available.\n"
3640 # endif
3641 # if !defined(KWSYS_SYSTEMINFORMATION_HAS_CPP_DEMANGLE)
3642     "WARNING: Function names will not be demangled "
3643     "because cxxabi is not available.\n"
3644 # endif
3645 #endif
3646     ;
3647 
3648   kwsys_ios::ostringstream oss;
3649 #if defined(KWSYS_SYSTEMINFORMATION_HAS_BACKTRACE)
3650   void *stackSymbols[256];
3651   int nFrames=backtrace(stackSymbols,256);
3652   for (int i=firstFrame; i<nFrames; ++i)
3653     {
3654     SymbolProperties symProps;
3655     symProps.SetReportPath(wholePath);
3656     symProps.Initialize(stackSymbols[i]);
3657     oss << symProps << kwsys_ios::endl;
3658     }
3659 #else
3660   (void)firstFrame;
3661   (void)wholePath;
3662 #endif
3663   programStack += oss.str();
3664 
3665   return programStack;
3666 }
3667 
3668 
3669 /**
3670 when set print stack trace in response to common signals.
3671 */
SetStackTraceOnError(int enable)3672 void SystemInformationImplementation::SetStackTraceOnError(int enable)
3673 {
3674 #if !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
3675   static int saOrigValid=0;
3676   static struct sigaction saABRTOrig;
3677   static struct sigaction saSEGVOrig;
3678   static struct sigaction saTERMOrig;
3679   static struct sigaction saINTOrig;
3680   static struct sigaction saILLOrig;
3681   static struct sigaction saBUSOrig;
3682   static struct sigaction saFPEOrig;
3683 
3684 
3685   if (enable && !saOrigValid)
3686     {
3687     // save the current actions
3688     sigaction(SIGABRT,0,&saABRTOrig);
3689     sigaction(SIGSEGV,0,&saSEGVOrig);
3690     sigaction(SIGTERM,0,&saTERMOrig);
3691     sigaction(SIGINT,0,&saINTOrig);
3692     sigaction(SIGILL,0,&saILLOrig);
3693     sigaction(SIGBUS,0,&saBUSOrig);
3694     sigaction(SIGFPE,0,&saFPEOrig);
3695 
3696     // enable read, disable write
3697     saOrigValid=1;
3698 
3699     // install ours
3700     struct sigaction sa;
3701     sa.sa_sigaction=(SigAction)StacktraceSignalHandler;
3702     sa.sa_flags=SA_SIGINFO|SA_RESETHAND;
3703 # ifdef SA_RESTART
3704     sa.sa_flags|=SA_RESTART;
3705 # endif
3706     sigemptyset(&sa.sa_mask);
3707 
3708     sigaction(SIGABRT,&sa,0);
3709     sigaction(SIGSEGV,&sa,0);
3710     sigaction(SIGTERM,&sa,0);
3711     sigaction(SIGINT,&sa,0);
3712     sigaction(SIGILL,&sa,0);
3713     sigaction(SIGBUS,&sa,0);
3714     sigaction(SIGFPE,&sa,0);
3715     }
3716   else
3717   if (!enable && saOrigValid)
3718     {
3719     // restore previous actions
3720     sigaction(SIGABRT,&saABRTOrig,0);
3721     sigaction(SIGSEGV,&saSEGVOrig,0);
3722     sigaction(SIGTERM,&saTERMOrig,0);
3723     sigaction(SIGINT,&saINTOrig,0);
3724     sigaction(SIGILL,&saILLOrig,0);
3725     sigaction(SIGBUS,&saBUSOrig,0);
3726     sigaction(SIGFPE,&saFPEOrig,0);
3727 
3728     // enable write, disable read
3729     saOrigValid=0;
3730     }
3731 #else
3732   // avoid warning C4100
3733   (void)enable;
3734 #endif
3735 }
3736 
QueryWindowsMemory()3737 bool SystemInformationImplementation::QueryWindowsMemory()
3738 {
3739 #if defined(_WIN32)
3740 # if defined(_MSC_VER) && _MSC_VER < 1300
3741   MEMORYSTATUS ms;
3742   unsigned long tv, tp, av, ap;
3743   ms.dwLength = sizeof(ms);
3744   GlobalMemoryStatus(&ms);
3745 #  define MEM_VAL(value) dw##value
3746 # else
3747   MEMORYSTATUSEX ms;
3748   DWORDLONG tv, tp, av, ap;
3749   ms.dwLength = sizeof(ms);
3750   if (0 == GlobalMemoryStatusEx(&ms))
3751   {
3752     return 0;
3753   }
3754 #  define MEM_VAL(value) ull##value
3755 # endif
3756   tv = ms.MEM_VAL(TotalVirtual);
3757   tp = ms.MEM_VAL(TotalPhys);
3758   av = ms.MEM_VAL(AvailVirtual);
3759   ap = ms.MEM_VAL(AvailPhys);
3760   this->TotalVirtualMemory = tv>>10>>10;
3761   this->TotalPhysicalMemory = tp>>10>>10;
3762   this->AvailableVirtualMemory = av>>10>>10;
3763   this->AvailablePhysicalMemory = ap>>10>>10;
3764   return true;
3765 #else
3766   return false;
3767 #endif
3768 }
3769 
QueryLinuxMemory()3770 bool SystemInformationImplementation::QueryLinuxMemory()
3771 {
3772 #if defined(__linux)
3773   unsigned long tv=0;
3774   unsigned long tp=0;
3775   unsigned long av=0;
3776   unsigned long ap=0;
3777 
3778   char buffer[1024]; // for reading lines
3779 
3780   int linuxMajor = 0;
3781   int linuxMinor = 0;
3782 
3783   // Find the Linux kernel version first
3784   struct utsname unameInfo;
3785   int errorFlag = uname(&unameInfo);
3786   if( errorFlag!=0 )
3787     {
3788     kwsys_ios::cout << "Problem calling uname(): " << strerror(errno) << kwsys_ios::endl;
3789     return false;
3790     }
3791 
3792   if( strlen(unameInfo.release)>=3 )
3793     {
3794     // release looks like "2.6.3-15mdk-i686-up-4GB"
3795     char majorChar=unameInfo.release[0];
3796     char minorChar=unameInfo.release[2];
3797 
3798     if( isdigit(majorChar) )
3799       {
3800       linuxMajor=majorChar-'0';
3801       }
3802 
3803     if( isdigit(minorChar) )
3804       {
3805       linuxMinor=minorChar-'0';
3806       }
3807     }
3808 
3809   FILE *fd = fopen("/proc/meminfo", "r" );
3810   if ( !fd )
3811     {
3812     kwsys_ios::cout << "Problem opening /proc/meminfo" << kwsys_ios::endl;
3813     return false;
3814     }
3815 
3816   if( linuxMajor>=3 || ( (linuxMajor>=2) && (linuxMinor>=6) ) )
3817     {
3818     // new /proc/meminfo format since kernel 2.6.x
3819     // Rigorously, this test should check from the developping version 2.5.x
3820     // that introduced the new format...
3821 
3822     enum { mMemTotal, mMemFree, mBuffers, mCached, mSwapTotal, mSwapFree };
3823     const char* format[6] =
3824       { "MemTotal:%lu kB", "MemFree:%lu kB", "Buffers:%lu kB",
3825         "Cached:%lu kB", "SwapTotal:%lu kB", "SwapFree:%lu kB" };
3826     bool have[6] = { false, false, false, false, false, false };
3827     unsigned long value[6];
3828     int count = 0;
3829     while(fgets(buffer, static_cast<int>(sizeof(buffer)), fd))
3830       {
3831       for(int i=0; i < 6; ++i)
3832         {
3833         if(!have[i] && sscanf(buffer, format[i], &value[i]) == 1)
3834           {
3835           have[i] = true;
3836           ++count;
3837           }
3838         }
3839       }
3840     if(count == 6)
3841       {
3842       this->TotalPhysicalMemory = value[mMemTotal] / 1024;
3843       this->AvailablePhysicalMemory =
3844         (value[mMemFree] + value[mBuffers] + value[mCached]) / 1024;
3845       this->TotalVirtualMemory = value[mSwapTotal] / 1024;
3846       this->AvailableVirtualMemory = value[mSwapFree] / 1024;
3847       }
3848     else
3849       {
3850       kwsys_ios::cout << "Problem parsing /proc/meminfo" << kwsys_ios::endl;
3851       fclose(fd);
3852       return false;
3853       }
3854     }
3855   else
3856     {
3857     // /proc/meminfo format for kernel older than 2.6.x
3858 
3859     unsigned long temp;
3860     unsigned long cachedMem;
3861     unsigned long buffersMem;
3862     // Skip "total: used:..."
3863     char *r=fgets(buffer, static_cast<int>(sizeof(buffer)), fd);
3864     int status=0;
3865     if(r==buffer)
3866       {
3867       status+=fscanf(fd, "Mem: %lu %lu %lu %lu %lu %lu\n",
3868                      &tp, &temp, &ap, &temp, &buffersMem, &cachedMem);
3869       }
3870     if(status==6)
3871       {
3872       status+=fscanf(fd, "Swap: %lu %lu %lu\n", &tv, &temp, &av);
3873       }
3874     if(status==9)
3875       {
3876       this->TotalVirtualMemory = tv>>10>>10;
3877       this->TotalPhysicalMemory = tp>>10>>10;
3878       this->AvailableVirtualMemory = av>>10>>10;
3879       this->AvailablePhysicalMemory = (ap+buffersMem+cachedMem)>>10>>10;
3880       }
3881     else
3882       {
3883       kwsys_ios::cout << "Problem parsing /proc/meminfo" << kwsys_ios::endl;
3884       fclose(fd);
3885       return false;
3886       }
3887     }
3888   fclose( fd );
3889 
3890   return true;
3891 #else
3892   return false;
3893 #endif
3894 }
3895 
QueryCygwinMemory()3896 bool SystemInformationImplementation::QueryCygwinMemory()
3897 {
3898 #ifdef __CYGWIN__
3899   // _SC_PAGE_SIZE does return the mmap() granularity on Cygwin,
3900   // see http://cygwin.com/ml/cygwin/2006-06/msg00350.html
3901   // Therefore just use 4096 as the page size of Windows.
3902   long m = sysconf(_SC_PHYS_PAGES);
3903   if (m < 0)
3904     {
3905     return false;
3906     }
3907   this->TotalPhysicalMemory = m >> 8;
3908   return true;
3909 #else
3910   return false;
3911 #endif
3912 }
3913 
QueryAIXMemory()3914 bool SystemInformationImplementation::QueryAIXMemory()
3915 {
3916 #if defined(_AIX) && defined(_SC_AIX_REALMEM)
3917   long c = sysconf(_SC_AIX_REALMEM);
3918   if (c <= 0)
3919     {
3920     return false;
3921     }
3922 
3923   this->TotalPhysicalMemory = c / 1024;
3924 
3925   return true;
3926 #else
3927   return false;
3928 #endif
3929 }
3930 
QueryMemoryBySysconf()3931 bool SystemInformationImplementation::QueryMemoryBySysconf()
3932 {
3933 #if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
3934   // Assume the mmap() granularity as returned by _SC_PAGESIZE is also
3935   // the system page size. The only known system where this isn't true
3936   // is Cygwin.
3937   long p = sysconf(_SC_PHYS_PAGES);
3938   long m = sysconf(_SC_PAGESIZE);
3939 
3940   if (p < 0 || m < 0)
3941     {
3942     return false;
3943     }
3944 
3945   // assume pagesize is a power of 2 and smaller 1 MiB
3946   size_t pagediv = (1024 * 1024 / m);
3947 
3948   this->TotalPhysicalMemory = p;
3949   this->TotalPhysicalMemory /= pagediv;
3950 
3951 #if defined(_SC_AVPHYS_PAGES)
3952   p = sysconf(_SC_AVPHYS_PAGES);
3953   if (p < 0)
3954     {
3955     return false;
3956     }
3957 
3958   this->AvailablePhysicalMemory = p;
3959   this->AvailablePhysicalMemory /= pagediv;
3960 #endif
3961 
3962   return true;
3963 #else
3964   return false;
3965 #endif
3966 }
3967 
3968 /** Query for the memory status */
QueryMemory()3969 bool SystemInformationImplementation::QueryMemory()
3970 {
3971   return this->QueryMemoryBySysconf();
3972 }
3973 
3974 /** */
GetTotalVirtualMemory()3975 size_t SystemInformationImplementation::GetTotalVirtualMemory()
3976 {
3977   return this->TotalVirtualMemory;
3978 }
3979 
3980 /** */
GetAvailableVirtualMemory()3981 size_t SystemInformationImplementation::GetAvailableVirtualMemory()
3982 {
3983   return this->AvailableVirtualMemory;
3984 }
3985 
GetTotalPhysicalMemory()3986 size_t SystemInformationImplementation::GetTotalPhysicalMemory()
3987 {
3988   return this->TotalPhysicalMemory;
3989 }
3990 
3991 /** */
GetAvailablePhysicalMemory()3992 size_t SystemInformationImplementation::GetAvailablePhysicalMemory()
3993 {
3994   return this->AvailablePhysicalMemory;
3995 }
3996 
3997 /** Get Cycle differences */
3998 SystemInformation::LongLong
GetCyclesDifference(DELAY_FUNC DelayFunction,unsigned int uiParameter)3999 SystemInformationImplementation::GetCyclesDifference (DELAY_FUNC DelayFunction,
4000                                                   unsigned int uiParameter)
4001 {
4002 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
4003   unsigned __int64 stamp1, stamp2;
4004 
4005   stamp1 = __rdtsc();
4006   DelayFunction(uiParameter);
4007   stamp2 = __rdtsc();
4008 
4009   return stamp2 - stamp1;
4010 #elif USE_ASM_INSTRUCTIONS
4011 
4012   unsigned int edx1, eax1;
4013   unsigned int edx2, eax2;
4014 
4015   // Calculate the frequency of the CPU instructions.
4016   __try {
4017     _asm {
4018       push uiParameter ; push parameter param
4019       mov ebx, DelayFunction ; store func in ebx
4020 
4021       RDTSC_INSTRUCTION
4022 
4023       mov esi, eax ; esi = eax
4024       mov edi, edx ; edi = edx
4025 
4026       call ebx ; call the delay functions
4027 
4028       RDTSC_INSTRUCTION
4029 
4030       pop ebx
4031 
4032       mov edx2, edx      ; edx2 = edx
4033       mov eax2, eax      ; eax2 = eax
4034 
4035       mov edx1, edi      ; edx2 = edi
4036       mov eax1, esi      ; eax2 = esi
4037     }
4038   }
4039   __except(1)
4040     {
4041     return -1;
4042     }
4043 
4044   return ((((__int64) edx2 << 32) + eax2) - (((__int64) edx1 << 32) + eax1));
4045 
4046 #else
4047   (void)DelayFunction;
4048   (void)uiParameter;
4049   return -1;
4050 #endif
4051 }
4052 
4053 
4054 /** Compute the delay overhead */
DelayOverhead(unsigned int uiMS)4055 void SystemInformationImplementation::DelayOverhead(unsigned int uiMS)
4056 {
4057 #if defined(_WIN32)
4058   LARGE_INTEGER Frequency, StartCounter, EndCounter;
4059   __int64 x;
4060 
4061   // Get the frequency of the high performance counter.
4062   if(!QueryPerformanceFrequency (&Frequency))
4063     {
4064     return;
4065     }
4066   x = Frequency.QuadPart / 1000 * uiMS;
4067 
4068   // Get the starting position of the counter.
4069   QueryPerformanceCounter (&StartCounter);
4070 
4071   do {
4072     // Get the ending position of the counter.
4073     QueryPerformanceCounter (&EndCounter);
4074   } while (EndCounter.QuadPart - StartCounter.QuadPart == x);
4075 #endif
4076   (void)uiMS;
4077 }
4078 
4079 /** Return the number of logical CPU per physical CPUs Works only for windows */
LogicalCPUPerPhysicalCPU(void)4080 unsigned char SystemInformationImplementation::LogicalCPUPerPhysicalCPU(void)
4081 {
4082 #ifdef __APPLE__
4083   size_t len = 4;
4084   int cores_per_package = 0;
4085   int err = sysctlbyname("machdep.cpu.cores_per_package", &cores_per_package, &len, NULL, 0);
4086   if (err != 0)
4087     {
4088       return 1; // That name was not found, default to 1
4089     }
4090   return static_cast<unsigned char>(cores_per_package);
4091 #else
4092   int Regs[4] = { 0, 0, 0, 0 };
4093 #if USE_CPUID
4094   if (!this->IsHyperThreadingSupported())
4095     {
4096     return static_cast<unsigned char>(1);  // HT not supported
4097     }
4098   call_cpuid(1, Regs);
4099 #endif
4100   return static_cast<unsigned char> ((Regs[1] & NUM_LOGICAL_BITS) >> 16);
4101 #endif
4102 }
4103 
4104 
4105 /** Works only for windows */
IsHyperThreadingSupported()4106 bool SystemInformationImplementation::IsHyperThreadingSupported()
4107 {
4108   if (this->Features.ExtendedFeatures.SupportsHyperthreading)
4109     {
4110     return true;
4111     }
4112 
4113 #if USE_CPUID
4114   int Regs[4] = { 0, 0, 0, 0 },
4115              VendorId[4] = { 0, 0, 0, 0 };
4116   // Get vendor id string
4117   if (!call_cpuid(0, VendorId))
4118     {
4119     return false;
4120     }
4121   // eax contains family processor type
4122   // edx has info about the availability of hyper-Threading
4123   if (!call_cpuid(1, Regs))
4124     {
4125     return false;
4126     }
4127 
4128   if (((Regs[0] & FAMILY_ID) == PENTIUM4_ID) || (Regs[0] & EXT_FAMILY_ID))
4129     {
4130     if (VendorId[1] == 0x756e6547) // 'uneG'
4131       {
4132       if (VendorId[3] == 0x49656e69) // 'Ieni'
4133         {
4134         if (VendorId[2] == 0x6c65746e) // 'letn'
4135           {
4136           // Genuine Intel with hyper-Threading technology
4137           this->Features.ExtendedFeatures.SupportsHyperthreading = ((Regs[3] & HT_BIT) != 0);
4138           return this->Features.ExtendedFeatures.SupportsHyperthreading;
4139           }
4140         }
4141       }
4142     }
4143 #endif
4144 
4145   return 0;    // Not genuine Intel processor
4146 }
4147 
4148 
4149 /** Return the APIC Id. Works only for windows. */
GetAPICId()4150 unsigned char SystemInformationImplementation::GetAPICId()
4151 {
4152   int Regs[4] = { 0, 0, 0, 0 };
4153 
4154 #if USE_CPUID
4155   if (!this->IsHyperThreadingSupported())
4156     {
4157     return static_cast<unsigned char>(-1);  // HT not supported
4158     } // Logical processor = 1
4159   call_cpuid(1, Regs);
4160 #endif
4161 
4162   return static_cast<unsigned char>((Regs[1] & INITIAL_APIC_ID_BITS) >> 24);
4163 }
4164 
4165 
4166 /** Count the number of CPUs. Works only on windows. */
CPUCount()4167 int SystemInformationImplementation::CPUCount()
4168 {
4169 #if defined(_WIN32)
4170   unsigned char StatusFlag  = 0;
4171   SYSTEM_INFO info;
4172 
4173   this->NumberOfPhysicalCPU = 0;
4174   this->NumberOfLogicalCPU = 0;
4175   info.dwNumberOfProcessors = 0;
4176   GetSystemInfo (&info);
4177 
4178   // Number of physical processors in a non-Intel system
4179   // or in a 32-bit Intel system with Hyper-Threading technology disabled
4180   this->NumberOfPhysicalCPU = (unsigned char) info.dwNumberOfProcessors;
4181 
4182   if (this->IsHyperThreadingSupported())
4183     {
4184     unsigned char HT_Enabled = 0;
4185     this->NumberOfLogicalCPU = this->LogicalCPUPerPhysicalCPU();
4186     if (this->NumberOfLogicalCPU >= 1)    // >1 Doesn't mean HT is enabled in the BIOS
4187       {
4188       HANDLE hCurrentProcessHandle;
4189 #ifndef _WIN64
4190 # define DWORD_PTR DWORD
4191 #endif
4192       DWORD_PTR  dwProcessAffinity;
4193       DWORD_PTR  dwSystemAffinity;
4194       DWORD  dwAffinityMask;
4195 
4196       // Calculate the appropriate  shifts and mask based on the
4197       // number of logical processors.
4198       unsigned int i = 1;
4199       unsigned char PHY_ID_MASK  = 0xFF;
4200       //unsigned char PHY_ID_SHIFT = 0;
4201 
4202       while (i < this->NumberOfLogicalCPU)
4203         {
4204         i *= 2;
4205          PHY_ID_MASK  <<= 1;
4206          // PHY_ID_SHIFT++;
4207         }
4208 
4209       hCurrentProcessHandle = GetCurrentProcess();
4210       GetProcessAffinityMask(hCurrentProcessHandle, &dwProcessAffinity,
4211                                                   &dwSystemAffinity);
4212 
4213       // Check if available process affinity mask is equal to the
4214       // available system affinity mask
4215       if (dwProcessAffinity != dwSystemAffinity)
4216         {
4217         StatusFlag = HT_CANNOT_DETECT;
4218         this->NumberOfPhysicalCPU = (unsigned char)-1;
4219         return StatusFlag;
4220         }
4221 
4222       dwAffinityMask = 1;
4223       while (dwAffinityMask != 0 && dwAffinityMask <= dwProcessAffinity)
4224         {
4225         // Check if this CPU is available
4226         if (dwAffinityMask & dwProcessAffinity)
4227           {
4228           if (SetProcessAffinityMask(hCurrentProcessHandle,
4229                                      dwAffinityMask))
4230             {
4231             unsigned char APIC_ID, LOG_ID;
4232             Sleep(0); // Give OS time to switch CPU
4233 
4234             APIC_ID = GetAPICId();
4235             LOG_ID  = APIC_ID & ~PHY_ID_MASK;
4236 
4237             if (LOG_ID != 0)
4238               {
4239               HT_Enabled = 1;
4240               }
4241             }
4242           }
4243         dwAffinityMask = dwAffinityMask << 1;
4244         }
4245       // Reset the processor affinity
4246       SetProcessAffinityMask(hCurrentProcessHandle, dwProcessAffinity);
4247 
4248       if (this->NumberOfLogicalCPU == 1)  // Normal P4 : HT is disabled in hardware
4249         {
4250         StatusFlag = HT_DISABLED;
4251         }
4252       else
4253         {
4254         if (HT_Enabled)
4255           {
4256           // Total physical processors in a Hyper-Threading enabled system.
4257           this->NumberOfPhysicalCPU /= (this->NumberOfLogicalCPU);
4258           StatusFlag = HT_ENABLED;
4259           }
4260         else
4261           {
4262           StatusFlag = HT_SUPPORTED_NOT_ENABLED;
4263           }
4264         }
4265       }
4266     }
4267   else
4268     {
4269     // Processors do not have Hyper-Threading technology
4270     StatusFlag = HT_NOT_CAPABLE;
4271     this->NumberOfLogicalCPU = 1;
4272     }
4273   return StatusFlag;
4274 #else
4275   return 0;
4276 #endif
4277 }
4278 
4279 
4280 /** Return the number of logical CPUs on the system */
GetNumberOfLogicalCPU()4281 unsigned int SystemInformationImplementation::GetNumberOfLogicalCPU()
4282 {
4283   return this->NumberOfLogicalCPU;
4284 }
4285 
4286 
4287 /** Return the number of physical CPUs on the system */
GetNumberOfPhysicalCPU()4288 unsigned int SystemInformationImplementation::GetNumberOfPhysicalCPU()
4289 {
4290   return this->NumberOfPhysicalCPU;
4291 }
4292 
4293 
4294 /** For Mac use sysctlbyname calls to find system info */
ParseSysCtl()4295 bool SystemInformationImplementation::ParseSysCtl()
4296 {
4297 #if defined(__APPLE__)
4298   char retBuf[128];
4299   int err = 0;
4300   uint64_t value = 0;
4301   size_t len = sizeof(value);
4302   sysctlbyname("hw.memsize", &value, &len, NULL, 0);
4303   this->TotalPhysicalMemory = static_cast< size_t >( value/1048576 );
4304 
4305   // Parse values for Mac
4306   this->AvailablePhysicalMemory = 0;
4307   vm_statistics_data_t  vmstat;
4308   mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
4309   if ( host_statistics(mach_host_self(), HOST_VM_INFO,
4310                        (host_info_t) &vmstat, &count) == KERN_SUCCESS )
4311     {
4312     len = sizeof(value);
4313     err = sysctlbyname("hw.pagesize", &value, &len, NULL, 0);
4314     int64_t available_memory = vmstat.free_count * value;
4315     this->AvailablePhysicalMemory = static_cast< size_t >( available_memory / 1048576 );
4316     }
4317 
4318 #ifdef VM_SWAPUSAGE
4319   // Virtual memory.
4320   int mib[2] = { CTL_VM, VM_SWAPUSAGE };
4321   size_t miblen = sizeof(mib) / sizeof(mib[0]);
4322   struct xsw_usage swap;
4323   len = sizeof(swap);
4324   err = sysctl(mib, miblen, &swap, &len, NULL, 0);
4325   if (err == 0)
4326     {
4327     this->AvailableVirtualMemory = static_cast< size_t >( swap.xsu_avail/1048576 );
4328     this->TotalVirtualMemory = static_cast< size_t >( swap.xsu_total/1048576 );
4329     }
4330 #else
4331    this->AvailableVirtualMemory = 0;
4332    this->TotalVirtualMemory = 0;
4333 #endif
4334 
4335 // CPU Info
4336   len = sizeof(this->NumberOfPhysicalCPU);
4337   sysctlbyname("hw.physicalcpu", &this->NumberOfPhysicalCPU, &len, NULL, 0);
4338   len = sizeof(this->NumberOfLogicalCPU);
4339   sysctlbyname("hw.logicalcpu", &this->NumberOfLogicalCPU, &len, NULL, 0);
4340   this->Features.ExtendedFeatures.LogicalProcessorsPerPhysical =
4341     this->LogicalCPUPerPhysicalCPU();
4342 
4343   len = sizeof(value);
4344   sysctlbyname("hw.cpufrequency", &value, &len, NULL, 0);
4345   this->CPUSpeedInMHz = static_cast< float >( value )/ 1000000;
4346 
4347 
4348   // Chip family
4349   len = sizeof(this->ChipID.Family);
4350   //Seems only the intel chips will have this name so if this fails it is
4351   //probably a PPC machine
4352   err = sysctlbyname("machdep.cpu.family",
4353                      &this->ChipID.Family, &len, NULL, 0);
4354   if (err != 0) // Go back to names we know but are less descriptive
4355     {
4356     this->ChipID.Family = 0;
4357     ::memset(retBuf, 0, 128);
4358     len = 32;
4359     err = sysctlbyname("hw.machine", &retBuf, &len, NULL, 0);
4360     kwsys_stl::string machineBuf(retBuf);
4361     if (machineBuf.find_first_of("Power") != kwsys_stl::string::npos)
4362       {
4363       this->ChipID.Vendor = "IBM";
4364       len = sizeof(this->ChipID.Family);
4365       err = sysctlbyname("hw.cputype", &this->ChipID.Family, &len, NULL, 0);
4366       len = sizeof(this->ChipID.Model);
4367       err = sysctlbyname("hw.cpusubtype", &this->ChipID.Model, &len, NULL, 0);
4368       this->FindManufacturer();
4369       }
4370     }
4371   else  // Should be an Intel Chip.
4372     {
4373     len = sizeof(this->ChipID.Family);
4374     err =
4375       sysctlbyname("machdep.cpu.family", &this->ChipID.Family, &len, NULL, 0);
4376 
4377     ::memset(retBuf, 0, 128);
4378     len = 128;
4379     err = sysctlbyname("machdep.cpu.vendor", retBuf, &len, NULL, 0);
4380     // Chip Vendor
4381     this->ChipID.Vendor = retBuf;
4382     this->FindManufacturer();
4383 
4384     // Chip Model
4385     len = sizeof(value);
4386     err = sysctlbyname("machdep.cpu.model", &value, &len, NULL, 0);
4387     this->ChipID.Model = static_cast< int >( value );
4388 
4389     // Chip Stepping
4390     len = sizeof(value);
4391     value = 0;
4392     err = sysctlbyname("machdep.cpu.stepping", &value, &len, NULL, 0);
4393     if (!err)
4394       {
4395       this->ChipID.Revision = static_cast< int >( value );
4396       }
4397 
4398     // feature string
4399     char *buf = 0;
4400     size_t allocSize = 128;
4401 
4402     err = 0;
4403     len = 0;
4404 
4405     // sysctlbyname() will return with err==0 && len==0 if the buffer is too small
4406     while (err == 0 && len == 0)
4407       {
4408       delete[] buf;
4409       allocSize *= 2;
4410       buf = new char[allocSize];
4411       if (!buf)
4412         {
4413         break;
4414         }
4415       buf[0] = ' ';
4416       len = allocSize - 2; // keep space for leading and trailing space
4417       err = sysctlbyname("machdep.cpu.features", buf + 1, &len, NULL, 0);
4418       }
4419     if (!err && buf && len)
4420       {
4421       // now we can match every flags as space + flag + space
4422       buf[len + 1] = ' ';
4423       kwsys_stl::string cpuflags(buf, len + 2);
4424 
4425       if ((cpuflags.find(" FPU ")!=kwsys_stl::string::npos))
4426         {
4427         this->Features.HasFPU = true;
4428         }
4429       if ((cpuflags.find(" TSC ")!=kwsys_stl::string::npos))
4430         {
4431         this->Features.HasTSC = true;
4432         }
4433       if ((cpuflags.find(" MMX ")!=kwsys_stl::string::npos))
4434         {
4435         this->Features.HasMMX = true;
4436         }
4437       if ((cpuflags.find(" SSE ")!=kwsys_stl::string::npos))
4438         {
4439         this->Features.HasSSE = true;
4440         }
4441       if ((cpuflags.find(" SSE2 ")!=kwsys_stl::string::npos))
4442         {
4443         this->Features.HasSSE2 = true;
4444         }
4445       if ((cpuflags.find(" APIC ")!=kwsys_stl::string::npos))
4446         {
4447         this->Features.HasAPIC = true;
4448         }
4449       if ((cpuflags.find(" CMOV ")!=kwsys_stl::string::npos))
4450         {
4451         this->Features.HasCMOV = true;
4452         }
4453       if ((cpuflags.find(" MTRR ")!=kwsys_stl::string::npos))
4454         {
4455         this->Features.HasMTRR = true;
4456         }
4457       if ((cpuflags.find(" ACPI ")!=kwsys_stl::string::npos))
4458         {
4459         this->Features.HasACPI = true;
4460         }
4461       }
4462     delete[] buf;
4463     }
4464 
4465   // brand string
4466   ::memset(retBuf, 0, sizeof(retBuf));
4467   len = sizeof(retBuf);
4468   err = sysctlbyname("machdep.cpu.brand_string", retBuf, &len, NULL, 0);
4469   if (!err)
4470     {
4471     this->ChipID.ProcessorName = retBuf;
4472     this->ChipID.ModelName = retBuf;
4473     }
4474 
4475   // Cache size
4476   len = sizeof(value);
4477   err = sysctlbyname("hw.l1icachesize", &value, &len, NULL, 0);
4478   this->Features.L1CacheSize = static_cast< int >( value );
4479   len = sizeof(value);
4480   err = sysctlbyname("hw.l2cachesize", &value, &len, NULL, 0);
4481   this->Features.L2CacheSize = static_cast< int >( value );
4482 
4483   return true;
4484 #else
4485   return false;
4486 #endif
4487 }
4488 
4489 
4490 /** Extract a value from sysctl command */
ExtractValueFromSysCtl(const char * word)4491 kwsys_stl::string SystemInformationImplementation::ExtractValueFromSysCtl(const char* word)
4492 {
4493   size_t pos = this->SysCtlBuffer.find(word);
4494   if(pos != this->SysCtlBuffer.npos)
4495     {
4496     pos = this->SysCtlBuffer.find(": ",pos);
4497     size_t pos2 = this->SysCtlBuffer.find("\n",pos);
4498     if(pos!=this->SysCtlBuffer.npos && pos2!=this->SysCtlBuffer.npos)
4499       {
4500       return this->SysCtlBuffer.substr(pos+2,pos2-pos-2);
4501       }
4502     }
4503   return "";
4504 }
4505 
4506 
4507 /** Run a given process */
RunProcess(kwsys_stl::vector<const char * > args)4508 kwsys_stl::string SystemInformationImplementation::RunProcess(kwsys_stl::vector<const char*> args)
4509 {
4510   kwsys_stl::string buffer = "";
4511 
4512   // Run the application
4513   kwsysProcess* gp = kwsysProcess_New();
4514   kwsysProcess_SetCommand(gp, &*args.begin());
4515   kwsysProcess_SetOption(gp,kwsysProcess_Option_HideWindow,1);
4516 
4517   kwsysProcess_Execute(gp);
4518 
4519   char* data = NULL;
4520   int length;
4521   double timeout = 255;
4522   int pipe; // pipe id as returned by kwsysProcess_WaitForData()
4523 
4524   while( ( pipe = kwsysProcess_WaitForData(gp,&data,&length,&timeout),
4525            (pipe == kwsysProcess_Pipe_STDOUT || pipe == kwsysProcess_Pipe_STDERR) ) ) // wait for 1s
4526     {
4527       buffer.append(data, length);
4528     }
4529   kwsysProcess_WaitForExit(gp, 0);
4530 
4531   int result = 0;
4532   switch(kwsysProcess_GetState(gp))
4533     {
4534     case kwsysProcess_State_Exited:
4535       {
4536       result = kwsysProcess_GetExitValue(gp);
4537       } break;
4538     case kwsysProcess_State_Error:
4539       {
4540       kwsys_ios::cerr << "Error: Could not run " << args[0] << ":\n";
4541       kwsys_ios::cerr << kwsysProcess_GetErrorString(gp) << "\n";
4542       } break;
4543     case kwsysProcess_State_Exception:
4544       {
4545       kwsys_ios::cerr << "Error: " << args[0]
4546                 << " terminated with an exception: "
4547                 << kwsysProcess_GetExceptionString(gp) << "\n";
4548       } break;
4549     case kwsysProcess_State_Starting:
4550     case kwsysProcess_State_Executing:
4551     case kwsysProcess_State_Expired:
4552     case kwsysProcess_State_Killed:
4553       {
4554       // Should not get here.
4555       kwsys_ios::cerr << "Unexpected ending state after running " << args[0]
4556                 << kwsys_ios::endl;
4557       } break;
4558     }
4559   kwsysProcess_Delete(gp);
4560   if(result)
4561     {
4562     kwsys_ios::cerr << "Error " << args[0] << " returned :" << result << "\n";
4563     }
4564   return buffer;
4565 }
4566 
4567 
ParseValueFromKStat(const char * arguments)4568 kwsys_stl::string SystemInformationImplementation::ParseValueFromKStat(const char* arguments)
4569 {
4570   kwsys_stl::vector<const char*> args;
4571   args.clear();
4572   args.push_back("kstat");
4573   args.push_back("-p");
4574 
4575   kwsys_stl::string command = arguments;
4576   size_t start = command.npos;
4577   size_t pos = command.find(' ',0);
4578   while(pos!=command.npos)
4579     {
4580     bool inQuotes = false;
4581     // Check if we are between quotes
4582     size_t b0 = command.find('"',0);
4583     size_t b1 = command.find('"',b0+1);
4584     while(b0 != command.npos && b1 != command.npos && b1>b0)
4585       {
4586       if(pos>b0 && pos<b1)
4587         {
4588         inQuotes = true;
4589         break;
4590         }
4591       b0 = command.find('"',b1+1);
4592       b1 = command.find('"',b0+1);
4593       }
4594 
4595     if(!inQuotes)
4596       {
4597       kwsys_stl::string arg = command.substr(start+1,pos-start-1);
4598 
4599       // Remove the quotes if any
4600       size_t quotes = arg.find('"');
4601       while(quotes != arg.npos)
4602         {
4603         arg.erase(quotes,1);
4604         quotes = arg.find('"');
4605         }
4606       args.push_back(arg.c_str());
4607       start = pos;
4608       }
4609     pos = command.find(' ',pos+1);
4610     }
4611   kwsys_stl::string lastArg = command.substr(start+1,command.size()-start-1);
4612   args.push_back(lastArg.c_str());
4613 
4614   args.push_back(0);
4615 
4616   kwsys_stl::string buffer = this->RunProcess(args);
4617 
4618   kwsys_stl::string value = "";
4619   for(size_t i=buffer.size()-1;i>0;i--)
4620     {
4621     if(buffer[i] == ' ' || buffer[i] == '\t')
4622       {
4623       break;
4624       }
4625     if(buffer[i] != '\n' && buffer[i] != '\r')
4626       {
4627       kwsys_stl::string val = value;
4628       value = buffer[i];
4629       value += val;
4630       }
4631     }
4632   return value;
4633 }
4634 
4635 /** Querying for system information from Solaris */
QuerySolarisMemory()4636 bool SystemInformationImplementation::QuerySolarisMemory()
4637 {
4638 #if defined (__SVR4) && defined (__sun)
4639   // Solaris allows querying this value by sysconf, but if this is
4640   // a 32 bit process on a 64 bit host the returned memory will be
4641   // limited to 4GiB. So if this is a 32 bit process or if the sysconf
4642   // method fails use the kstat interface.
4643 #if SIZEOF_VOID_P == 8
4644   if (this->QueryMemoryBySysconf())
4645     {
4646     return true;
4647     }
4648 #endif
4649 
4650   char* tail;
4651   unsigned long totalMemory =
4652        strtoul(this->ParseValueFromKStat("-s physmem").c_str(),&tail,0);
4653   this->TotalPhysicalMemory = totalMemory/128;
4654 
4655   return true;
4656 #else
4657   return false;
4658 #endif
4659 }
4660 
QuerySolarisProcessor()4661 bool SystemInformationImplementation::QuerySolarisProcessor()
4662 {
4663   if (!this->QueryProcessorBySysconf())
4664     {
4665     return false;
4666     }
4667 
4668   // Parse values
4669   this->CPUSpeedInMHz = static_cast<float>(atoi(this->ParseValueFromKStat("-s clock_MHz").c_str()));
4670 
4671   // Chip family
4672   this->ChipID.Family = 0;
4673 
4674   // Chip Model
4675   this->ChipID.ProcessorName = this->ParseValueFromKStat("-s cpu_type");
4676   this->ChipID.Model = 0;
4677 
4678   // Chip Vendor
4679   if (this->ChipID.ProcessorName != "i386")
4680     {
4681     this->ChipID.Vendor = "Sun";
4682     this->FindManufacturer();
4683     }
4684 
4685   return true;
4686 }
4687 
4688 
4689 /** Querying for system information from Haiku OS */
QueryHaikuInfo()4690 bool SystemInformationImplementation::QueryHaikuInfo()
4691 {
4692 #if defined(__HAIKU__)
4693 
4694   // CPU count
4695   system_info info;
4696   get_system_info(&info);
4697   this->NumberOfPhysicalCPU = info.cpu_count;
4698 
4699   // CPU speed
4700   uint32 topologyNodeCount = 0;
4701   cpu_topology_node_info* topology = 0;
4702   get_cpu_topology_info(0, &topologyNodeCount);
4703   if (topologyNodeCount != 0)
4704     topology = new cpu_topology_node_info[topologyNodeCount];
4705   get_cpu_topology_info(topology, &topologyNodeCount);
4706 
4707   for (uint32 i = 0; i < topologyNodeCount; i++) {
4708     if (topology[i].type == B_TOPOLOGY_CORE) {
4709       this->CPUSpeedInMHz = topology[i].data.core.default_frequency /
4710         1000000.0f;
4711       break;
4712     }
4713   }
4714 
4715   delete[] topology;
4716 
4717   // Physical Memory
4718   this->TotalPhysicalMemory = (info.max_pages * B_PAGE_SIZE) / (1024 * 1024) ;
4719   this->AvailablePhysicalMemory = this->TotalPhysicalMemory -
4720     ((info.used_pages * B_PAGE_SIZE) / (1024 * 1024));
4721 
4722 
4723   // NOTE: get_system_info_etc is currently a private call so just set to 0
4724   // until it becomes public
4725   this->TotalVirtualMemory = 0;
4726   this->AvailableVirtualMemory = 0;
4727 
4728   // Retrieve cpuid_info union for cpu 0
4729   cpuid_info cpu_info;
4730   get_cpuid(&cpu_info, 0, 0);
4731 
4732   // Chip Vendor
4733   // Use a temporary buffer so that we can add NULL termination to the string
4734   char vbuf[13];
4735   strncpy(vbuf, cpu_info.eax_0.vendor_id, 12);
4736   vbuf[12] = '\0';
4737   this->ChipID.Vendor = vbuf;
4738 
4739   this->FindManufacturer();
4740 
4741   // Retrieve cpuid_info union for cpu 0 this time using a register value of 1
4742   get_cpuid(&cpu_info, 1, 0);
4743 
4744   this->NumberOfLogicalCPU = cpu_info.eax_1.logical_cpus;
4745 
4746   // Chip type
4747   this->ChipID.Type = cpu_info.eax_1.type;
4748 
4749   // Chip family
4750   this->ChipID.Family = cpu_info.eax_1.family;
4751 
4752   // Chip Model
4753   this->ChipID.Model = cpu_info.eax_1.model;
4754 
4755   // Chip Revision
4756   this->ChipID.Revision = cpu_info.eax_1.stepping;
4757 
4758   // Chip Extended Family
4759   this->ChipID.ExtendedFamily = cpu_info.eax_1.extended_family;
4760 
4761   // Chip Extended Model
4762   this->ChipID.ExtendedModel = cpu_info.eax_1.extended_model;
4763 
4764   // Get ChipID.ProcessorName from other information already gathered
4765   this->RetrieveClassicalCPUIdentity();
4766 
4767   // Cache size
4768   this->Features.L1CacheSize = 0;
4769   this->Features.L2CacheSize = 0;
4770 
4771   return true;
4772 
4773 #else
4774   return false;
4775 #endif
4776 }
4777 
QueryQNXMemory()4778 bool SystemInformationImplementation::QueryQNXMemory()
4779 {
4780 #if defined(__QNX__)
4781   kwsys_stl::string buffer;
4782   kwsys_stl::vector<const char*> args;
4783   args.clear();
4784 
4785   args.push_back("showmem");
4786   args.push_back("-S");
4787   args.push_back(0);
4788   buffer = this->RunProcess(args);
4789   args.clear();
4790 
4791   size_t pos = buffer.find("System RAM:");
4792   if (pos == buffer.npos)
4793     return false;
4794   pos = buffer.find(":", pos);
4795   size_t pos2 = buffer.find("M (", pos);
4796   if (pos2 == buffer.npos)
4797     return false;
4798 
4799   pos++;
4800   while (buffer[pos] == ' ')
4801     pos++;
4802 
4803   this->TotalPhysicalMemory = atoi(buffer.substr(pos, pos2 - pos).c_str());
4804   return true;
4805 #endif
4806   return false;
4807 }
4808 
QueryBSDMemory()4809 bool SystemInformationImplementation::QueryBSDMemory()
4810 {
4811 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
4812   int ctrl[2] = { CTL_HW, HW_PHYSMEM };
4813 #if defined(HW_PHYSMEM64)
4814   int64_t k;
4815   ctrl[1] = HW_PHYSMEM64;
4816 #else
4817   int k;
4818 #endif
4819   size_t sz = sizeof(k);
4820 
4821   if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0)
4822     {
4823     return false;
4824     }
4825 
4826   this->TotalPhysicalMemory = k>>10>>10;
4827 
4828   return true;
4829 #else
4830   return false;
4831 #endif
4832 }
4833 
QueryQNXProcessor()4834 bool SystemInformationImplementation::QueryQNXProcessor()
4835 {
4836 #if defined(__QNX__)
4837   // the output on my QNX 6.4.1 looks like this:
4838   // Processor1: 686 Pentium II Stepping 3 2175MHz FPU
4839   kwsys_stl::string buffer;
4840   kwsys_stl::vector<const char*> args;
4841   args.clear();
4842 
4843   args.push_back("pidin");
4844   args.push_back("info");
4845   args.push_back(0);
4846   buffer = this->RunProcess(args);
4847   args.clear();
4848 
4849   size_t pos = buffer.find("Processor1:");
4850   if (pos == buffer.npos)
4851     return false;
4852 
4853   size_t pos2 = buffer.find("MHz", pos);
4854   if (pos2 == buffer.npos)
4855     return false;
4856 
4857   size_t pos3 = pos2;
4858   while (buffer[pos3] != ' ')
4859     --pos3;
4860 
4861   this->CPUSpeedInMHz = atoi(buffer.substr(pos3 + 1, pos2 - pos3 - 1).c_str());
4862 
4863   pos2 = buffer.find(" Stepping", pos);
4864   if (pos2 != buffer.npos)
4865     {
4866     pos2 = buffer.find(" ", pos2 + 1);
4867     if (pos2 != buffer.npos && pos2 < pos3)
4868       {
4869       this->ChipID.Revision = atoi(buffer.substr(pos2 + 1, pos3 - pos2).c_str());
4870       }
4871     }
4872 
4873   this->NumberOfPhysicalCPU = 0;
4874   do
4875     {
4876     pos = buffer.find("\nProcessor", pos + 1);
4877     ++this->NumberOfPhysicalCPU;
4878     } while (pos != buffer.npos);
4879   this->NumberOfLogicalCPU = 1;
4880 
4881   return true;
4882 #else
4883   return false;
4884 #endif
4885 }
4886 
QueryBSDProcessor()4887 bool SystemInformationImplementation::QueryBSDProcessor()
4888 {
4889 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
4890   int k;
4891   size_t sz = sizeof(k);
4892   int ctrl[2] = { CTL_HW, HW_NCPU };
4893 
4894   if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0)
4895     {
4896     return false;
4897     }
4898 
4899   this->NumberOfPhysicalCPU = k;
4900   this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
4901 
4902 #if defined(HW_CPUSPEED)
4903   ctrl[1] = HW_CPUSPEED;
4904 
4905   if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0)
4906     {
4907     return false;
4908     }
4909 
4910   this->CPUSpeedInMHz = (float) k;
4911 #endif
4912 
4913 #if defined(CPU_SSE)
4914   ctrl[0] = CTL_MACHDEP;
4915   ctrl[1] = CPU_SSE;
4916 
4917   if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0)
4918     {
4919     return false;
4920     }
4921 
4922   this->Features.HasSSE = (k > 0);
4923 #endif
4924 
4925 #if defined(CPU_SSE2)
4926   ctrl[0] = CTL_MACHDEP;
4927   ctrl[1] = CPU_SSE2;
4928 
4929   if (sysctl(ctrl, 2, &k, &sz, NULL, 0) != 0)
4930     {
4931     return false;
4932     }
4933 
4934   this->Features.HasSSE2 = (k > 0);
4935 #endif
4936 
4937 #if defined(CPU_CPUVENDOR)
4938   ctrl[0] = CTL_MACHDEP;
4939   ctrl[1] = CPU_CPUVENDOR;
4940   char vbuf[25];
4941   ::memset(vbuf, 0, sizeof(vbuf));
4942   sz = sizeof(vbuf) - 1;
4943   if (sysctl(ctrl, 2, vbuf, &sz, NULL, 0) != 0)
4944     {
4945     return false;
4946     }
4947 
4948   this->ChipID.Vendor = vbuf;
4949   this->FindManufacturer();
4950 #endif
4951 
4952   return true;
4953 #else
4954   return false;
4955 #endif
4956 }
4957 
QueryHPUXMemory()4958 bool SystemInformationImplementation::QueryHPUXMemory()
4959 {
4960 #if defined(__hpux)
4961   unsigned long tv=0;
4962   unsigned long tp=0;
4963   unsigned long av=0;
4964   unsigned long ap=0;
4965   struct pst_static pst;
4966   struct pst_dynamic pdy;
4967 
4968   unsigned long ps = 0;
4969   if (pstat_getstatic(&pst, sizeof(pst), (size_t) 1, 0) == -1)
4970     {
4971     return false;
4972     }
4973 
4974   ps = pst.page_size;
4975   tp =  pst.physical_memory *ps;
4976   tv = (pst.physical_memory + pst.pst_maxmem) * ps;
4977   if (pstat_getdynamic(&pdy, sizeof(pdy), (size_t) 1, 0) == -1)
4978     {
4979     return false;
4980     }
4981 
4982   ap = tp - pdy.psd_rm * ps;
4983   av = tv - pdy.psd_vm;
4984   this->TotalVirtualMemory = tv>>10>>10;
4985   this->TotalPhysicalMemory = tp>>10>>10;
4986   this->AvailableVirtualMemory = av>>10>>10;
4987   this->AvailablePhysicalMemory = ap>>10>>10;
4988   return true;
4989 #else
4990   return false;
4991 #endif
4992 }
4993 
QueryHPUXProcessor()4994 bool SystemInformationImplementation::QueryHPUXProcessor()
4995 {
4996 #if defined(__hpux)
4997 # if defined(KWSYS_SYS_HAS_MPCTL_H)
4998   int c = mpctl(MPC_GETNUMSPUS_SYS, 0, 0);
4999   if (c <= 0)
5000     {
5001     return false;
5002     }
5003 
5004   this->NumberOfPhysicalCPU = c;
5005   this->NumberOfLogicalCPU = this->NumberOfPhysicalCPU;
5006 
5007   long t = sysconf(_SC_CPU_VERSION);
5008 
5009   if (t == -1)
5010     {
5011     return false;
5012     }
5013 
5014   switch (t)
5015     {
5016     case CPU_PA_RISC1_0:
5017       this->ChipID.Vendor = "Hewlett-Packard";
5018       this->ChipID.Family = 0x100;
5019       break;
5020     case CPU_PA_RISC1_1:
5021       this->ChipID.Vendor = "Hewlett-Packard";
5022       this->ChipID.Family = 0x110;
5023       break;
5024     case CPU_PA_RISC2_0:
5025       this->ChipID.Vendor = "Hewlett-Packard";
5026       this->ChipID.Family = 0x200;
5027       break;
5028 #  if defined(CPU_HP_INTEL_EM_1_0) || defined(CPU_IA64_ARCHREV_0)
5029 #   ifdef CPU_HP_INTEL_EM_1_0
5030     case CPU_HP_INTEL_EM_1_0:
5031 #   endif
5032 #   ifdef CPU_IA64_ARCHREV_0
5033     case CPU_IA64_ARCHREV_0:
5034 #   endif
5035       this->ChipID.Vendor = "GenuineIntel";
5036       this->Features.HasIA64 = true;
5037       break;
5038 #  endif
5039     default:
5040       return false;
5041     }
5042 
5043   this->FindManufacturer();
5044 
5045   return true;
5046 # else
5047   return false;
5048 # endif
5049 #else
5050   return false;
5051 #endif
5052 }
5053 
5054 /** Query the operating system information */
QueryOSInformation()5055 bool SystemInformationImplementation::QueryOSInformation()
5056 {
5057 #if defined(_WIN32)
5058 
5059   this->OSName = "Windows";
5060 
5061   OSVERSIONINFOEXW osvi;
5062   BOOL bIsWindows64Bit;
5063   BOOL bOsVersionInfoEx;
5064   char operatingSystem[256];
5065 
5066   // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
5067   ZeroMemory (&osvi, sizeof (OSVERSIONINFOEXW));
5068   osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW);
5069 #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
5070 # pragma warning (push)
5071 # pragma warning (disable:4996)
5072 #endif
5073   bOsVersionInfoEx = GetVersionExW ((OSVERSIONINFOW*)&osvi);
5074   if (!bOsVersionInfoEx)
5075     {
5076     osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOW);
5077     if (!GetVersionExW((OSVERSIONINFOW*)&osvi))
5078       {
5079       return false;
5080       }
5081     }
5082 #ifdef KWSYS_WINDOWS_DEPRECATED_GetVersionEx
5083 # pragma warning (pop)
5084 #endif
5085 
5086   switch (osvi.dwPlatformId)
5087     {
5088     case VER_PLATFORM_WIN32_NT:
5089       // Test for the product.
5090       if (osvi.dwMajorVersion <= 4)
5091         {
5092         this->OSRelease = "NT";
5093         }
5094       if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
5095         {
5096         this->OSRelease = "2000";
5097         }
5098       if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
5099         {
5100         this->OSRelease = "XP";
5101         }
5102       // XP Professional x64
5103       if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
5104         {
5105         this->OSRelease = "XP";
5106         }
5107 #ifdef VER_NT_WORKSTATION
5108       // Test for product type.
5109       if (bOsVersionInfoEx)
5110         {
5111         if (osvi.wProductType == VER_NT_WORKSTATION)
5112           {
5113           if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
5114             {
5115             this->OSRelease = "Vista";
5116             }
5117           if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
5118             {
5119             this->OSRelease = "7";
5120             }
5121 // VER_SUITE_PERSONAL may not be defined
5122 #ifdef VER_SUITE_PERSONAL
5123           else
5124             {
5125             if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
5126               {
5127               this->OSRelease += " Personal";
5128               }
5129             else
5130               {
5131               this->OSRelease += " Professional";
5132               }
5133             }
5134 #endif
5135           }
5136         else if (osvi.wProductType == VER_NT_SERVER)
5137           {
5138           // Check for .NET Server instead of Windows XP.
5139           if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
5140             {
5141             this->OSRelease = ".NET";
5142             }
5143 
5144           // Continue with the type detection.
5145           if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
5146             {
5147             this->OSRelease += " DataCenter Server";
5148             }
5149           else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
5150             {
5151             this->OSRelease += " Advanced Server";
5152             }
5153           else
5154             {
5155             this->OSRelease += " Server";
5156             }
5157           }
5158 
5159         sprintf (operatingSystem, "%ls (Build %ld)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
5160         this->OSVersion = operatingSystem;
5161         }
5162       else
5163 #endif        // VER_NT_WORKSTATION
5164         {
5165         HKEY hKey;
5166         wchar_t szProductType[80];
5167         DWORD dwBufLen;
5168 
5169         // Query the registry to retrieve information.
5170         RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", 0, KEY_QUERY_VALUE, &hKey);
5171         RegQueryValueExW(hKey, L"ProductType", NULL, NULL, (LPBYTE) szProductType, &dwBufLen);
5172         RegCloseKey (hKey);
5173 
5174         if (lstrcmpiW(L"WINNT", szProductType) == 0)
5175           {
5176           this->OSRelease += " Professional";
5177           }
5178         if (lstrcmpiW(L"LANMANNT", szProductType) == 0)
5179           {
5180           // Decide between Windows 2000 Advanced Server and Windows .NET Enterprise Server.
5181           if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
5182             {
5183             this->OSRelease += " Standard Server";
5184             }
5185           else
5186             {
5187             this->OSRelease += " Server";
5188             }
5189           }
5190         if (lstrcmpiW(L"SERVERNT", szProductType) == 0)
5191           {
5192           // Decide between Windows 2000 Advanced Server and Windows .NET Enterprise Server.
5193           if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
5194             {
5195             this->OSRelease += " Enterprise Server";
5196             }
5197           else
5198             {
5199             this->OSRelease += " Advanced Server";
5200             }
5201           }
5202          }
5203 
5204       // Display version, service pack (if any), and build number.
5205       if (osvi.dwMajorVersion <= 4)
5206         {
5207         // NB: NT 4.0 and earlier.
5208         sprintf (operatingSystem, "version %ld.%ld %ls (Build %ld)",
5209                  osvi.dwMajorVersion,
5210                  osvi.dwMinorVersion,
5211                  osvi.szCSDVersion,
5212                  osvi.dwBuildNumber & 0xFFFF);
5213         this->OSVersion = operatingSystem;
5214         }
5215       else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
5216         {
5217         // Windows XP and .NET server.
5218         typedef BOOL (CALLBACK* LPFNPROC) (HANDLE, BOOL *);
5219         HINSTANCE hKernelDLL;
5220         LPFNPROC DLLProc;
5221 
5222         // Load the Kernel32 DLL.
5223         hKernelDLL = LoadLibraryW(L"kernel32");
5224         if (hKernelDLL != NULL)  {
5225           // Only XP and .NET Server support IsWOW64Process so... Load dynamically!
5226           DLLProc = (LPFNPROC) GetProcAddress (hKernelDLL, "IsWow64Process");
5227 
5228           // If the function address is valid, call the function.
5229           if (DLLProc != NULL) (DLLProc) (GetCurrentProcess (), &bIsWindows64Bit);
5230           else bIsWindows64Bit = false;
5231 
5232           // Free the DLL module.
5233           FreeLibrary (hKernelDLL);
5234           }
5235         }
5236       else
5237         {
5238         // Windows 2000 and everything else.
5239         sprintf (operatingSystem,"%ls (Build %ld)", osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF);
5240         this->OSVersion = operatingSystem;
5241         }
5242       break;
5243 
5244     case VER_PLATFORM_WIN32_WINDOWS:
5245       // Test for the product.
5246       if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
5247         {
5248         this->OSRelease = "95";
5249         if(osvi.szCSDVersion[1] == 'C')
5250           {
5251           this->OSRelease += "OSR 2.5";
5252           }
5253         else if(osvi.szCSDVersion[1] == 'B')
5254           {
5255           this->OSRelease += "OSR 2";
5256           }
5257       }
5258 
5259       if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
5260         {
5261         this->OSRelease = "98";
5262         if (osvi.szCSDVersion[1] == 'A' )
5263           {
5264           this->OSRelease += "SE";
5265           }
5266         }
5267 
5268       if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
5269         {
5270         this->OSRelease = "Me";
5271         }
5272       break;
5273 
5274     case VER_PLATFORM_WIN32s:
5275       this->OSRelease = "Win32s";
5276       break;
5277 
5278     default:
5279       this->OSRelease = "Unknown";
5280       break;
5281   }
5282 
5283   // Get the hostname
5284   WORD wVersionRequested;
5285   WSADATA wsaData;
5286   char name[255];
5287   wVersionRequested = MAKEWORD(2,0);
5288 
5289   if ( WSAStartup( wVersionRequested, &wsaData ) == 0 )
5290     {
5291     gethostname(name,sizeof(name));
5292     WSACleanup( );
5293     }
5294   this->Hostname = name;
5295 
5296   const char* arch = getenv("PROCESSOR_ARCHITECTURE");
5297   if(arch)
5298     {
5299     this->OSPlatform = arch;
5300     }
5301 
5302 #else
5303 
5304   struct utsname unameInfo;
5305   int errorFlag = uname(&unameInfo);
5306   if(errorFlag == 0)
5307     {
5308     this->OSName = unameInfo.sysname;
5309     this->Hostname = unameInfo.nodename;
5310     this->OSRelease = unameInfo.release;
5311     this->OSVersion = unameInfo.version;
5312     this->OSPlatform = unameInfo.machine;
5313     }
5314 
5315 #ifdef __APPLE__
5316   this->OSName="Unknown Apple OS";
5317   this->OSRelease="Unknown product version";
5318   this->OSVersion="Unknown build version";
5319 
5320   this->CallSwVers("-productName",this->OSName);
5321   this->CallSwVers("-productVersion",this->OSRelease);
5322   this->CallSwVers("-buildVersion",this->OSVersion);
5323 #endif
5324 
5325 #endif
5326 
5327   return true;
5328 }
5329 
CallSwVers(const char * arg,kwsys_stl::string & ver)5330 int SystemInformationImplementation::CallSwVers(
5331       const char *arg,
5332       kwsys_stl::string &ver)
5333 {
5334 #ifdef __APPLE__
5335   kwsys_stl::vector<const char*> args;
5336   args.push_back("sw_vers");
5337   args.push_back(arg);
5338   args.push_back(0);
5339   ver = this->RunProcess(args);
5340   this->TrimNewline(ver);
5341 #else
5342   // avoid C4100
5343   (void)arg;
5344   (void)ver;
5345 #endif
5346   return 0;
5347 }
5348 
TrimNewline(kwsys_stl::string & output)5349 void SystemInformationImplementation::TrimNewline(kwsys_stl::string& output)
5350 {
5351   // remove \r
5352   kwsys_stl::string::size_type pos=0;
5353   while((pos = output.find("\r", pos)) != kwsys_stl::string::npos)
5354     {
5355     output.erase(pos);
5356     }
5357 
5358   // remove \n
5359   pos = 0;
5360   while((pos = output.find("\n", pos)) != kwsys_stl::string::npos)
5361     {
5362     output.erase(pos);
5363     }
5364 }
5365 
5366 
5367 /** Return true if the machine is 64 bits */
Is64Bits()5368 bool SystemInformationImplementation::Is64Bits()
5369 {
5370   return (sizeof(void*) == 8);
5371 }
5372 
5373 
5374 } // namespace @KWSYS_NAMESPACE@
5375