static void flatten_tree(struct node *tree, struct emitter *emit, void *etarget, struct data *strbuf, struct version_info *vi) { struct property *prop; struct node *child; int seen_name_prop = 0; emit->beginnode(etarget, tree->label); if (vi->flags & FTF_FULLPATH) emit->string(etarget, tree->fullpath, 0); else emit->string(etarget, tree->name, 0); emit->align(etarget, sizeof(cell_t)); for_each_property(tree, prop) { int nameoff; if (streq(prop->name, "name")) seen_name_prop = 1; nameoff = stringtable_insert(strbuf, prop->name); emit->property(etarget, prop->label); emit->cell(etarget, prop->val.len); emit->cell(etarget, nameoff); if ((vi->flags & FTF_VARALIGN) && (prop->val.len >= 8)) emit->align(etarget, 8); emit->data(etarget, prop->val); emit->align(etarget, sizeof(cell_t)); }
void *loom_asset_lock(const char *name, unsigned int type, int block) { const char *namePtr = stringtable_insert(name); loom_mutex_lock(gAssetLock); // Look it up. loom_asset_t *asset = loom_asset_getAssetByName(namePtr, 1); lmAssert(asset != NULL, "Didn't get asset even though we should have!"); // If not loaded, and we aren't ready to block, return NULL. if ((block == 0) && (asset->state != loom_asset_t::Loaded)) { lmLogDebug(gAssetLogGroup, "Not blocking and not loaded yet; lock of '%s' failed.", namePtr); loom_mutex_unlock(gAssetLock); return NULL; } // Otherwise, let's force it to load now. if (asset->state != loom_asset_t::Loaded) { lmLogDebug(gAssetLogGroup, "Blocking so forcing load of '%s'.", namePtr); loom_asset_preload(namePtr); lmAssert(loom_asset_isOnTrackToLoad(asset), "Preloaded but wasn't on track to load!"); while (loom_asset_checkLoadedPercentage(namePtr) != 1.f && loom_asset_isOnTrackToLoad(asset)) { lmLogDebug(gAssetLogGroup, "Pumping load of '%s'...", namePtr); loom_asset_pump(); } if (asset->state != loom_asset_t::Loaded) { lmLogError(gAssetLogGroup, "Unable to load asset '%s'!", name); loom_mutex_unlock(gAssetLock); return NULL; } } // Check type. if (asset->type != type) { lmLogError(gAssetLogGroup, "Tried to lock asset '%s' with wrong type, assetType=%x, requestedType=%x", name, asset->type, type); loom_mutex_unlock(gAssetLock); return NULL; } // Inc count. asset->blob->incRef(); loom_mutex_unlock(gAssetLock); lmLogDebug(gAssetLogGroup, "Locked asset '%s'...", namePtr); // Return ptr. return asset->blob->bits; }
ktap_str_t *kp_str_new(const char *str, size_t l) { ktap_str_t *ts = stringtable_search(str, l); if (ts) return ts; ts = createstrobj(str, l); stringtable_insert(ts); return ts; }
/** * Post all known files to all clients, or if specified, a single client. * * Useful for fully synching client with the current asset state. * * TODO: Optimize to use hashes to only transmit modified data, based on * client's starting assets. */ static void postAllFiles(int clientId = -1) { lmLog(gAssetAgentLogGroup, "Queueing all files for client %d.", clientId); loom_mutex_lock(gFileScannerLock); // Walk all the files. utArray<FileEntry> *list = lmNew(NULL) utArray<FileEntry>(); platform_walkFiles(".", handleFileStateWalkCallback, list); // Queue them all to be sent. for (UTsize i = 0; i < list->size(); i++) { FileModificationNote note; note.path = stringtable_insert((*list)[i].path.c_str()); note.lastSeenTime = 0; note.onlyForClient = clientId; gPendingModifications.push_back(note); } loom_mutex_unlock(gFileScannerLock); }
LoomProfilerRoot::LoomProfilerRoot(const char *name) { for (LoomProfilerRoot *walk = sRootList; walk; walk = walk->mNextRoot) { if (!strcmp(walk->mName, name)) { lmAssert(false, "Duplicate profile name: %s", name); } } mName = name; mNameHash = (int)(long long)stringtable_insert(name); // Poor man's hash mNextRoot = sRootList; sRootList = this; mTotalTime = 0; mSubTime = 0; mMaxTime = 0; mMinTime = INFINITY; mTotalInvokeCount = 0; mFirstLoomProfilerEntry = NULL; mEnabled = true; }
// Take a difference report from compareFileEntries and issue appropriate // file modification notes, and check whether they have settled. If so, // transmit updates to clients. static void processFileEntryDeltas(utArray<FileEntryDelta> *deltas) { int curTime = platform_getMilliseconds(); loom_mutex_lock(gFileScannerLock); // Update the pending list with all the stuff we've seen. for (UTsize i = 0; i < deltas->size(); i++) { // Get the delta. const FileEntryDelta& fed = deltas->at(i); // If it's removal, we don't currently send a notification. if (fed.action == FileEntryDelta::Removed) { continue; } // If it's not whitelisted, ignore it. if (!checkInWhitelist(fed.path)) { continue; } // Note it in the pending modification list. bool sawInList = false; for (UTsize i = 0; i < gPendingModifications.size(); i++) { FileModificationNote& fmn = gPendingModifications.at(i); if (strcmp(fmn.path, fed.path.c_str())) { continue; } // Match - update time. lmLogDebug(gAssetAgentLogGroup, "FILE CHANGING - '%s'", fed.path.c_str()); fmn.lastSeenTime = curTime; sawInList = true; } if (!sawInList) { FileModificationNote fmn; fmn.path = stringtable_insert(fed.path.c_str()); fmn.lastSeenTime = curTime; gPendingModifications.push_back(fmn); lmLogDebug(gAssetAgentLogGroup, "FILE CHANGED - '%s'", fed.path.c_str()); } } // Now, walk the pending list and send everyone who hasn't been touched for the settling period. // See how many files we're sending and note that state. const int settleTimeMs = 750; int transferStartTime = platform_getMilliseconds(); int totalPendingTransfers = 0; for (UTsize i = 0; i < gPendingModifications.size(); i++) { // Only consider pending items that have aged out. FileModificationNote& fmn = gPendingModifications.at(i); if (curTime - fmn.lastSeenTime < settleTimeMs) { continue; } totalPendingTransfers++; } bool didWeNotifyUserAboutPending = false; for (UTsize i = 0; i < gPendingModifications.size(); i++) { // Only consider pending items that have aged out. FileModificationNote& fmn = gPendingModifications.at(i); if (curTime - fmn.lastSeenTime < settleTimeMs) { continue; } // Make the path canonical. utString filename = fmn.path; char canonicalFile[MAXPATHLEN]; makeAssetPathCanonical(filename.c_str(), canonicalFile); // Note: we don't deal with deleted files properly (by uploading new state) because realpath // only works right when the file exists. So we just skip doing anything about it. // Note we are using gActiveHandlers.size() outside of a lock, but this is ok as it's a word. if ((strstr(canonicalFile, ".loom") || strstr(canonicalFile, ".ls")) && (gActiveHandlers.size() > 0)) { lmLog(gAssetAgentLogGroup, "Changed '%s'", canonicalFile); } if (canonicalFile[0] == 0) { lmLog(gAssetAgentLogGroup, " o Ignoring file missing from the asset folder!"); // Remove from the pending list. gPendingModifications.erase(i); i--; continue; } // Queue the callback. enqueueFileChangeCallback(canonicalFile); // Map the file. void *fileBits = NULL; long fileBitsLength = 0; if (!platform_mapFile(canonicalFile, &fileBits, &fileBitsLength)) { lmLog(gAssetAgentLogGroup, " o Skipping due to file failing to map."); continue; } // Loop over the active sockets. loom_mutex_lock(gActiveSocketsMutex); // Blast it out to all clients. for (UTsize j = 0; j < gActiveHandlers.size(); j++) { // If it's for a specific client then only send to that client. if ((fmn.onlyForClient != -1) && (fmn.onlyForClient != gActiveHandlers[j]->getId())) { continue; } gActiveHandlers[j]->sendFile(canonicalFile, fileBits, fileBitsLength, totalPendingTransfers); // If it has been more than a second, note that we are still working. const int remainingTransferCount = (totalPendingTransfers * gActiveHandlers.size()) - j; if (((platform_getMilliseconds() - transferStartTime) > 2000) && (remainingTransferCount > 1)) { transferStartTime = platform_getMilliseconds(); lmLog(gAssetAgentLogGroup, "Still transferring files. %d to go!", remainingTransferCount - 1); didWeNotifyUserAboutPending = true; } } loom_mutex_unlock(gActiveSocketsMutex); totalPendingTransfers--; // Unmap the file. platform_unmapFile(fileBits); // Remove from the pending list. gPendingModifications.erase(i); i--; } loom_mutex_unlock(gFileScannerLock); if (didWeNotifyUserAboutPending) { lmLog(gAssetAgentLogGroup, "Done transferring files!"); } }