static void GuestInfoLegacy(GuestInfoCollector *current, // IN: current collection GuestMemInfo *legacy) // OUT: data filled out { GuestInfoStat *stat; memset(legacy, 0, sizeof *legacy); legacy->version = GUESTMEMINFO_V5; legacy->flags = 0; stat = NULL; HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_MemPhysUsable), (void **) &stat); if ((stat != NULL) && (stat->err == 0)) { legacy->memTotal = stat->value; legacy->flags |= MEMINFO_MEMTOTAL; } stat = NULL; HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_HugePagesTotal), (void **) &stat); if ((stat != NULL) && (stat->err == 0)) { legacy->hugePagesTotal = stat->value; legacy->flags |= MEMINFO_HUGEPAGESTOTAL; } }
static void GuestInfoDeriveSwapData(GuestInfoCollector *collector) // IN: current collection { uint64 swapFree = 0; uint64 swapTotal = 0; uint64 swapUsed = 0; GuestInfoStat *swapSpaceRemaining = NULL; GuestInfoStat *swapSpaceUsed = NULL; GuestInfoStat *swapFilesCurrent = NULL; GuestInfoStat *swapFilesMax = NULL; HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_SwapFilesMax), (void **) &swapFilesMax); HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_SwapFilesCurrent), (void **) &swapFilesCurrent); HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_SwapSpaceUsed), (void **) &swapSpaceUsed); HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_SwapSpaceRemaining), (void **) &swapSpaceRemaining); /* * Start by getting SwapTotal (from Id_SwapFilesCurrent). * Set Id_SwapFilesMax to that if it doesn't have its own opinion. */ if ((swapFilesCurrent != NULL) && (swapFilesCurrent->err == 0)) { swapTotal = swapFilesCurrent->value; if ((swapFilesMax != NULL) && (swapFilesMax->err != 0)) { swapFilesMax->value = swapTotal; swapFilesMax->count = 1; swapFilesMax->err = 0; } /* * Get SwapFree (from Id_SwapSpaceRemaining) * Set Id_SwapSpaceUsed to SwapTotal-SwapFree if it doesn't have its * own opinion. */ if ((swapSpaceRemaining != NULL) && (swapSpaceRemaining->err == 0)) { swapFree = swapSpaceRemaining->value; ASSERT(swapTotal >= swapFree); swapUsed = (swapTotal >= swapFree) ? swapTotal - swapFree : 0; if ((swapSpaceUsed != NULL) && (swapSpaceUsed->err != 0)) { swapSpaceUsed->value = swapUsed; swapSpaceUsed->count = 1; swapSpaceUsed->err = 0; } } } }
static void GuestInfoAppendRate(Bool emitNameSpace, // IN: GuestStatToolsID reportID, // IN: Id of the stat GuestInfoCollector *current, // IN: current collection GuestInfoCollector *previous, // IN: previous collection DynBuf *statBuf) // IN/OUT: stat data { double valueDouble = 0.0; int errnoValue = ENOENT; GuestInfoStat *currentStat = NULL; GuestInfoStat *previousStat = NULL; HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(reportID), (void **) ¤tStat); HashTable_Lookup(previous->reportMap, INT_AS_HASHKEY(reportID), (void **) &previousStat); if (current->timeData && previous->timeData && ((currentStat != NULL) && (currentStat->err == 0)) && ((previousStat != NULL) && (previousStat->err == 0))) { double timeDelta = current->timeStamp - previous->timeStamp; double valueDelta = currentStat->value - previousStat->value; valueDouble = valueDelta / timeDelta; errnoValue = 0; } if (currentStat != NULL) { float valueFloat; void *valuePointer; size_t valueSize; if (valueDouble == 0) { valuePointer = NULL; valueSize = 0; } else { valueFloat = (float)valueDouble; if ((double)valueFloat == valueDouble) { valuePointer = &valueFloat; valueSize = sizeof valueFloat; } else { valuePointer = &valueDouble; valueSize = sizeof valueDouble; } } GuestInfoAppendStat(errnoValue, emitNameSpace, reportID, currentStat->query->units, GuestTypeDouble, valuePointer, valueSize, statBuf); } }
Err_Number Err_String2Errno(const char *string) // IN { HashTable *ptrTable = PTRTABLE(); ErrInfo *info; if (!HashTable_Lookup(ptrTable, string, (void **) &info)) { return ERR_INVALID; } ASSERT(info->string == string); ASSERT(info->number != ERR_INVALID); return info->number; }
static INLINE MsgCatalog * MsgGetCatalog(const char *domain) { MsgState *state = MsgGetState(); MsgCatalog *catalog = NULL; ASSERT(domain != NULL); if (state->domains != NULL) { MsgCatalog *domaincat; if (HashTable_Lookup(state->domains, domain, (void **) &domaincat)) { catalog = domaincat; } } return catalog; }
ConstUnicode Unicode_GetStatic(const char *asciiBytes, // IN Bool unescape) // IN { Unicode result = NULL; HashTable *stringTable; if (unescape) { stringTable = HashTable_AllocOnce(&UnicodeUnescapedStringTable, 4096, HASH_FLAG_ATOMIC | HASH_STRING_KEY, UnicodeHashFree); } else { stringTable = HashTable_AllocOnce(&UnicodeStringTable, 4096, HASH_FLAG_ATOMIC | HASH_STRING_KEY, UnicodeHashFree); } /* * Attempt a lookup for the key value; if it is found things are easy and * fine. Otherwise HashTable_LookupOrInsert is used to attempt to enter * the data in a racey manner. Should multiple threads attempt to enter * the same key concurrently one thread will get the entered data and the * other threads will detect that their entries were rejected; they * discard their copies of the data and use the entered data (values * will be stable). */ if (!HashTable_Lookup(stringTable, asciiBytes, (void **) &result)) { Unicode newData = UnicodeAllocStatic(asciiBytes, unescape); if (newData) { result = HashTable_LookupOrInsert(stringTable, asciiBytes, newData); if (result != newData) { Unicode_Free(newData); } } } return result; }
Err_Number Err_String2ErrnoDebug(const char *string) // IN { #ifdef __linux__ HashTable *strTable = STRTABLE(); ErrInfo *info; if (!HashTable_Lookup(strTable, string, (void **) &info)) { return ERR_INVALID; } ASSERT(Str_Strcmp(info->string, string) == 0); ASSERT(info->number != ERR_INVALID); if (info->string != string) { Log("%s: errno %d, string \"%s\" at %p, originally at %p.\n", __FUNCTION__, info->number, string, string, info->string); } return info->number; #else return ERR_INVALID; #endif }
static void GuestInfoCollectStat(const char *pathName, // IN: GuestInfoCollector *collector, // IN/OUT: const char *fieldName, // IN: uint64 value) // IN: { GuestInfoStat *stat = NULL; if (!HashTable_Lookup(collector->exactMatches, fieldName, (void **) &stat)) { uint32 i; for (i = 0; i < collector->numRegExps; i++) { GuestInfoStat *thisOne = collector->regExps[i]; if (StrUtil_StartsWith(fieldName, thisOne->query->locatorString)) { stat = thisOne; } } } if (stat != NULL) { GuestInfoStoreStat(pathName, stat, value); } }
static HolderContext * MXUserGetHolderContext(MXUserRWLock *lock) // IN: { HolderContext *result; void *threadID = MXUserCastedThreadID(); ASSERT(lock->holderTable); if (!HashTable_Lookup(lock->holderTable, threadID, (void **) &result)) { HolderContext *newContext = Util_SafeMalloc(sizeof(HolderContext)); newContext->holdStart = 0; newContext->state = RW_UNLOCKED; result = HashTable_LookupOrInsert(lock->holderTable, threadID, (void *) newContext); if (result != newContext) { free(newContext); } } return result; }
static void GuestInfoAppendMemNeeded(GuestInfoCollector *current, // IN: current collection Bool emitNameSpace, // IN: DynBuf *statBuf) // IN/OUT: stats data { uint64 memNeeded; uint64 memNeededReservation; uint64 memAvailable = 0; GuestInfoStat *memAvail = NULL; GuestInfoStat *memPhysUsable = NULL; HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_MemPhysUsable), (void **) &memPhysUsable); ASSERT(memPhysUsable != NULL); HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemAvailable), (void **) &memAvail); if ((memAvail != NULL) && (memAvail->err == 0)) { memAvailable = memAvail->value; } else { GuestInfoStat *memFree = NULL; GuestInfoStat *memCache = NULL; GuestInfoStat *memBuffers = NULL; GuestInfoStat *memActiveFile = NULL; GuestInfoStat *memSlabReclaim = NULL; GuestInfoStat *memInactiveFile = NULL; GuestInfoStat *lowWaterMark = NULL; HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_MemFree), (void **) &memFree); HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemCached), (void **) &memCache); HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemBuffers), (void **) &memBuffers); HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_MemActiveFileCache), (void **) &memActiveFile); HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemSlabReclaim), (void **) &memSlabReclaim); HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemInactiveFile), (void **) &memInactiveFile); HashTable_Lookup(current->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_LowWaterMark), (void **) &lowWaterMark); if (((memFree != NULL) && (memFree->err == 0)) && ((memCache != NULL) && (memCache->err == 0)) && ((memBuffers != NULL) && (memBuffers->err == 0)) && (memActiveFile != NULL) && (memSlabReclaim != NULL) && (memInactiveFile != NULL) && ((lowWaterMark != NULL) && (lowWaterMark->err == 0))) { uint64 pageCache; unsigned long kbPerPage = sysconf(_SC_PAGESIZE) / 1024UL; uint64 lowWaterMarkValue = lowWaterMark->value * kbPerPage; memAvailable = memFree->value - lowWaterMarkValue; if ((memActiveFile->err == 0) && (memInactiveFile->err == 0)) { pageCache = memActiveFile->value + memInactiveFile->value; } else { /* * If the kernel is too old to expose Active/Inactive file, * this is the best approxmation for pageCache. */ pageCache = memCache->value + memBuffers->value; } pageCache -= MIN(pageCache / 2, lowWaterMarkValue); memAvailable += pageCache; if (memSlabReclaim->err == 0) { memAvailable += memSlabReclaim->value - MIN(memSlabReclaim->value / 2, lowWaterMarkValue); } if ((int64)memAvailable < 0) { memAvailable = 0; } } } if (memPhysUsable->err == 0) { /* * Reserve 5% of physical RAM for surges. */ memNeededReservation = memPhysUsable->value / 20; if (memAvailable > memNeededReservation) { memAvailable -= memNeededReservation; } else { memAvailable = 0; } /* * We got these values from one read of /proc/meminfo. Everything should * really be coherent. */ ASSERT(memPhysUsable->value >= memAvailable); memNeeded = memPhysUsable->value - memAvailable; } else { memNeeded = 0; memNeededReservation = 0; } GuestInfoAppendStat(0, emitNameSpace, GuestStatID_MemNeeded, GuestUnitsKiB, GuestTypeUint64, &memNeeded, GuestInfoBytesNeededUIntDatum(memNeeded), statBuf); emitNameSpace = FALSE; }
static void GuestInfoCollect(GuestInfoCollector *collector) // IN: { uint32 i; GuestInfoStat *stat; uint64 pageSize = sysconf(_SC_PAGESIZE); /* Reset all values */ for (i = 0; i < collector->numStats; i++) { GuestInfoStat *stat = &collector->stats[i]; stat->err = ENOENT; // There is no data here stat->count = 0; stat->value = 0; } /* Collect new values */ GuestInfoProcMemInfoData(collector); GuestInfoProcData(VMSTAT_FILE, collector); GuestInfoProcData(STAT_FILE, collector); GuestInfoProcData(ZONEINFO_FILE, collector); GuestInfoDeriveSwapData(collector); collector->timeData = GuestInfoGetUpTime(&collector->timeStamp); /* * We make sure physical page size is always present. */ stat = NULL; HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_PhysicalPageSize), (void **) &stat); if ((stat != NULL) && (stat->err != 0)) { stat->value = pageSize; stat->count = 1; stat->err = 0; } /* * Attempt to fix up memPhysUsable if it is not available. */ stat = NULL; HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_MemPhysUsable), (void **) &stat); ASSERT(stat != NULL); // Must be in table if (stat->err == 0) { stat->value *= (pageSize / 1024); // Convert pages to KiB } else { GuestInfoStat *memTotal = NULL; HashTable_Lookup(collector->reportMap, INT_AS_HASHKEY(GuestStatID_Linux_MemTotal), (void **) &memTotal); if ((memTotal != NULL) && (memTotal->err == 0)) { stat->err = 0; stat->count = 1; stat->value = memTotal->value; } } }
const char * Err_Errno2String(Err_Number errorNumber) // IN { HashTable *numTable; HashTable *ptrTable; ErrInfo *info; ErrInfo *oldInfo; Err_Number oldErrno = Err_Errno(); ASSERT(errorNumber != ERR_INVALID); /* * Look up the error in numTable. * Or insert it if it's not there. */ numTable = NUMTABLE(); if (!HashTable_Lookup(numTable, (void *) (uintptr_t) errorNumber, (void **) &info)) { char buf[2048]; const char *p; size_t n; /* * Convert number to string and build the info structure. */ p = ErrErrno2String(errorNumber, buf, sizeof buf); info = Util_SafeMalloc(sizeof *info); info->number = errorNumber; info->string = Util_SafeStrdup(p); /* * To be safe, make sure the end of the string is at * a UTF-8 boundary, but we can only do this when the * string is in our buffer (it may not be). */ n = strlen(info->string); n = CodeSet_Utf8FindCodePointBoundary(info->string, n); info->string[n] = '\0'; /* * Try to insert new info into numTable. * If that fails, then we must have lost out to someone else. * Use theirs in that case. */ oldInfo = HashTable_LookupOrInsert(numTable, (void *) (uintptr_t) errorNumber, info); if (oldInfo != info) { ASSERT(oldInfo->number == info->number); ASSERT(Str_Strcmp(oldInfo->string, info->string) == 0); free(info->string); free(info); info = oldInfo; } } /* * Try to insert info into ptrTable. * We need to do it even if we didn't create this entry, * because we may get here before the other guy (who created * the entry and inserted it into numTable). */ ptrTable = PTRTABLE(); oldInfo = HashTable_LookupOrInsert(ptrTable, info->string, info); ASSERT(oldInfo == info); #if defined VMX86_DEBUG && defined __linux__ { HashTable *strTable = STRTABLE(); ErrInfo *i = HashTable_LookupOrInsert(strTable, info->string, info); ASSERT(i == info); } #endif Err_SetErrno(oldErrno); return info->string; }
static const void * MsgGetString(const char *domain, const char *msgid, StringEncoding encoding) { const char *idp; const char *strp; char idBuf[MSG_MAX_ID]; size_t len; HashTable *source = NULL; MsgCatalog *catalog; MsgState *state = MsgGetState(); /* All message strings must be prefixed by the message ID. */ ASSERT(domain != NULL); ASSERT(msgid != NULL); ASSERT(MsgHasMsgID(msgid)); #if defined(_WIN32) ASSERT(encoding == STRING_ENCODING_UTF8 || encoding == STRING_ENCODING_UTF16_LE); #else ASSERT(encoding == STRING_ENCODING_UTF8); #endif /* * Find the beginning of the ID (idp) and the string (strp). * The string should have the correct MSG_MAGIC(...)... form. */ idp = msgid + MSG_MAGIC_LEN + 1; strp = strchr(idp, ')') + 1; len = strp - idp - 1; ASSERT_NOT_IMPLEMENTED(len <= MSG_MAX_ID - 1); memcpy(idBuf, idp, len); idBuf[len] = '\0'; /* * This lock is pretty coarse-grained, but a lot of the code below just runs * in exceptional situations, so it should be OK. */ g_static_mutex_lock(&state->lock); catalog = MsgGetCatalog(domain); if (catalog != NULL) { switch (encoding) { case STRING_ENCODING_UTF8: source = catalog->utf8; break; #if defined(_WIN32) case STRING_ENCODING_UTF16_LE: source = catalog->utf16; break; #endif default: NOT_IMPLEMENTED(); } } #if defined(_WIN32) /* * Lazily create the local and UTF-16 dictionaries. This may require also * registering an empty message catalog for the desired domain. */ if (source == NULL && encoding == STRING_ENCODING_UTF16_LE) { catalog = MsgGetCatalog(domain); if (catalog == NULL) { if (domain == NULL) { g_error("Application did not set up a default text domain."); } catalog = g_new0(MsgCatalog, 1); MsgSetCatalog(domain, catalog); } catalog->utf16 = HashTable_Alloc(8, HASH_STRING_KEY, g_free); ASSERT_MEM_ALLOC(catalog->utf16); source = catalog->utf16; } #endif /* * Look up the localized string, converting to requested encoding as needed. */ if (source != NULL) { const void *retval = NULL; if (HashTable_Lookup(source, idBuf, (void **) &retval)) { strp = retval; #if defined(_WIN32) } else if (encoding == STRING_ENCODING_UTF16_LE) { gchar *converted; Bool success; /* * Look up the string in UTF-8, convert it and cache it. */ retval = MsgGetString(domain, msgid, STRING_ENCODING_UTF8); ASSERT(retval); converted = (gchar *) g_utf8_to_utf16(retval, -1, NULL, NULL, NULL); ASSERT(converted != NULL); success = HashTable_Insert(source, idBuf, converted); ASSERT(success); strp = converted; #endif } } g_static_mutex_unlock(&state->lock); return strp; }
static void VThreadBaseSimpleNoID(void) { VThreadID newID; Bool reused = FALSE; Bool result; void *newNative = VThreadBaseGetNative(); HashTable *ht = VThreadBaseGetNativeHash(); VThreadBaseData *base; /* Require key allocation before TLS read */ VThreadBaseGetKey(); /* Before allocating a new ID, try to reclaim any old IDs. */ for (newID = 0; newID < Atomic_Read(&vthreadBaseGlobals.dynamicID); newID++) { void *newKey = (void *)(uintptr_t)newID; /* * Windows: any entry that is found and not (alive or NULL) * is reclaimable. The check is slightly racy, but the race * would only cause missing a reclaim which isn't a problem. * Posix: thread exit is hooked (via TLS destructor) and sets * entries to NULL, so any entry that is NULL is reclaimable. */ #ifdef _WIN32 void *oldNative; reused = HashTable_Lookup(ht, newKey, &oldNative) && (oldNative == NULL || !VThreadBaseNativeIsAlive(oldNative)) && HashTable_ReplaceIfEqual(ht, newKey, oldNative, newNative); #else reused = HashTable_ReplaceIfEqual(ht, newKey, NULL, newNative); #endif if (reused) { break; } } if (!reused) { void *newKey; newID = Atomic_FetchAndInc(&vthreadBaseGlobals.dynamicID); /* * Detect VThreadID overflow (~0 is used as a sentinel). * Leave a space of ~10 IDs, since the increment and bounds-check * are not atomic. */ ASSERT_NOT_IMPLEMENTED(newID < VTHREAD_INVALID_ID - 10); newKey = (void *)(uintptr_t)newID; result = HashTable_Insert(ht, newKey, newNative); ASSERT_NOT_IMPLEMENTED(result); } /* ID picked. Now do the important stuff. */ base = Util_SafeCalloc(1, sizeof *base); base->id = newID; Str_Sprintf(base->name, sizeof base->name, "vthread-%u", newID); result = VThreadBase_InitWithTLS(base); ASSERT(result); if (vmx86_debug && reused) { Log("VThreadBase reused VThreadID %d.\n", newID); } if (Atomic_Read(&vthreadBaseGlobals.numThreads) > 1) { LOG_ONCE(("VThreadBase detected multiple threads.\n")); } }