app.dhover×229 error×40all
// X11 F05 demo — loop wakeup & external fds (../../../features/f05-loop-wakeup.md).
// Built on the scaffold (../scaffold/app.d): same ImportC binding style, same
// poll(2)-driven readiness loop, same instrument.d event log.
//
// What it measures (F05 requirements 1-3):
//
//   * Mechanism A (`mech=clientmessage`): a second thread with its OWN
//     Display* connection injects a ClientMessage into the main window via
//     XSendEvent + XFlush. This is the documented thread-safe injection
//     without XInitThreads: Xlib is only thread-unsafe when two threads share
//     one Display, so one-connection-per-thread sidesteps locking entirely.
//     The event makes a full round-trip through the X server (thread socket
//     -> server -> main-loop socket).
//   * Mechanism B (`mech=eventfd`): the same thread writes an eventfd(2) that
//     the main loop poll(2)s alongside ConnectionNumber(dpy) — no server
//     involvement, a pure kernel futex/wait wake.
//   * An arbitrary external fd: a periodic timerfd(2) in the same poll set,
//     logged as `fd_tick` interleaved with window events.
//
// Each mechanism fires 10x/second for 30 s (WSI_DURATION_MS overrides),
// offset by 50 ms so they interleave; every wakeup logs
// `wakeup latency_us=… mech=…` computed from a monotonic timestamp carried
// in the event (ClientMessage: split across two 32-bit data.l slots — the
// wire format truncates each slot to 32 bits) or in an atomic side-channel
// (eventfd is a counter, not a queue). min/p50/p99/max per mechanism at exit.
//
// Headless-safe: no X server -> prints `SKIP:` and exits 0. WSI_AUTO_EXIT=1
// bounds the run (exits after the wakeup phase completes). Findings:
// ../../f05-loop-wakeup.md.
module 
(module) app
app
;
import
(module) c
c
; // ImportC: Xlib + poll + eventfd + timerfd + unistd
C preprocess command `cpp` failed for file `/home/runner/work/sparkles/sparkles/docs/research/window-system-integration/os-apis/x11/examples/f05-loop-wakeup/c.c`, exit status 1
import
(module) instrument
instrument
;
import
(package) core
core
.
(module) core.atomic

The 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);
@copyrightCopyright Sean Kelly 2005 - 2016.@licenseBoost License 1.0@authorsSean Kelly, Alex Rønne Petersen, Manu Evans
atomic
:
(alias template) app.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.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
,
(alias template) app.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.

@paramval The target variable.@paramnewval The value to store.
atomicStore
;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.config

D compatible types that correspond to various basic types in associated C and C++ compilers.

Source

core/stdc/config.d

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly@standardsISO/IEC 9899:1999 (E)
config
: c_long, c_ulong;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.stdio

D header file for C99 <stdio.h>

pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html, stdio.h

Source

core/stdc/stdio.d

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly, Alex Rønne Petersen@standardsISO/IEC 9899:1999 (E)
stdio
:
(alias) app.printf = int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
;
import
(package) core
core
.
(package) core.stdc
stdc
.
(module) core.stdc.stdlib

D header file for C99.

pubs.opengroup.org/onlinepubs/009695399/basedefs/stdlib.h.html, stdlib.h

Source

core/stdc/stdlib.d

@copyrightCopyright Sean Kelly 2005 - 2014.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly@standardsISO/IEC 9899:1999 (E)
stdlib
:
(alias) app.atoi = int core.stdc.stdlib.atoi(scope const(char*) nptr) nothrow @nogc
atoi
,
(alias) app.getenv = char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
,
(alias) app.qsort = void core.stdc.stdlib.qsort(void* base, ulong nmemb, ulong size, extern (C) int function(const(void*), const(void*)) compar) nothrow @nogc
qsort
;
import
(package) core
core
.
(package) core.thread
thread
.
(module) core.thread.osthread

The osthread module provides low-level, OS-dependent code for thread creation and management.

Source

core/thread/osthread.d

@copyrightCopyright Sean Kelly 2005 - 2012.@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
osthread
:
(class) core.thread.osthread.Thread

This class encapsulates all threading functionality for the D programming language. As thread manipulation is a required facility for garbage collection, all user threads should derive from this class, and instances of this class should never be explicitly deleted. A new thread may be created using either derivation or composition, as in the following example.

