VirtualBox

Changeset 27264 in vbox


Ignore:
Timestamp:
Mar 11, 2010 8:48:15 AM (15 years ago)
Author:
vboxsync
Message:

Devices/ACPI: on Linux, start a poller thread for collecting information from /proc/acpi because on some hosts it takes ages to access these files

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/PC/DrvACPI.cpp

    r26173 r27264  
    3636
    3737#ifdef RT_OS_LINUX
    38 # include <iprt/string.h>
    39 # include <sys/types.h>
    40 # include <dirent.h>
    41 # include <stdio.h>
     38# include <iprt/critsect.h>
     39# include <iprt/dir.h>
     40# include <iprt/semaphore.h>
     41# include <iprt/stream.h>
    4242#endif
    4343
     
    7878    /** Pointer to the driver instance. */
    7979    PPDMDRVINS          pDrvIns;
     80
     81#ifdef RT_OS_LINUX
     82    /** The current power source. */
     83    PDMACPIPOWERSOURCE  enmPowerSource;
     84    /** true = one or more batteries preset, false = no battery present. */
     85    bool                fBatteryPresent;
     86    /** Remaining battery capacity. */
     87    PDMACPIBATCAPACITY  enmBatteryRemainingCapacity;
     88    /** Battery state. */
     89    PDMACPIBATSTATE     enmBatteryState;
     90    /** Preset battery charging/discharging rate. */
     91    uint32_t            u32BatteryPresentRate;
     92    /** The poller thread. */
     93    PPDMTHREAD          pPollerThread;
     94    /** Synchronize access to the above fields.
     95     * XXX A spinlock is probaly cheaper ... */
     96    RTCRITSECT          CritSect;
     97    /** Event semaphore the poller thread is sleeping on. */
     98    RTSEMEVENT          hPollerSleepEvent;
     99#endif
     100
    80101} DRVACPI, *PDRVACPI;
    81102
     
    133154        *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
    134155    }
    135 #elif defined (RT_OS_LINUX) /* !RT_OS_WINDOWS */
    136     DIR *dfd;
    137     struct dirent *dp;
    138     FILE *statusFile = NULL;
    139     char buff[NAME_MAX+50];
    140 
    141     /* start with no result */
    142     *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
    143 
    144     dfd = opendir("/proc/acpi/ac_adapter/");
    145     if (dfd)
    146     {
    147         for (;;)
    148         {
    149             dp = readdir(dfd);
    150             if (dp == 0)
    151                 break;
    152             if (strcmp(dp->d_name, ".") == 0 ||
    153                 strcmp(dp->d_name, "..") == 0)
    154                 continue;
    155             strcpy(buff, "/proc/acpi/ac_adapter/");
    156             strcat(buff, dp->d_name);
    157             strcat(buff, "/status");
    158             statusFile = fopen(buff, "r");
    159             /* there's another possible name for this file */
    160             if (!statusFile)
    161             {
    162                 strcpy(buff, "/proc/acpi/ac_adapter/");
    163                 strcat(buff, dp->d_name);
    164                 strcat(buff, "/state");
    165                 statusFile = fopen(buff, "r");
    166             }
    167             if (statusFile)
    168                 break;
    169         }
    170         closedir(dfd);
    171     }
    172 
    173     if (statusFile)
    174     {
    175         for (;;)
    176         {
    177             char buff2[1024];
    178             if (fgets(buff2, sizeof(buff), statusFile) == NULL)
    179                 break;
    180             if (strstr(buff2, "Status:") != NULL ||
    181                 strstr(buff2, "state:") != NULL)
    182             {
    183                 if (strstr(buff2, "on-line") != NULL)
    184                     *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
    185                 else
    186                     *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
    187             }
    188         }
    189         fclose(statusFile);
    190     }
    191 #elif defined (RT_OS_DARWIN) /* !RT_OS_LINUX */
     156
     157#elif defined (RT_OS_LINUX)
     158    PDRVACPI pThis = RT_FROM_MEMBER(pInterface, DRVACPI, IACPIConnector);
     159    RTCritSectEnter(&pThis->CritSect);
     160    *pPowerSource = pThis->enmPowerSource, pPowerSource;
     161    RTCritSectLeave(&pThis->CritSect);
     162
     163#elif defined (RT_OS_DARWIN)
    192164    *pPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
    193165
     
    197169    CFDictionaryRef pSource = NULL;
    198170    const void *psValue;
    199     bool result;
     171    bool fResult;
    200172
    201173    if (CFArrayGetCount(pSources) > 0)
    202174    {
    203         for(int i = 0; i < CFArrayGetCount(pSources); ++i)
     175        for (int i = 0; i < CFArrayGetCount(pSources); ++i)
    204176        {
    205177            pSource = IOPSGetPowerSourceDescription(pBlob, CFArrayGetValueAtIndex(pSources, i));
     
    212184                continue;
    213185            /* Only internal power types are of interest. */
    214             result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);
    215             if (result &&
    216                 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)
     186            fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);
     187            if (   fResult
     188                && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)
    217189            {
    218190                /* Check which power source we are connect on. */
    219                 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);
    220                 if (result &&
    221                     CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)
     191                fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);
     192                if (   fResult
     193                    && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)
    222194                    *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
    223                 else if (result &&
    224                          CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
     195                else if (   fResult
     196                         && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
    225197                    *pPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
    226198            }
     
    229201    CFRelease(pBlob);
    230202    CFRelease(pSources);
    231 #elif defined(RT_OS_FREEBSD) /* !RT_OS_DARWIN */
     203
     204#elif defined(RT_OS_FREEBSD)
    232205    int fAcLine = 0;
    233206    size_t cbParameter = sizeof(fAcLine);
     
    251224#else /* !RT_OS_FREEBSD either - what could this be? */
    252225    *pPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
    253 #endif /* !RT_OS_WINDOWS */
     226
     227#endif /* !RT_OS_FREEBSD */
    254228    return VINF_SUCCESS;
    255229}
     
    294268                        GetLastError()));
    295269    }
     270
    296271#elif defined(RT_OS_LINUX)
    297     DIR *dfd;
    298     struct dirent *dp;
    299     FILE *statusFile = NULL;
    300     FILE *infoFile = NULL;
    301     char buff[NAME_MAX+50];
    302     /* the summed up maximum capacity */
    303     int  maxCapacityTotal = ~0;
    304     /* the summed up total capacity */
    305     int  currentCapacityTotal = ~0;
    306     int  presentRate = 0;
    307     int  presentRateTotal = 0;
    308     bool fBatteryPresent = false, fCharging=false, fDischarging=false, fCritical=false;
    309 
    310     dfd = opendir("/proc/acpi/battery/");
    311     if (dfd)
    312     {
    313         for (;;)
    314         {
    315             dp = readdir(dfd);
    316             if (dp == 0)
    317                 break;
    318             if (strcmp(dp->d_name, ".") == 0 ||
    319                 strcmp(dp->d_name, "..") == 0)
    320                 continue;
    321             strcpy(buff, "/proc/acpi/battery/");
    322             strcat(buff, dp->d_name);
    323             strcat(buff, "/status");
    324             statusFile = fopen(buff, "r");
    325             /* there is a 2nd variant of that file */
    326             if (!statusFile)
    327             {
    328                 strcpy(buff, "/proc/acpi/battery/");
    329                 strcat(buff, dp->d_name);
    330                 strcat(buff, "/state");
    331                 statusFile = fopen(buff, "r");
    332             }
    333             strcpy(buff, "/proc/acpi/battery/");
    334             strcat(buff, dp->d_name);
    335             strcat(buff, "/info");
    336             infoFile = fopen(buff, "r");
    337             /* we need both files */
    338             if (!statusFile || !infoFile)
    339             {
    340                 if (statusFile)
    341                     fclose(statusFile);
    342                 if (infoFile)
    343                     fclose(infoFile);
    344                 break;
    345             }
    346 
    347             /* get 'present' status from the info file */
    348             for (;;)
    349             {
    350                 char buff2[1024];
    351                 if (fgets(buff2, sizeof(buff), infoFile) == NULL)
    352                     break;
    353 
    354                 if (strstr(buff2, "present:") != NULL)
    355                 {
    356                     if (strstr(buff2, "yes") != NULL)
    357                         fBatteryPresent = true;
    358                 }
    359             }
    360 
    361             /* move file pointer back to start of file */
    362             fseek(infoFile, 0, SEEK_SET);
    363 
    364             if (fBatteryPresent)
    365             {
    366                 /* get the maximum capacity from the info file */
    367                 for (;;)
    368                 {
    369                     char buff2[1024];
    370                     int maxCapacity = ~0;
    371                     if (fgets(buff2, sizeof(buff), infoFile) == NULL)
    372                         break;
    373                     if (strstr(buff2, "last full capacity:") != NULL)
    374                     {
    375                         if (sscanf(buff2 + 19, "%d", &maxCapacity) <= 0)
    376                             maxCapacity = ~0;
    377 
    378                         /* did we get a valid capacity and it's the first value we got? */
    379                         if (maxCapacityTotal < 0 && maxCapacity > 0)
    380                         {
    381                             /* take this as the maximum capacity */
    382                             maxCapacityTotal = maxCapacity;
    383                         }
    384                         else
    385                         {
    386                             /* sum up the maximum capacity */
    387                             if (maxCapacityTotal > 0 && maxCapacity > 0)
    388                                 maxCapacityTotal += maxCapacity;
    389                         }
    390                         /* we got all we need */
    391                         break;
    392                     }
    393                 }
    394 
    395                 /* get the current capacity/state from the status file */
    396                 bool gotRemainingCapacity=false, gotBatteryState=false,
    397                      gotCapacityState=false,     gotPresentRate=false;
    398                 while (!gotRemainingCapacity || !gotBatteryState ||
    399                        !gotCapacityState     || !gotPresentRate)
    400                 {
    401                     char buff2[1024];
    402                     int currentCapacity = ~0;
    403                     if (fgets(buff2, sizeof(buff), statusFile) == NULL)
    404                         break;
    405                     if (strstr(buff2, "remaining capacity:") != NULL)
    406                     {
    407                         if (sscanf(buff2 + 19, "%d", &currentCapacity) <= 0)
    408                             currentCapacity = ~0;
    409 
    410                         /* is this the first valid value we see? If so, take it! */
    411                         if (currentCapacityTotal < 0 && currentCapacity >= 0)
    412                         {
    413                             currentCapacityTotal = currentCapacity;
    414                         }
    415                         else
    416                         {
    417                             /* just sum up the current value */
    418                             if (currentCapacityTotal > 0 && currentCapacity > 0)
    419                                 currentCapacityTotal += currentCapacity;
    420                         }
    421                         gotRemainingCapacity = true;
    422                     }
    423                     if (strstr(buff2, "charging state:") != NULL)
    424                     {
    425                         if (strstr(buff2 + 15, "discharging") != NULL)
    426                             fDischarging = true;
    427                         else if (strstr(buff2 + 15, "charging") != NULL)
    428                             fCharging = true;
    429                         gotBatteryState = true;
    430                     }
    431                     if (strstr(buff2, "capacity state:") != NULL)
    432                     {
    433                         if (strstr(buff2 + 15, "critical") != NULL)
    434                             fCritical = true;
    435                         gotCapacityState = true;
    436                     }
    437                     if (strstr(buff2, "present rate:") != NULL)
    438                     {
    439                         if (sscanf(buff2 + 13, "%d", &presentRate) <= 0)
    440                             presentRate = 0;
    441                         gotPresentRate = true;
    442                     }
    443                 }
    444             }
    445 
    446             if (presentRate)
    447             {
    448                 if (fDischarging)
    449                     presentRateTotal -= presentRate;
    450                 else
    451                     presentRateTotal += presentRate;
    452             }
    453 
    454             if (statusFile)
    455                 fclose(statusFile);
    456             if (infoFile)
    457                 fclose(infoFile);
    458 
    459         }
    460         closedir(dfd);
    461     }
    462 
    463     *pfPresent = fBatteryPresent;
    464 
    465     /* charging/discharging bits are mutual exclusive */
    466     uint32_t uBs = PDM_ACPI_BAT_STATE_CHARGED;
    467     if (fDischarging)
    468         uBs = PDM_ACPI_BAT_STATE_DISCHARGING;
    469     else if (fCharging)
    470         uBs = PDM_ACPI_BAT_STATE_CHARGING;
    471     if (fCritical)
    472         uBs |= PDM_ACPI_BAT_STATE_CRITICAL;
    473     *penmBatteryState = (PDMACPIBATSTATE)uBs;
    474 
    475     if (presentRateTotal < 0)
    476         presentRateTotal = -presentRateTotal;
    477 
    478     if (maxCapacityTotal > 0 && currentCapacityTotal > 0)
    479     {
    480         /* calculate the percentage */
    481         *penmRemainingCapacity = (PDMACPIBATCAPACITY)(((float)currentCapacityTotal / (float)maxCapacityTotal)
    482                                                       * PDM_ACPI_BAT_CAPACITY_MAX);
    483         *pu32PresentRate = (uint32_t)(((float)presentRateTotal / (float)maxCapacityTotal) * 1000);
    484     }
     272    PDRVACPI pThis = RT_FROM_MEMBER(pInterface, DRVACPI, IACPIConnector);
     273    RTCritSectEnter(&pThis->CritSect);
     274    *pfPresent = pThis->fBatteryPresent;
     275    *penmRemainingCapacity = pThis->enmBatteryRemainingCapacity;
     276    *penmBatteryState = pThis->enmBatteryState, penmBatteryState;
     277    *pu32PresentRate = pThis->u32BatteryPresentRate;
     278    RTCritSectLeave(&pThis->CritSect);
     279
    485280#elif defined(RT_OS_DARWIN)
    486281    CFTypeRef pBlob = IOPSCopyPowerSourcesInfo();
     
    489284    CFDictionaryRef pSource = NULL;
    490285    const void *psValue;
    491     bool result;
     286    bool fResult;
    492287
    493288    if (CFArrayGetCount(pSources) > 0)
    494289    {
    495         for(int i = 0; i < CFArrayGetCount(pSources); ++i)
     290        for (int i = 0; i < CFArrayGetCount(pSources); ++i)
    496291        {
    497292            pSource = IOPSGetPowerSourceDescription(pBlob, CFArrayGetValueAtIndex(pSources, i));
     
    504299                continue;
    505300            /* Only internal power types are of interest. */
    506             result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);
    507             if (result &&
    508                 CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)
     301            fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTransportTypeKey), &psValue);
     302            if (   fResult
     303                && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSInternalType), 0) == kCFCompareEqualTo)
    509304            {
    510305                PDMACPIPOWERSOURCE powerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
    511306                /* First check which power source we are connect on. */
    512                 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);
    513                 if (result &&
    514                     CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)
     307                fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSPowerSourceStateKey), &psValue);
     308                if (   fResult
     309                    && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSACPowerValue), 0) == kCFCompareEqualTo)
    515310                    powerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
    516                 else if (result &&
    517                          CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
     311                else if (   fResult
     312                         && CFStringCompare((CFStringRef)psValue, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo)
    518313                    powerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
    519314
     
    527322
    528323                /* Fetch the current capacity value of the power source */
    529                 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSCurrentCapacityKey), &psValue);
    530                 if (result)
     324                fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSCurrentCapacityKey), &psValue);
     325                if (fResult)
    531326                    CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &curCapacity);
    532327                /* Fetch the maximum capacity value of the power source */
    533                 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSMaxCapacityKey), &psValue);
    534                 if (result)
     328                fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSMaxCapacityKey), &psValue);
     329                if (fResult)
    535330                    CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &maxCapacity);
    536331
     
    546341                    int timeToEmpty = -1;
    547342                    /* Get the time till the battery source will be empty */
    548                     result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToEmptyKey), &psValue);
    549                     if (result)
     343                    fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToEmptyKey), &psValue);
     344                    if (fResult)
    550345                        CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &timeToEmpty);
    551346                    if (timeToEmpty != -1)
     
    554349                }
    555350
    556                 if (powerSource == PDM_ACPI_POWER_SOURCE_OUTLET &&
    557                     CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSIsChargingKey), &psValue))
     351                if (   powerSource == PDM_ACPI_POWER_SOURCE_OUTLET
     352                    && CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSIsChargingKey), &psValue))
    558353                {
    559354                    /* We are running on an AC power source, but we also have a
     
    565360                        int timeToFull = -1;
    566361                        /* Get the time till the battery source will be charged */
    567                         result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToFullChargeKey), &psValue);
    568                         if (result)
     362                        fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSTimeToFullChargeKey), &psValue);
     363                        if (fResult)
    569364                            CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &timeToFull);
    570365                        if (timeToFull != -1)
     
    576371                /* Check for critical */
    577372                int criticalValue = 20;
    578                 result = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSDeadWarnLevelKey), &psValue);
    579                 if (result)
     373                fResult = CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSDeadWarnLevelKey), &psValue);
     374                if (fResult)
    580375                    CFNumberGetValue((CFNumberRef)psValue, kCFNumberSInt32Type, &criticalValue);
    581376                if (remCapacity < criticalValue)
     
    586381    CFRelease(pBlob);
    587382    CFRelease(pSources);
     383
    588384#elif defined(RT_OS_FREEBSD)
    589385    /* We try to use /dev/acpi first and if that fails use the sysctls. */
     
    650446                             * The current power rate can be calculated with P = U * I
    651447                             */
    652                             *pu32PresentRate = (uint32_t)((((float)BatteryIo.bst.volt/1000.0) * ((float)BatteryIo.bst.rate/1000.0)) * 1000.0);
     448                            *pu32PresentRate = (uint32_t)(  (  ((float)BatteryIo.bst.volt/1000.0)
     449                                                             * ((float)BatteryIo.bst.rate/1000.0))
     450                                                          * 1000.0);
    653451                        }
    654452                    }
     
    690488                cbParameter = sizeof(curCapacity);
    691489                rc = sysctlbyname("hw.acpi.battery.life", &curCapacity, &cbParameter, NULL, NULL);
    692                 if ((!rc) && (curCapacity >= 0))
     490                if (!rc && curCapacity >= 0)
    693491                    *penmRemainingCapacity = (PDMACPIBATCAPACITY)curCapacity;
    694492
     
    697495        }
    698496    }
     497
    699498#endif /* RT_OS_FREEBSD */
     499
    700500    return VINF_SUCCESS;
    701501}
     502
     503#ifdef RT_OS_LINUX
     504/**
     505 * Poller thread for /proc/acpi status files.
     506 *
     507 * Reading these files takes ages (several seconds) on some hosts, therefore
     508 * start this thread. The termination of this thread may take some seconds
     509 * on such a hosts!
     510 *
     511 * @param   pDrvIns     The driver instance data.
     512 * @param   pThread     The thread.
     513 */
     514static DECLCALLBACK(int) drvACPIPoller(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
     515{
     516    PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
     517
     518    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
     519        return VINF_SUCCESS;
     520
     521    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     522    {
     523        /*
     524         * Read the status of the powerline-adapter.
     525         */
     526
     527        PDMACPIPOWERSOURCE enmPowerSource = PDM_ACPI_POWER_SOURCE_UNKNOWN;
     528        PRTSTREAM pStrmStatus;
     529        PRTDIR pDir = NULL;
     530        RTDIRENTRY DirEntry;
     531        char szLine[1024];
     532        int rc = RTDirOpen(&pDir, "/proc/acpi/ac_adapter/");
     533        if (RT_SUCCESS(rc))
     534        {
     535            while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     536            {
     537                rc = RTDirRead(pDir, &DirEntry, NULL);
     538                if (RT_FAILURE(rc))
     539                    break;
     540                if (   strcmp(DirEntry.szName, ".") == 0
     541                    || strcmp(DirEntry.szName, "..") == 0)
     542                    continue;
     543                rc = RTStrmOpenF("r", &pStrmStatus,
     544                                 "/proc/acpi/ac_adapter/%s/status", DirEntry.szName);
     545                if (RT_FAILURE(rc))
     546                    rc = RTStrmOpenF("r", &pStrmStatus,
     547                                     "/proc/acpi/ac_adapter/%s/state", DirEntry.szName);
     548                if (RT_SUCCESS(rc))
     549                {
     550                    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     551                    {
     552                        rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
     553                        if (RT_FAILURE(rc))
     554                            break;
     555                        if (   strstr(szLine, "Status:") != NULL
     556                            || strstr(szLine, "state:") != NULL)
     557                        {
     558                            if (strstr(szLine, "on-line") != NULL)
     559                                enmPowerSource = PDM_ACPI_POWER_SOURCE_OUTLET;
     560                            else
     561                                enmPowerSource = PDM_ACPI_POWER_SOURCE_BATTERY;
     562                            break;
     563                        }
     564                    }
     565                    RTStrmClose(pStrmStatus);
     566                    break;
     567                }
     568            }
     569            RTDirClose(pDir);
     570        }
     571
     572        /*
     573         * Read the status of all batteries and collect it into one.
     574         */
     575
     576        int32_t maxCapacityTotal = INT32_MIN; /* the summed up maximum capacity */
     577        int32_t currentCapacityTotal = INT32_MIN; /* the summed up total capacity */
     578        int32_t presentRate = 0;
     579        int32_t presentRateTotal = 0;
     580        bool    fBatteryPresent = false;
     581        bool    fCharging = false;
     582        bool    fDischarging = false;
     583        bool    fCritical = false;
     584
     585        rc = RTDirOpen(&pDir, "/proc/acpi/battery/");
     586        if (RT_SUCCESS(rc))
     587        {
     588            while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     589            {
     590                rc = RTDirRead(pDir, &DirEntry, NULL);
     591                if (RT_FAILURE(rc))
     592                    break;
     593                if (   strcmp(DirEntry.szName, ".") == 0
     594                    || strcmp(DirEntry.szName, "..") == 0)
     595                    continue;
     596
     597                pStrmStatus;
     598                rc = RTStrmOpenF("r", &pStrmStatus,
     599                                 "/proc/acpi/battery/%s/status", DirEntry.szName);
     600                /* there is a 2nd variant of that file */
     601                if (RT_FAILURE(rc))
     602                {
     603                    rc = RTStrmOpenF("r", &pStrmStatus,
     604                                     "/proc/acpi/battery/%s/state", DirEntry.szName);
     605                }
     606                if (RT_FAILURE(rc))
     607                    continue;
     608
     609                PRTSTREAM pStrmInfo;
     610                rc = RTStrmOpenF("r", &pStrmInfo,
     611                                 "/proc/acpi/battery/%s/info", DirEntry.szName);
     612                if (RT_FAILURE(rc))
     613                {
     614                    RTStrmClose(pStrmStatus);
     615                    continue;
     616                }
     617
     618                /* get 'present' status from the info file */
     619                while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     620                {
     621                    rc = RTStrmGetLine(pStrmInfo, szLine, sizeof(szLine));
     622                    if (RT_FAILURE(rc))
     623                        break;
     624                    if (strstr(szLine, "present:") != NULL)
     625                    {
     626                        if (strstr(szLine, "yes") != NULL)
     627                        {
     628                            fBatteryPresent = true;
     629                            break;
     630                        }
     631                    }
     632                }
     633
     634                RTStrmRewind(pStrmInfo);
     635                if (fBatteryPresent)
     636                {
     637                    /* get the maximum capacity from the info file */
     638                    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     639                    {
     640                        int32_t maxCapacity = INT32_MIN;
     641                        rc = RTStrmGetLine(pStrmInfo, szLine, sizeof(szLine));
     642                        if (RT_FAILURE(rc))
     643                            break;
     644                        if (strstr(szLine, "last full capacity:") != NULL)
     645                        {
     646                            rc = RTStrToInt32Full(szLine + 19, 0, &maxCapacity);
     647                            if (RT_FAILURE(rc))
     648                                maxCapacity = INT32_MIN;
     649
     650                            /* did we get a valid capacity and it's the first value we got? */
     651                            if (maxCapacityTotal < 0 && maxCapacity > 0)
     652                            {
     653                                /* take this as the maximum capacity */
     654                                maxCapacityTotal = maxCapacity;
     655                            }
     656                            else
     657                            {
     658                                /* sum up the maximum capacity */
     659                                if (maxCapacityTotal > 0 && maxCapacity > 0)
     660                                    maxCapacityTotal += maxCapacity;
     661                            }
     662                            /* we got all we need */
     663                            break;
     664                        }
     665                    }
     666
     667                    /* get the current capacity/state from the status file */
     668                    bool fGotRemainingCapacity = false;
     669                    bool fGotBatteryState = false;
     670                    bool fGotCapacityState = false;
     671                    bool fGotPresentRate = false;
     672                    while (  (   !fGotRemainingCapacity
     673                              || !fGotBatteryState
     674                              || !fGotCapacityState
     675                              || !fGotPresentRate)
     676                           && pThread->enmState == PDMTHREADSTATE_RUNNING)
     677                    {
     678                        int32_t currentCapacity = INT32_MIN;
     679                        rc = RTStrmGetLine(pStrmStatus, szLine, sizeof(szLine));
     680                        if (RT_FAILURE(rc))
     681                            break;
     682                        if (strstr(szLine, "remaining capacity:") != NULL)
     683                        {
     684                            rc = RTStrToInt32Full(szLine + 19, 0, &currentCapacity);
     685                            if (RT_FAILURE(rc))
     686                                currentCapacity = INT32_MIN;
     687
     688                            /* is this the first valid value we see? If so, take it! */
     689                            if (currentCapacityTotal < 0 && currentCapacity >= 0)
     690                            {
     691                                currentCapacityTotal = currentCapacity;
     692                            }
     693                            else
     694                            {
     695                                /* just sum up the current value */
     696                                if (currentCapacityTotal > 0 && currentCapacity > 0)
     697                                    currentCapacityTotal += currentCapacity;
     698                            }
     699                            fGotRemainingCapacity = true;
     700                        }
     701                        else if (strstr(szLine, "charging state:") != NULL)
     702                        {
     703                            if (strstr(szLine + 15, "discharging") != NULL)
     704                                fDischarging = true;
     705                            else if (strstr(szLine + 15, "charging") != NULL)
     706                                fCharging = true;
     707                            fGotBatteryState = true;
     708                        }
     709                        else if (strstr(szLine, "capacity state:") != NULL)
     710                        {
     711                            if (strstr(szLine + 15, "critical") != NULL)
     712                                fCritical = true;
     713                            fGotCapacityState = true;
     714                        }
     715                        if (strstr(szLine, "present rate:") != NULL)
     716                        {
     717                            rc = RTStrToInt32Full(szLine + 13, 0, &presentRate);
     718                            if (RT_FAILURE(rc))
     719                                presentRate = 0;
     720                            fGotPresentRate = true;
     721                        }
     722                    }
     723                }
     724
     725                if (presentRate)
     726                {
     727                    if (fDischarging)
     728                        presentRateTotal -= presentRate;
     729                    else
     730                        presentRateTotal += presentRate;
     731                }
     732
     733                RTStrmClose(pStrmStatus);
     734                RTStrmClose(pStrmInfo);
     735            }
     736            RTDirClose(pDir);
     737        }
     738
     739        /* atomic update of the state */
     740        RTCritSectEnter(&pThis->CritSect);
     741        pThis->enmPowerSource = enmPowerSource;
     742        pThis->fBatteryPresent = fBatteryPresent;
     743
     744        /* charging/discharging bits are mutual exclusive */
     745        uint32_t uBs = PDM_ACPI_BAT_STATE_CHARGED;
     746        if (fDischarging)
     747            uBs = PDM_ACPI_BAT_STATE_DISCHARGING;
     748        else if (fCharging)
     749            uBs = PDM_ACPI_BAT_STATE_CHARGING;
     750        if (fCritical)
     751            uBs |= PDM_ACPI_BAT_STATE_CRITICAL;
     752        pThis->enmBatteryState = (PDMACPIBATSTATE)uBs;
     753
     754        if (maxCapacityTotal > 0 && currentCapacityTotal > 0)
     755        {
     756            if (presentRateTotal < 0)
     757                presentRateTotal = -presentRateTotal;
     758
     759            /* calculate the percentage */
     760            pThis->enmBatteryRemainingCapacity =
     761                                 (PDMACPIBATCAPACITY)( (  (float)currentCapacityTotal
     762                                                        / (float)maxCapacityTotal)
     763                                                      * PDM_ACPI_BAT_CAPACITY_MAX);
     764            pThis->u32BatteryPresentRate =
     765                                 (uint32_t)((  (float)presentRateTotal
     766                                             / (float)maxCapacityTotal) * 1000);
     767        }
     768        RTCritSectLeave(&pThis->CritSect);
     769
     770        /* wait a bit (e.g. Ubuntu/GNOME polls every 30 seconds) */
     771        rc = RTSemEventWait(pThis->hPollerSleepEvent, 20000);
     772    }
     773
     774    return VINF_SUCCESS;
     775}
     776
     777static DECLCALLBACK(int) drvACPIPollerWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
     778{
     779    PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
     780
     781    RTSemEventSignal(pThis->hPollerSleepEvent);
     782    RTThreadPoke(pThread->Thread);
     783    return VINF_SUCCESS;
     784}
     785#endif /* RT_OS_LINUX */
     786
    702787
    703788/**
     
    711796static DECLCALLBACK(void) drvACPIDestruct(PPDMDRVINS pDrvIns)
    712797{
     798    PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
     799
    713800    LogFlow(("drvACPIDestruct\n"));
    714801    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
     802
     803    RTSemEventDestroy(pThis->hPollerSleepEvent);
     804    pThis->hPollerSleepEvent = NIL_RTSEMEVENT;
     805    RTCritSectDelete(&pThis->CritSect);
    715806}
    716807
     
    724815    PDRVACPI pThis = PDMINS_2_DATA(pDrvIns, PDRVACPI);
    725816    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
     817    int rc = VINF_SUCCESS;
    726818
    727819    /*
     
    758850    }
    759851
    760     return VINF_SUCCESS;
     852#ifdef RT_OS_LINUX
     853    /*
     854     * Start the poller thread.
     855     */
     856    rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pThis->pPollerThread, pThis, drvACPIPoller,
     857                                  drvACPIPollerWakeup, 0, RTTHREADTYPE_INFREQUENT_POLLER, "ACPI Poller");
     858    if (RT_FAILURE(rc))
     859        return rc;
     860
     861    rc = RTCritSectInit(&pThis->CritSect);
     862    if (RT_FAILURE(rc))
     863        return rc;
     864
     865    rc = RTSemEventCreate(&pThis->hPollerSleepEvent);
     866#endif
     867
     868    return rc;
    761869}
    762870
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette