| 122 | } |
| 123 | |
| 124 | void BackupSizeCache::workerLoop(void) |
| 125 | { |
| 126 | // std::thread inherits the creator's priority (0x2C, same as the main thread) |
| 127 | // and default core. Horizon does not time-slice same-priority threads on the |
| 128 | // same core, so a long directory walk starves the UI until it blocks on fs |
| 129 | // IPC. Drop below the main thread so the UI always preempts the walk. |
| 130 | // Applications may only use priorities 0x2C-0x3B; anything else fails with |
| 131 | // kernel InvalidPriority (0xE001), so take the lowest allowed one. |
| 132 | const Result prioRc = svcSetThreadPriority(CUR_THREAD_HANDLE, 0x3B); |
| 133 | if (R_FAILED(prioRc)) { |
| 134 | Logging::warning("[sizecache] svcSetThreadPriority failed: 0x{:08X}", prioRc); |
| 135 | } |
| 136 | |
| 137 | for (;;) { |
| 138 | std::pair<u64, std::string> task; |
| 139 | { |
| 140 | std::unique_lock<std::mutex> lock(mMutex); |
| 141 | mCond.wait(lock, [this]() { return mStop.load() || !mQueue.empty(); }); |
| 142 | if (mStop.load()) { |
| 143 | return; |
| 144 | } |
| 145 | // LIFO: take the most recently queued task. While browsing the title list |
| 146 | // this computes the size for the title the user just landed on before the |
| 147 | // now-unfocused ones queued earlier. |
| 148 | task = std::move(mQueue.back()); |
| 149 | mQueue.pop_back(); |
| 150 | } |
| 151 | compute(task.first, task.second); |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | void BackupSizeCache::compute(u64 id, const std::string& rootPath) |
| 156 | { |