app.dhover×496 error×80all
// F17 X11 demo — threading probes: deliberately violate (and then obey)
// Xlib's threading rules and record exactly what breaks and how
// (../../../features/f17-threading.md; findings in ../../f17-threading.md).
//
// Probes (--probe=N; no argument = fork+run every probe TWICE, the CI default,
// so race-dependent outcomes show their spread):
//   1  window created on a worker thread WITHOUT XInitThreads while the main
//      thread pumps events and XSyncs on the same Display — the classic
//      "unexpected async reply" corruption / XIO / crash
//   2  the same choreography WITH XInitThreads — legal; prove it
//   3  two threads sharing one Display, BOTH blocking in XNextEvent (with
//      XInitThreads): how do queued events distribute? does one starve?
//   4  render thread: XShmPutImage + XFlush from a worker while the main
//      thread pumps (with XInitThreads); completion events land on the pump
//   5  one Display per thread, NO XInitThreads — the always-safe model
//   6  XInitThreads called LATE (after XOpenDisplay), then the probe-1
//      choreography — does the late call rescue the existing Display?
//
// Every probe ends in a verdict line
//     probe n=<N> result=ok|error|crash|deadlock|silent detail=...
// that survives ANY outcome: XSetErrorHandler counts protocol errors,
// XSetIOErrorHandler + SIGSEGV/SIGABRT/SIGBUS handlers turn crashes into a
// flushed verdict + _exit(0), and a SIGALRM watchdog turns hangs into
// result=deadlock. Crash probes still exit 0 — crashing is their job.
//
// Headless-safe: no X server -> prints `SKIP:` and exits 0.
module 
(module) app
app
;
import
(module) c
c
; // ImportC: Xlib + Xutil + Xatom + XShm + sys/ipc + sys/shm + poll
C preprocess command `cpp` failed for file `/home/runner/work/sparkles/sparkles/docs/research/window-system-integration/os-apis/x11/examples/f17-threading/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.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.

@paramval The target variable.@parammod The modifier to apply.@returnsThe result of the operation.
atomicOp
,
(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
,
(alias) app.snprintf = int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
;
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.memset = void* core.stdc.string.memset(return scope void* s, int c, ulong n) pure nothrow @nogc
memset
,
(alias) app.strlen = ulong core.stdc.string.strlen(scope const(char*) s) pure nothrow @nogc
strlen
;
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.sys
sys
.
(package) core.sys.posix
posix
.
(module) core.sys.posix.signal

D header file for POSIX.

Source

core/sys/posix/signal.d

@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
signal
:
(alias constant) app.SA_RESTART = int core.sys.posix.signal.SA_RESTART = 268435456
SA_RESTART
,
(alias) app.sigaction = int core.sys.posix.signal.sigaction(int, scope const(core.sys.posix.signal.sigaction_t*), core.sys.posix.signal.sigaction_t*) nothrow @nogc
sigaction
,
(struct) core.sys.posix.signal.sigaction_t
sigaction_t
,
(alias) app.sigemptyset = int core.sys.posix.signal.sigemptyset(core.sys.posix.signal.sigset_t*) nothrow @nogc
sigemptyset
,
(alias constant) app.SIGABRT = int core.stdc.signal.SIGABRT = 6
SIGABRT
,
(alias constant) app.SIGALRM = int core.sys.posix.signal.SIGALRM = 14
SIGALRM
,
(alias constant) app.SIGBUS = int core.sys.posix.signal.SIGBUS = 7
SIGBUS
,
(alias constant) app.SIGSEGV = int core.stdc.signal.SIGSEGV = 11
SIGSEGV
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(package) core.sys.posix.sys
sys
.
(module) core.sys.posix.sys.wait

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
wait
:
(alias) app.waitpid = int core.sys.posix.sys.wait.waitpid(int, int*, int) nothrow @nogc
waitpid
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.posix
posix
.
(module) core.sys.posix.unistd

D header file for POSIX.

@copyrightCopyright Sean Kelly 2005 - 2009.@licenseBoost License 1.0.@authorsSean Kelly@standardsThe Open Group Base Specifications Issue 8, IEEE Std 1003.1, 2024 Edition
unistd
:
(alias) app._exit = noreturn core.sys.posix.unistd._exit(int) nothrow @nogc @trusted
_exit
,
(alias) app.alarm = uint core.sys.posix.unistd.alarm(uint) nothrow @nogc @trusted
alarm
,
(alias) app.fork = int core.sys.posix.unistd.fork() nothrow @nogc @trusted
fork
,
(alias) app.usleep = int core.sys.posix.unistd.usleep(uint) nothrow @nogc @trusted
usleep
,
(alias) app.write = long core.sys.posix.unistd.write(int, scope const(void*), ulong) nothrow @nogc
write
;
// -- macro constants ImportC cannot export ------------------------------------ enum : c_long {
(enum value) app.ExposureMask = 32768L
ExposureMask
= 1L << 15,
(enum value) app.StructureNotifyMask = 131072L
StructureNotifyMask
= 1L << 17,
} enum // XEvent.type discriminators {
(enum value) app.Expose = 12
Expose
= 12,
(enum value) app.MapNotify = 19
MapNotify
= 19,
(enum value) app.ClientMessage = 33
ClientMessage
= 33,
} enum
(constant) int app.ZPixmap = 2
ZPixmap
= 2;
enum
(constant) int app.False = 0
False
= 0;
enum
(constant) int app.True = 1
True
= 1;
enum
(constant) int app.IPC_PRIVATE = 0
IPC_PRIVATE
= 0;
enum
(constant) int app.IPC_CREAT = 512
IPC_CREAT
= 0x200;
enum
(constant) int app.IPC_RMID = 0
IPC_RMID
= 0;
// -- verdict plumbing: must survive crashes ------------------------------------ private __gshared int
(__gshared global) int app.g_probe
g_probe
;
private shared int
(shared global) shared(int) app.g_xlibErrors
g_xlibErrors
;
private __gshared char[128]
(__gshared global) char[128] app.g_lastXlibError
g_lastXlibError
= '\0';
private shared bool
(shared global) shared(bool) app.g_verdictDone
g_verdictDone
;
/// The one line the spec requires per run. Async-signal-safe on purpose /// (snprintf into a static buffer + write(2)) so the signal/XIO handlers can /// call it; the normal path uses it too so the format is identical. void
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
(scope const(char)*
(parameter) const(char)* result
result
, scope const(char)*
(parameter) const(char)* detail
detail
) @nogc nothrow
{ if (
bool core.atomic.atomicLoad!(MemoryOrder.seq, 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
(
(shared global) shared(bool) app.g_verdictDone
g_verdictDone
))
return;
void core.atomic.atomicStore!(MemoryOrder.seq, 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
(
(shared global) shared(bool) app.g_verdictDone
g_verdictDone
, true);
static __gshared char[256]
(__gshared global) char[256] app.verdict.buf
buf
;
const
(local variable) const(int) n
n
=
int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
(
(__gshared global) char[256] app.verdict.buf
buf
.
(constant) char* char[256].ptr = &buf
ptr
,
(__gshared global) char[256] app.verdict.buf
buf
.
(constant) ulong char[256].length = 256LU
length
, "%lld f17_x11 probe n=%d result=%s detail=%s\n",
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
(),
(__gshared global) int app.g_probe
g_probe
,
(parameter) const(char)* result
result
,
(parameter) const(char)* detail
detail
);
long core.sys.posix.unistd.write(int, scope const(void*), ulong) nothrow @nogc
write
(2,
(__gshared global) char[256] app.verdict.buf
buf
.
(constant) char* char[256].ptr = &buf
ptr
,
(local variable) const(int) n
n
);
} extern (C) int
app.xlibErrorHandler
xlibErrorHandler
(Display*
(parameter) Display* dpy
dpy
, XErrorEvent* e) @nogc nothrow
undefined identifier `Display`
undefined identifier `XErrorEvent`
{
(template instance) atomicOp!"+="
atomicOp
!"+="(g_xlibErrors, 1);
char[64]
_error_ text
text
;
XGetErrorText(dpy, e.error_code, text.
text.ptr
ptr
, text.
text.length
length
);
snprintf(g_lastXlibError.
g_lastXlibError.ptr
ptr
, g_lastXlibError.
g_lastXlibError.length
length
,
"code=%d(%s)_request=%d.%d_resource=0x%lx", e.error_code, text.
text.ptr
ptr
, e.request_code, e.minor_code, e.resourceid);
emitf("xlib_error", "%s", g_lastXlibError.
g_lastXlibError.ptr
ptr
);
return 0; // continue; the verdict decides } extern (C) int
app.xioErrorHandler
xioErrorHandler
(Display*) @nogc nothrow
undefined identifier `Display`
{ // Xlib is about to exit() — flush the verdict first. Must not return. verdict("crash", "xio_error_connection_lost"); _exit(0); return 0; } extern (C) void
void app.signalHandler(int sig) nothrow @nogc
signalHandler
(int
(parameter) int sig
sig
) @nogc nothrow
{ static __gshared char[64]
(__gshared global) char[64] app.signalHandler.d
d
;
int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
(
(__gshared global) char[64] app.signalHandler.d
d
.
(constant) char* char[64].ptr = &d
ptr
,
(__gshared global) char[64] app.signalHandler.d
d
.
(constant) ulong char[64].length = 64LU
length
, "fatal_signal=%d",
(parameter) int sig
sig
);
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
("crash",
(__gshared global) char[64] app.signalHandler.d
d
.
(constant) char* char[64].ptr = &d
ptr
);
noreturn core.sys.posix.unistd._exit(int) nothrow @nogc @trusted
_exit
(0);
} extern (C) void
void app.alarmHandler(int __param_0) nothrow @nogc
alarmHandler
(int) @nogc nothrow
{
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
("deadlock", "watchdog_timeout_8s");
noreturn core.sys.posix.unistd._exit(int) nothrow @nogc @trusted
_exit
(0);
} void
void app.installCrashHandlers() nothrow @nogc
installCrashHandlers
() @nogc nothrow
{ XSetErrorHandler(&xlibErrorHandler);
undefined identifier `XSetErrorHandler`
XSetIOErrorHandler(&xioErrorHandler);
undefined identifier `XSetIOErrorHandler`
(struct) core.sys.posix.signal.sigaction_t
sigaction_t
(local variable) core.sys.posix.signal.sigaction_t sa
sa
;
(local variable) core.sys.posix.signal.sigaction_t sa
sa
.
(field) extern (C) void function(int) core.sys.posix.signal.sigaction_t.sa_handler
sa_handler
= &
void app.signalHandler(int sig) nothrow @nogc
signalHandler
;
int core.sys.posix.signal.sigemptyset(core.sys.posix.signal.sigset_t*) nothrow @nogc
sigemptyset
(&
(local variable) core.sys.posix.signal.sigaction_t sa
sa
.
(field) core.sys.posix.signal.sigset_t core.sys.posix.signal.sigaction_t.sa_mask
sa_mask
);
(local variable) core.sys.posix.signal.sigaction_t sa
sa
.
(field) int core.sys.posix.signal.sigaction_t.sa_flags
sa_flags
= 0;
int core.sys.posix.signal.sigaction(int, scope const(core.sys.posix.signal.sigaction_t*), core.sys.posix.signal.sigaction_t*) nothrow @nogc
sigaction
(
(constant) int core.stdc.signal.SIGSEGV = 11
SIGSEGV
, &
(local variable) core.sys.posix.signal.sigaction_t sa
sa
, null);
int core.sys.posix.signal.sigaction(int, scope const(core.sys.posix.signal.sigaction_t*), core.sys.posix.signal.sigaction_t*) nothrow @nogc
sigaction
(
(constant) int core.sys.posix.signal.SIGBUS = 7
SIGBUS
, &
(local variable) core.sys.posix.signal.sigaction_t sa
sa
, null);
int core.sys.posix.signal.sigaction(int, scope const(core.sys.posix.signal.sigaction_t*), core.sys.posix.signal.sigaction_t*) nothrow @nogc
sigaction
(
(constant) int core.stdc.signal.SIGABRT = 6
SIGABRT
, &
(local variable) core.sys.posix.signal.sigaction_t sa
sa
, null);
(local variable) core.sys.posix.signal.sigaction_t sa
sa
.
(field) extern (C) void function(int) core.sys.posix.signal.sigaction_t.sa_handler
sa_handler
= &
void app.alarmHandler(int __param_0) nothrow @nogc
alarmHandler
;
int core.sys.posix.signal.sigaction(int, scope const(core.sys.posix.signal.sigaction_t*), core.sys.posix.signal.sigaction_t*) nothrow @nogc
sigaction
(
(constant) int core.sys.posix.signal.SIGALRM = 14
SIGALRM
, &
(local variable) core.sys.posix.signal.sigaction_t sa
sa
, null);
uint core.sys.posix.unistd.alarm(uint) nothrow @nogc @trusted
alarm
(8); // the deadlock watchdog
} // -- probes 1/2/6: window on a worker thread, pump + XSync storm on main ------- private __gshared Display*
_error_ app.g_dpy
g_dpy
;
undefined identifier `Display`
private shared bool
(shared global) shared(bool) app.g_workerDone
g_workerDone
;
/// Worker: create/map a window, then hammer reply-carrying requests /// (XInternAtom round-trips) for ~1.2 s. Without XInitThreads both threads /// read the one connection -> interleaved replies -> corruption. extern (C) void*
void* app.windowWorker(void* __param_0) nothrow @nogc

Worker

create/map a window, then hammer reply-carrying requests (XInternAtom round-trips) for ~1.2 s. Without XInitThreads both threads read the one connection -> interleaved replies -> corruption.

windowWorker
(void*) @nogc nothrow
{ auto
(local variable) _error_ dpy
dpy
= g_dpy;
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("thread=worker action=XCreateSimpleWindow");
Window
(local variable) _error_ win
win
= XCreateSimpleWindow(dpy, XRootWindow(dpy, XDefaultScreen(dpy)),
undefined identifier `Window`
undefined identifier `XCreateSimpleWindow`
0, 0, 200, 120, 1, 0, 0xffffff); XSelectInput(dpy, win, ExposureMask | StructureNotifyMask);
undefined identifier `XSelectInput`
XMapWindow(dpy, win);
undefined identifier `XMapWindow`
XFlush(dpy);
undefined identifier `XFlush`
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

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

emitf
("thread=worker", "action=window_created xid=0x%lx", win);
XEvent
(local variable) _error_ msg
msg
;
undefined identifier `XEvent`
msg.xclient.type = ClientMessage; msg.xclient.window = win; msg.xclient.message_type = XInternAtom(dpy, "WSI_F17_TICK", False); msg.xclient.format = 32; // Request storm: buffered requests (XStoreName marshals into the shared // Display output buffer) mixed with reply-carrying round-trips and event // traffic — while the main thread appends to the SAME buffer and reads // the SAME reply/event stream, unlocked. const
(local variable) const(long) deadline
deadline
=
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
() + 1_200_000;
int
(local variable) int i
i
= 0;
char[32]
(local variable) char[32] name
name
;
while (
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
() <
(local variable) const(long) deadline
deadline
)
{
int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
(
(local variable) char[32] name
name
.
(constant) char* char[32].ptr = &name
ptr
,
(local variable) char[32] name
name
.
(constant) ulong char[32].length = 32LU
length
, "WSI_F17_%d",
(local variable) int i
i
++);
XStoreName(dpy, win, name.
name.ptr
ptr
); // buffered (no reply)
undefined identifier `XStoreName`
if (
(local variable) int i
i
% 8 == 0)
XInternAtom(dpy, name.
name.ptr
ptr
, False); // round-trip
undefined identifier `XInternAtom`
if (
(local variable) int i
i
% 64 == 0)
{ msg.xclient.data.l[0] = 42; // event traffic for the main pump XSendEvent(dpy, win, False, 0, &msg);
undefined identifier `XSendEvent`
} }
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

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

emitf
("thread=worker", "action=done roundtrips=%d",
(local variable) int i
i
* 2);
void core.atomic.atomicStore!(MemoryOrder.seq, 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
(
(shared global) shared(bool) app.g_workerDone
g_workerDone
, true);
msg.xclient.data.l[0] = 99; // wake the main pump out of XNextEvent XSendEvent(dpy, win, False, 0, &msg);
undefined identifier `XSendEvent`
XFlush(dpy);
undefined identifier `XFlush`
return null; } /// XGetGeometry needs 9 out-params; tuck them away. void
app.XGetGeometry_

XGetGeometry needs 9 out-params; tuck them away.

XGetGeometry_
(Display*
(parameter) Display* dpy
dpy
, Window
(parameter) Window win
win
) @nogc nothrow
undefined identifier `Display`
undefined identifier `Window`
{ Window
_error_ root
root
;
int
_error_ x
x
,
_error_ y
y
;
uint
_error_ w
w
,
_error_ h
h
,
_error_ bw
bw
,
_error_ depth
depth
;
XGetGeometry(dpy, win, &root, &x, &y, &w, &h, &bw, &depth); } int
int app.probeWindowOnWorker(bool initFirst, bool initLate) nothrow @nogc
probeWindowOnWorker
(bool
(parameter) bool initFirst
initFirst
, bool
(parameter) bool initLate
initLate
) @nogc nothrow
{ if (
(parameter) bool initFirst
initFirst
)
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=XInitThreads ret=%d order=first", XInitThreads());
undefined identifier `XInitThreads`
g_dpy = XOpenDisplay(null); if (
(parameter) bool initLate
initLate
)
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=XInitThreads ret=%d order=AFTER_XOpenDisplay", XInitThreads());
undefined identifier `XInitThreads`
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 fd=%d xinitthreads=%s",
XConnectionNumber(g_dpy),
undefined identifier `XConnectionNumber`
(parameter) bool initFirst
initFirst
? "first".
(constant) immutable(char)* "first".ptr = "first"
ptr
:
(parameter) bool initLate
initLate
? "late".
(constant) immutable(char)* "late".ptr = "late"
ptr
: "no".
(constant) immutable(char)* "no".ptr = "no"
ptr
);
void core.atomic.atomicStore!(MemoryOrder.seq, 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
(
(shared global) shared(bool) app.g_workerDone
g_workerDone
, false);
pthread_t
(local variable) ulong t
t
;
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 t
t
, null, &
void* app.windowWorker(void* __param_0) nothrow @nogc

Worker

create/map a window, then hammer reply-carrying requests (XInternAtom round-trips) for ~1.2 s. Without XInitThreads both threads read the one connection -> interleaved replies -> corruption.

windowWorker
, null);
// Main pumps events while issuing its own (buffered) requests — i.e. a // normal GUI main loop — on the same unlocked Display the worker is // hammering. XNoOp appends to the output buffer; XPending flushes it and // reads events; both race the worker's marshalling and replies. int
(local variable) int eventsOnMain
eventsOnMain
= 0;
bool
(local variable) bool sawDoneWakeup
sawDoneWakeup
= false;
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("thread=main action=pump_start");
while (!
(local variable) bool sawDoneWakeup
sawDoneWakeup
&& !(
bool core.atomic.atomicLoad!(MemoryOrder.seq, 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
(
(shared global) shared(bool) app.g_workerDone
g_workerDone
) && XPending(g_dpy) == 0))
undefined identifier `XPending`
{ XNoOp(g_dpy); // buffered request from the main thread
undefined identifier `XNoOp`
while (XPending(g_dpy) > 0)
undefined identifier `XPending`
{ XEvent
(local variable) _error_ ev
ev
;
undefined identifier `XEvent`
XNextEvent(g_dpy, &ev);
undefined identifier `XNextEvent`
++
(local variable) int eventsOnMain
eventsOnMain
;
if (ev.type ==
(enum value) app.MapNotify = 19
MapNotify
)
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

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

emitf
("thread=main", "action=event type=MapNotify window=0x%lx events_on_main=%d",
ev.xmap.window,
(local variable) int eventsOnMain
eventsOnMain
);
if (ev.type ==
(enum value) app.ClientMessage = 33
ClientMessage
&& ev.xclient.data.l[0] == 99)
(local variable) bool sawDoneWakeup
sawDoneWakeup
= true; // the worker's done-wakeup
} }
int core.sys.posix.pthread.pthread_join(ulong, void**) nothrow @nogc
pthread_join
(
(local variable) ulong t
t
, null);
XSync(g_dpy, False);
undefined identifier `XSync`
static __gshared char[192]
(__gshared global) char[192] app.probeWindowOnWorker.d
d
;
const
(local variable) const(int) errs
errs
=
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_xlibErrors
g_xlibErrors
);
if (
(local variable) const(int) errs
errs
> 0)
{
int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
(
(__gshared global) char[192] app.probeWindowOnWorker.d
d
.
(constant) char* char[192].ptr = &d
ptr
,
(__gshared global) char[192] app.probeWindowOnWorker.d
d
.
(constant) ulong char[192].length = 192LU
length
, "xlib_errors=%d last=%s events_on_main=%d",
(local variable) const(int) errs
errs
,
(__gshared global) char[128] app.g_lastXlibError
g_lastXlibError
.
(constant) char* char[128].ptr = &g_lastXlibError
ptr
,
(local variable) int eventsOnMain
eventsOnMain
);
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
("error",
(__gshared global) char[192] app.probeWindowOnWorker.d
d
.
(constant) char* char[192].ptr = &d
ptr
);
} else if (
(parameter) bool initFirst
initFirst
)
{
int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
(
(__gshared global) char[192] app.probeWindowOnWorker.d
d
.
(constant) char* char[192].ptr = &d
ptr
,
(__gshared global) char[192] app.probeWindowOnWorker.d
d
.
(constant) ulong char[192].length = 192LU
length
, "window_created_on_worker events_on_main=%d",
(local variable) int eventsOnMain
eventsOnMain
);
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
("ok",
(__gshared global) char[192] app.probeWindowOnWorker.d
d
.
(constant) char* char[192].ptr = &d
ptr
);
} else {
int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
(
(__gshared global) char[192] app.probeWindowOnWorker.d
d
.
(constant) char* char[192].ptr = &d
ptr
,
(__gshared global) char[192] app.probeWindowOnWorker.d
d
.
(constant) ulong char[192].length = 192LU
length
,
"no_corruption_observed_this_run events_on_main=%d (nondeterministic)",
(local variable) int eventsOnMain
eventsOnMain
);
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
("silent",
(__gshared global) char[192] app.probeWindowOnWorker.d
d
.
(constant) char* char[192].ptr = &d
ptr
);
} XCloseDisplay(g_dpy);
undefined identifier `XCloseDisplay`
return 0; } // -- probe 3: two threads blocked in XNextEvent on one Display ------------------ private shared int
(shared global) shared(int) app.g_recvCount
g_recvCount
;
private shared int[2]
(shared global) shared(int[2]) app.g_perThread
g_perThread
;
private shared int
(shared global) shared(int) app.g_waitersAlive
g_waitersAlive
;
extern (C) void*
void* app.eventWaiter(void* arg) nothrow @nogc
eventWaiter
(void*
(parameter) void* arg
arg
) @nogc nothrow
{ const
(local variable) const(int) idx
idx
= cast(int) cast(
(alias) object.size_t = ulong
size_t
)
(parameter) void* arg
arg
;
int core.atomic.atomicOp!("+=", int, int)(ref shared(int) val, int mod) pure nothrow @nogc @safe

Performs the binary operation 'op' on val using 'mod' as the modifier.

@paramval The target variable.@parammod The modifier to apply.@returnsThe result of the operation.
atomicOp
!"+="(
(shared global) shared(int) app.g_waitersAlive
g_waitersAlive
, 1);
for (;;) { XEvent
(local variable) _error_ ev
ev
;
undefined identifier `XEvent`
XNextEvent(g_dpy, &ev); // blocking; the lock is released while waiting
undefined identifier `XNextEvent`
if (ev.type !=
(enum value) app.ClientMessage = 33
ClientMessage
)
continue; if (ev.xclient.data.l[0] == 99) // sentinel: drain and exit break;
int core.atomic.atomicOp!("+=", int, int)(ref shared(int) val, int mod) pure nothrow @nogc @safe

Performs the binary operation 'op' on val using 'mod' as the modifier.

@paramval The target variable.@parammod The modifier to apply.@returnsThe result of the operation.
atomicOp
!"+="(
(shared global) shared(int[2]) app.g_perThread
g_perThread
[
(local variable) const(int) idx
idx
], 1);
int core.atomic.atomicOp!("+=", int, int)(ref shared(int) val, int mod) pure nothrow @nogc @safe

Performs the binary operation 'op' on val using 'mod' as the modifier.

@paramval The target variable.@parammod The modifier to apply.@returnsThe result of the operation.
atomicOp
!"+="(
(shared global) shared(int) app.g_recvCount
g_recvCount
, 1);
}
int core.atomic.atomicOp!("-=", int, int)(ref shared(int) val, int mod) pure nothrow @nogc @safe

Performs the binary operation 'op' on val using 'mod' as the modifier.

@paramval The target variable.@parammod The modifier to apply.@returnsThe result of the operation.
atomicOp
!"-="(
(shared global) shared(int) app.g_waitersAlive
g_waitersAlive
, 1);
return null; } int
int app.probeTwoReaders() nothrow @nogc
probeTwoReaders
() @nogc nothrow
{
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=XInitThreads ret=%d order=first", XInitThreads());
undefined identifier `XInitThreads`
g_dpy = XOpenDisplay(null); Window
(local variable) _error_ win
win
= XCreateSimpleWindow(g_dpy, XRootWindow(g_dpy, XDefaultScreen(g_dpy)),
undefined identifier `Window`
undefined identifier `XCreateSimpleWindow`
0, 0, 100, 100, 0, 0, 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=window_created xid=0x%lx", win);
pthread_t[2]
(local variable) ulong[2] ts
ts
;
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[2] ts
ts
[0], null, &
void* app.eventWaiter(void* arg) nothrow @nogc
eventWaiter
, cast(void*) 0);
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[2] ts
ts
[1], null, &
void* app.eventWaiter(void* arg) nothrow @nogc
eventWaiter
, cast(void*) 1);
int core.sys.posix.unistd.usleep(uint) nothrow @nogc @trusted
usleep
(50_000); // let both block inside XNextEvent
enum
(constant) int app.probeTwoReaders.N = 100
N
= 100;
XEvent
(local variable) _error_ ev
ev
;
undefined identifier `XEvent`
ev.xclient.type = ClientMessage; ev.xclient.window = win; ev.xclient.message_type = XInternAtom(g_dpy, "WSI_F17_MSG", False); ev.xclient.format = 32; foreach (
(local variable) int i
i
; 0 ..
(constant) int app.probeTwoReaders.N = 100
N
)
{ ev.xclient.data.l[0] = 42; XSendEvent(g_dpy, win, False, 0, &ev); // self-addressed event
undefined identifier `XSendEvent`
XFlush(g_dpy);
undefined identifier `XFlush`
int core.sys.posix.unistd.usleep(uint) nothrow @nogc @trusted
usleep
(1000);
} // Wake the (possibly both-blocked) waiters out of XNextEvent. int
(local variable) int sentinels
sentinels
= 0;
while (
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_waitersAlive
g_waitersAlive
) > 0 &&
(local variable) int sentinels
sentinels
< 200)
{ ev.xclient.data.l[0] = 99; XSendEvent(g_dpy, win, False, 0, &ev);
undefined identifier `XSendEvent`
XFlush(g_dpy);
undefined identifier `XFlush`
++
(local variable) int sentinels
sentinels
;
int core.sys.posix.unistd.usleep(uint) nothrow @nogc @trusted
usleep
(5000);
}
int core.sys.posix.pthread.pthread_join(ulong, void**) nothrow @nogc
pthread_join
(
(local variable) ulong[2] ts
ts
[0], null);
int core.sys.posix.pthread.pthread_join(ulong, void**) nothrow @nogc
pthread_join
(
(local variable) ulong[2] ts
ts
[1], null);
static __gshared char[160]
(__gshared global) char[160] app.probeTwoReaders.d
d
;
const
(local variable) const(int) t0
t0
=
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int[2]) app.g_perThread
g_perThread
[0]),
(local variable) const(int) t1
t1
=
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int[2]) app.g_perThread
g_perThread
[1]);
int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
(
(__gshared global) char[160] app.probeTwoReaders.d
d
.
(constant) char* char[160].ptr = &d
ptr
,
(__gshared global) char[160] app.probeTwoReaders.d
d
.
(constant) ulong char[160].length = 160LU
length
,
"sent=%d received=%d thread_a=%d thread_b=%d sentinels_to_unblock=%d xlib_errors=%d",
(constant) int app.probeTwoReaders.N = 100
N
,
(local variable) const(int) t0
t0
+
(local variable) const(int) t1
t1
,
(local variable) const(int) t0
t0
,
(local variable) const(int) t1
t1
,
(local variable) int sentinels
sentinels
,
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_xlibErrors
g_xlibErrors
));
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
(
(local variable) const(int) t0
t0
+
(local variable) const(int) t1
t1
==
(constant) int app.probeTwoReaders.N = 100
N
? "ok" : "error",
(__gshared global) char[160] app.probeTwoReaders.d
d
.
(constant) char* char[160].ptr = &d
ptr
);
XCloseDisplay(g_dpy);
undefined identifier `XCloseDisplay`
return 0; } // -- probe 4: XShmPutImage from a render thread, events pumped on main ---------- private __gshared Window
_error_ app.g_win
g_win
;
undefined identifier `Window`
private __gshared GC
_error_ app.g_gc
g_gc
;
undefined identifier `GC`
private __gshared XImage*
_error_ app.g_ximg
g_ximg
;
undefined identifier `XImage`
private shared int
(shared global) shared(int) app.g_puts
g_puts
;
extern (C) void*
void* app.renderWorker(void* __param_0) nothrow @nogc
renderWorker
(void*) @nogc nothrow
{ foreach (
(local variable) int frame
frame
; 0 .. 60)
{
void* core.stdc.string.memset(return scope void* s, int c, ulong n) pure nothrow @nogc
memset
(g_ximg.data,
(local variable) int frame
frame
* 4, cast(
(alias) object.size_t = ulong
size_t
)(g_ximg.bytes_per_line * g_ximg.height));
XShmPutImage(g_dpy, g_win, g_gc, g_ximg, 0, 0, 0, 0,
undefined identifier `XShmPutImage`
cast(uint) g_ximg.width, cast(uint) g_ximg.height, True); XFlush(g_dpy); // the worker owns its own flushes
undefined identifier `XFlush`
int core.atomic.atomicOp!("+=", int, int)(ref shared(int) val, int mod) pure nothrow @nogc @safe

Performs the binary operation 'op' on val using 'mod' as the modifier.

@paramval The target variable.@parammod The modifier to apply.@returnsThe result of the operation.
atomicOp
!"+="(
(shared global) shared(int) app.g_puts
g_puts
, 1);
int core.sys.posix.unistd.usleep(uint) nothrow @nogc @trusted
usleep
(3000); // paced by time, not by completion (main eats those)
}
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("thread=render action=done puts=60");
void core.atomic.atomicStore!(MemoryOrder.seq, 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
(
(shared global) shared(bool) app.g_workerDone
g_workerDone
, true);
return null; } int
int app.probeRenderThread() nothrow @nogc
probeRenderThread
() @nogc nothrow
{
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=XInitThreads ret=%d order=first", XInitThreads());
undefined identifier `XInitThreads`
g_dpy = XOpenDisplay(null); const
(local variable) const(_error_) screen
screen
= XDefaultScreen(g_dpy);
undefined identifier `XDefaultScreen`
if (!XShmQueryExtension(g_dpy))
undefined identifier `XShmQueryExtension`
{
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
("ok", "skipped_no_MIT_SHM");
return 0; } const
(local variable) const(_error_) completionType
completionType
= XShmGetEventBase(g_dpy) + 0 /* ShmCompletion */ ;
undefined identifier `XShmGetEventBase`
g_win = XCreateSimpleWindow(g_dpy, XRootWindow(g_dpy, screen), 0, 0, 320, 240, 1, 0, 0xffffff); XSelectInput(g_dpy, g_win, ExposureMask | StructureNotifyMask);
undefined identifier `XSelectInput`
XMapWindow(g_dpy, g_win);
undefined identifier `XMapWindow`
g_gc = XDefaultGC(g_dpy, screen); XShmSegmentInfo
(local variable) _error_ shminfo
shminfo
;
undefined identifier `XShmSegmentInfo`
g_ximg = XShmCreateImage(g_dpy, XDefaultVisual(g_dpy, screen), cast(uint) XDefaultDepth(g_dpy, screen), ZPixmap, null, &shminfo, 320, 240); shminfo.shmid = shmget(IPC_PRIVATE, cast(
(unresolved type) size_t
size_t
)(g_ximg.bytes_per_line * g_ximg.height), IPC_CREAT | 0x180);
shminfo.shmaddr = cast(char*) shmat(shminfo.shmid, null, 0); g_ximg.data = shminfo.shmaddr; shminfo.readOnly = False; XShmAttach(g_dpy, &shminfo);
undefined identifier `XShmAttach`
XSync(g_dpy, False);
undefined identifier `XSync`
shmctl(shminfo.shmid, IPC_RMID, null);
undefined identifier `shmctl`
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=shm_image size=320x240 completion_event=%d", completionType);
void core.atomic.atomicStore!(MemoryOrder.seq, 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
(
(shared global) shared(bool) app.g_workerDone
g_workerDone
, false);
pthread_t
(local variable) ulong t
t
;
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 t
t
, null, &
void* app.renderWorker(void* __param_0) nothrow @nogc
renderWorker
, null);
int
(local variable) int completions
completions
= 0,
(local variable) int otherEvents
otherEvents
= 0;
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("thread=main action=pump_start");
const
(local variable) const(long) deadline
deadline
=
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
() + 4_000_000;
while (
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
() <
(local variable) const(long) deadline
deadline
)
{ while (XPending(g_dpy) > 0)
undefined identifier `XPending`
{ XEvent
(local variable) _error_ ev
ev
;
undefined identifier `XEvent`
XNextEvent(g_dpy, &ev);
undefined identifier `XNextEvent`
if (ev.type == completionType) ++
(local variable) int completions
completions
;
else ++
(local variable) int otherEvents
otherEvents
;
} if (
bool core.atomic.atomicLoad!(MemoryOrder.seq, 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
(
(shared global) shared(bool) app.g_workerDone
g_workerDone
) &&
(local variable) int completions
completions
>=
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_puts
g_puts
))
break;
int core.sys.posix.unistd.usleep(uint) nothrow @nogc @trusted
usleep
(1000);
}
int core.sys.posix.pthread.pthread_join(ulong, void**) nothrow @nogc
pthread_join
(
(local variable) ulong t
t
, null);
static __gshared char[160]
(__gshared global) char[160] app.probeRenderThread.d
d
;
int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
(
(__gshared global) char[160] app.probeRenderThread.d
d
.
(constant) char* char[160].ptr = &d
ptr
,
(__gshared global) char[160] app.probeRenderThread.d
d
.
(constant) ulong char[160].length = 160LU
length
,
"puts_from_render_thread=%d completions_on_main=%d other_events_on_main=%d xlib_errors=%d",
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_puts
g_puts
),
(local variable) int completions
completions
,
(local variable) int otherEvents
otherEvents
,
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_xlibErrors
g_xlibErrors
));
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
(
(local variable) int completions
completions
==
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_puts
g_puts
) &&
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_xlibErrors
g_xlibErrors
) == 0
? "ok" : "error",
(__gshared global) char[160] app.probeRenderThread.d
d
.
(constant) char* char[160].ptr = &d
ptr
);
XSync(g_dpy, False);
undefined identifier `XSync`
XShmDetach(g_dpy, &shminfo);
undefined identifier `XShmDetach`
g_ximg.f.destroy_image(g_ximg); shmdt(shminfo.shmaddr);
undefined identifier `shmdt`
XCloseDisplay(g_dpy);
undefined identifier `XCloseDisplay`
return 0; } // -- probe 5: one Display per thread, no XInitThreads --------------------------- private shared int
(shared global) shared(int) app.g_threadOk
g_threadOk
;
extern (C) void*
void* app.displayPerThread(void* arg) nothrow @nogc
displayPerThread
(void*
(parameter) void* arg
arg
) @nogc nothrow
{ const
(local variable) const(int) idx
idx
= cast(int) cast(
(alias) object.size_t = ulong
size_t
)
(parameter) void* arg
arg
;
Display*
(local variable) _error_ dpy
dpy
= XOpenDisplay(null); // private connection: nothing shared
undefined identifier `Display`
undefined identifier `XOpenDisplay`
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`
160, 120, 1, 0, 0xffffff); XSelectInput(dpy, win, ExposureMask | 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
("thread=t%d", "action=window_created xid=0x%lx fd=%d",
(local variable) const(int) idx
idx
, win, XConnectionNumber(dpy));
undefined identifier `XConnectionNumber`
bool
(local variable) bool exposed
exposed
= false;
const
(local variable) const(long) deadline
deadline
=
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
() + 3_000_000;
while (!
(local variable) bool exposed
exposed
&&
long instrument.nowUs() nothrow @nogc

Microseconds elapsed since initInstrument.

nowUs
() <
(local variable) const(long) deadline
deadline
)
{ XEvent
(local variable) _error_ ev
ev
;
undefined identifier `XEvent`
XNextEvent(dpy, &ev); // each thread blocks on ITS OWN connection
undefined identifier `XNextEvent`
if (ev.type ==
(enum value) app.Expose = 12
Expose
)
{ XFillRectangle(dpy, win, XDefaultGC(dpy, screen), 10, 10, 140, 100);
undefined identifier `XFillRectangle`
XSync(dpy, False);
undefined identifier `XSync`
(local variable) bool exposed
exposed
= true;
} }
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

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

emitf
("thread=t%d", "action=done exposed=%d",
(local variable) const(int) idx
idx
, cast(int)
(local variable) bool exposed
exposed
);
if (
(local variable) bool exposed
exposed
)
int core.atomic.atomicOp!("+=", int, int)(ref shared(int) val, int mod) pure nothrow @nogc @safe

Performs the binary operation 'op' on val using 'mod' as the modifier.

@paramval The target variable.@parammod The modifier to apply.@returnsThe result of the operation.
atomicOp
!"+="(
(shared global) shared(int) app.g_threadOk
g_threadOk
, 1);
XDestroyWindow(dpy, win);
undefined identifier `XDestroyWindow`
XCloseDisplay(dpy);
undefined identifier `XCloseDisplay`
return null; } int
int app.probeDisplayPerThread() nothrow @nogc
probeDisplayPerThread
() @nogc nothrow
{
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("step name=XInitThreads SKIPPED_ON_PURPOSE model=display_per_thread");
pthread_t[2]
(local variable) ulong[2] ts
ts
;
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[2] ts
ts
[0], null, &
void* app.displayPerThread(void* arg) nothrow @nogc
displayPerThread
, cast(void*) 0);
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[2] ts
ts
[1], null, &
void* app.displayPerThread(void* arg) nothrow @nogc
displayPerThread
, cast(void*) 1);
int core.sys.posix.pthread.pthread_join(ulong, void**) nothrow @nogc
pthread_join
(
(local variable) ulong[2] ts
ts
[0], null);
int core.sys.posix.pthread.pthread_join(ulong, void**) nothrow @nogc
pthread_join
(
(local variable) ulong[2] ts
ts
[1], null);
static __gshared char[96]
(__gshared global) char[96] app.probeDisplayPerThread.d
d
;
int core.stdc.stdio.snprintf(scope char* s, ulong n, scope const(char*) format, scope const ...) nothrow @nogc
snprintf
(
(__gshared global) char[96] app.probeDisplayPerThread.d
d
.
(constant) char* char[96].ptr = &d
ptr
,
(__gshared global) char[96] app.probeDisplayPerThread.d
d
.
(constant) ulong char[96].length = 96LU
length
, "threads_completed=%d/2 xlib_errors=%d no_xinitthreads=1",
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_threadOk
g_threadOk
),
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_xlibErrors
g_xlibErrors
));
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
(
int core.atomic.atomicLoad!(MemoryOrder.seq, int)(ref return scope shared(const(int)) 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
(
(shared global) shared(int) app.g_threadOk
g_threadOk
) == 2 ? "ok" : "error",
(__gshared global) char[96] app.probeDisplayPerThread.d
d
.
(constant) char* char[96].ptr = &d
ptr
);
return 0; } // --------------------------------------------------------------------------- int
int app.runProbe(int n) nothrow @nogc
runProbe
(int
(parameter) int n
n
) @nogc nothrow
{
(__gshared global) int app.g_probe
g_probe
=
(parameter) int n
n
;
void app.installCrashHandlers() nothrow @nogc
installCrashHandlers
();
void instrument.emitf(scope const(char)* kind, scope const(char)* fmt, ...) nothrow @nogc

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

emitf
("probe_start", "n=%d",
(parameter) int n
n
);
switch (
(parameter) int n
n
)
{ case 1:
int app.probeWindowOnWorker(bool initFirst, bool initLate) nothrow @nogc
probeWindowOnWorker
(false, false);
break; case 2:
int app.probeWindowOnWorker(bool initFirst, bool initLate) nothrow @nogc
probeWindowOnWorker
(true, false);
break; case 3:
int app.probeTwoReaders() nothrow @nogc
probeTwoReaders
();
break; case 4:
int app.probeRenderThread() nothrow @nogc
probeRenderThread
();
break; case 5:
int app.probeDisplayPerThread() nothrow @nogc
probeDisplayPerThread
();
break; case 6:
int app.probeWindowOnWorker(bool initFirst, bool initLate) nothrow @nogc
probeWindowOnWorker
(false, true);
break; default:
void app.verdict(scope const(char)* result, scope const(char)* detail) nothrow @nogc

The one line the spec requires per run. Async-signal-safe on purpose (snprintf into a static buffer + write(2)) so the signal/XIO handlers can call it; the normal path uses it too so the format is identical.

verdict
("error", "unknown_probe");
}
uint core.sys.posix.unistd.alarm(uint) nothrow @nogc @trusted
alarm
(0);
return 0; } int
int D main(string[] args)
main
(
(alias) object.string = string
string
[]
(parameter) string[] args
args
)
{
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
("f17_x11");
int
(local variable) int probe
probe
= 0;
foreach (
(parameter) string a
a
;
(parameter) string[] args
args
[1 .. $])
if (
(local variable) string a
a
.
(field) ulong string.length
length
> 8 &&
(local variable) string a
a
[0 .. 8] == "--probe=")
(local variable) int probe
probe
=
(local variable) string a
a
[8] - '0';
// Capability gate in the parent, before any fork. Display*
(local variable) _error_ test
test
= XOpenDisplay(null);
undefined identifier `Display`
undefined identifier `XOpenDisplay`
if (test 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; } XCloseDisplay(test);
undefined identifier `XCloseDisplay`
if (
(local variable) int probe
probe
!= 0)
return
int app.runProbe(int n) nothrow @nogc
runProbe
(
(local variable) int probe
probe
);
// No argument: run the full matrix, each probe TWICE (the F17 spec's // nondeterminism rule), each in a forked child so a corrupted Xlib or a // caught crash never poisons the next probe. Children always _exit(0). foreach (
(local variable) int n
n
; 1 .. 7)
foreach (
(local variable) int run
run
; 1 .. 3)
{ const
(local variable) const(int) pid
pid
=
int core.sys.posix.unistd.fork() nothrow @nogc @trusted
fork
();
if (
(local variable) const(int) pid
pid
== 0)
{
int app.runProbe(int n) nothrow @nogc
runProbe
(
(local variable) int n
n
);
noreturn core.sys.posix.unistd._exit(int) nothrow @nogc @trusted
_exit
(0);
} int
(local variable) int status
status
;
int core.sys.posix.sys.wait.waitpid(int, int*, int) nothrow @nogc
waitpid
(
(local variable) const(int) pid
pid
, &
(local variable) int status
status
, 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
("probe_child", "n=%d run=%d wait_status=%d",
(local variable) int n
n
,
(local variable) int run
run
,
(local variable) int status
status
);
}
void instrument.emit(scope const(char)* kind) nothrow @nogc

Emit an event with no key=value payload.

emit
("teardown all_probes_done");
return 0; }