Annotate more of Task/TaskLocal as safe.

This commit is contained in:
Sönke Ludwig 2016-11-04 21:33:01 +01:00
parent d5e19e1db6
commit 0c3c31b969

View file

@ -37,11 +37,15 @@ struct Task {
m_taskCounter = task_counter; m_taskCounter = task_counter;
} }
this(in Task other) nothrow { m_fiber = cast(shared(TaskFiber))other.m_fiber; m_taskCounter = other.m_taskCounter; } this(in Task other)
@safe nothrow {
m_fiber = () @trusted { return cast(shared(TaskFiber))other.m_fiber; } ();
m_taskCounter = other.m_taskCounter;
}
/** Returns the Task instance belonging to the calling task. /** Returns the Task instance belonging to the calling task.
*/ */
static Task getThis() nothrow @safe static Task getThis() @safe nothrow
{ {
// In 2067, synchronized statements where annotated nothrow. // In 2067, synchronized statements where annotated nothrow.
// DMD#4115, Druntime#1013, Druntime#1021, Phobos#2704 // DMD#4115, Druntime#1013, Druntime#1021, Phobos#2704
@ -73,16 +77,16 @@ struct Task {
} }
// FIXME: this is not thread safe! // FIXME: this is not thread safe!
@property ref ThreadInfo tidInfo() { return m_fiber ? taskFiber.tidInfo : s_tidInfo; } @property ref ThreadInfo tidInfo() @safe { return m_fiber ? taskFiber.tidInfo : s_tidInfo; }
@property Tid tid() { return tidInfo.ident; } @property Tid tid() @safe { return tidInfo.ident; }
} }
T opCast(T)() const nothrow if (is(T == bool)) { return m_fiber !is null; } T opCast(T)() const @safe nothrow if (is(T == bool)) { return m_fiber !is null; }
void join() { if (running) taskFiber.join(m_taskCounter); } void join() @safe { if (running) taskFiber.join(m_taskCounter); }
void interrupt() { if (running) taskFiber.interrupt(m_taskCounter); } void interrupt() @safe { if (running) taskFiber.interrupt(m_taskCounter); }
string toString() const { import std.string; return format("%s:%s", cast(void*)m_fiber, m_taskCounter); } string toString() const @safe { import std.string; return format("%s:%s", () @trusted { return cast(void*)m_fiber; } (), m_taskCounter); }
void getDebugID(R)(ref R dst) void getDebugID(R)(ref R dst)
{ {
@ -97,13 +101,13 @@ struct Task {
MD5 md; MD5 md;
md.start(); md.start();
md.put(nativeToLittleEndian(cast(size_t)cast(void*)m_fiber)); md.put(nativeToLittleEndian(() @trusted { return cast(size_t)cast(void*)m_fiber; } ()));
md.put(nativeToLittleEndian(cast(size_t)cast(void*)m_taskCounter)); md.put(nativeToLittleEndian(m_taskCounter));
Base64.encode(md.finish()[0 .. 3], dst); Base64.encode(md.finish()[0 .. 3], dst);
} }
bool opEquals(in ref Task other) const nothrow @safe { return m_fiber is other.m_fiber && m_taskCounter == other.m_taskCounter; } bool opEquals(in ref Task other) const @safe nothrow { return m_fiber is other.m_fiber && m_taskCounter == other.m_taskCounter; }
bool opEquals(in Task other) const nothrow @safe { return m_fiber is other.m_fiber && m_taskCounter == other.m_taskCounter; } bool opEquals(in Task other) const @safe nothrow { return m_fiber is other.m_fiber && m_taskCounter == other.m_taskCounter; }
} }
/** /**
@ -159,7 +163,9 @@ struct TaskLocal(T)
void opAssign(T value) { this.storage = value; } void opAssign(T value) { this.storage = value; }
@property ref T storage() @property ref T storage()
{ @safe {
import std.conv : emplace;
auto fiber = TaskFiber.getThis(); auto fiber = TaskFiber.getThis();
// lazily register in FLS storage // lazily register in FLS storage
@ -178,13 +184,13 @@ struct TaskLocal(T)
// make sure the current fiber has enough FLS storage // make sure the current fiber has enough FLS storage
if (fiber.m_fls.length < TaskFiber.ms_flsFill) { if (fiber.m_fls.length < TaskFiber.ms_flsFill) {
fiber.m_fls.length = TaskFiber.ms_flsFill + 128; fiber.m_fls.length = TaskFiber.ms_flsFill + 128;
fiber.m_flsInit.length = TaskFiber.ms_flsCounter + 64; () @trusted { fiber.m_flsInit.length = TaskFiber.ms_flsCounter + 64; } ();
} }
// return (possibly default initialized) value // return (possibly default initialized) value
auto data = fiber.m_fls.ptr[m_offset .. m_offset+T.sizeof]; auto data = () @trusted { return fiber.m_fls.ptr[m_offset .. m_offset+T.sizeof]; } ();
if (!fiber.m_flsInit[m_id]) { if (!() @trusted { return fiber.m_flsInit[m_id]; } ()) {
fiber.m_flsInit[m_id] = true; () @trusted { fiber.m_flsInit[m_id] = true; } ();
import std.traits : hasElaborateDestructor, hasAliasing; import std.traits : hasElaborateDestructor, hasAliasing;
static if (hasElaborateDestructor!T || hasAliasing!T) { static if (hasElaborateDestructor!T || hasAliasing!T) {
void function(void[], size_t) destructor = (void[] fls, size_t offset){ void function(void[], size_t) destructor = (void[] fls, size_t offset){
@ -206,19 +212,19 @@ struct TaskLocal(T)
fls_info.offset = m_offset; fls_info.offset = m_offset;
// make sure flsInfo has enough space // make sure flsInfo has enough space
if (ms_flsInfo.length <= m_id) if (TaskFiber.ms_flsInfo.length <= m_id)
ms_flsInfo.length = m_id + 64; TaskFiber.ms_flsInfo.length = m_id + 64;
ms_flsInfo[m_id] = fls_info; TaskFiber.ms_flsInfo[m_id] = fls_info;
} }
if (m_hasInitValue) { if (m_hasInitValue) {
static if (__traits(compiles, emplace!T(data, m_initValue))) static if (__traits(compiles, emplace!T(data, m_initValue)))
emplace!T(data, m_initValue); () @trusted { emplace!T(data, m_initValue); } ();
else assert(false, "Cannot emplace initialization value for type "~T.stringof); else assert(false, "Cannot emplace initialization value for type "~T.stringof);
} else emplace!T(data); } else () @trusted { emplace!T(data); } ();
} }
return (cast(T[])data)[0]; return *() @trusted { return cast(T*)data.ptr; } ();
} }
alias storage this; alias storage this;
@ -403,14 +409,14 @@ final package class TaskFiber : Fiber {
*/ */
@property Task task() @safe nothrow { return Task(this, m_taskCounter); } @property Task task() @safe nothrow { return Task(this, m_taskCounter); }
@property ref inout(ThreadInfo) tidInfo() inout nothrow { return m_tidInfo; } @property ref inout(ThreadInfo) tidInfo() inout @safe nothrow { return m_tidInfo; }
@property size_t taskCounter() const { return m_taskCounter; } @property size_t taskCounter() const @safe nothrow { return m_taskCounter; }
/** Blocks until the task has ended. /** Blocks until the task has ended.
*/ */
void join(size_t task_counter) void join(size_t task_counter)
{ @safe {
while (m_running && m_taskCounter == task_counter) while (m_running && m_taskCounter == task_counter)
m_onExit.wait(); m_onExit.wait();
} }
@ -418,7 +424,7 @@ final package class TaskFiber : Fiber {
/** Throws an InterruptExeption within the task as soon as it calls an interruptible function. /** Throws an InterruptExeption within the task as soon as it calls an interruptible function.
*/ */
void interrupt(size_t task_counter) void interrupt(size_t task_counter)
{ @safe {
import vibe.core.core : taskScheduler; import vibe.core.core : taskScheduler;
if (m_taskCounter != task_counter) if (m_taskCounter != task_counter)
@ -428,7 +434,7 @@ final package class TaskFiber : Fiber {
if (caller != Task.init) { if (caller != Task.init) {
assert(caller != this.task, "A task cannot interrupt itself."); assert(caller != this.task, "A task cannot interrupt itself.");
assert(caller.thread is this.thread, "Interrupting tasks in different threads is not yet supported."); assert(caller.thread is this.thread, "Interrupting tasks in different threads is not yet supported.");
} else assert(Thread.getThis() is this.thread, "Interrupting tasks in different threads is not yet supported."); } else assert(() @trusted { return Thread.getThis(); } () is this.thread, "Interrupting tasks in different threads is not yet supported.");
logTrace("Resuming task with interrupt flag."); logTrace("Resuming task with interrupt flag.");
m_interrupt = true; m_interrupt = true;
taskScheduler.switchTo(this.task); taskScheduler.switchTo(this.task);