app.dhover×337 error×96all
// F05 loop wakeup & external fds on Wayland (../../f05-loop-wakeup.md): can a
// second thread wake the native event loop, and can arbitrary fds join it?
//
// Wayland's answer is structural: the wl_display connection IS a file
// descriptor, and libwayland's documented thread-safe pump —
// wl_display_prepare_read / poll / wl_display_read_events /
// wl_display_dispatch_pending — is *designed* around the application owning
// the poll(2) call. So "integrate an external fd" is not a workaround on
// Wayland, it is the intended shape: put the wl fd, an eventfd, and a timerfd
// into ONE pollfd array (see pumpOnce, the deliverable of this demo).
//
// What Wayland does NOT have is a protocol-level user event (no XSendEvent /
// PostMessage analogue): a client cannot send itself a message through the
// compositor. The absence is the finding — cross-thread wakeup must be a
// client-owned fd. This demo uses eventfd(2):
//
//   1. A producer pthread writes the eventfd 10×/s for 30 s; each post's
//      monotonic timestamp travels through a lock-free ring (the eventfd
//      counter is a *sum*, so coalesced posts would corrupt an inline
//      timestamp — the side buffer is the correct pattern). The main loop
//      logs `wakeup latency_us=… mech=eventfd` per post.
//   2. A timerfd ticking at 7 Hz is the arbitrary-fd probe; its `fd_tick`
//      lines interleave with the 60 Hz frame-callback redraws.
//   3. min/median/p99/max latency is printed at exit.
//
// Based on the scaffold (../scaffold/app.d, findings ../../scaffold.md);
// instrumentation contract: ./instrument.d. Headless-safe: no compositor →
// SKIP, exit 0. WSI_AUTO_EXIT is accepted for runner symmetry; the run is
// inherently bounded (producer stops after WSI_F05_WAKEUPS posts, default 300).
module 
(module) app
app
;
import c; // ImportC: <wayland-client.h> + xdg-shell glue + eventfd/timerfd/poll + wsi_* wrappers
unable to read module `c` Expected 'c.d' or 'c/package.d' in one of the following import paths:
unable to read module `c` Expected 'c.d' or 'c/package.d' in one of the following import paths:
import instrument;
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
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
,
(enum) core.atomic.MemoryOrder

Specifies the memory ordering semantics of an atomic operation.

@see
MemoryOrder
;
// glibc 2.42's <pthread.h> is not ImportC-able (linux/types.h __int128), so // the thread API comes from druntime's POSIX declarations instead (see c.c). import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(module) core.sys.posix.pthread

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly, Alex Rønne Petersen@standardsThe Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
pthread
:
(alias) app.pthread_create = int core.sys.posix.pthread.pthread_create(ulong*, scope const(core.sys.posix.sys.types.pthread_attr_t*), extern (C) void* function(void*), void*) nothrow @nogc
pthread_create
,
(alias) app.pthread_join = int core.sys.posix.pthread.pthread_join(ulong, void**) nothrow @nogc
pthread_join
, pthread_t;
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.stdc
stdc
.
(module) core.stdc.string

D header file for C99.

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

Source

core/stdc/string.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)
string
:
(alias) app.strcmp = int core.stdc.string.strcmp(scope const(char*) s1, scope const(char*) s2) pure nothrow @nogc
strcmp
;
// ----------------------------------------------------------------- tunables enum int
(constant) int app.defaultWidth = 640
defaultWidth
= 640;
enum int
(constant) int app.defaultHeight = 480
defaultHeight
= 480;
enum int
(constant) int app.wakeupHz = 10
wakeupHz
= 10; // producer posts 10×/s …
enum int
(constant) int app.defaultWakeups = 300
defaultWakeups
= 300; // … for 30 s (override: WSI_F05_WAKEUPS)
enum long
(constant) long app.timerTickNs = 142857142L
timerTickNs
= 1_000_000_000L / 7; // the 7 Hz timerfd probe
enum int
(constant) int app.pollTimeoutMs = 250
pollTimeoutMs
= 250; // backstop tick (poll is the real wait)
enum long
(constant) long app.hardCapSlackUs = 10000000L
hardCapSlackUs
= 10_000_000; // grace beyond the nominal run length
enum int
(constant) int app.maxSamples = 4096
maxSamples
= 4096;
// -------------------------------------------------------------------- state /// One wl_shm-backed ARGB8888 buffer. `busy` is owned by the compositor /// between wl_surface.commit and the wl_buffer.release event. struct
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer. busy is owned by the compositor between wl_surface.commit and the wl_buffer.release event.

