From d9e545bf609d1898716a80915af6f13ca2e96f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Sun, 25 Aug 2019 12:02:08 +0200 Subject: [PATCH] Fix getFileInfo's exception handling and reduce overhead of the background work. Instead of asyncWork, now uses a worker task directly and signals the finalization of the result using message passing. This avoids the roundtrip required to return the task handle, as well as the heap allocated result buffer of Future!T. --- source/vibe/core/file.d | 50 +++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/source/vibe/core/file.d b/source/vibe/core/file.d index 86ee6f3..410ddf3 100644 --- a/source/vibe/core/file.d +++ b/source/vibe/core/file.d @@ -7,7 +7,6 @@ */ module vibe.core.file; -import vibe.core.concurrency : asyncWork; import eventcore.core : NativeEventDriver, eventDriver; import eventcore.driver; import vibe.core.internal.release; @@ -282,7 +281,7 @@ bool existsFile(string path) nothrow static if (__VERSION__ < 2067) scope(failure) assert(0, "Error: existsFile should never throw"); - try return asyncWork((string p) => std.file.exists(p), path).getResult(); + try return performInWorker((string p) => std.file.exists(p), path); catch (Exception e) { logDebug("Failed to determine file existence for '%s': %s", path, e.msg); return false; @@ -300,10 +299,18 @@ FileInfo getFileInfo(NativePath path) /// ditto FileInfo getFileInfo(string path) { - return asyncWork((string p) { - auto ent = DirEntry(p); - return makeFileInfo(ent); - }, path).getResult(); + import std.typecons : tuple; + + auto ret = performInWorker((string p) { + try { + auto ent = DirEntry(p); + return tuple(makeFileInfo(ent), ""); + } catch (Exception e) { + return tuple(FileInfo.init, e.msg.length ? e.msg : "Failed to get file information"); + } + }, path); + if (ret[1].length) throw new Exception(ret[1]); + return ret[0]; } /** @@ -316,7 +323,7 @@ void createDirectory(NativePath path) /// ditto void createDirectory(string path, Flag!"recursive" recursive = No.recursive) { - auto fail = asyncWork((string p, bool rec) { + auto fail = performInWorker((string p, bool rec) { try { if (rec) mkdirRecurse(p); else mkdir(p); @@ -870,3 +877,32 @@ unittest { assert(readFile(name) == "create, then append"); } + + +private auto performInWorker(C, ARGS...)(C callable, auto ref ARGS args) +{ + version (none) { + import vibe.core.concurrency : asyncWork; + return asyncWork(callable, args).getResult(); + } else { + import vibe.core.core : runWorkerTask; + import core.atomic : atomicFence; + import std.concurrency : Tid, send, receiveOnly, thisTid; + + struct R {} + + alias RET = typeof(callable(args)); + shared(RET) ret; + runWorkerTask((shared(RET)* r, Tid caller, C c, ref ARGS a) nothrow { + *() @trusted { return cast(RET*)r; } () = c(a); + // Just as a precaution, because ManualEvent is not well defined in + // terms of fence semantics + atomicFence(); + try caller.send(R.init); + catch (Exception e) assert(false, e.msg); + }, () @trusted { return &ret; } (), thisTid, callable, args); + () @trusted { receiveOnly!R(); } (); + atomicFence(); + return ret; + } +}