summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/r3/solaris/mp-solaris.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/r3/solaris/mp-solaris.cpp')
-rw-r--r--src/VBox/Runtime/r3/solaris/mp-solaris.cpp182
1 files changed, 164 insertions, 18 deletions
diff --git a/src/VBox/Runtime/r3/solaris/mp-solaris.cpp b/src/VBox/Runtime/r3/solaris/mp-solaris.cpp
index 0f2c6fdf..d21bbb42 100644
--- a/src/VBox/Runtime/r3/solaris/mp-solaris.cpp
+++ b/src/VBox/Runtime/r3/solaris/mp-solaris.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2008 Oracle Corporation
+ * Copyright (C) 2008-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -57,19 +57,77 @@ static kstat_ctl_t *g_pKsCtl;
static kstat_t **g_papCpuInfo;
/** The number of entries in g_papCpuInfo */
static RTCPUID g_capCpuInfo;
+/** Array of core ids. */
+static uint64_t *g_pu64CoreIds;
+/** Number of entries in g_pu64CoreIds. */
+static size_t g_cu64CoreIds;
+/** Number of cores in the system. */
+static size_t g_cCores;
+
+
+/**
+ * Helper for getting the core ID for a given CPU/strand/hyperthread.
+ *
+ * @returns The core ID.
+ * @param idCpu The CPU ID instance.
+ */
+static inline uint64_t rtMpSolarisGetCoreId(RTCPUID idCpu)
+{
+ kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char *)"core_id");
+ Assert(pStat->data_type == KSTAT_DATA_LONG);
+ Assert(pStat->value.l >= 0);
+ AssertCompile(sizeof(uint64_t) >= sizeof(long)); /* Paranoia. */
+ return (uint64_t)pStat->value.l;
+}
+
+
+/**
+ * Populates 'g_pu64CoreIds' array with unique core identifiers in the system.
+ *
+ * @returns VBox status code.
+ */
+static int rtMpSolarisGetCoreIds(void)
+{
+ for (RTCPUID idCpu = 0; idCpu < g_capCpuInfo; idCpu++)
+ {
+ if (kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0) != -1)
+ {
+ /* Strands/Hyperthreads share the same core ID. */
+ uint64_t u64CoreId = rtMpSolarisGetCoreId(idCpu);
+ bool fAddedCore = false;
+ for (RTCPUID i = 0; i < g_cCores; i++)
+ {
+ if (g_pu64CoreIds[i] == u64CoreId)
+ {
+ fAddedCore = true;
+ break;
+ }
+ }
+
+ if (!fAddedCore)
+ {
+ g_pu64CoreIds[g_cCores] = u64CoreId;
+ ++g_cCores;
+ }
+ }
+ else
+ return VERR_INTERNAL_ERROR_2;
+ }
+
+ return VINF_SUCCESS;
+}
/**
* Run once function that initializes the kstats we need here.
*
* @returns IPRT status code.
- * @param pvUser1 Unused.
- * @param pvUser2 Unused.
+ * @param pvUser Unused.
*/
-static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2)
+static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser)
{
int rc = VINF_SUCCESS;
- NOREF(pvUser1); NOREF(pvUser2);
+ NOREF(pvUser);
/*
* Open kstat and find the cpu_info entries for each of the CPUs.
@@ -81,25 +139,40 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2)
g_papCpuInfo = (kstat_t **)RTMemAllocZ(g_capCpuInfo * sizeof(kstat_t *));
if (g_papCpuInfo)
{
- rc = RTCritSectInit(&g_MpSolarisCritSect);
- if (RT_SUCCESS(rc))
+ g_cu64CoreIds = g_capCpuInfo;
+ g_pu64CoreIds = (uint64_t *)RTMemAllocZ(g_cu64CoreIds * sizeof(uint64_t));
+ if (g_pu64CoreIds)
{
- RTCPUID i = 0;
- for (kstat_t *pKsp = g_pKsCtl->kc_chain; pKsp != NULL; pKsp = pKsp->ks_next)
+ rc = RTCritSectInit(&g_MpSolarisCritSect);
+ if (RT_SUCCESS(rc))
{
- if (!strcmp(pKsp->ks_module, "cpu_info"))
+ RTCPUID i = 0;
+ for (kstat_t *pKsp = g_pKsCtl->kc_chain; pKsp != NULL; pKsp = pKsp->ks_next)
{
- AssertBreak(i < g_capCpuInfo);
- g_papCpuInfo[i++] = pKsp;
- /** @todo ks_instance == cpu_id (/usr/src/uts/common/os/cpu.c)? Check this and fix it ASAP. */
+ if (!RTStrCmp(pKsp->ks_module, "cpu_info"))
+ {
+ AssertBreak(i < g_capCpuInfo);
+ g_papCpuInfo[i++] = pKsp;
+ /** @todo ks_instance == cpu_id (/usr/src/uts/common/os/cpu.c)? Check this and fix it ASAP. */
+ }
}
+
+ rc = rtMpSolarisGetCoreIds();
+ if (RT_SUCCESS(rc))
+ return VINF_SUCCESS;
+ else
+ Log(("rtMpSolarisGetCoreIds failed. rc=%Rrc\n", rc));
}
- return VINF_SUCCESS;
+ RTMemFree(g_pu64CoreIds);
+ g_pu64CoreIds = NULL;
}
+ else
+ rc = VERR_NO_MEMORY;
/* bail out, we failed. */
RTMemFree(g_papCpuInfo);
+ g_papCpuInfo = NULL;
}
else
rc = VERR_NO_MEMORY;
@@ -119,6 +192,21 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2)
/**
+ * RTOnceEx() cleanup function.
+ *
+ * @param pvUser Unused.
+ * @param fLazyCleanUpOk Whether lazy cleanup is okay or not.
+ */
+static DECLCALLBACK(void) rtMpSolarisCleanUp(void *pvUser, bool fLazyCleanUpOk)
+{
+ if (g_pKsCtl)
+ kstat_close(g_pKsCtl);
+ RTMemFree(g_pu64CoreIds);
+ RTMemFree(g_papCpuInfo);
+}
+
+
+/**
* Worker for RTMpGetCurFrequency and RTMpGetMaxFrequency.
*
* @returns The desired frequency on success, 0 on failure.
@@ -126,10 +214,10 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2)
* @param idCpu The CPU ID.
* @param pszStatName The cpu_info stat name.
*/
-static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, char *pszStatName)
+static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, const char *pszStatName)
{
uint64_t u64 = 0;
- int rc = RTOnce(&g_MpSolarisOnce, rtMpSolarisOnce, NULL, NULL);
+ int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */);
if (RT_SUCCESS(rc))
{
if ( idCpu < g_capCpuInfo
@@ -141,7 +229,8 @@ static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, char *pszStatName)
{
if (kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0) != -1)
{
- kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], pszStatName);
+ /* Solaris really need to fix their APIs. Explicitly cast for now. */
+ kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char*)pszStatName);
if (pStat)
{
Assert(pStat->data_type == KSTAT_DATA_UINT64 || pStat->data_type == KSTAT_DATA_LONG);
@@ -280,7 +369,7 @@ RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
RTDECL(PRTCPUSET) RTMpGetPresentSet(PRTCPUSET pSet)
{
#ifdef RT_STRICT
- long cCpusPresent = 0;
+ RTCPUID cCpusPresent = 0;
#endif
RTCpuSetEmpty(pSet);
RTCPUID cCpus = RTMpGetCount();
@@ -305,3 +394,60 @@ RTDECL(RTCPUID) RTMpGetPresentCount(void)
return sysconf(_SC_NPROCESSORS_CONF);
}
+
+RTDECL(RTCPUID) RTMpGetPresentCoreCount(void)
+{
+ return RTMpGetCoreCount();
+}
+
+
+RTDECL(RTCPUID) RTMpGetCoreCount(void)
+{
+ int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */);
+ if (RT_SUCCESS(rc))
+ return g_cCores;
+
+ return 0;
+}
+
+
+RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void)
+{
+ RTCPUID uOnlineCores = 0;
+ int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTCritSectEnter(&g_MpSolarisCritSect);
+ AssertRC(rc);
+
+ /*
+ * For each core in the system, count how many are currently online.
+ */
+ for (RTCPUID j = 0; j < g_cCores; j++)
+ {
+ uint64_t u64CoreId = g_pu64CoreIds[j];
+ for (RTCPUID idCpu = 0; idCpu < g_capCpuInfo; idCpu++)
+ {
+ rc = kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0);
+ AssertReturn(rc != -1, 0 /* rc */);
+ uint64_t u64ThreadCoreId = rtMpSolarisGetCoreId(idCpu);
+ if (u64ThreadCoreId == u64CoreId)
+ {
+ kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char *)"state");
+ Assert(pStat->data_type == KSTAT_DATA_CHAR);
+ if( !RTStrNCmp(pStat->value.c, PS_ONLINE, sizeof(PS_ONLINE) - 1)
+ || !RTStrNCmp(pStat->value.c, PS_NOINTR, sizeof(PS_NOINTR) - 1))
+ {
+ uOnlineCores++;
+ break; /* Move to the next core. We have at least 1 hyperthread online in the current core. */
+ }
+ }
+ }
+ }
+
+ RTCritSectLeave(&g_MpSolarisCritSect);
+ }
+
+ return uOnlineCores;
+}
+