Thread
;
import
(package) core
core
.
(module) core.time

Module 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&nbsp;days&nbsp;hours

minutes&nbsp;seconds&nbsp;msecs

usecs&nbsp;hnsecs&nbsp;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

@copyrightCopyright 2010 - 2012@licenseBoost License 1.0.@authorsJonathan M Davis and Kato Shoichi
time
: msecs;
// --------------------------------------------------------------------------- // Constants Xlib/glibc expose as macros that ImportC cannot import // (expression macros like `(1L<<15)`); re-declared per the scaffold gotcha. enum : c_long {
(enum value) app.KeyPressMask = 1L
KeyPressMask
= 1L << 0,
(enum value) app.ExposureMask = 32768L
ExposureMask
= 1L << 15,
(enum value) app.StructureNotifyMask = 131072L
StructureNotifyMask
= 1L << 17,
} enum // XEvent.type discriminators {
(enum value) app.KeyPress = 2
KeyPress
= 2,
(enum value) app.Expose = 12
Expose
= 12,
(enum value) app.MapNotify = 19
MapNotify
= 19,
(enum value) app.ConfigureNotify = 22
ConfigureNotify
= 22,
(enum value) app.ClientMessage = 33
ClientMessage
= 33,
} enum
(constant) int app.False = 0
False
= 0;
enum
(constant) int app.True = 1
True
= 1;
enum
(constant) int app.POLLIN = 1
POLLIN
= 0x001;
enum
(constant) int app.CLOCK_MONOTONIC = 1
CLOCK_MONOTONIC
= 1;
enum
(constant) int app.EFD_CLOEXEC = 524288
EFD_CLOEXEC
= 0x80000; // 02000000
enum
(constant) int app.EFD_NONBLOCK = 2048
EFD_NONBLOCK
= 0x800; // 00004000
enum
(constant) int app.TFD_CLOEXEC = 524288
TFD_CLOEXEC
= 0x80000;
enum
(constant) int app.WAKE_MAGIC = 1463896901
WAKE_MAGIC
= 0x57414b45; // "WAKE" — data.l[0] tag of our ClientMessage
// --------------------------------------------------------------------------- // Worker-thread <-> main-loop shared state. The worker owns its own Display; // the only data crossing threads outside X are these atomics + the eventfd. __gshared Window
_error_ app.g_win
g_win
; // injection target (XIDs are connection-independent)
undefined identifier `Window`
__gshared Atom
_error_ app.g_wakeAtom
g_wakeAtom
; // atoms are server-global ids, safe to share
undefined identifier `Atom`
__gshared int
(__gshared global) int app.g_efd
g_efd
= -1;
__gshared long
(__gshared global) long app.g_efdStamp
g_efdStamp
; // nowUs() at the instant of the eventfd write
__gshared int
(__gshared global) int app.g_wakeupsPerMech
g_wakeupsPerMech
= 300; // 10/s for 30 s
__gshared bool
(__gshared global) bool app.g_workerDone
g_workerDone
;
/// The injector thread (F05 requirement 1). Opens its own connection — the /// documented no-XInitThreads-needed pattern — and alternates the two /// mechanisms on a 50 ms grid, so each one fires 10x/s. void
void app.injectorThread()

The injector thread (F05 requirement 1). Opens its own connection — the documented no-XInitThreads-needed pattern — and alternates the two mechanisms on a 50 ms grid, so each one fires 10x/s.