Buffer
{ wl_buffer*
(field) _error_ app.Buffer.handle
handle
;
undefined identifier `wl_buffer`
uint*
(field) uint* app.Buffer.pixels
pixels
; // mmap'ed, shared with the compositor
(alias) object.size_t = ulong
size_t
(field) ulong app.Buffer.byteSize
byteSize
;
int
(field) int app.Buffer.width
width
,
(field) int app.Buffer.height
height
;
bool
(field) bool app.Buffer.busy
busy
;
} __gshared { wl_display*
_error_ app.g_display
g_display
;
undefined identifier `wl_display`, did you mean variable `g_display`?
wl_registry*
_error_ app.g_registry
g_registry
;
undefined identifier `wl_registry`, did you mean variable `g_registry`?
wl_compositor*
_error_ app.g_compositor
g_compositor
;
undefined identifier `wl_compositor`, did you mean variable `g_compositor`?
wl_shm*
_error_ app.g_shm
g_shm
;
undefined identifier `wl_shm`, did you mean variable `g_shm`?
wl_seat*
_error_ app.g_seat
g_seat
;
undefined identifier `wl_seat`, did you mean variable `g_seat`?
xdg_wm_base*
_error_ app.g_wmBase
g_wmBase
;
undefined identifier `xdg_wm_base`
wl_surface*
_error_ app.g_surface
g_surface
;
undefined identifier `wl_surface`, did you mean variable `g_surface`?
xdg_surface*
_error_ app.g_xdgSurface
g_xdgSurface
;
undefined identifier `xdg_surface`, did you mean variable `g_surface`?
xdg_toplevel*
_error_ app.g_toplevel
g_toplevel
;
undefined identifier `xdg_toplevel`, did you mean variable `g_toplevel`?
wl_callback*
_error_ app.g_frameCb
g_frameCb
; // at most one outstanding frame callback
undefined identifier `wl_callback`
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer. busy is owned by the compositor between wl_surface.commit and the wl_buffer.release event.

Buffer
[2]
_error_ app.g_buffers
g_buffers
;
int
(__gshared global) int app.g_width
g_width
= defaultWidth; // last *acked* size — buffers must match it
int
(__gshared global) int app.g_height
g_height
= defaultHeight;
int
(__gshared global) int app.g_pendingWidth
g_pendingWidth
;
int
(__gshared global) int app.g_pendingHeight
g_pendingHeight
;
bool
(__gshared global) bool app.g_configured
g_configured
;
bool
(__gshared global) bool app.g_presented
g_presented
;
bool
(__gshared global) bool app.g_running
g_running
= true;
int
(__gshared global) int app.g_frames
g_frames
;
int
(__gshared global) int app.g_commits
g_commits
;
// The two external fds multiplexed with the wl_display fd. int
(__gshared global) int app.g_eventfd
g_eventfd
= -1; // cross-thread wakeup channel (mech=eventfd)
int
(__gshared global) int app.g_timerfd
g_timerfd
= -1; // arbitrary-fd probe (mech=timerfd, 7 Hz)
// Producer → consumer timestamp ring. The eventfd's 8-byte counter is a // SUM of the posted values, so coalesced posts (two writes before one // read) would add two timestamps into garbage; the ring carries each // timestamp intact and the counter only says how many to pop. long[
(constant) int app.maxSamples = 4096
maxSamples
]
(__gshared global) long[4096] app.g_ring
g_ring
;
ulong
(__gshared global) ulong app.g_ringWrite
g_ringWrite
; // producer-owned, release-published
ulong
(__gshared global) ulong app.g_ringRead
g_ringRead
; // consumer-owned
bool
(__gshared global) bool app.g_producerDone
g_producerDone
; // release-published by the producer thread
int
(__gshared global) int app.g_wakeupsWanted
g_wakeupsWanted
= defaultWakeups;
long[
(constant) int app.maxSamples = 4096
maxSamples
]
(__gshared global) long[4096] app.g_latencies
g_latencies
; // consumed-wakeup latencies, µs
int
(__gshared global) int app.g_latCount
g_latCount
;
int
(__gshared global) int app.g_coalesced
g_coalesced
; // posts that arrived >1 per eventfd read
long
(__gshared global) long app.g_fdTicks
g_fdTicks
; // timerfd expirations seen
} // --------------------------------------------------------- producer thread /// Second thread: every 100 ms, stamp "now", publish it in the ring, write /// the eventfd. The write(2) is the only wakeup mechanism Wayland offers a /// thread that is not the dispatcher — there is no protocol-level user event /// to post. (libwayland itself is thread-safe, but events it queues are only /// seen when the *dispatching* thread next wakes — which is this eventfd.) extern (C) void*
void* app.producerMain(void* __param_0) nothrow @nogc

Second thread: every 100 ms, stamp "now", publish it in the ring, write the eventfd. The write(2) is the only wakeup mechanism Wayland offers a thread that is not the dispatcher — there is no protocol-level user event to post. (libwayland itself is thread-safe, but events it queues are only seen when the dispatching thread next wakes — which is this eventfd.)

