remove loadedFoldersMutex; bugfixes

This commit is contained in:
nakst 2021-08-19 17:22:38 +01:00
parent 9ad6930ac7
commit db3f454bba
7 changed files with 127 additions and 160 deletions

View File

@ -64,8 +64,11 @@ void CommandRename(Instance *instance, EsElement *, EsCommand *) {
EsDirectoryChild information = {}; EsDirectoryChild information = {};
EsPathQueryInformation(newPath, newPathBytes, &information); EsPathQueryInformation(newPath, newPathBytes, &information);
EsMutexAcquire(&folder->modifyEntriesMutex);
EsAssert(folder->doneInitialEnumeration);
uint64_t id = FolderRemoveEntryAndUpdateInstances(folder, STRING(task->string2)); uint64_t id = FolderRemoveEntryAndUpdateInstances(folder, STRING(task->string2));
FolderAddEntryAndUpdateInstances(folder, STRING(task->string), &information, instance, false, id); FolderAddEntryAndUpdateInstances(folder, STRING(task->string), &information, instance, id);
EsMutexRelease(&folder->modifyEntriesMutex);
EsHeapFree(oldPath); EsHeapFree(oldPath);
EsHeapFree(newPath); EsHeapFree(newPath);
@ -102,7 +105,10 @@ void CommandNewFolder(Instance *instance, EsElement *, EsCommand *) {
Folder *folder = instance->folder; Folder *folder = instance->folder;
EsDirectoryChild information = {}; EsDirectoryChild information = {};
information.type = ES_NODE_DIRECTORY; information.type = ES_NODE_DIRECTORY;
FolderAddEntryAndUpdateInstances(folder, STRING(task->string), &information, instance, false); EsMutexAcquire(&folder->modifyEntriesMutex);
EsAssert(folder->doneInitialEnumeration);
FolderAddEntryAndUpdateInstances(folder, STRING(task->string), &information, instance);
EsMutexRelease(&folder->modifyEntriesMutex);
CommandRename(instance, nullptr, nullptr); CommandRename(instance, nullptr, nullptr);
} }
@ -136,9 +142,7 @@ void InstanceRegisterCommands(Instance *instance) {
}, stableCommandID++, "Alt+Up"); }, stableCommandID++, "Alt+Up");
EsCommandRegister(&instance->commandRefresh, instance, [] (Instance *instance, EsElement *, EsCommand *) { EsCommandRegister(&instance->commandRefresh, instance, [] (Instance *instance, EsElement *, EsCommand *) {
EsMutexAcquire(&loadedFoldersMutex);
FolderRefresh(instance->folder); FolderRefresh(instance->folder);
EsMutexRelease(&loadedFoldersMutex);
}, stableCommandID++, "F5"); }, stableCommandID++, "F5");
EsCommandRegister(&instance->commandNewFolder, instance, CommandNewFolder, stableCommandID++, "Ctrl+Shift+N"); EsCommandRegister(&instance->commandNewFolder, instance, CommandNewFolder, stableCommandID++, "Ctrl+Shift+N");

View File