injectorThread
()
{ Display*
(local variable) _error_ d2
d2
= XOpenDisplay(null);
undefined identifier `Display`
undefined identifier `XOpenDisplay`
if (d2 is null) {
void core.atomic.atomicStore!(MemoryOrder.seq, bool, bool)(ref bool val, bool newval) pure nothrow @nogc @trusted

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.

@paramval The target variable.@paramnewval The value to store.
atomicStore
(
(__gshared global) bool app.g_workerDone
g_workerDone
, true);
return; }
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("step", "name=XOpenDisplay conn=injector fd=%d", XConnectionNumber(d2));
undefined identifier `XConnectionNumber`
const
(local variable) const(long) t0
t0
=
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
();
foreach (
(local variable) int i
i
; 0 .. 2 *
(__gshared global) int app.g_wakeupsPerMech
g_wakeupsPerMech
)
{ const
(local variable) const(long) target
target
=
(local variable) const(long) t0
t0
+ (
(local variable) int i
i
+ 1) * 50_000L;
const
(local variable) const(long) wait
wait
=
(local variable) const(long) target
target
-
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
();
if (
(local variable) const(long) wait
wait
> 0)
(class) core.thread.osthread.Thread

This class encapsulates all threading functionality for the D programming language. As thread manipulation is a required facility for garbage collection, all user threads should derive from this class, and instances of this class should never be explicitly deleted. A new thread may be created using either derivation or composition, as in the following example.

Thread
.
void core.thread.osthread.Thread.sleep(core.time.Duration val) nothrow @nogc @trusted

Suspends the calling thread for at least the supplied period. This may result in multiple OS calls if period is greater than the maximum sleep duration supported by the operating system.

In

period must be non-negative.

Example


Thread.sleep( dur!("msecs")( 50 ) );  // sleep for 50 milliseconds
Thread.sleep( dur!("seconds")( 5 ) ); // sleep for 5 seconds

@paramval The minimum duration the calling thread should be suspended.
sleep
((
(local variable) const(long) wait
wait
/ 1000).msecs);
if (
(local variable) int i
i
% 2 == 0) // mechanism A: ClientMessage through the server
{ XEvent
(local variable) _error_ ev
ev
;
undefined identifier `XEvent`
ev.xclient.type = ClientMessage; ev.xclient.window = g_win; ev.xclient.message_type = g_wakeAtom; ev.xclient.format = 32; const
(local variable) const(long) ts
ts
=
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
();
ev.xclient.data.l[0] = WAKE_MAGIC; ev.xclient.data.l[1] = cast(c_long)(ts >> 32); // wire slots are ev.xclient.data.l[2] = cast(c_long)(ts & 0xffff_ffffL); // 32-bit // event_mask=0: deliver to the client that created g_win. XSendEvent(d2, g_win, False, 0, &ev);
undefined identifier `XSendEvent`
XFlush(d2); // scaffold gotcha: nothing moves until the flush
undefined identifier `XFlush`
} else // mechanism B: eventfd, kernel-only {
void core.atomic.atomicStore!(MemoryOrder.seq, long, long)(ref long val, long newval) pure nothrow @nogc @trusted

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.

@paramval The target variable.@paramnewval The value to store.
atomicStore
(
(__gshared global) long app.g_efdStamp
g_efdStamp
,
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
());
ulong
(local variable) ulong one
one
= 1;
write(g_efd, &one, one.
one.sizeof
sizeof
);
undefined identifier `write`
} } XCloseDisplay(d2);
undefined identifier `XCloseDisplay`
void core.atomic.atomicStore!(MemoryOrder.seq, bool, bool)(ref bool val, bool newval) pure nothrow @nogc @trusted

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.