producerMain
(void*) nothrow @nogc
{ foreach (
(local variable) int i
i
; 0 ..
(__gshared global) int app.g_wakeupsWanted
g_wakeupsWanted
)
{ timespec
(local variable) _error_ ts
ts
;
undefined identifier `timespec`
ts.tv_sec = 0; ts.tv_nsec = 1_000_000_000 / wakeupHz; nanosleep(&ts, null);
undefined identifier `nanosleep`
immutable
(local variable) immutable(_error_) stamp
stamp
= instrNowUs(); // same MonoTime epoch as the main loop
undefined identifier `instrNowUs`
immutable
(local variable) immutable(ulong) wi
wi
=
ulong core.atomic.atomicLoad!(MemoryOrder.raw, ulong)(ref return scope shared(const(ulong)) 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
!(
(enum) core.atomic.MemoryOrder

Specifies the memory ordering semantics of an atomic operation.

@see
MemoryOrder
.
(enum value) core.atomic.MemoryOrder.raw = 0

Not sequenced. Corresponds to LLVM AtomicOrdering.Monotonic and C++11/C11 memory_order_relaxed.

raw
)(*cast(shared ulong*)&
(__gshared global) ulong app.g_ringWrite
g_ringWrite
);
(__gshared global) long[4096] app.g_ring
g_ring
[cast(
(alias) object.size_t = ulong
size_t
)(
(local variable) immutable(ulong) wi
wi
%
(constant) int app.maxSamples = 4096
maxSamples
)] = stamp;
void core.atomic.atomicStore!(MemoryOrder.rel, ulong, ulong)(ref shared(ulong) val, ulong 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
!(
(enum) core.atomic.MemoryOrder

Specifies the memory ordering semantics of an atomic operation.

@see
MemoryOrder
.
(enum value) core.atomic.MemoryOrder.rel = 3

Sink-load + sink-store barrier. Corresponds to LLVM AtomicOrdering.Release and C++11/C11 memory_order_release.

rel
)(*cast(shared ulong*)&
(__gshared global) ulong app.g_ringWrite
g_ringWrite
,
(local variable) immutable(ulong) wi
wi
+ 1);
ulong
(local variable) ulong one
one
= 1;
write(g_eventfd, &one, one.
one.sizeof
sizeof
); // the doorbell: kicks poll()
undefined identifier `write`
}
void core.atomic.atomicStore!(MemoryOrder.rel, bool, bool)(ref shared(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
!(
(enum) core.atomic.MemoryOrder

Specifies the memory ordering semantics of an atomic operation.

@see
MemoryOrder
.
(enum value) core.atomic.MemoryOrder.rel = 3

Sink-load + sink-store barrier. Corresponds to LLVM AtomicOrdering.Release and C++11/C11 memory_order_release.

rel
)(*cast(shared bool*)&
(__gshared global) bool app.g_producerDone
g_producerDone
, true);
ulong
(local variable) ulong one
one
= 1;
write(g_eventfd, &one, one.
one.sizeof
sizeof
); // final kick so the loop notices done
undefined identifier `write`
return null; } // ------------------------------------------------- external-fd drain hooks /// eventfd readable: one read returns (and zeroes) the whole counter — the /// number of posts since the last read. Latency is measured per post against /// the timestamp it carried through the ring. void
void app.drainEventfd() nothrow @nogc

eventfd readable: one read returns (and zeroes) the whole counter — the number of posts since the last read. Latency is measured per post against the timestamp it carried through the ring.

drainEventfd
() nothrow @nogc
{ ulong
(local variable) ulong count
count
;
if (read(g_eventfd, &count, count.
count.sizeof
sizeof
) !=
(local variable) ulong count
count
.sizeof)
undefined identifier `read`
return; immutable
(local variable) immutable(_error_) now
now
= instrNowUs();
undefined identifier `instrNowUs`
immutable
(local variable) immutable(ulong) wi
wi
=
ulong core.atomic.atomicLoad!(MemoryOrder.acq, ulong)(ref return scope shared(const(ulong)) 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
!(
(enum) core.atomic.MemoryOrder

Specifies the memory ordering semantics of an atomic operation.

@see
MemoryOrder
.
(enum value) core.atomic.MemoryOrder.acq = 2

Hoist-load + hoist-store barrier. Corresponds to LLVM AtomicOrdering.Acquire and C++11/C11 memory_order_acquire.

acq
)(*cast(shared ulong*)&
(__gshared global) ulong app.g_ringWrite
g_ringWrite
);
int
(local variable) int popped
popped
;
while (
(__gshared global) ulong app.g_ringRead
g_ringRead
<
(local variable) immutable(ulong) wi
wi
)
{ immutable
(local variable) immutable(long) stamp
stamp
=
(__gshared global) long[4096] app.g_ring
g_ring
[cast(
(alias) object.size_t = ulong
size_t
)(
(__gshared global) ulong app.g_ringRead
g_ringRead
%
(constant) int app.maxSamples = 4096
maxSamples
)];
immutable
(local variable) immutable(_error_) lat
lat
= now -
(local variable) immutable(long) stamp
stamp
;
if (
(__gshared global) int app.g_latCount
g_latCount
<
(constant) int app.maxSamples = 4096
maxSamples
)
(__gshared global) long[4096] app.g_latencies
g_latencies
[
(__gshared global) int app.g_latCount
g_latCount
++] = lat;
instrEvent("wakeup", "latency_us=%lld mech=eventfd seq=%llu", lat, g_ringRead);
undefined identifier `instrEvent`, did you mean import `instrument`?
(__gshared global) ulong app.g_ringRead
g_ringRead
++;
(local variable) int popped
popped
++;
} if (
(local variable) int popped
popped
> 1)
{
(__gshared global) int app.g_coalesced
g_coalesced
+=
(local variable) int popped
popped
- 1;
instrEvent("wakeup_coalesced", "posts=%d eventfd_count=%llu", popped, count);
undefined identifier `instrEvent`, did you mean import `instrument`?
} } /// timerfd readable: the 8-byte read is the number of expirations since the /// last read (>1 means the loop was late by a full period). void
void app.drainTimerfd() nothrow @nogc

timerfd readable: the 8-byte read is the number of expirations since the last read (>1 means the loop was late by a full period).

drainTimerfd
() nothrow @nogc
{ ulong
(local variable) ulong expirations
expirations
;
if (read(g_timerfd, &expirations, expirations.
expirations.sizeof
sizeof
) !=
(local variable) ulong expirations
expirations
.sizeof)
undefined identifier `read`
return;
(__gshared global) long app.g_fdTicks
g_fdTicks
+=
(local variable) ulong expirations
expirations
;
instrEvent("fd_tick", "t=%lld mech=timerfd expirations=%llu n=%lld",
undefined identifier `instrEvent`, did you mean import `instrument`?
instrNowUs(), expirations, g_fdTicks); } // ------------------------------------------- the canonical multiplexing loop /// THE deliverable: the wl_display fd multiplexed with arbitrary fds in one /// poll(2), via libwayland's thread-safe read pattern. /// /// wl_display_prepare_read's contract (wayland-client.h): it registers this /// thread's intent to read the socket and FAILS (-1) while the default queue /// still holds undispatched events — so step 1 loops dispatch_pending until /// the queue is empty and the intent is registered. After it succeeds, this /// thread must call exactly one of read_events (socket readable) or /// cancel_read (woken for any other reason) — leaking the intent deadlocks /// other readers. Requests are flushed *before* blocking so the compositor is /// never left waiting on a half-sent message. bool
bool app.pumpOnce(int timeoutMs) nothrow @nogc

THE deliverable: the wl_display fd multiplexed with arbitrary fds in one poll(2), via libwayland's thread-safe read pattern.

wl_display_prepare_read's contract (wayland-client.h): it registers this thread's intent to read the socket and FAILS (-1) while the default queue still holds undispatched events — so step 1 loops dispatch_pending until the queue is empty and the intent is registered. After it succeeds, this thread must call exactly one of read_events (socket readable) or cancel_read (woken for any other reason) — leaking the intent deadlocks other readers. Requests are flushed before blocking so the compositor is never left waiting on a half-sent message.

pumpOnce
(int
(parameter) int timeoutMs
timeoutMs
) nothrow @nogc
{ // 1. Dispatch what is already queued; acquire the read intent. while (wl_display_prepare_read(g_display) != 0)
undefined identifier `wl_display_prepare_read`
if (wl_display_dispatch_pending(g_display) < 0)
undefined identifier `wl_display_dispatch_pending`
return false; // 2. Flush outgoing requests before sleeping. wl_display_flush(g_display);
undefined identifier `wl_display_flush`
// 3. ONE poll over all event sources — the whole point of the pattern. pollfd[3]
(local variable) _error_ pfds
pfds
;
undefined identifier `pollfd`
pfds[0].
(__error)[0].fd
fd
= wl_display_get_fd(g_display);
pfds[0].events = POLLIN; pfds[1].
(__error)[1].fd
fd
= g_eventfd;
pfds[1].events = POLLIN; pfds[2].
(__error)[2].fd
fd
= g_timerfd;
pfds[2].events = POLLIN; immutable
(local variable) immutable(_error_) r
r
= poll(pfds.
pfds.ptr
ptr
, 3, timeoutMs);
undefined identifier `poll`
if (r < 0) { wl_display_cancel_read(g_display);
undefined identifier `wl_display_cancel_read`
return false; } // 4. Exactly one of read_events / cancel_read, per the contract. if (pfds[0].revents & POLLIN)
undefined identifier `POLLIN`
{ if (wl_display_read_events(g_display) < 0)
undefined identifier `wl_display_read_events`
return false; // read_events consumed the intent if (wl_display_dispatch_pending(g_display) < 0)
undefined identifier `wl_display_dispatch_pending`
return false; } else wl_display_cancel_read(g_display);
undefined identifier `wl_display_cancel_read`
// 5. The external fds, on the same wakeup. if (pfds[1].revents & POLLIN)
undefined identifier `POLLIN`
void app.drainEventfd() nothrow @nogc

eventfd readable: one read returns (and zeroes) the whole counter — the number of posts since the last read. Latency is measured per post against the timestamp it carried through the ring.

drainEventfd
();
if (pfds[2].revents & POLLIN)
undefined identifier `POLLIN`
void app.drainTimerfd() nothrow @nogc

timerfd readable: the 8-byte read is the number of expirations since the last read (>1 means the loop was late by a full period).

drainTimerfd
();
return true; } // ---------------------------------------------------------- shm buffer pool /// (Re)allocate `b` so it matches `w`×`h` (scaffold pattern). bool
app.ensureBuffer

(Re)allocate b so it matches w×h (scaffold pattern).

ensureBuffer
(ref
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer. busy is owned by the compositor between wl_surface.commit and the wl_buffer.release event.

Buffer
(parameter) Buffer b
b
, int
(parameter) int w
w
, int
(parameter) int h
h
) nothrow @nogc
{ if (b.
b.handle
handle
!is null && (b.
b.width
width
!= w || b.
b.height
height
!= h))
{ wsi_buffer_destroy(b.
b.handle
handle
);
munmap(b.
b.pixels
pixels
, b.
b.byteSize
byteSize
);
b = Buffer.init; } if (b.
b.handle
handle
!is null)
return true; immutable
_error_ stride
stride
= w * 4;
immutable
_error_ size
size
= cast(
(unresolved type) size_t
size_t
)(stride) * h;
immutable
_error_ fd
fd
= memfd_create("wsi-f05", MFD_CLOEXEC);
if (fd < 0) return false; if (ftruncate(fd, cast(long) size) != 0) { close(fd); return false; } void*
_error_ mem
mem
= mmap(null, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mem is cast(void*)-1) { close(fd); return false; } wl_shm_pool*
_error_ pool
pool
= wsi_shm_create_pool(g_shm, fd, cast(int) size);
b.
b.handle
handle
= wsi_shm_pool_create_buffer(pool, 0, w, h, stride, WL_SHM_FORMAT_ARGB8888);
wsi_shm_pool_destroy(pool); close(fd); wsi_buffer_add_listener(b.
b.handle
handle
, &g_bufferListener, &b);
b.
b.pixels
pixels
= cast(uint*) mem;
b.
b.byteSize
byteSize
= size;
b.
b.width
width
= w;
b.
b.height
height
= h;
b.
b.busy
busy
= false;
instrEvent("buffer_alloc", "size=%dx%d bytes=%zu", w, h, size); return true; } /// Trivially cheap redraw (two alternating solid colors) — the window's only /// job here is to keep real frame callbacks interleaving with the fd events. void
app.paint

Trivially cheap redraw (two alternating solid colors) — the window's only job here is to keep real frame callbacks interleaving with the fd events.

paint
(ref
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer. busy is owned by the compositor between wl_surface.commit and the wl_buffer.release event.

Buffer
(parameter) Buffer b
b
, int frame) nothrow @nogc
{ immutable uint
_error_ color
color
= (frame & 1) ? 0xff20_6080 : 0xff80_4020;
immutable
_error_ n
n
= cast(
(unresolved type) size_t
size_t
) b.
b.width
width
* b.
b.height
height
;
foreach (
(parameter) i
i
; 0 .. n)
b.
b.pixels
pixels
[i] = color;
} /// Paint into a free buffer and commit it, requesting the next frame callback. void
void app.render() nothrow @nogc

Paint into a free buffer and commit it, requesting the next frame callback.

render
() nothrow @nogc
{
(struct) app.Buffer

One wl_shm-backed ARGB8888 buffer. busy is owned by the compositor between wl_surface.commit and the wl_buffer.release event.

Buffer
*
(local variable) _error_ buf
buf
= null;
foreach (ref
(parameter) b
b
; g_buffers)
if (!b.
b.busy
busy
)
{ buf = &b; break; } if (buf is null) { instrEvent("frame_skipped", "reason=all_buffers_busy");
undefined identifier `instrEvent`, did you mean import `instrument`?
return; } if (!ensureBuffer(*buf, g_width, g_height)) {
(__gshared global) bool app.g_running
g_running
= false;
return; } paint(*buf, g_frames); assert(buf.
(field) _error_ buf.width
width
==
(__gshared global) int app.g_width
g_width
&& buf.
(field) _error_ buf.height
height
==
(__gshared global) int app.g_height
g_height
,
"committed buffer size does not match the acked configure size"); wsi_surface_attach(g_surface, buf.
buf.handle
handle
, 0, 0);
undefined identifier `wsi_surface_attach`
wsi_surface_damage_buffer(g_surface, 0, 0, buf.
buf.width
width
, buf.
buf.height
height
);
undefined identifier `wsi_surface_damage_buffer`
if (g_frameCb is null) // keep exactly one frame callback in flight { g_frameCb = wsi_surface_frame(g_surface); wsi_callback_add_listener(g_frameCb, &g_frameListener, null);
undefined identifier `wsi_callback_add_listener`
} wsi_surface_commit(g_surface);
undefined identifier `wsi_surface_commit`
buf.
buf.busy
busy
= true;
(__gshared global) int app.g_commits
g_commits
++;
if (
(__gshared global) int app.g_commits
g_commits
== 1)
instrEvent("first_commit", "size=%dx%d", buf.
buf.width
width
, buf.
buf.height
height
);
undefined identifier `instrEvent`, did you mean import `instrument`?
} // ---------------------------------------------------------------- listeners // All callbacks are `extern (C) nothrow @nogc` to match the listener // function-pointer types the ImportC `#pragma attribute` stamped in c.c. extern (C) void
app.onGlobal
onGlobal
(void* data, wl_registry* reg, uint name,
undefined identifier `wl_registry`, did you mean variable `g_registry`?
const(char)* iface, uint ver) nothrow @nogc { static uint
uint capped(uint advertised, uint want) nothrow @nogc
capped
(uint
(parameter) uint advertised
advertised
, uint
(parameter) uint want
want
) nothrow @nogc
{ return advertised < want ? advertised : want; } if (strcmp(iface, wl_compositor_interface.name) == 0) g_compositor = cast(wl_compositor*) wsi_registry_bind(reg, name, &wl_compositor_interface, capped(ver, 4)); else if (strcmp(iface, wl_shm_interface.name) == 0) g_shm = cast(wl_shm*) wsi_registry_bind(reg, name, &wl_shm_interface, 1); else if (strcmp(iface, xdg_wm_base_interface.name) == 0) g_wmBase = cast(xdg_wm_base*) wsi_registry_bind(reg, name, &xdg_wm_base_interface, 1); else if (strcmp(iface, wl_seat_interface.name) == 0) g_seat = cast(wl_seat*) wsi_registry_bind(reg, name, &wl_seat_interface, capped(ver, 2)); } extern (C) void
app.onGlobalRemove
onGlobalRemove
(void* data, wl_registry* reg, uint name) nothrow @nogc
undefined identifier `wl_registry`, did you mean variable `g_registry`?
{ } extern (C) void
app.onWmBasePing
onWmBasePing
(void* data, xdg_wm_base*
(parameter) xdg_wm_base* b
b
, uint serial) nothrow @nogc
undefined identifier `xdg_wm_base`
{ wsi_wm_base_pong(b, serial); } extern (C) void
app.onSeatCapabilities
onSeatCapabilities
(void* data, wl_seat* s, uint caps) nothrow @nogc
undefined identifier `wl_seat`, did you mean variable `g_seat`?
{ } extern (C) void
app.onSeatName
onSeatName
(void* data, wl_seat* s, const(char)* name) nothrow @nogc
undefined identifier `wl_seat`, did you mean variable `g_seat`?
{ } extern (C) void
app.onToplevelConfigure
onToplevelConfigure
(void* data, xdg_toplevel* t, int
(parameter) int w
w
, int
(parameter) int h
h
,
undefined identifier `xdg_toplevel`, did you mean variable `g_toplevel`?
wl_array* states) nothrow @nogc
undefined identifier `wl_array`
{ g_pendingWidth = w; g_pendingHeight = h; } extern (C) void
app.onXdgSurfaceConfigure
onXdgSurfaceConfigure
(void* data, xdg_surface* s, uint serial) nothrow @nogc
undefined identifier `xdg_surface`, did you mean variable `g_surface`?
{ immutable
_error_ w
w
= g_pendingWidth > 0 ? g_pendingWidth : defaultWidth;
immutable
_error_ h
h
= g_pendingHeight > 0 ? g_pendingHeight : defaultHeight;
instrEvent("configure", "serial=%u size=%dx%d", serial, w, h); wsi_xdg_surface_ack_configure(s, serial); immutable
_error_ resized
resized
= w != g_width || h != g_height;
g_width = w; g_height = h; if (!g_configured) { g_configured = true; instrFirstConfigure(); render(); } else if (resized) { instrResize(w, h, 1); render(); } } extern (C) void
app.onToplevelClose
onToplevelClose
(void* data, xdg_toplevel* t) nothrow @nogc
undefined identifier `xdg_toplevel`, did you mean variable `g_toplevel`?
{ instrCloseRequested(); g_running = false; } extern (C) void
app.onToplevelConfigureBounds
onToplevelConfigureBounds
(void* data, xdg_toplevel* t, int
(parameter) int w
w
, int
(parameter) int h
h
) nothrow @nogc
undefined identifier `xdg_toplevel`, did you mean variable `g_toplevel`?
{ } extern (C) void
app.onToplevelWmCapabilities
onToplevelWmCapabilities
(void* data, xdg_toplevel* t, wl_array* caps) nothrow @nogc
undefined identifier `xdg_toplevel`, did you mean variable `g_toplevel`?
undefined identifier `wl_array`
{ } extern (C) void
app.onBufferRelease
onBufferRelease
(void* data, wl_buffer*
(parameter) wl_buffer* b
b
) nothrow @nogc
undefined identifier `wl_buffer`
{ auto
_error_ buf
buf
= cast(
(unresolved type) Buffer
Buffer
*) data;
buf.
buf.busy
busy
= false;
if (g_running && g_configured && g_frameCb is null) render(); } extern (C) void
app.onFrameDone
onFrameDone
(void* data, wl_callback* cb, uint timeMs) nothrow @nogc
undefined identifier `wl_callback`
{ wsi_callback_destroy(cb); g_frameCb = null; g_frames++; // Log every 30th redraw so the fd_tick interleaving stays visible without // 60 Hz noise drowning the trace. if (g_frames % 30 == 0) instrFrameCallback(timeMs); if (!g_presented) { g_presented = true; instrFirstPixelPresented(); } render(); } __gshared wl_registry_listener
_error_ app.g_registryListener
g_registryListener
= {&onGlobal, &onGlobalRemove};
undefined identifier `wl_registry_listener`
__gshared xdg_wm_base_listener
_error_ app.g_wmBaseListener
g_wmBaseListener
= {&onWmBasePing};
undefined identifier `xdg_wm_base_listener`
__gshared wl_seat_listener
_error_ app.g_seatListener
g_seatListener
= {&onSeatCapabilities, &onSeatName};
undefined identifier `wl_seat_listener`
__gshared xdg_surface_listener
_error_ app.g_xdgSurfaceListener
g_xdgSurfaceListener
= {&onXdgSurfaceConfigure};
undefined identifier `xdg_surface_listener`
__gshared xdg_toplevel_listener
_error_ app.g_toplevelListener
g_toplevelListener
= {
undefined identifier `xdg_toplevel_listener`
&onToplevelConfigure, &onToplevelClose, &onToplevelConfigureBounds, &onToplevelWmCapabilities }; __gshared wl_buffer_listener
_error_ app.g_bufferListener
g_bufferListener
= {&onBufferRelease};
undefined identifier `wl_buffer_listener`
__gshared wl_callback_listener
_error_ app.g_frameListener
g_frameListener
= {&onFrameDone};
undefined identifier `wl_callback_listener`
// ------------------------------------------------------------------ stats 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
) nothrow @nogc
{ immutable
(local variable) immutable(long) x
x
= *cast(const(long)*)
(parameter) const(void)* a
a
;
immutable
(local variable) immutable(long) y
y
= *cast(const(long)*)
(parameter) const(void)* b
b
;
return (
(local variable) immutable(long) x
x
>
(local variable) immutable(long) y
y
) - (
(local variable) immutable(long) x
x
<
(local variable) immutable(long) y
y
);
} /// min/median/p99/max over the recorded wakeup latencies, to stdout. void
void app.printStats() nothrow @nogc

min/median/p99/max over the recorded wakeup latencies, to stdout.

printStats
() nothrow @nogc
{ if (
(__gshared global) int app.g_latCount
g_latCount
== 0)
{
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("stats: no wakeups recorded\n");
return; }
void core.stdc.stdlib.qsort(void* base, ulong nmemb, ulong size, extern (C) int function(const(void*), const(void*)) compar) nothrow @nogc
qsort
(
(__gshared global) long[4096] app.g_latencies
g_latencies
.
(constant) long* long[4096].ptr = &g_latencies
ptr
,
(__gshared global) int app.g_latCount
g_latCount
, long.
(constant) ulong long.sizeof = 8LU
sizeof
, &
int app.cmpLong(const(void)* a, const(void)* b) nothrow @nogc
cmpLong
);
immutable
(alias) object.size_t = ulong
size_t
(local variable) immutable(ulong) p99Idx
p99Idx
= cast(
(alias) object.size_t = ulong
size_t
)(
(__gshared global) int app.g_latCount
g_latCount
- 1) * 99 / 100;
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("stats mech=eventfd n=%d min_us=%lld median_us=%lld p99_us=%lld max_us=%lld coalesced=%d\n",
(__gshared global) int app.g_latCount
g_latCount
,
(__gshared global) long[4096] app.g_latencies
g_latencies
[0],
(__gshared global) long[4096] app.g_latencies
g_latencies
[
(__gshared global) int app.g_latCount
g_latCount
/ 2],
(__gshared global) long[4096] app.g_latencies
g_latencies
[
(local variable) immutable(ulong) p99Idx
p99Idx
],
(__gshared global) long[4096] app.g_latencies
g_latencies
[
(__gshared global) int app.g_latCount
g_latCount
- 1],
(__gshared global) int app.g_coalesced
g_coalesced
);
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("stats mech=timerfd ticks=%lld expected_hz=7\n",
(__gshared global) long app.g_fdTicks
g_fdTicks
);
} // ----------------------------------------------------------------- teardown void
void app.teardown() nothrow @nogc
teardown
() nothrow @nogc
{ foreach (ref
(parameter) b
b
; g_buffers)
if (b.
b.handle
handle
!is null)
{ wsi_buffer_destroy(b.
b.handle
handle
);
munmap(b.
b.pixels
pixels
, b.
b.byteSize
byteSize
);
b = Buffer.init; } if (g_frameCb !is null) wsi_callback_destroy(g_frameCb);
undefined identifier `wsi_callback_destroy`
if (g_toplevel !is null) wsi_toplevel_destroy(g_toplevel);
undefined identifier `wsi_toplevel_destroy`
if (g_xdgSurface !is null) wsi_xdg_surface_destroy(g_xdgSurface);
undefined identifier `wsi_xdg_surface_destroy`
if (g_surface !is null) wsi_surface_destroy(g_surface);
undefined identifier `wsi_surface_destroy`
if (g_wmBase !is null) wsi_wm_base_destroy(g_wmBase);
undefined identifier `wsi_wm_base_destroy`
if (g_seat !is null) wl_proxy_destroy(cast(wl_proxy*) g_seat);
undefined identifier `wl_proxy_destroy`
if (g_shm !is null) wl_proxy_destroy(cast(wl_proxy*) g_shm);
undefined identifier `wl_proxy_destroy`
if (g_compositor !is null) wl_proxy_destroy(cast(wl_proxy*) g_compositor);
undefined identifier `wl_proxy_destroy`
if (g_registry !is null) wl_proxy_destroy(cast(wl_proxy*) g_registry);
undefined identifier `wl_proxy_destroy`
wl_display_disconnect(g_display);
undefined identifier `wl_display_disconnect`
if (
(__gshared global) int app.g_eventfd
g_eventfd
>= 0)
close(g_eventfd);
undefined identifier `close`
if (
(__gshared global) int app.g_timerfd
g_timerfd
>= 0)
close(g_timerfd);
undefined identifier `close`
} // --------------------------------------------------------------------- main int
int D main()
main
()
{ instrInit("f05-wayland");
undefined identifier `instrInit`
cast(void)
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_AUTO_EXIT"); // accepted for runner symmetry; the run is bounded
if (const
(local variable) const(char*) n
n
=
char* core.stdc.stdlib.getenv(scope const(char*) name) nothrow @nogc
getenv
("WSI_F05_WAKEUPS")) // shorter smoke runs
if (
int core.stdc.stdlib.atoi(scope const(char*) nptr) nothrow @nogc
atoi
(
(local variable) const(char*) n
n
) > 0 &&
int core.stdc.stdlib.atoi(scope const(char*) nptr) nothrow @nogc
atoi
(
(local variable) const(char*) n
n
) <=
(constant) int app.maxSamples = 4096
maxSamples
)
(__gshared global) int app.g_wakeupsWanted
g_wakeupsWanted
=
int core.stdc.stdlib.atoi(scope const(char*) nptr) nothrow @nogc
atoi
(
(local variable) const(char*) n
n
);
// 1. Connect (SKIP cleanly on hosts without a compositor). g_display = wl_display_connect(null); if (g_display is null) {
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: no Wayland compositor (wl_display_connect returned null)\n");
return 0; } // 2. Registry: bind the globals a window needs. g_registry = wsi_display_get_registry(g_display); wsi_registry_add_listener(g_registry, &g_registryListener, null);
undefined identifier `wsi_registry_add_listener`
wl_display_roundtrip(g_display);
undefined identifier `wl_display_roundtrip`
if (g_compositor is null || g_shm is null || g_wmBase is null) {
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: compositor lacks a required global (wl_compositor/wl_shm/xdg_wm_base)\n");
void app.teardown() nothrow @nogc
teardown
();
return 0; } wsi_wm_base_add_listener(g_wmBase, &g_wmBaseListener, null);
undefined identifier `wsi_wm_base_add_listener`
if (g_seat !is null) wsi_seat_add_listener(g_seat, &g_seatListener, null);
undefined identifier `wsi_seat_add_listener`
// 3. Window object tree (scaffold handshake). g_surface = wsi_compositor_create_surface(g_compositor); g_xdgSurface = wsi_wm_base_get_xdg_surface(g_wmBase, g_surface); wsi_xdg_surface_add_listener(g_xdgSurface, &g_xdgSurfaceListener, null);
undefined identifier `wsi_xdg_surface_add_listener`
g_toplevel = wsi_xdg_surface_get_toplevel(g_xdgSurface); wsi_toplevel_add_listener(g_toplevel, &g_toplevelListener, null);
undefined identifier `wsi_toplevel_add_listener`
wsi_toplevel_set_title(g_toplevel, "wsi-f05-loop-wakeup");
undefined identifier `wsi_toplevel_set_title`
wsi_toplevel_set_app_id(g_toplevel, "wsi-f05-loop-wakeup");
undefined identifier `wsi_toplevel_set_app_id`
instrWindowCreated();
undefined identifier `instrWindowCreated`
wsi_surface_commit(g_surface); // mandatory initial no-buffer commit
undefined identifier `wsi_surface_commit`
// 4. The two external fds. EFD_NONBLOCK/TFD_NONBLOCK: a spurious-looking // drain must never block the loop.
(__gshared global) int app.g_eventfd
g_eventfd
= eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
undefined identifier `eventfd`, did you mean variable `g_eventfd`?
(__gshared global) int app.g_timerfd
g_timerfd
= timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
undefined identifier `timerfd_create`
if (
(__gshared global) int app.g_eventfd
g_eventfd
< 0 ||
(__gshared global) int app.g_timerfd
g_timerfd
< 0)
{
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: eventfd/timerfd unavailable\n");
void app.teardown() nothrow @nogc
teardown
();
return 0; } itimerspec
(local variable) _error_ its
its
;
undefined identifier `itimerspec`
its.it_value.tv_nsec = timerTickNs; its.it_interval.tv_nsec = timerTickNs; timerfd_settime(g_timerfd, 0, &its, null);
undefined identifier `timerfd_settime`
instrEvent("fd_setup", "eventfd=%d timerfd=%d timer_hz=7", g_eventfd, g_timerfd);
undefined identifier `instrEvent`, did you mean import `instrument`?
// 5. The producer thread — raw pthread_create (druntime's POSIX decls): // no GC interaction to rule out, the demo is allocation-free after // startup, and the thread only touches atomics + write(2). pthread_t
(local variable) ulong producer
producer
;
if (
int core.sys.posix.pthread.pthread_create(ulong*, scope const(core.sys.posix.sys.types.pthread_attr_t*), extern (C) void* function(void*), void*) nothrow @nogc
pthread_create
(&
(local variable) ulong producer
producer
, null, &
void* app.producerMain(void* __param_0) nothrow @nogc

Second thread: every 100 ms, stamp "now", publish it in the ring, write the eventfd. The write(2) is the only wakeup mechanism Wayland offers a thread that is not the dispatcher — there is no protocol-level user event to post. (libwayland itself is thread-safe, but events it queues are only seen when the dispatching thread next wakes — which is this eventfd.)

producerMain
, null) != 0)
{
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("SKIP: pthread_create failed\n");
void app.teardown() nothrow @nogc
teardown
();
return 0; } instrEvent("producer_started", "hz=%d posts=%d", wakeupHz, g_wakeupsWanted);
undefined identifier `instrEvent`, did you mean import `instrument`?
// 6. The multiplexing loop (see pumpOnce). Terminates when every posted // wakeup has been consumed; hard wall-clock cap as a backstop. immutable long
(local variable) immutable(long) capUs
capUs
= (cast(long)
(__gshared global) int app.g_wakeupsWanted
g_wakeupsWanted
* 1_000_000) /
(constant) int app.wakeupHz = 10
wakeupHz
+
(constant) long app.hardCapSlackUs = 10000000L
hardCapSlackUs
;
while (
(__gshared global) bool app.g_running
g_running
)
{ if (!
bool app.pumpOnce(int timeoutMs) nothrow @nogc

THE deliverable: the wl_display fd multiplexed with arbitrary fds in one poll(2), via libwayland's thread-safe read pattern.

wl_display_prepare_read's contract (wayland-client.h): it registers this thread's intent to read the socket and FAILS (-1) while the default queue still holds undispatched events — so step 1 loops dispatch_pending until the queue is empty and the intent is registered. After it succeeds, this thread must call exactly one of read_events (socket readable) or cancel_read (woken for any other reason) — leaking the intent deadlocks other readers. Requests are flushed before blocking so the compositor is never left waiting on a half-sent message.

pumpOnce
(
(constant) int app.pollTimeoutMs = 250
pollTimeoutMs
))
break; if (
bool core.atomic.atomicLoad!(MemoryOrder.acq, bool)(ref return scope shared(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
!(
(enum) core.atomic.MemoryOrder

Specifies the memory ordering semantics of an atomic operation.

@see
MemoryOrder
.
(enum value) core.atomic.MemoryOrder.acq = 2

Hoist-load + hoist-store barrier. Corresponds to LLVM AtomicOrdering.Acquire and C++11/C11 memory_order_acquire.

acq
)(*cast(shared bool*)&
(__gshared global) bool app.g_producerDone
g_producerDone
)
&&
(__gshared global) ulong app.g_ringRead
g_ringRead
>=
ulong core.atomic.atomicLoad!(MemoryOrder.acq, ulong)(ref return scope shared(const(ulong)) 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
!(
(enum) core.atomic.MemoryOrder

Specifies the memory ordering semantics of an atomic operation.

@see
MemoryOrder
.
(enum value) core.atomic.MemoryOrder.acq = 2

Hoist-load + hoist-store barrier. Corresponds to LLVM AtomicOrdering.Acquire and C++11/C11 memory_order_acquire.

acq
)(*cast(shared ulong*)&
(__gshared global) ulong app.g_ringWrite
g_ringWrite
))
(__gshared global) bool app.g_running
g_running
= false;
if (instrNowUs() >
(local variable) immutable(long) capUs
capUs
)
undefined identifier `instrNowUs`
{ instrEvent("hard_cap_hit");
undefined identifier `instrEvent`, did you mean import `instrument`?
(__gshared global) bool app.g_running
g_running
= false;
} }
int core.sys.posix.pthread.pthread_join(ulong, void**) nothrow @nogc
pthread_join
(
(local variable) ulong producer
producer
, null);
// 7. Teardown + the numbers.
void app.teardown() nothrow @nogc
teardown
();
void app.printStats() nothrow @nogc

min/median/p99/max over the recorded wakeup latencies, to stdout.

printStats
();
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
("ok: %d wakeups consumed, %lld fd_ticks, %d frame callbacks, %d commits\n",
(__gshared global) int app.g_latCount
g_latCount
,
(__gshared global) long app.g_fdTicks
g_fdTicks
,
(__gshared global) int app.g_frames
g_frames
,
(__gshared global) int app.g_commits
g_commits
);
return
(__gshared global) int app.g_latCount
g_latCount
==
(__gshared global) int app.g_wakeupsWanted
g_wakeupsWanted
? 0 : 1;
}