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 GuestInfoCollector * GuestInfoConstructCollector(GuestInfoQuery *queries, // IN: uint32 numQueries) // IN: { uint32 i; uint32 regExp = 0; GuestInfoCollector *collector = calloc(1, sizeof *collector); if (collector == NULL) { return NULL; } collector->reportMap = HashTable_Alloc(256, HASH_INT_KEY, NULL); collector->exactMatches = HashTable_Alloc(256, HASH_STRING_KEY | HASH_FLAG_COPYKEY, NULL); collector->numRegExps = 0; for (i = 0; i < numQueries; i++) { if (queries[i].isRegExp && queries[i].collect) { collector->numRegExps++; } } collector->numStats = numQueries; collector->stats = calloc(numQueries, sizeof *collector->stats); collector->regExps = calloc(collector->numRegExps, sizeof(GuestInfoStat *)); if ((collector->exactMatches == NULL) || (collector->reportMap == NULL) || ((collector->numRegExps != 0) && (collector->regExps == NULL)) || ((collector->numStats != 0) && (collector->stats == NULL))) { GuestInfoDestroyCollector(collector); return NULL; } regExp = 0; for (i = 0; i < numQueries; i++) { GuestInfoQuery *query = &queries[i]; GuestInfoStat *stat = &collector->stats[i]; ASSERT(query->reportID); stat->query = query; if (!query->collect) { continue; } if (query->isRegExp) { ASSERT(query->locatorString); collector->regExps[regExp++] = stat; } else { if (query->locatorString != NULL) { HashTable_Insert(collector->exactMatches, query->locatorString, stat); } } /* The report lookup */ HashTable_Insert(collector->reportMap, INT_AS_HASHKEY(query->reportID), stat); } return collector; }
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")); } }