@paramval The target variable.@paramnewval The value to store.
atomicStore
(
(__gshared global) bool app.g_workerDone
g_workerDone
, true);
} // --------------------------------------------------------------------------- // Latency bookkeeping. struct
(struct) app.Series
Series
{ long[4096]
(field) long[4096] app.Series.v
v
;
int
(field) int app.Series.n
n
;
void
void app.Series.record(long x) nothrow @nogc
record
(long
(parameter) long x
x
) @nogc nothrow
{ if (
(field) int app.Series.n
n
<
(field) long[4096] app.Series.v
v
.
(constant) ulong long[4096].length = 4096LU
length
)
(field) long[4096] app.Series.v
v
[
(field) int app.Series.n
n
++] =
(parameter) long x
x
;
} long
long app.Series.at(double q) nothrow @nogc
at
(double
(parameter) double q
q
) @nogc nothrow // q in [0,1] on the sorted array
{ auto
(local variable) int i
i
= cast(int)(
(parameter) double q
q
* (
(field) int app.Series.n
n
- 1) + 0.5);
return
(field) long[4096] app.Series.v
v
[
(local variable) int i
i
< 0 ? 0 : (
(local variable) int i
i
>=
(field) int app.Series.n
n
?
(field) int app.Series.n
n
- 1 :
(local variable) int i
i
)];
} } extern (C) int
int app.cmpLong(const(void*) a, const(void*) b) nothrow @nogc
cmpLong
(const void*
(parameter) const(void*) a
a
, const void*
(parameter) const(void*) b
b
) @nogc nothrow
{ const
(local variable) const(long) x
x
= *cast(const long*)
(parameter) const(void*) a
a
,
(local variable) const(long) y
y
= *cast(const long*)
(parameter) const(void*) b
b
;
return (
(local variable) const(long) x
x
>
(local variable) const(long) y
y
) - (
(local variable) const(long) x
x
<
(local variable) const(long) y
y
);
} void
void app.emitStats(const(char)* mech, ref app.Series s) nothrow @nogc
emitStats
(const(char)*
(parameter) const(char)* mech
mech
, ref
(struct) app.Series
Series
(parameter) app.Series s
s
) @nogc nothrow
{ if (
(parameter) app.Series s
s
.
(field) int app.Series.n
n
== 0)
return;
void core.stdc.stdlib.qsort(void* base, ulong nmemb, ulong size, extern (C) int function(const(void*), const(void*)) compar) nothrow @nogc
qsort
(
(parameter) app.Series s
s
.
(field) long[4096] app.Series.v
v
.
(constant) long* long[4096].ptr = &s.v
ptr
,
(parameter) app.Series s
s
.
(field) int app.Series.n
n
, long.
(constant) ulong long.sizeof = 8LU
sizeof
, &
int app.cmpLong(const(void*) a, const(void*) b) nothrow @nogc
cmpLong
);
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("stats", "mech=%s n=%d min=%lld p50=%lld p99=%lld max=%lld",
(parameter) const(char)* mech
mech
,
(parameter) app.Series s
s
.
(field) int app.Series.n
n
,
(parameter) app.Series s
s
.
(field) long[4096] app.Series.v
v
[0],
(parameter) app.Series s
s
.
long app.Series.at(double q) nothrow @nogc
at
(0.50),
(parameter) app.Series s
s
.
long app.Series.at(double q) nothrow @nogc
at
(0.99),
(parameter) app.Series s
s
.
(field) long[4096] app.Series.v
v
[
(parameter) app.Series s
s
.
(field) int app.Series.n
n
- 1]);
} int
int D main()
main
()
{
void instrument.initInstrument(const(char)* demoName) nothrow @nogc

Names the demo, starts the monotonic clock, and emits init_start. Call this first, before any platform API call.

initInstrument
("f05_x11");
const
(local variable) const(char*) envAuto
envAuto
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_AUTO_EXIT");
const
(local variable) const(bool) autoExit
autoExit
=
(local variable) const(char*) envAuto
envAuto
!is null &&
(local variable) const(char*) envAuto
envAuto
[0] == '1';
const
(local variable) const(char*) envDur
envDur
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_DURATION_MS");
const
(local variable) const(int) durationMs
durationMs
=
(local variable) const(char*) envDur
envDur
!is null ?
int core.stdc.stdlib.atoi(scope const(char*) nptr) nothrow @nogc
atoi
(
(local variable) const(char*) envDur
envDur
) : 30_000;
(__gshared global) int app.g_wakeupsPerMech
g_wakeupsPerMech
=
(local variable) const(int) durationMs
durationMs
/ 100; // each mechanism fires every 100 ms
// -- Connect + window (scaffold sequence, minus the SHM backbuffer) ------ Display*
(local variable) _error_ dpy
dpy
= XOpenDisplay(null);
undefined identifier `Display`
undefined identifier `XOpenDisplay`
if (dpy is null) {
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: no X11 display (XOpenDisplay returned null)\n");
return 0; }
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("step", "name=XOpenDisplay conn=main fd=%d", XConnectionNumber(dpy));
undefined identifier `XConnectionNumber`
const
(local variable) const(_error_) screen
screen
= XDefaultScreen(dpy);
undefined identifier `XDefaultScreen`
Window
(local variable) _error_ win
win
= XCreateSimpleWindow(dpy, XRootWindow(dpy, screen), 0, 0,
undefined identifier `Window`
undefined identifier `XCreateSimpleWindow`
480, 320, 1, XBlackPixel(dpy, screen), XWhitePixel(dpy, screen)); XStoreName(dpy, win, "Sparkles · X11 F05 loop wakeup");
undefined identifier `XStoreName`
Atom
(local variable) _error_ wmDelete
wmDelete
= XInternAtom(dpy, "WM_DELETE_WINDOW", False);
undefined identifier `Atom`
undefined identifier `XInternAtom`
XSetWMProtocols(dpy, win, &wmDelete, 1);
undefined identifier `XSetWMProtocols`
Atom
(local variable) _error_ wakeAtom
wakeAtom
= XInternAtom(dpy, "SPARKLES_WSI_WAKEUP", False);
undefined identifier `Atom`
undefined identifier `XInternAtom`
XSelectInput(dpy, win, ExposureMask | KeyPressMask | StructureNotifyMask);
undefined identifier `XSelectInput`
XMapWindow(dpy, win);
undefined identifier `XMapWindow`
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("window_created", "xid=0x%lx size=480x320", win);
// -- The two external fds (F05 requirement 2) ----------------------------- const
(local variable) const(_error_) efd
efd
= eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
undefined identifier `eventfd`
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("step", "name=eventfd fd=%d", efd);
const
(local variable) const(_error_) tfd
tfd
= timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
undefined identifier `timerfd_create`
itimerspec
(local variable) _error_ its
its
;
undefined identifier `itimerspec`
its.it_interval.tv_sec = 0; its.it_interval.tv_nsec = 250_000_000; // 4 Hz probe tick its.it_value = its.it_interval; timerfd_settime(tfd, 0, &its, null);
undefined identifier `timerfd_settime`
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("step", "name=timerfd fd=%d period_ms=250", tfd);
g_win = win; g_wakeAtom = wakeAtom;
(__gshared global) int app.g_efd
g_efd
= efd;
auto
(local variable) core.thread.osthread.Thread worker
worker
= new
(class) core.thread.osthread.Thread

This class encapsulates all threading functionality for the D programming language. As thread manipulation is a required facility for garbage collection, all user threads should derive from this class, and instances of this class should never be explicitly deleted. A new thread may be created using either derivation or composition, as in the following example.

Thread
(&
void app.injectorThread()

The injector thread (F05 requirement 1). Opens its own connection — the documented no-XInitThreads-needed pattern — and alternates the two mechanisms on a 50 ms grid, so each one fires 10x/s.

injectorThread
);
(local variable) core.thread.osthread.Thread worker
worker
.
core.thread.osthread.Thread core.thread.osthread.Thread.start() nothrow

Starts the thread and invokes the function or delegate passed upon construction.

In

This routine may only be called once per thread instance.

@throwsThreadException if the thread fails to start.
start
();
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("step", "name=thread_start wakeups_per_mech=%d period_ms=100",
(__gshared global) int app.g_wakeupsPerMech
g_wakeupsPerMech
);
(struct) app.Series
Series
(local variable) app.Series latClientMsg
latClientMsg
,
(local variable) app.Series latEventfd
latEventfd
;
int
(local variable) int fdTicks
fdTicks
= 0,
(local variable) int frames
frames
= 0;
bool
(local variable) bool running
running
= true,
(local variable) bool sawFirstPixel
sawFirstPixel
= false;
long
(local variable) long doneAtUs
doneAtUs
= 0;
// -- Readiness loop: ConnectionNumber fd + eventfd + timerfd in one poll -- while (
(local variable) bool running
running
)
{ while (XPending(dpy) > 0) // also flushes the output buffer
undefined identifier `XPending`
{ XEvent
(local variable) _error_ ev
ev
;
undefined identifier `XEvent`
XNextEvent(dpy, &ev);
undefined identifier `XNextEvent`
switch (ev.type) { case Expose: if (ev.xexpose.
ev.xexpose.count
count
== 0)
{ XFillRectangle(dpy, win, XDefaultGC(dpy, screen), 20, 20, 440, 280); XFlush(dpy); ++frames; if (!sawFirstPixel) { sawFirstPixel = true; emit("first_pixel_presented method=XFillRectangle"); } } break; case ClientMessage: if (ev.xclient.message_type == wakeAtom && ev.xclient.data.l[0] == WAKE_MAGIC) { // Reassemble the 64-bit monotonic stamp from the two // sign-extended 32-bit wire slots. const
_error_ ts
ts
= (cast(long) ev.xclient.data.l[1] << 32)
| cast(uint) ev.xclient.data.l[2]; const
_error_ lat
lat
= nowUs() - ts;
latClientMsg.
latClientMsg.record
record
(lat);
emitf("wakeup", "latency_us=%lld mech=clientmessage", lat); } else if (cast(Atom) ev.xclient.data.l[0] == wmDelete) { emit("close_requested via=WM_DELETE_WINDOW"); running = false; } break; case KeyPress: emit("close_requested via=KeyPress"); running = false; break; default: break; } } if (
bool core.atomic.atomicLoad!(MemoryOrder.seq, bool)(ref return scope const(bool) val) pure nothrow @nogc @trusted

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.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
(
(__gshared global) bool app.g_workerDone
g_workerDone
))
{ if (
(local variable) long doneAtUs
doneAtUs
== 0)
(local variable) long doneAtUs
doneAtUs
=
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
();
else if (
(local variable) const(bool) autoExit
autoExit
&&
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
() -
(local variable) long doneAtUs
doneAtUs
> 300_000) // drain grace
{
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("auto_exit", "frames=%d",
(local variable) int frames
frames
);
break; } } pollfd[3]
(local variable) _error_ pfds
pfds
;
undefined identifier `pollfd`
pfds[0].fd = XConnectionNumber(dpy); pfds[1].fd = efd; pfds[2].fd = tfd; foreach (ref
(parameter) p
p
; pfds)
{ p.events = POLLIN; p.revents = 0; } poll(pfds.
pfds.ptr
ptr
, 3, 50);
undefined identifier `poll`
if (pfds[1].revents & POLLIN) // mechanism B fired { ulong
(local variable) ulong count
count
;
read(efd, &count, count.
count.sizeof
sizeof
);
undefined identifier `read`, did you mean alias `Thread`?
const
(local variable) const(long) lat
lat
=
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
() -
long core.atomic.atomicLoad!(MemoryOrder.seq, long)(ref return scope const(long) val) pure nothrow @nogc @trusted

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.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
(
(__gshared global) long app.g_efdStamp
g_efdStamp
);
(local variable) app.Series latEventfd
latEventfd
.
void app.Series.record(long x) nothrow @nogc
record
(
(local variable) const(long) lat
lat
);
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("wakeup", "latency_us=%lld mech=eventfd coalesced=%llu",
(local variable) const(long) lat
lat
,
(local variable) ulong count
count
);
} if (pfds[2].revents & POLLIN) // the arbitrary-fd probe { ulong
(local variable) ulong expirations
expirations
;
read(tfd, &expirations, expirations.
expirations.sizeof
sizeof
);
undefined identifier `read`, did you mean alias `Thread`?
++
(local variable) int fdTicks
fdTicks
;
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("fd_tick", "t=%lld expirations=%llu src=timerfd",
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
(),
(local variable) ulong expirations
expirations
);
} } // -- Stats + teardown (F05 requirement 3) ---------------------------------
void app.emitStats(const(char)* mech, ref app.Series s) nothrow @nogc
emitStats
("clientmessage",
(local variable) app.Series latClientMsg
latClientMsg
);
void app.emitStats(const(char)* mech, ref app.Series s) nothrow @nogc
emitStats
("eventfd",
(local variable) app.Series latEventfd
latEventfd
);
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

Emit an event with a printf-formatted key=value ... payload.

emitf
("stats", "mech=timerfd ticks=%d period_ms=250",
(local variable) int fdTicks
fdTicks
);
(local variable) core.thread.osthread.Thread worker
worker
.
object.Throwable core.thread.osthread.Thread.join(bool rethrow = true)

Waits for this thread to complete. If the thread terminated as the result of an unhandled exception, this exception will be rethrown.

@paramrethrow Rethrow any unhandled exception which may have caused this thread to terminate.@throwsThreadException if the operation fails. Any exception not handled by the joined thread.@returnsAny exception not handled by this thread if rethrow = false, null otherwise.
join
();
close(efd);
undefined identifier `close`
close(tfd);
undefined identifier `close`
XDestroyWindow(dpy, win);
undefined identifier `XDestroyWindow`
XCloseDisplay(dpy);
undefined identifier `XCloseDisplay`
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("teardown");
return 0; }