Index: trunk/src/VBox/Runtime/r3/solaris/mp-solaris.cpp
===================================================================
--- trunk/src/VBox/Runtime/r3/solaris/mp-solaris.cpp	(revision 48768)
+++ trunk/src/VBox/Runtime/r3/solaris/mp-solaris.cpp	(revision 48812)
@@ -58,4 +58,63 @@
 /** 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;
+}
 
 
@@ -81,23 +140,38 @@
         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
@@ -119,4 +193,19 @@
 
 /**
+ * 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.
  *
@@ -129,5 +218,5 @@
 {
     uint64_t u64 = 0;
-    int rc = RTOnce(&g_MpSolarisOnce, rtMpSolarisOnce, NULL);
+    int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */);
     if (RT_SUCCESS(rc))
     {
@@ -281,5 +370,5 @@
 {
 #ifdef RT_STRICT
-    long cCpusPresent = 0;
+    RTCPUID cCpusPresent = 0;
 #endif
     RTCpuSetEmpty(pSet);
@@ -312,2 +401,53 @@
 }
 
+
+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))
+                       || !RTStrNCmp(pStat->value.c, PS_NOINTR, sizeof(PS_NOINTR)))
+                    {
+                        uOnlineCores++;
+                        break;      /* Move to the next core. We have at least 1 hyperthread online in the current core. */
+                    }
+                }
+            }
+        }
+
+        RTCritSectLeave(&g_MpSolarisCritSect);
+    }
+
+    return uOnlineCores;
+}
+
