1
0
forked from mirrors/0ad
Files
0ad/source/lib/sysdep/win/wcpu.cpp
T
janwas 7a5655edde # major refactoring of system-dependent code (simplifies build system)
cpu.cpp: avoided the need for wrapper functions by calling the
OS-specific function directly (declared in central header, implemented
in the platform's cpp file)

avoid the need for init in cpu and ia32 via if(!init) Init() pattern.

optimized memcpy now requires SSE support

remove error-prone CAS macro; replace with cpu_CAS
config: no longer require inline asm for float->int conversions
lib_error: remove special-case in CHECK_ERR for windows (no longer
needed)

This was SVN commit r5365.
2007-09-23 15:36:29 +00:00

137 lines
3.6 KiB
C++

/**
* =========================================================================
* File : wcpu.cpp
* Project : 0 A.D.
* Description : Windows implementation of sysdep/cpu
* =========================================================================
*/
// license: GPL; see lib/license.txt
#include "precompiled.h"
#include "../cpu.h"
#include "win.h"
#include "lib/bits.h"
uint cpu_NumProcessors()
{
SYSTEM_INFO si;
GetSystemInfo(&si); // can't fail
const uint numProcessors = (uint)si.dwNumberOfProcessors;
return numProcessors;
}
static LibError ReadFrequencyFromRegistry(DWORD* freqMhz)
{
HKEY hKey;
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
return ERR::NO_SYS;
DWORD size = sizeof(*freqMhz);
LONG ret = RegQueryValueEx(hKey, "~MHz", 0, 0, (LPBYTE)freqMhz, &size);
RegCloseKey(hKey);
if(ret != ERROR_SUCCESS)
WARN_RETURN(ERR::FAIL);
return INFO::OK;
}
double cpu_ClockFrequency()
{
DWORD freqMhz;
if(ReadFrequencyFromRegistry(&freqMhz) < 0)
return -1.0;
const double clockFrequency = freqMhz * 1e6;
return clockFrequency;
}
size_t cpu_PageSize()
{
SYSTEM_INFO si;
GetSystemInfo(&si); // can't fail
const size_t pageSize = (size_t)si.dwPageSize;
return pageSize;
}
size_t cpu_MemorySize(CpuMemoryIndicators mem_type)
{
// note: we no longer bother dynamically importing GlobalMemoryStatusEx -
// it's available on Win2k and above. this function safely handles
// systems with > 4 GB of memory.
MEMORYSTATUSEX mse = { sizeof(mse) };
BOOL ok = GlobalMemoryStatusEx(&mse);
WARN_IF_FALSE(ok);
if(mem_type == CPU_MEM_TOTAL)
{
size_t memoryTotal = (size_t)mse.ullTotalPhys;
// Richter, "Programming Applications for Windows": the reported
// value doesn't include non-paged pool reserved during boot;
// it's not considered available to the kernel. (the amount is
// 528 KiB on a 512 MiB WinXP/Win2k machine). we'll round up
// to the nearest megabyte to fix this.
memoryTotal = round_up(memoryTotal, 1*MiB);
return memoryTotal;
}
else
{
const size_t memoryAvailable = (size_t)mse.ullAvailPhys;
return memoryAvailable;
}
}
//-----------------------------------------------------------------------------
// execute the specified function once on each CPU.
// this includes logical HT units and proceeds serially (function
// is never re-entered) in order of increasing OS CPU ID.
// note: implemented by switching thread affinity masks and forcing
// a reschedule, which is apparently not possible with POSIX.
//
// may fail if e.g. OS is preventing us from running on some CPUs.
// called from ia32.cpp get_cpu_count.
LibError cpu_CallByEachCPU(CpuCallback cb, void* param)
{
const HANDLE hProcess = GetCurrentProcess();
DWORD process_affinity, system_affinity;
if(!GetProcessAffinityMask(hProcess, &process_affinity, &system_affinity))
WARN_RETURN(ERR::FAIL);
// our affinity != system affinity: OS is limiting the CPUs that
// this process can run on. fail (cannot call back for each CPU).
if(process_affinity != system_affinity)
WARN_RETURN(ERR::CPU_RESTRICTED_AFFINITY);
for(DWORD_PTR cpu_bit = 1; cpu_bit != 0 && cpu_bit <= process_affinity; cpu_bit *= 2)
{
// check if we can switch to target CPU
if(!(process_affinity & cpu_bit))
continue;
// .. and do so.
if(!SetThreadAffinityMask(GetCurrentThread(), cpu_bit))
{
WARN_ERR(ERR::CPU_RESTRICTED_AFFINITY);
continue;
}
// reschedule to make sure we switch CPUs.
Sleep(1);
cb(param);
}
// restore to original value
SetThreadAffinityMask(hProcess, process_affinity);
return INFO::OK;
}