@ -3,10 +3,11 @@
#define NAMESPACE_HANDLER_ROOT (3) // Acts as a container handler where needed. #define NAMESPACE_HANDLER_ROOT (3) // Acts as a container handler where needed.
#define NAMESPACE_HANDLER_INVALID (4) // For when a folder does not exist. #define NAMESPACE_HANDLER_INVALID (4) // For when a folder does not exist.
EsMutex loadedFoldersMutex;
Array<Folder *> loadedFolders; Array<Folder *> loadedFolders;
#define MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES (20) // #define MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES (20)
// TODO Temporary.
#define MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES (0)
Array<Folder *> foldersWithNoAttachedInstances; Array<Folder *> foldersWithNoAttachedInstances;
///////////////////////////////// /////////////////////////////////
@ -68,15 +69,16 @@ EsError FSDirEnumerate(Folder *folder) {
EsDirectoryChild *buffer = nullptr; EsDirectoryChild *buffer = nullptr;
ptrdiff_t _entryCount = EsDirectoryEnumerateChildren(STRING(folder->path), &buffer); ptrdiff_t _entryCount = EsDirectoryEnumerateChildren(STRING(folder->path), &buffer);
if (ES_CHECK_ERROR(_entryCount)) { if (!ES_CHECK_ERROR(_entryCount)) {
EsHeapFree(buffer); for (intptr_t i = 0; i < _entryCount; i++) {
return (EsError) _entryCount; FolderAddEntry(folder, buffer[i].name, buffer[i].nameBytes, &buffer[i]);
}
_entryCount = ES_SUCCESS;
} }
FolderAddEntries(folder, buffer, _entryCount);
EsHeapFree(buffer); EsHeapFree(buffer);
return (EsError) _entryCount;
return ES_SUCCESS;
} }
void FSDirGetTotalSize(Folder *folder) { void FSDirGetTotalSize(Folder *folder) {
@ -252,6 +254,8 @@ void NamespaceFindHandlersForPath(NamespaceHandler **itemHandler, NamespaceHandl
} }
} }
} }
EsAssert(*itemHandler && *containerHandler); // NAMESPACE_HANDLER_INVALID should handle failure cases.
} }
uint32_t NamespaceGetIcon(String path) { uint32_t NamespaceGetIcon(String path) {
@ -327,6 +331,10 @@ void FolderDestroy(Folder *folder) {
} }
} }
StringDestroy(&folder->path);
folder->attachedInstances.Free();
HashTableFree(&folder->entries, false);
EsMutexDestroy(&folder->modifyEntriesMutex);
EsHeapFree(folder); EsHeapFree(folder);
} }
@ -335,8 +343,10 @@ void FolderDetachInstance(Instance *instance) {
if (!folder) return; if (!folder) return;
instance->folder = nullptr; instance->folder = nullptr;
folder->attachedInstances.FindAndDeleteSwap(instance, true); folder->attachedInstances.FindAndDeleteSwap(instance, true);
folder->referenceCount--;
if (!folder->attachedInstances.Length() && !folder->attachingInstances.Length()) { if (!folder->referenceCount) {
EsAssert(!folder->attachedInstances.Length());
foldersWithNoAttachedInstances.Add(folder); foldersWithNoAttachedInstances.Add(folder);
if (foldersWithNoAttachedInstances.Length() > MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES) { if (foldersWithNoAttachedInstances.Length() > MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES) {
@ -391,16 +401,8 @@ FolderEntry *FolderAddEntry(Folder *folder, const char *_name, size_t nameBytes,
return entry; return entry;
} }
void FolderAddEntries(Folder *folder, EsDirectoryChild *buffer, size_t entryCount) {
for (uintptr_t i = 0; i < entryCount; i++) {
FolderAddEntry(folder, buffer[i].name, buffer[i].nameBytes, &buffer[i]);
}
}
void FolderAddEntryAndUpdateInstances(Folder *folder, const char *name, size_t nameBytes, void FolderAddEntryAndUpdateInstances(Folder *folder, const char *name, size_t nameBytes,
EsDirectoryChild *information, Instance *selectItem, bool mutexAlreadyAcquired, uint64_t id = 0) { EsDirectoryChild *information, Instance *selectItem, uint64_t id = 0) {
if (!mutexAlreadyAcquired) EsMutexAcquire(&loadedFoldersMutex);
if (folder->containerHandler->getTotalSize) { if (folder->containerHandler->getTotalSize) {
folder->containerHandler->getTotalSize(folder); folder->containerHandler->getTotalSize(folder);
} }
@ -414,13 +416,9 @@ void FolderAddEntryAndUpdateInstances(Folder *folder, const char *name, size_t n
InstanceAddSingle(instance, listEntry); InstanceAddSingle(instance, listEntry);
InstanceUpdateStatusString(instance); InstanceUpdateStatusString(instance);
} }
if (!mutexAlreadyAcquired) EsMutexRelease(&loadedFoldersMutex);
} }
uint64_t FolderRemoveEntryAndUpdateInstances(Folder *folder, const char *name, size_t nameBytes) { uint64_t FolderRemoveEntryAndUpdateInstances(Folder *folder, const char *name, size_t nameBytes) {
EsMutexAcquire(&loadedFoldersMutex);
FolderEntry *entry = (FolderEntry *) HashTableGetLong(&folder->entries, name, nameBytes); FolderEntry *entry = (FolderEntry *) HashTableGetLong(&folder->entries, name, nameBytes);
uint64_t id = 0; uint64_t id = 0;
@ -434,15 +432,12 @@ uint64_t FolderRemoveEntryAndUpdateInstances(Folder *folder, const char *name, s
FolderEntryCloseHandle(folder, entry); FolderEntryCloseHandle(folder, entry);
} }
EsMutexRelease(&loadedFoldersMutex);
return id; return id;
} }
void FolderPathMoved(Instance *instance, String oldPath, String newPath) { void FolderPathMoved(Instance *instance, String oldPath, String newPath) {
_EsPathAnnouncePathMoved(instance, STRING(oldPath), STRING(newPath)); _EsPathAnnouncePathMoved(instance, STRING(oldPath), STRING(newPath));
EsMutexAcquire(&loadedFoldersMutex);
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) { for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
Folder *folder = loadedFolders[i]; Folder *folder = loadedFolders[i];
@ -453,8 +448,6 @@ void FolderPathMoved(Instance *instance, String oldPath, String newPath) {
} }
} }
EsMutexRelease(&loadedFoldersMutex);
for (uintptr_t i = 0; i < bookmarks.Length(); i++) { for (uintptr_t i = 0; i < bookmarks.Length(); i++) {
PathReplacePrefix(&bookmarks[i], oldPath, newPath); PathReplacePrefix(&bookmarks[i], oldPath, newPath);
} }
@ -502,21 +495,12 @@ void FolderPathMoved(Instance *instance, String oldPath, String newPath) {
ConfigurationSave(); ConfigurationSave();
} }
EsError FolderAttachInstance(Instance *instance, String path, bool recurse, Folder **newFolder) { void FolderAttachInstance(Instance *instance, String path, bool recurse) {
// TODO Don't modify attachedInstances/attachingInstances/loadedFolders without the message mutex!
// And then we can remove loadedFoldersMutex.
// (Called on the blocking task thread.)
Folder *folder = nullptr; Folder *folder = nullptr;
NamespaceHandler *itemHandler = nullptr, *containerHandler = nullptr;
EsError error;
bool driveRemoved = false; bool driveRemoved = false;
// Check if we've already loaded the folder. // Check if we've already loaded the folder.
EsMutexAcquire(&loadedFoldersMutex);
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) { for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
if (StringEquals(loadedFolders[i]->path, path) && loadedFolders[i]->recurse == recurse) { if (StringEquals(loadedFolders[i]->path, path) && loadedFolders[i]->recurse == recurse) {
if (!loadedFolders[i]->refreshing) { if (!loadedFolders[i]->refreshing) {
@ -528,70 +512,39 @@ EsError FolderAttachInstance(Instance *instance, String path, bool recurse, Fold
} }
} }
EsMutexRelease(&loadedFoldersMutex);
// Find the handler for the path.
NamespaceFindHandlersForPath(&itemHandler, &containerHandler, path);
if (!itemHandler || !containerHandler) {
return ES_ERROR_FILE_DOES_NOT_EXIST;
}
// Load a new folder.
folder = (Folder *) EsHeapAllocate(sizeof(Folder), true); folder = (Folder *) EsHeapAllocate(sizeof(Folder), true);
folder->path = StringDuplicate(path); folder->path = StringDuplicate(path);
folder->recurse = recurse; folder->recurse = recurse;
folder->itemHandler = itemHandler; NamespaceFindHandlersForPath(&folder->itemHandler, &folder->containerHandler, path);
folder->containerHandler = containerHandler;
folder->cEmptyMessage = interfaceString_FileManagerEmptyFolderView; folder->cEmptyMessage = interfaceString_FileManagerEmptyFolderView;
folder->driveRemoved = driveRemoved; folder->driveRemoved = driveRemoved;
EsArenaInitialise(&folder->entryArena, 1048576, sizeof(FolderEntry)); EsArenaInitialise(&folder->entryArena, 1048576, sizeof(FolderEntry));
// TODO Make this asynchronous for some folder providers, or recursive requests
// (that is, immediately present to the user while streaming data in).
error = itemHandler->enumerate(folder);
folder->driveRemoved = false;
folder->refreshing = false;
if (error != ES_SUCCESS) {
StringDestroy(&folder->path);
EsHeapFree(folder);
return error;
}
if (containerHandler->getTotalSize) {
containerHandler->getTotalSize(folder);
}
EsMutexAcquire(&loadedFoldersMutex);
loadedFolders.Add(folder); loadedFolders.Add(folder);
success:; success:;
foldersWithNoAttachedInstances.FindAndDeleteSwap(folder, false); foldersWithNoAttachedInstances.FindAndDeleteSwap(folder, false);
folder->attachingInstances.Add(instance); folder->referenceCount++;
FolderDetachInstance(instance);
EsMutexRelease(&loadedFoldersMutex); instance->folder = folder;
*newFolder = folder;
return ES_SUCCESS;
} }
void FolderRefresh(Folder *folder) { void FolderRefresh(Folder *folder) {
// EsMutexAssertLocked(&loadedFoldersMutex);
if (folder->refreshing) { if (folder->refreshing) {
return; return;
} }
folder->refreshing = true; folder->refreshing = true;
Array<Instance *> instancesToRefresh = {};
for (uintptr_t i = 0; i < folder->attachedInstances.Length(); i++) { for (uintptr_t i = 0; i < folder->attachedInstances.Length(); i++) {
InstanceLoadFolder(folder->attachedInstances[i], StringDuplicate(folder->path), LOAD_FOLDER_REFRESH); instancesToRefresh.Add(folder->attachedInstances[i]);
} }
for (uintptr_t i = 0; i < instancesToRefresh.Length(); i++) {
InstanceLoadFolder(instancesToRefresh[i], StringDuplicate(folder->path), LOAD_FOLDER_REFRESH);
}
instancesToRefresh.Free();
} }

View File

@ -101,7 +101,7 @@ struct HistoryEntry {
}; };
struct Drive { struct Drive {
const char *prefix; char *prefix;
size_t prefixBytes; size_t prefixBytes;
EsVolumeInformation information; EsVolumeInformation information;
}; };
@ -201,18 +201,20 @@ struct Folder {
EsArena entryArena; EsArena entryArena;
Array<Instance *> attachedInstances; Array<Instance *> attachedInstances;
Array<Instance *> attachingInstances; uintptr_t referenceCount;
String path; String path;
bool recurse; bool recurse;
bool refreshing; bool refreshing;
bool driveRemoved; bool driveRemoved;
bool doneInitialEnumeration;
EsMutex modifyEntriesMutex;
EsFileOffset spaceTotal; EsFileOffset spaceTotal;
EsFileOffset spaceUsed; EsFileOffset spaceUsed;
NamespaceHandler *itemHandler, *containerHandler; NamespaceHandler *itemHandler, *containerHandler;
const char *cEmptyMessage; const char *cEmptyMessage;
}; };
@ -409,6 +411,25 @@ void ConfigurationSave() {
#include "commands.cpp" #include "commands.cpp"
#include "ui.cpp" #include "ui.cpp"
void DriveRefreshFolders(bool removed, const char *prefix, size_t prefixBytes) {
Array<Folder *> foldersToRefresh = {};
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
Folder *folder = loadedFolders[i];
if (folder->itemHandler->type == NAMESPACE_HANDLER_DRIVES_PAGE || StringStartsWith(folder->path, StringFromLiteralWithSize(prefix, prefixBytes))) {
foldersToRefresh.Add(folder);
}
}
for (uintptr_t i = 0; i < foldersToRefresh.Length(); i++) {
foldersToRefresh[i]->driveRemoved = removed;
FolderRefresh(foldersToRefresh[i]);
}
foldersToRefresh.Free();
}
void DriveRemove(const char *prefix, size_t prefixBytes) { void DriveRemove(const char *prefix, size_t prefixBytes) {
if (!prefixBytes || prefix[0] == '|') return; if (!prefixBytes || prefix[0] == '|') return;
EsMutexAcquire(&drivesMutex); EsMutexAcquire(&drivesMutex);
@ -416,6 +437,7 @@ void DriveRemove(const char *prefix, size_t prefixBytes) {
for (uintptr_t index = 0; index < drives.Length(); index++) { for (uintptr_t index = 0; index < drives.Length(); index++) {
if (0 == EsStringCompareRaw(prefix, prefixBytes, drives[index].prefix, drives[index].prefixBytes)) { if (0 == EsStringCompareRaw(prefix, prefixBytes, drives[index].prefix, drives[index].prefixBytes)) {
EsHeapFree(drives[index].prefix);
drives.Delete(index); drives.Delete(index);
found = true; found = true;
@ -429,20 +451,7 @@ void DriveRemove(const char *prefix, size_t prefixBytes) {
EsAssert(found); EsAssert(found);
EsMutexRelease(&drivesMutex); EsMutexRelease(&drivesMutex);
DriveRefreshFolders(true, prefix, prefixBytes);
EsMutexAcquire(&loadedFoldersMutex);
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
Folder *folder = loadedFolders[i];
if (folder->itemHandler->type == NAMESPACE_HANDLER_DRIVES_PAGE
|| StringStartsWith(folder->path, StringFromLiteralWithSize(prefix, prefixBytes))) {
folder->driveRemoved = true;
FolderRefresh(folder);
}
}
EsMutexRelease(&loadedFoldersMutex);
} }
void DriveAdd(const char *prefix, size_t prefixBytes) { void DriveAdd(const char *prefix, size_t prefixBytes) {
@ -451,7 +460,8 @@ void DriveAdd(const char *prefix, size_t prefixBytes) {
EsMutexAcquire(&drivesMutex); EsMutexAcquire(&drivesMutex);
Drive drive = {}; Drive drive = {};
drive.prefix = prefix; drive.prefix = (char *) EsHeapAllocate(prefixBytes, false);
EsMemoryCopy(drive.prefix, prefix, prefixBytes);
drive.prefixBytes = prefixBytes; drive.prefixBytes = prefixBytes;
EsMountPointGetVolumeInformation(prefix, prefixBytes, &drive.information); EsMountPointGetVolumeInformation(prefix, prefixBytes, &drive.information);
drives.Add(drive); drives.Add(drive);
@ -461,13 +471,7 @@ void DriveAdd(const char *prefix, size_t prefixBytes) {
} }
EsMutexRelease(&drivesMutex); EsMutexRelease(&drivesMutex);
DriveRefreshFolders(false, prefix, prefixBytes);
for (uintptr_t i = 0; i < instances.Length(); i++) {
if (instances[i]->folder->itemHandler->type == NAMESPACE_HANDLER_DRIVES_PAGE
|| StringStartsWith(instances[i]->folder->path, StringFromLiteralWithSize(prefix, prefixBytes))) {
FolderRefresh(instances[i]->folder);
}
}
} }
void LoadSettings() { void LoadSettings() {
@ -528,7 +532,6 @@ void _start() {
InstanceCreateUI(instance); InstanceCreateUI(instance);
} else if (message->type == ES_MSG_INSTANCE_DESTROY) { } else if (message->type == ES_MSG_INSTANCE_DESTROY) {
// TODO Cleanup/cancel any unfinished non-blocking tasks before we get here! // TODO Cleanup/cancel any unfinished non-blocking tasks before we get here!
Instance *instance = message->instanceDestroy.instance; Instance *instance = message->instanceDestroy.instance;
InstanceDestroy(instance); InstanceDestroy(instance);
instances.FindAndDeleteSwap(instance, true); instances.FindAndDeleteSwap(instance, true);
@ -549,15 +552,18 @@ void _start() {
EsDirectoryChild information = {}; EsDirectoryChild information = {};
if (EsPathQueryInformation(STRING(path), &information)) { if (EsPathQueryInformation(STRING(path), &information)) {
EsMutexAcquire(&loadedFoldersMutex);
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) { for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
if (loadedFolders[i]->itemHandler->type != NAMESPACE_HANDLER_FILE_SYSTEM) continue; if (loadedFolders[i]->itemHandler->type != NAMESPACE_HANDLER_FILE_SYSTEM) continue;
if (EsStringCompareRaw(STRING(loadedFolders[i]->path), STRING(folder))) continue; if (EsStringCompareRaw(STRING(loadedFolders[i]->path), STRING(folder))) continue;
FolderAddEntryAndUpdateInstances(loadedFolders[i], file.text, file.bytes, &information, nullptr, true);
}
EsMutexRelease(&loadedFoldersMutex); EsMutexAcquire(&loadedFolders[i]->modifyEntriesMutex);
if (loadedFolders[i]->doneInitialEnumeration) {
FolderAddEntryAndUpdateInstances(loadedFolders[i], file.text, file.bytes, &information, nullptr);
}
EsMutexRelease(&loadedFolders[i]->modifyEntriesMutex);
}
} }
} }

View File

@ -23,37 +23,46 @@ void InstanceFolderPathChanged(Instance *instance, bool fromLoadFolder) {
} }
bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, int historyMode) { bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, int historyMode) {
// Check if the path hasn't changed.
if (instance->folder && !instance->folder->refreshing && StringEquals(path, instance->folder->path)) { if (instance->folder && !instance->folder->refreshing && StringEquals(path, instance->folder->path)) {
// The path hasn't changed; ignore.
StringDestroy(&path); StringDestroy(&path);
return true; return true;
} }
InstanceRemoveContents(instance);
FolderAttachInstance(instance, path, false);
StringDestroy(&path);
Task task = {}; Task task = {};
task.context = historyMode; task.context = historyMode;
task.string = path;
task.cDescription = interfaceString_FileManagerOpenFolderTask; task.cDescription = interfaceString_FileManagerOpenFolderTask;
task.callback = [] (Instance *instance, Task *task) { task.callback = [] (Instance *instance, Task *) {
Folder *newFolder = nullptr; Folder *folder = instance->folder;
task->result = FolderAttachInstance(instance, task->string, false, &newFolder); EsMutexAcquire(&folder->modifyEntriesMutex);
task->context2 = newFolder;
StringDestroy(&task->string); if (!folder->doneInitialEnumeration) {
folder->itemHandler->enumerate(folder);
if (folder->containerHandler->getTotalSize) {
folder->containerHandler->getTotalSize(folder);
}
folder->driveRemoved = false;
folder->refreshing = false;
folder->doneInitialEnumeration = true;
}
EsMutexRelease(&folder->modifyEntriesMutex);
}; };
task.then = [] (Instance *instance, Task *task) { task.then = [] (Instance *instance, Task *task) {
if (ES_CHECK_ERROR(task->result)) { // TODO Check if folder was marked for refresh.
EsTextboxSelectAll(instance->breadcrumbBar);
EsTextboxInsert(instance->breadcrumbBar, STRING(instance->path));
InstanceReportError(instance, ERROR_LOAD_FOLDER, task->result);
return;
}
int historyMode = task->context.i & 0xFF; int historyMode = task->context.i & 0xFF;
int flags = task->context.i; int flags = task->context.i;
Folder *folder = (Folder *) task->context2.p; Folder *folder = instance->folder;
folder->attachedInstances.Add(instance);
// Add the path to the history array. // Add the path to the history array.
@ -92,13 +101,6 @@ bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, i
EsCommandSetDisabled(&instance->commandRename, true); EsCommandSetDisabled(&instance->commandRename, true);
EsCommandSetDisabled(&instance->commandRefresh, false); EsCommandSetDisabled(&instance->commandRefresh, false);
// Detach from the old folder.
EsMutexAcquire(&loadedFoldersMutex);
InstanceRemoveContents(instance);
FolderDetachInstance(instance);
// Load the view settings for the folder. // Load the view settings for the folder.
bool foundViewSettings = false; bool foundViewSettings = false;
@ -129,24 +131,13 @@ bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, i
InstanceRefreshViewType(instance); InstanceRefreshViewType(instance);
// Attach to the new folder. // Update the user interface.
folder->attachingInstances.FindAndDeleteSwap(instance, true);
instance->folder = folder;
folder->attachedInstances.Add(instance);
EsListViewSetEmptyMessage(instance->list, folder->cEmptyMessage); EsListViewSetEmptyMessage(instance->list, folder->cEmptyMessage);
InstanceAddContents(instance, &folder->entries); InstanceAddContents(instance, &folder->entries);
EsMutexRelease(&loadedFoldersMutex);
InstanceFolderPathChanged(instance, true); InstanceFolderPathChanged(instance, true);
if (~flags & LOAD_FOLDER_NO_FOCUS) {
EsElementFocus(instance->list);
}
EsListViewInvalidateAll(instance->placesView); EsListViewInvalidateAll(instance->placesView);
if (~flags & LOAD_FOLDER_NO_FOCUS) EsElementFocus(instance->list);
}; };
BlockingTaskQueue(instance, task); BlockingTaskQueue(instance, task);
@ -277,7 +268,7 @@ void InstanceUpdateStatusString(Instance *instance) {
} }
void InstanceAddSingle(Instance *instance, ListEntry entry) { void InstanceAddSingle(Instance *instance, ListEntry entry) {
// Call with loadedFoldersMutex and message mutex. // Call with the message mutex acquired.
if (!InstanceAddInternal(instance, &entry)) { if (!InstanceAddInternal(instance, &entry)) {
return; // Filtered out. return; // Filtered out.
@ -326,7 +317,7 @@ ES_MACRO_SORT(InstanceSortListContents, ListEntry, {
}, uint16_t); }, uint16_t);
void InstanceAddContents(Instance *instance, HashTable *newEntries) { void InstanceAddContents(Instance *instance, HashTable *newEntries) {
// Call with loadedFoldersMutex and message mutex. // Call with the message mutex acquired.
size_t oldListEntryCount = instance->listContents.Length(); size_t oldListEntryCount = instance->listContents.Length();

View File

@ -742,7 +742,7 @@ EsMessage *EsMessageReceive() {
elements.Free(); elements.Free();
} }
instance->commands.Free(false); instance->commands.Free();
if (instance->fileStore) FileStoreCloseHandle(instance->fileStore); if (instance->fileStore) FileStoreCloseHandle(instance->fileStore);
EsHeapFree(instance); EsHeapFree(instance);
EsHeapFree(message.message.instanceDestroy.instance); EsHeapFree(message.message.instanceDestroy.instance);

View File

@ -116,6 +116,7 @@ struct InstalledApplication {
uint64_t permissions; uint64_t permissions;
size_t openInstanceCount; // Only used if useSingleProcess is true. size_t openInstanceCount; // Only used if useSingleProcess is true.
EsHandle singleProcessHandle; EsHandle singleProcessHandle;
bool notified; // Temporary flag.
}; };
struct CrashedTabInstance : EsInstance { struct CrashedTabInstance : EsInstance {
@ -2010,19 +2011,31 @@ void DesktopMessage(EsMessage *message) {
for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) {
ApplicationInstance *instance = desktop.allApplicationInstances[i]; ApplicationInstance *instance = desktop.allApplicationInstances[i];
if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) && instance->processHandle) { if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES)
&& instance->processHandle && !instance->application->notified) {
message->registerFileSystem.rootDirectory = EsSyscall(ES_SYSCALL_NODE_SHARE, rootDirectory, instance->processHandle, 0, 0); message->registerFileSystem.rootDirectory = EsSyscall(ES_SYSCALL_NODE_SHARE, rootDirectory, instance->processHandle, 0, 0);
EsMessagePostRemote(instance->processHandle, message); EsMessagePostRemote(instance->processHandle, message);
if (instance->application->useSingleProcess) instance->application->notified = true;
} }
} }
for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) {
desktop.installedApplications[i]->notified = false;
}
} else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) { } else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) {
for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) {
ApplicationInstance *instance = desktop.allApplicationInstances[i]; ApplicationInstance *instance = desktop.allApplicationInstances[i];
if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) && instance->processHandle) { if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES)
&& instance->processHandle && !instance->application->notified) {
EsMessagePostRemote(instance->processHandle, message); EsMessagePostRemote(instance->processHandle, message);
if (instance->application->useSingleProcess) instance->application->notified = true;
} }
} }
for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) {
desktop.installedApplications[i]->notified = false;
}
} else if (message->type == ES_MSG_DEVICE_CONNECTED) { } else if (message->type == ES_MSG_DEVICE_CONNECTED) {
desktop.connectedDevices.Add(message->device); desktop.connectedDevices.Add(message->device);
} else if (message->type == ES_MSG_DEVICE_DISCONNECTED) { } else if (message->type == ES_MSG_DEVICE_DISCONNECTED) {

View File

@ -349,7 +349,7 @@ bool HashStoreDelete(HashTable *table, HashStoreOptions *options, const void *ke
////////////////////////////////////////// //////////////////////////////////////////
template <class K /* set to char * for long keys */, class V> template <class K /* set to char for long keys */, class V>
struct HashStore { struct HashStore {
HashTable table; HashTable table;
@ -393,8 +393,8 @@ struct HashStore {
return HashStoreDelete(&table, &options, k, bytes); return HashStoreDelete(&table, &options, k, bytes);
} }
inline void Free(bool variableLengthKeys) { inline void Free() {
HashTableFree(&table, variableLengthKeys); HashTableFree(&table, sizeof(K) == 1);
} }
}; };