#!/usr/bin/env dub
/+ dub.sdl:
name "gcd_source_timer_leeway"
platforms "osx"
targetPath "build"
+/
/**
* GCD — timers are a source type, and `leeway` is a first-class parameter.
*
* `dispatch_source_set_timer(source, start, interval, leeway)` has no
* equivalent in `timerfd`, `setitimer` or `EVFILT_TIMER` as most loops use it:
* the fourth argument tells the kernel how much *later* than the deadline the
* timer may fire, so unrelated timers across the whole system coalesce into one
* wakeup. It lowers to kqueue's `NOTE_LEEWAY` (`DISPATCH_HAVE_TIMER_COALESCING`
* in `src/event/event_config.h`); libdispatch clamps a leeway larger than half
* the interval down to `interval / 2` (`_dispatch_timer_config_create`,
* `src/source.c`).
*
* A leeway is a licence to be late, never to be early. This program arms a
* repeating timer with a leeway equal to half its interval, records the arrival
* time of each of five fires, and asserts that no fire landed before its
* nominal deadline.
*
* Companion to the GCD deep-dive:
* see docs/research/async-io/gcd/index.md § "Timers, leeway and coalescing".
*
* Run with: `dub run --single source-timer-leeway.d`
*
* Portability: macOS only (`platforms "osx"`).
*/
module (module) gcd_source_timer_leewayGCD — timers are a source type, and leeway is a first-class parameter.
dispatch_source_set_timer(source, start, interval, leeway) has no
equivalent in timerfd, setitimer or EVFILT_TIMER as most loops use it:
the fourth argument tells the kernel how much later than the deadline the
timer may fire, so unrelated timers across the whole system coalesce into one
wakeup. It lowers to kqueue's NOTE_LEEWAY (DISPATCH_HAVE_TIMER_COALESCING
in src/event/event_config.h); libdispatch clamps a leeway larger than half
the interval down to interval / 2 (_dispatch_timer_config_create,
src/source.c).
A leeway is a licence to be late, never to be early. This program arms a
repeating timer with a leeway equal to half its interval, records the arrival
time of each of five fires, and asserts that no fire landed before its
nominal deadline.
Companion to the GCD deep-dive:
see docs/research/async-io/gcd/index.md § "Timers, leeway and coalescing".
Run with: dub run --single source-timer-leeway.d
Portability
macOS only (platforms "osx").
gcd_source_timer_leeway;
import (package) corecore.(module) core.atomicThe atomic module provides basic support for lock-free
concurrent programming.
Use the -preview=nosharedaccess compiler flag to detect
unsafe individual read or write operations on shared data.
Source
core/atomic.d
Examples
int y = 2;
shared int x = y; // OK
//x++; // read modify write error
x.atomicOp!"+="(1); // OK
//y = x; // read error with preview flag
y = x.atomicLoad(); // OK
assert(y == 3);
//x = 5; // write error with preview flag
x.atomicStore(5); // OK
assert(x.atomicLoad() == 5);
atomic : (alias template) gcd_source_timer_leeway.atomicLoad = core.atomic.atomicLoad(MemoryOrder ms = MemoryOrder.seq, T)(auto ref return scope const T val) if (!is(T == shared(U), U) && !is(T == shared(inout(U)), U) && !is(T == shared(const(U)), U))Loads 'val' from memory and returns it. The memory barrier specified
by 'ms' is applied to the operation, which is fully sequenced by
default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq,
and MemoryOrder.seq.
atomicLoad, (alias template) gcd_source_timer_leeway.atomicOp = core.atomic.atomicOp(string op, T, V1)(ref shared T val, V1 mod) if (__traits(compiles, mixin("*cast(T*)&val" ~ op ~ "mod")))Performs the binary operation 'op' on val using 'mod' as the modifier.
atomicOp, (alias template) gcd_source_timer_leeway.atomicStore = core.atomic.atomicStore(MemoryOrder ms = MemoryOrder.seq, T, V)(ref T val, V newval) if (!is(T == shared) && !is(V == shared))Writes 'newval' into 'val'. The memory barrier specified by 'ms' is
applied to the operation, which is fully sequenced by default.
Valid memory orders are MemoryOrder.raw, MemoryOrder.rel, and
MemoryOrder.seq.
atomicStore;
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stdintD header file for C99.
pubs.opengroup.org/onlinepubs/009695399/basedefs/stdint.h.html, stdint.h
Source
core/stdc/stdint.d
stdint : uintptr_t;
import (package) corecore.(module) core.timeModule containing core time functionality, such as Duration (which
represents a duration of time) or MonoTime (which represents a
timestamp of the system's monotonic clock).
Various functions take a string (or strings) to represent a unit of time
(e.g. convert!("days", "hours")(numDays)). The valid strings to use
with such functions are "years", "months", "weeks", "days", "hours",
"minutes", "seconds", "msecs" (milliseconds), "usecs" (microseconds),
"hnsecs" (hecto-nanoseconds - i.e. 100 ns) or some subset thereof. There
are a few functions that also allow "nsecs", but very little actually
has precision greater than hnsecs.
Symbol Description Types Duration Represents a duration of time of weeks or less (kept internally as hnsecs). (e.g. 22 days or 700 seconds). TickDuration DEPRECATED Represents a duration of time in system clock ticks, using the highest precision that the system provides. MonoTime Represents a monotonic timestamp in system clock ticks, using the highest precision that the system provides. Functions convert Generic way of converting between two time units. dur Allows constructing a Duration from the given time units with the given length. weeks days hours
minutes seconds msecs
usecs hnsecs nsecs |
Convenience aliases for dur. |
| abs | Returns the absolute value of a duration. |
From Duration
From TickDuration
From units
To Duration tickDuration.to, std,conv!Duration() dur!"msecs"(5) or 5.msecs()
| To TickDuration |
duration.to, std,conv!TickDuration() |
|
TickDuration.from!"msecs"(msecs) |
| To units |
duration.total!"days" |
tickDuration.msecs |
convert!("days", "msecs")(msecs) |
Source
core/time.d
time : (struct) core.time.MonoTimeImpl!(ClockType.normal)MonoTime, msecs, nsecs;
import (package) stdstd.(module) std.stdioCategory Symbols File handles _popen File isFileHandle openNetwork stderr stdin stdout Reading chunks lines readf readfln readln Writing toFile write writef writefln writeln Misc KeepTerminator LockType StdioException
Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio
is publically imported when importing std.stdio.
There are three layers of I/O:
The lowest layer is the operating system layer. The two main schemes are Windows and Posix.
C's stdio.h which unifies the two operating system schemes.
std.stdio, this module, unifies the various stdio.h implementations into
a high level package for D programs.
Source
std/stdio.d
stdio : (alias template) gcd_source_timer_leeway.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))Equivalent to writef(fmt, args, '\n').
writefln, (alias template) gcd_source_timer_leeway.writeln = std.stdio.writeln(T...)(T args)Equivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
alias (alias) gcd_source_timer_leeway.dispatch_queue_t = void*dispatch_queue_t = void*;
alias (alias) gcd_source_timer_leeway.dispatch_source_t = void*dispatch_source_t = void*;
alias (alias) gcd_source_timer_leeway.dispatch_semaphore_t = void*dispatch_semaphore_t = void*;
alias (alias) gcd_source_timer_leeway.dispatch_function_t = extern (C) void function(void*) nothrowdispatch_function_t = extern (C) void function(void*) nothrow;
extern (C) nothrow @nogc
{
/// `DISPATCH_SOURCE_TYPE_TIMER` is `&_dispatch_source_type_timer`.
extern __gshared const ubyte (constant global) const(ubyte) gcd_source_timer_leeway._dispatch_source_type_timerDISPATCH_SOURCE_TYPE_TIMER is &_dispatch_source_type_timer``.
_dispatch_source_type_timer;
(alias) gcd_source_timer_leeway.dispatch_queue_t = void*dispatch_queue_t void* gcd_source_timer_leeway.dispatch_queue_create(const(char)* label, void* attr) nothrow @nogcdispatch_queue_create(const(char)* (parameter) const(char)* labellabel, void* (parameter) void* attrattr);
(alias) gcd_source_timer_leeway.dispatch_source_t = void*dispatch_source_t void* gcd_source_timer_leeway.dispatch_source_create(const(void)* type, ulong handle, ulong mask, void* queue) nothrow @nogcdispatch_source_create(const(void)* (parameter) const(void)* typetype, uintptr_t (parameter) ulong handlehandle,
uintptr_t (parameter) ulong maskmask, (alias) gcd_source_timer_leeway.dispatch_queue_t = void*dispatch_queue_t (parameter) void* queuequeue);
void void gcd_source_timer_leeway.dispatch_source_set_timer(void* source, ulong start, ulong interval, ulong leeway) nothrow @nogcdispatch_source_set_timer((alias) gcd_source_timer_leeway.dispatch_source_t = void*dispatch_source_t (parameter) void* sourcesource, ulong (parameter) ulong startstart,
ulong (parameter) ulong intervalinterval, ulong (parameter) ulong leewayleeway);
void void gcd_source_timer_leeway.dispatch_source_set_event_handler_f(void* source, extern (C) void function(void*) nothrow handler) nothrow @nogcdispatch_source_set_event_handler_f((alias) gcd_source_timer_leeway.dispatch_source_t = void*dispatch_source_t (parameter) void* sourcesource, (alias) gcd_source_timer_leeway.dispatch_function_t = extern (C) void function(void*) nothrowdispatch_function_t (parameter) extern (C) void function(void*) nothrow handlerhandler);
void void gcd_source_timer_leeway.dispatch_source_set_cancel_handler_f(void* source, extern (C) void function(void*) nothrow handler) nothrow @nogcdispatch_source_set_cancel_handler_f((alias) gcd_source_timer_leeway.dispatch_source_t = void*dispatch_source_t (parameter) void* sourcesource, (alias) gcd_source_timer_leeway.dispatch_function_t = extern (C) void function(void*) nothrowdispatch_function_t (parameter) extern (C) void function(void*) nothrow handlerhandler);
void void gcd_source_timer_leeway.dispatch_source_cancel(void* source) nothrow @nogcdispatch_source_cancel((alias) gcd_source_timer_leeway.dispatch_source_t = void*dispatch_source_t (parameter) void* sourcesource);
void void gcd_source_timer_leeway.dispatch_resume(void* object) nothrow @nogcdispatch_resume(void* (parameter) void* objectobject);
void void gcd_source_timer_leeway.dispatch_release(void* object) nothrow @nogcdispatch_release(void* (parameter) void* objectobject);
ulong ulong gcd_source_timer_leeway.dispatch_time(ulong when, long delta) nothrow @nogcdispatch_time(ulong (parameter) ulong whenwhen, long (parameter) long deltadelta);
(alias) gcd_source_timer_leeway.dispatch_semaphore_t = void*dispatch_semaphore_t void* gcd_source_timer_leeway.dispatch_semaphore_create(long value) nothrow @nogcdispatch_semaphore_create(long (parameter) long valuevalue);
long long gcd_source_timer_leeway.dispatch_semaphore_wait(void* sema, ulong timeout) nothrow @nogcdispatch_semaphore_wait((alias) gcd_source_timer_leeway.dispatch_semaphore_t = void*dispatch_semaphore_t (parameter) void* semasema, ulong (parameter) ulong timeouttimeout);
long long gcd_source_timer_leeway.dispatch_semaphore_signal(void* sema) nothrow @nogcdispatch_semaphore_signal((alias) gcd_source_timer_leeway.dispatch_semaphore_t = void*dispatch_semaphore_t (parameter) void* semasema);
}
enum (constant) ulong gcd_source_timer_leeway.DISPATCH_TIME_NOW = 0LUDISPATCH_TIME_NOW = 0UL;
enum (constant) ulong gcd_source_timer_leeway.DISPATCH_TIME_FOREVER = 18446744073709551615LUDISPATCH_TIME_FOREVER = ~0UL;
enum (constant) int gcd_source_timer_leeway.intervalMs = 20intervalMs = 20;
enum (constant) int gcd_source_timer_leeway.fireBudget = 5fireBudget = 5;
struct (struct) gcd_source_timer_leeway.TimerTimer
{
(alias) gcd_source_timer_leeway.dispatch_source_t = void*dispatch_source_t (field) void* gcd_source_timer_leeway.Timer.sourcesource;
(alias) gcd_source_timer_leeway.dispatch_semaphore_t = void*dispatch_semaphore_t (field) void* gcd_source_timer_leeway.Timer.finishedfinished;
(struct) core.time.MonoTimeImpl!(ClockType.normal)MonoTime (field) core.time.MonoTimeImpl!(ClockType.normal) gcd_source_timer_leeway.Timer.armedAtarmedAt;
shared int (field) shared(int) gcd_source_timer_leeway.Timer.firesfires;
shared long[(constant) int gcd_source_timer_leeway.fireBudget = 5fireBudget] (field) shared(long[5]) gcd_source_timer_leeway.Timer.arrivalsUsecsarrivalsUsecs;
}
__gshared (struct) gcd_source_timer_leeway.TimerTimer (__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer;
extern (C) void void gcd_source_timer_leeway.onFire(void* context) nothrowonFire(void* (parameter) void* contextcontext) nothrow
{
const (local variable) const(core.time.Duration) elapsedelapsed = (struct) core.time.MonoTimeImpl!(ClockType.normal)MonoTime.core.time.MonoTimeImpl!(ClockType.normal) core.time.MonoTimeImpl!(ClockType.normal).currTime() nothrow @nogc @property @trustedThe current time of the system's monotonic clock. This has no relation
to the wall clock time, as the wall clock time can be adjusted (e.g.
by NTP), whereas the monotonic clock always moves forward. The source
of the monotonic time is system-specific.
On Windows, QueryPerformanceCounter is used. On Mac OS X,
mach_absolute_time is used, while on other POSIX systems,
clock_gettime is used.
Warning: On some systems, the monotonic clock may stop counting
when the computer goes to sleep or hibernates. So, the
monotonic clock may indicate less time than has actually
passed if that occurs. This is known to happen on
Mac OS X. It has not been tested whether it occurs on
either Windows or Linux.
currTime - core.time.Duration core.time.MonoTimeImpl!(ClockType.normal).opBinary!"-"(core.time.MonoTimeImpl!(ClockType.normal) rhs) const pure nothrow @nogc @safeSubtracting two MonoTimes results in a Duration representing
the amount of time which elapsed between them.
The primary way that programs should time how long something takes is to
do
MonoTime before = MonoTime.currTime;
// do stuff
MonoTime after = MonoTime.currTime;
// How long it took.
Duration timeElapsed = after - before;
or to use a wrapper (such as a stop watch type) which does that.
Warning:
Because Duration is in hnsecs, whereas MonoTime is in system
ticks, it's usually the case that this assertion will fail
auto before = MonoTime.currTime;
// do stuff
auto after = MonoTime.currTime;
auto timeElapsed = after - before;
assert(before + timeElapsed == after);
This is generally fine, and by its very nature, converting from
system ticks to any type of seconds (hnsecs, nsecs, etc.) will
introduce rounding errors, but if code needs to avoid any of the
small rounding errors introduced by conversion, then it needs to use
MonoTime's ticks property and keep all calculations in ticks
rather than using Duration.
timer.(field) core.time.MonoTimeImpl!(ClockType.normal) gcd_source_timer_leeway.Timer.armedAtarmedAt;
const (local variable) const(int) nn = int core.atomic.atomicOp!("+=", int, int)(ref shared(int) val, int mod) pure nothrow @nogc @safePerforms the binary operation 'op' on val using 'mod' as the modifier.
atomicOp!"+="((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) shared(int) gcd_source_timer_leeway.Timer.firesfires, 1);
if ((local variable) const(int) nn <= (constant) int gcd_source_timer_leeway.fireBudget = 5fireBudget)
void core.atomic.atomicStore!(MemoryOrder.seq, long, long)(ref shared(long) val, long newval) pure nothrow @nogc @trustedWrites 'newval' into 'val'. The memory barrier specified by 'ms' is
applied to the operation, which is fully sequenced by default.
Valid memory orders are MemoryOrder.raw, MemoryOrder.rel, and
MemoryOrder.seq.
atomicStore((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) shared(long[5]) gcd_source_timer_leeway.Timer.arrivalsUsecsarrivalsUsecs[(local variable) const(int) nn - 1], (local variable) const(core.time.Duration) elapsedelapsed.long core.time.Duration.total!"usecs"() const pure nothrow @nogc @property @safeReturns the total number of the given units in this Duration.
So, unlike split, it does not strip out the larger units.
Examples
assert(dur!"weeks"(12).total!"weeks" == 12);
assert(dur!"weeks"(12).total!"days" == 84);
assert(dur!"days"(13).total!"weeks" == 1);
assert(dur!"days"(13).total!"days" == 13);
assert(dur!"hours"(49).total!"days" == 2);
assert(dur!"hours"(49).total!"hours" == 49);
assert(dur!"nsecs"(2007).total!"hnsecs" == 20);
assert(dur!"nsecs"(2007).total!"nsecs" == 2000);
total!"usecs");
if ((local variable) const(int) nn >= (constant) int gcd_source_timer_leeway.fireBudget = 5fireBudget)
void gcd_source_timer_leeway.dispatch_source_cancel(void* source) nothrow @nogcdispatch_source_cancel((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) void* gcd_source_timer_leeway.Timer.sourcesource);
}
extern (C) void void gcd_source_timer_leeway.onCancel(void* context) nothrowonCancel(void* (parameter) void* contextcontext) nothrow
{
long gcd_source_timer_leeway.dispatch_semaphore_signal(void* sema) nothrow @nogcdispatch_semaphore_signal((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) void* gcd_source_timer_leeway.Timer.finishedfinished);
}
int int D main()main()
{
auto (local variable) void* queuequeue = void* gcd_source_timer_leeway.dispatch_queue_create(const(char)* label, void* attr) nothrow @nogcdispatch_queue_create("dev.sparkles.research.gcd.timer", null);
scope (exit)
void gcd_source_timer_leeway.dispatch_release(void* object) nothrow @nogcdispatch_release((local variable) void* queuequeue);
(__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) void* gcd_source_timer_leeway.Timer.finishedfinished = void* gcd_source_timer_leeway.dispatch_semaphore_create(long value) nothrow @nogcdispatch_semaphore_create(0);
(__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) void* gcd_source_timer_leeway.Timer.sourcesource = void* gcd_source_timer_leeway.dispatch_source_create(const(void)* type, ulong handle, ulong mask, void* queue) nothrow @nogcdispatch_source_create(&(constant global) const(ubyte) gcd_source_timer_leeway._dispatch_source_type_timerDISPATCH_SOURCE_TYPE_TIMER is &_dispatch_source_type_timer``.
_dispatch_source_type_timer, 0, 0, (local variable) void* queuequeue);
void gcd_source_timer_leeway.dispatch_source_set_event_handler_f(void* source, extern (C) void function(void*) nothrow handler) nothrow @nogcdispatch_source_set_event_handler_f((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) void* gcd_source_timer_leeway.Timer.sourcesource, &void gcd_source_timer_leeway.onFire(void* context) nothrowonFire);
void gcd_source_timer_leeway.dispatch_source_set_cancel_handler_f(void* source, extern (C) void function(void*) nothrow handler) nothrow @nogcdispatch_source_set_cancel_handler_f((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) void* gcd_source_timer_leeway.Timer.sourcesource, &void gcd_source_timer_leeway.onCancel(void* context) nothrowonCancel);
const (local variable) const(long) intervalNsintervalNs = (constant) int gcd_source_timer_leeway.intervalMs = 20intervalMs * 1_000_000L;
// Leeway == interval / 2 is the largest value libdispatch will honour for
// this interval; anything bigger is clamped to exactly this.
const (local variable) const(long) leewayNsleewayNs = (local variable) const(long) intervalNsintervalNs / 2;
(__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) core.time.MonoTimeImpl!(ClockType.normal) gcd_source_timer_leeway.Timer.armedAtarmedAt = (struct) core.time.MonoTimeImpl!(ClockType.normal)MonoTime.core.time.MonoTimeImpl!(ClockType.normal) core.time.MonoTimeImpl!(ClockType.normal).currTime() nothrow @nogc @property @trustedThe current time of the system's monotonic clock. This has no relation
to the wall clock time, as the wall clock time can be adjusted (e.g.
by NTP), whereas the monotonic clock always moves forward. The source
of the monotonic time is system-specific.
On Windows, QueryPerformanceCounter is used. On Mac OS X,
mach_absolute_time is used, while on other POSIX systems,
clock_gettime is used.
Warning: On some systems, the monotonic clock may stop counting
when the computer goes to sleep or hibernates. So, the
monotonic clock may indicate less time than has actually
passed if that occurs. This is known to happen on
Mac OS X. It has not been tested whether it occurs on
either Windows or Linux.
currTime;
void gcd_source_timer_leeway.dispatch_source_set_timer(void* source, ulong start, ulong interval, ulong leeway) nothrow @nogcdispatch_source_set_timer((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) void* gcd_source_timer_leeway.Timer.sourcesource, ulong gcd_source_timer_leeway.dispatch_time(ulong when, long delta) nothrow @nogcdispatch_time((constant) ulong gcd_source_timer_leeway.DISPATCH_TIME_NOW = 0LUDISPATCH_TIME_NOW, (local variable) const(long) intervalNsintervalNs),
(local variable) const(long) intervalNsintervalNs, (local variable) const(long) leewayNsleewayNs);
void gcd_source_timer_leeway.dispatch_resume(void* object) nothrow @nogcdispatch_resume((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) void* gcd_source_timer_leeway.Timer.sourcesource);
long gcd_source_timer_leeway.dispatch_semaphore_wait(void* sema, ulong timeout) nothrow @nogcdispatch_semaphore_wait((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) void* gcd_source_timer_leeway.Timer.finishedfinished, (constant) ulong gcd_source_timer_leeway.DISPATCH_TIME_FOREVER = 18446744073709551615LUDISPATCH_TIME_FOREVER);
void gcd_source_timer_leeway.dispatch_release(void* object) nothrow @nogcdispatch_release((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) void* gcd_source_timer_leeway.Timer.sourcesource);
void std.stdio.writefln!(char, int, long)(in char[] fmt, int __param_1, long __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln("interval = %d ms, leeway = %d ms", (constant) int gcd_source_timer_leeway.intervalMs = 20intervalMs, (local variable) const(long) leewayNsleewayNs / 1_000_000);
void std.stdio.writeln!()() @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln();
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("fire deadline (ms) arrival (ms) lateness (ms)");
foreach ((local variable) int ii; 0 .. (constant) int gcd_source_timer_leeway.fireBudget = 5fireBudget)
{
const (local variable) const(int) deadlineMsdeadlineMs = ((local variable) int ii + 1) * (constant) int gcd_source_timer_leeway.intervalMs = 20intervalMs;
const (local variable) const(double) arrivalMsarrivalMs = long core.atomic.atomicLoad!(MemoryOrder.seq, long)(ref return scope shared(const(long)) val) pure nothrow @nogc @trustedLoads 'val' from memory and returns it. The memory barrier specified
by 'ms' is applied to the operation, which is fully sequenced by
default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq,
and MemoryOrder.seq.
atomicLoad((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) shared(long[5]) gcd_source_timer_leeway.Timer.arrivalsUsecsarrivalsUsecs[(local variable) int ii]) / 1000.0;
void std.stdio.writefln!(char, int, const(int), const(double), double)(in char[] fmt, int __param_1, const(int) __param_2, const(double) __param_3, double __param_4) @safeEquivalent to writef(fmt, args, '\n').
writefln("%4d %13d %12.1f %13.1f", (local variable) int ii + 1, (local variable) const(int) deadlineMsdeadlineMs, (local variable) const(double) arrivalMsarrivalMs,
(local variable) const(double) arrivalMsarrivalMs - (local variable) const(int) deadlineMsdeadlineMs);
// The contract: a leeway lets the kernel fire late, never early. A
// 1 ms slack absorbs the clock read inside the handler itself.
assert((local variable) const(double) arrivalMsarrivalMs + 1.0 >= (local variable) const(int) deadlineMsdeadlineMs, "timer fired before its deadline");
}
assert(int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) val) pure nothrow @nogc @trustedLoads 'val' from memory and returns it. The memory barrier specified
by 'ms' is applied to the operation, which is fully sequenced by
default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq,
and MemoryOrder.seq.
atomicLoad((__gshared global) gcd_source_timer_leeway.Timer gcd_source_timer_leeway.timertimer.(field) shared(int) gcd_source_timer_leeway.Timer.firesfires) >= (constant) int gcd_source_timer_leeway.fireBudget = 5fireBudget, "timer under-delivered");
void std.stdio.writeln!()() @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln();
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("leeway buys coalescing with other timers; it never moves a deadline earlier");
return 0;
}