source-read-pipe.dhover×258all
#!/usr/bin/env dub
/+ dub.sdl:
    name "gcd_source_read_pipe"
    platforms "osx"
    targetPath "build"
+/
/**
 * GCD — `DISPATCH_SOURCE_TYPE_READ` is `EVFILT_READ` with the loop hidden.
 *
 * A dispatch source is libdispatch's whole event-loop surface: you never call
 * `kqueue()` or `kevent()`, you attach a handler to a source and the kernel
 * delivers the event straight to a workqueue thread. `_dispatch_source_type_read`
 * (`src/event/event.c`) is literally `{ .dst_filter = EVFILT_READ, .dst_flags =
 * EV_UDATA_SPECIFIC|EV_DISPATCH|EV_VANISHED }`, so the observable behaviour is
 * kqueue's: `dispatch_source_get_data()` returns the same byte count kqueue puts
 * in `kevent.data`, the registration auto-disables itself while the handler runs
 * (`EV_DISPATCH`), and a closed writer surfaces as a wakeup with zero bytes.
 *
 * The program drives a pipe through three states — readable, drained, EOF —
 * sequencing each with a semaphore so the output is deterministic, and asserts
 * the byte counts and the cancel-handler ordering.
 *
 * Companion to the GCD deep-dive:
 * see docs/research/async-io/gcd/index.md § "Dispatch sources: a kqueue vocabulary".
 *
 * Run with: `dub run --single source-read-pipe.d`
 *
 * Portability: macOS only (`platforms "osx"`).
 */
module 
(module) gcd_source_read_pipe

GCD — DISPATCH_SOURCE_TYPE_READ is EVFILT_READ with the loop hidden.

A dispatch source is libdispatch's whole event-loop surface: you never call kqueue() or kevent(), you attach a handler to a source and the kernel delivers the event straight to a workqueue thread. _dispatch_source_type_read (src/event/event.c) is literally { .dst_filter = EVFILT_READ, .dst_flags = EV_UDATA_SPECIFIC|EV_DISPATCH|EV_VANISHED }, so the observable behaviour is kqueue's: dispatch_source_get_data() returns the same byte count kqueue puts in kevent.data, the registration auto-disables itself while the handler runs (EV_DISPATCH), and a closed writer surfaces as a wakeup with zero bytes.

The program drives a pipe through three states — readable, drained, EOF — sequencing each with a semaphore so the output is deterministic, and asserts the byte counts and the cancel-handler ordering.

Companion to the GCD deep-dive: see docs/research/async-io/gcd/index.md § "Dispatch sources: a kqueue vocabulary".

Run with: dub run --single source-read-pipe.d

Portability

macOS only (platforms "osx").

gcd_source_read_pipe
;
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) gcd_source_read_pipe.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) gcd_source_read_pipe.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) gcd_source_read_pipe.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.stdint

D header file for C99.

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

Source

core/stdc/stdint.d

@copyrightCopyright Sean Kelly 2005 - 2018@licenseDistributed under the Boost Software License 1.0. (See accompanying file LICENSE)@authorsSean Kelly@standardsISO/IEC 9899:1999 (E)
stdint
: uintptr_t;
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) gcd_source_read_pipe.close = int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
,
(alias) gcd_source_read_pipe.pipe = int core.sys.posix.unistd.pipe(ref int[2]) nothrow @nogc @trusted
pipe
,
(alias) gcd_source_read_pipe.read = long core.sys.posix.unistd.read(int, void*, ulong) nothrow @nogc
read
,
(alias) gcd_source_read_pipe.write = long core.sys.posix.unistd.write(int, scope const(void*), ulong) nothrow @nogc
write
;
import
(package) std
std
.
(module) std.stdio
Category Symbols
File handles _popen File isFileHandle openNetwork stderr stdin stdout
Reading chunks lines readf readfln readln
Writing toFile write writef writefln writeln
Misc KeepTerminator LockType StdioException

Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio is publically imported when importing std.stdio.

There are three layers of I/O:

  1. The lowest layer is the operating system layer. The two main schemes are Windows and Posix.

  2. C's stdio.h which unifies the two operating system schemes.

  3. std.stdio, this module, unifies the various stdio.h implementations into a high level package for D programs.

Source

std/stdio.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Alex Rønne Petersen
stdio
:
(alias template) gcd_source_read_pipe.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))

Equivalent to writef(fmt, args, '\n').

writefln
,
(alias template) gcd_source_read_pipe.writeln = std.stdio.writeln(T...)(T args)

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
;
alias
(alias) gcd_source_read_pipe.dispatch_queue_t = void*
dispatch_queue_t
= void*;
alias
(alias) gcd_source_read_pipe.dispatch_source_t = void*
dispatch_source_t
= void*;
alias
(alias) gcd_source_read_pipe.dispatch_semaphore_t = void*
dispatch_semaphore_t
= void*;
alias
(alias) gcd_source_read_pipe.dispatch_function_t = extern (C) void function(void*) nothrow
dispatch_function_t
= extern (C) void function(void*) nothrow;
extern (C) nothrow @nogc { // `DISPATCH_SOURCE_TYPE_READ` is `&_dispatch_source_type_read` — an opaque // descriptor record, referenced only by address. extern __gshared const ubyte
(constant global) const(ubyte) gcd_source_read_pipe._dispatch_source_type_read
_dispatch_source_type_read
;
(alias) gcd_source_read_pipe.dispatch_queue_t = void*
dispatch_queue_t
void* gcd_source_read_pipe.dispatch_queue_create(const(char)* label, void* attr) nothrow @nogc
dispatch_queue_create
(const(char)*
(parameter) const(char)* label
label
, void*
(parameter) void* attr
attr
);
(alias) gcd_source_read_pipe.dispatch_source_t = void*
dispatch_source_t
void* gcd_source_read_pipe.dispatch_source_create(const(void)* type, ulong handle, ulong mask, void* queue) nothrow @nogc
dispatch_source_create
(const(void)*
(parameter) const(void)* type
type
, uintptr_t
(parameter) ulong handle
handle
,
uintptr_t
(parameter) ulong mask
mask
,
(alias) gcd_source_read_pipe.dispatch_queue_t = void*
dispatch_queue_t
(parameter) void* queue
queue
);
void
void gcd_source_read_pipe.dispatch_source_set_event_handler_f(void* source, extern (C) void function(void*) nothrow handler) nothrow @nogc
dispatch_source_set_event_handler_f
(
(alias) gcd_source_read_pipe.dispatch_source_t = void*
dispatch_source_t
(parameter) void* source
source
,
(alias) gcd_source_read_pipe.dispatch_function_t = extern (C) void function(void*) nothrow
dispatch_function_t
(parameter) extern (C) void function(void*) nothrow handler
handler
);
void
void gcd_source_read_pipe.dispatch_source_set_cancel_handler_f(void* source, extern (C) void function(void*) nothrow handler) nothrow @nogc
dispatch_source_set_cancel_handler_f
(
(alias) gcd_source_read_pipe.dispatch_source_t = void*
dispatch_source_t
(parameter) void* source
source
,
(alias) gcd_source_read_pipe.dispatch_function_t = extern (C) void function(void*) nothrow
dispatch_function_t
(parameter) extern (C) void function(void*) nothrow handler
handler
);
void
void gcd_source_read_pipe.dispatch_set_context(void* object, void* context) nothrow @nogc
dispatch_set_context
(void*
(parameter) void* object
object
, void*
(parameter) void* context
context
);
uintptr_t
ulong gcd_source_read_pipe.dispatch_source_get_data(void* source) nothrow @nogc
dispatch_source_get_data
(
(alias) gcd_source_read_pipe.dispatch_source_t = void*
dispatch_source_t
(parameter) void* source
source
);
uintptr_t
ulong gcd_source_read_pipe.dispatch_source_get_handle(void* source) nothrow @nogc
dispatch_source_get_handle
(
(alias) gcd_source_read_pipe.dispatch_source_t = void*
dispatch_source_t
(parameter) void* source
source
);
void
void gcd_source_read_pipe.dispatch_source_cancel(void* source) nothrow @nogc
dispatch_source_cancel
(
(alias) gcd_source_read_pipe.dispatch_source_t = void*
dispatch_source_t
(parameter) void* source
source
);
void
void gcd_source_read_pipe.dispatch_resume(void* object) nothrow @nogc
dispatch_resume
(void*
(parameter) void* object
object
);
void
void gcd_source_read_pipe.dispatch_release(void* object) nothrow @nogc
dispatch_release
(void*
(parameter) void* object
object
);
(alias) gcd_source_read_pipe.dispatch_semaphore_t = void*
dispatch_semaphore_t
void* gcd_source_read_pipe.dispatch_semaphore_create(long value) nothrow @nogc
dispatch_semaphore_create
(long
(parameter) long value
value
);
long
long gcd_source_read_pipe.dispatch_semaphore_wait(void* sema, ulong timeout) nothrow @nogc
dispatch_semaphore_wait
(
(alias) gcd_source_read_pipe.dispatch_semaphore_t = void*
dispatch_semaphore_t
(parameter) void* sema
sema
, ulong
(parameter) ulong timeout
timeout
);
long
long gcd_source_read_pipe.dispatch_semaphore_signal(void* sema) nothrow @nogc
dispatch_semaphore_signal
(
(alias) gcd_source_read_pipe.dispatch_semaphore_t = void*
dispatch_semaphore_t
(parameter) void* sema
sema
);
} enum
(constant) ulong gcd_source_read_pipe.DISPATCH_TIME_FOREVER = 18446744073709551615LU
DISPATCH_TIME_FOREVER
= ~0UL;
struct
(struct) gcd_source_read_pipe.Watch
Watch
{
(alias) gcd_source_read_pipe.dispatch_source_t = void*
dispatch_source_t
(field) void* gcd_source_read_pipe.Watch.source
source
;
(alias) gcd_source_read_pipe.dispatch_semaphore_t = void*
dispatch_semaphore_t
(field) void* gcd_source_read_pipe.Watch.wakeup
wakeup
; // signalled once per event handler invocation
(alias) gcd_source_read_pipe.dispatch_semaphore_t = void*
dispatch_semaphore_t
(field) void* gcd_source_read_pipe.Watch.cancelled
cancelled
;
shared int
(field) shared(int) gcd_source_read_pipe.Watch.events
events
;
shared long
(field) shared(long) gcd_source_read_pipe.Watch.lastAvailable
lastAvailable
;
shared long
(field) shared(long) gcd_source_read_pipe.Watch.lastRead
lastRead
;
shared long
(field) shared(long) gcd_source_read_pipe.Watch.totalRead
totalRead
;
} __gshared
(struct) gcd_source_read_pipe.Watch
Watch
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
;
/// The event handler. Runs on the source's target queue, on a workqueue thread — /// so it stays allocation-free and reports through `printf` and atomics. extern (C) void
void gcd_source_read_pipe.onReadable(void* context) nothrow

The event handler. Runs on the source's target queue, on a workqueue thread — so it stays allocation-free and reports through printf and atomics.

onReadable
(void*
(parameter) void* context
context
) nothrow
{ 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) printf = int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
;
// kqueue's `kevent.data` for EVFILT_READ: bytes available right now. const
(local variable) const(long) available
available
= cast(long)
ulong gcd_source_read_pipe.dispatch_source_get_data(void* source) nothrow @nogc
dispatch_source_get_data
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.source
source
);
const
(local variable) const(int) fd
fd
= cast(int)
ulong gcd_source_read_pipe.dispatch_source_get_handle(void* source) nothrow @nogc
dispatch_source_get_handle
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.source
source
);
char[512]
(local variable) char[512] buffer
buffer
= void;
const
(local variable) const(ulong) wanted
wanted
=
(local variable) const(long) available
available
> 0 &&
(local variable) const(long) available
available
<
(local variable) char[512] buffer
buffer
.
(constant) ulong char[512].length = 512LU
length
? cast(
(alias) object.size_t = ulong
size_t
)
(local variable) const(long) available
available
:
(local variable) char[512] buffer
buffer
.
(constant) ulong char[512].length = 512LU
length
;
const
(local variable) const(long) got
got
=
(local variable) const(long) available
available
== 0 ? 0 :
long core.sys.posix.unistd.read(int, void*, ulong) nothrow @nogc
read
(
(local variable) const(int) fd
fd
,
(local variable) char[512] buffer
buffer
.
(constant) char* char[512].ptr = &buffer
ptr
,
(local variable) const(ulong) wanted
wanted
);
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
!"+="(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(int) gcd_source_read_pipe.Watch.events
events
, 1);
void core.atomic.atomicStore!(MemoryOrder.seq, long, const(long))(ref shared(long) val, const(long) newval) pure nothrow @nogc @trusted

Writes 'newval' into 'val'. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.rel, and MemoryOrder.seq.

@paramval The target variable.@paramnewval The value to store.
atomicStore
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(long) gcd_source_read_pipe.Watch.lastAvailable
lastAvailable
,
(local variable) const(long) available
available
);
void core.atomic.atomicStore!(MemoryOrder.seq, long, long)(ref shared(long) val, long newval) pure nothrow @nogc @trusted

Writes 'newval' into 'val'. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.rel, and MemoryOrder.seq.

@paramval The target variable.@paramnewval The value to store.
atomicStore
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(long) gcd_source_read_pipe.Watch.lastRead
lastRead
, cast(long)
(local variable) const(long) got
got
);
if (
(local variable) const(long) got
got
> 0)
long core.atomic.atomicOp!("+=", long, long)(ref shared(long) val, long 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
!"+="(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(long) gcd_source_read_pipe.Watch.totalRead
totalRead
, cast(long)
(local variable) const(long) got
got
);
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
(" event %d: get_data()=%lld read()=%lld\n",
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
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(int) gcd_source_read_pipe.Watch.events
events
),
(local variable) const(long) available
available
, cast(long)
(local variable) const(long) got
got
);
// EOF is not a distinct event: kqueue keeps reporting the descriptor // readable with zero bytes, and `EV_DISPATCH` re-arms the registration as // soon as this handler returns. A source that is not cancelled here spins // at full speed. Cancelling from inside the handler is the only way to stop // it deterministically. if (
(local variable) const(long) available
available
== 0)
void gcd_source_read_pipe.dispatch_source_cancel(void* source) nothrow @nogc
dispatch_source_cancel
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.source
source
);
long gcd_source_read_pipe.dispatch_semaphore_signal(void* sema) nothrow @nogc
dispatch_semaphore_signal
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.wakeup
wakeup
);
} /// Runs after the source is fully cancelled — the only point at which the file /// descriptor may be closed. extern (C) void
void gcd_source_read_pipe.onCancel(void* context) nothrow

Runs after the source is fully cancelled — the only point at which the file descriptor may be closed.

onCancel
(void*
(parameter) void* context
context
) nothrow
{ 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) printf = int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
;
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogc
printf
(" cancel handler: safe to close the descriptor now\n");
long gcd_source_read_pipe.dispatch_semaphore_signal(void* sema) nothrow @nogc
dispatch_semaphore_signal
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.cancelled
cancelled
);
} int
int D main()
main
()
{ int[2]
(local variable) int[2] fds
fds
;
if (
int core.sys.posix.unistd.pipe(ref int[2]) nothrow @nogc @trusted
pipe
(
(local variable) int[2] fds
fds
) != 0)
{
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("SKIP: pipe(2) failed");
return 0; } const
(local variable) const(int) readEnd
readEnd
=
(local variable) int[2] fds
fds
[0],
(local variable) const(int) writeEnd
writeEnd
=
(local variable) int[2] fds
fds
[1];
auto
(local variable) void* queue
queue
=
void* gcd_source_read_pipe.dispatch_queue_create(const(char)* label, void* attr) nothrow @nogc
dispatch_queue_create
("dev.sparkles.research.gcd.pipe", null);
scope (exit)
void gcd_source_read_pipe.dispatch_release(void* object) nothrow @nogc
dispatch_release
(
(local variable) void* queue
queue
);
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.wakeup
wakeup
=
void* gcd_source_read_pipe.dispatch_semaphore_create(long value) nothrow @nogc
dispatch_semaphore_create
(0);
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.cancelled
cancelled
=
void* gcd_source_read_pipe.dispatch_semaphore_create(long value) nothrow @nogc
dispatch_semaphore_create
(0);
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.source
source
=
void* gcd_source_read_pipe.dispatch_source_create(const(void)* type, ulong handle, ulong mask, void* queue) nothrow @nogc
dispatch_source_create
(&
(constant global) const(ubyte) gcd_source_read_pipe._dispatch_source_type_read
_dispatch_source_type_read
,
(local variable) const(int) readEnd
readEnd
, 0,
(local variable) void* queue
queue
);
void gcd_source_read_pipe.dispatch_set_context(void* object, void* context) nothrow @nogc
dispatch_set_context
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.source
source
, &
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
);
void gcd_source_read_pipe.dispatch_source_set_event_handler_f(void* source, extern (C) void function(void*) nothrow handler) nothrow @nogc
dispatch_source_set_event_handler_f
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.source
source
, &
void gcd_source_read_pipe.onReadable(void* context) nothrow

The event handler. Runs on the source's target queue, on a workqueue thread — so it stays allocation-free and reports through printf and atomics.

onReadable
);
void gcd_source_read_pipe.dispatch_source_set_cancel_handler_f(void* source, extern (C) void function(void*) nothrow handler) nothrow @nogc
dispatch_source_set_cancel_handler_f
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.source
source
, &
void gcd_source_read_pipe.onCancel(void* context) nothrow

Runs after the source is fully cancelled — the only point at which the file descriptor may be closed.

onCancel
);
// Sources are created suspended; nothing is registered with kqueue until // the first resume.
void gcd_source_read_pipe.dispatch_resume(void* object) nothrow @nogc
dispatch_resume
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.source
source
);
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("state 1 — writer writes 11 bytes:");
long core.sys.posix.unistd.write(int, scope const(void*), ulong) nothrow @nogc
write
(
(local variable) const(int) writeEnd
writeEnd
, "hello world".
(constant) immutable(char)* "hello world".ptr = "hello world"
ptr
, 11);
long gcd_source_read_pipe.dispatch_semaphore_wait(void* sema, ulong timeout) nothrow @nogc
dispatch_semaphore_wait
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.wakeup
wakeup
,
(constant) ulong gcd_source_read_pipe.DISPATCH_TIME_FOREVER = 18446744073709551615LU
DISPATCH_TIME_FOREVER
);
assert(
long core.atomic.atomicLoad!(MemoryOrder.seq, long)(ref return scope shared(const(long)) val) pure nothrow @nogc @trusted

Loads 'val' from memory and returns it. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq, and MemoryOrder.seq.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(long) gcd_source_read_pipe.Watch.lastAvailable
lastAvailable
) == 11, "EVFILT_READ data was not the byte count");
assert(
long core.atomic.atomicLoad!(MemoryOrder.seq, long)(ref return scope shared(const(long)) val) pure nothrow @nogc @trusted

Loads 'val' from memory and returns it. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq, and MemoryOrder.seq.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(long) gcd_source_read_pipe.Watch.lastRead
lastRead
) == 11, "short read");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("state 2 — writer writes 4 more bytes:");
long core.sys.posix.unistd.write(int, scope const(void*), ulong) nothrow @nogc
write
(
(local variable) const(int) writeEnd
writeEnd
, "more".
(constant) immutable(char)* "more".ptr = "more"
ptr
, 4);
long gcd_source_read_pipe.dispatch_semaphore_wait(void* sema, ulong timeout) nothrow @nogc
dispatch_semaphore_wait
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.wakeup
wakeup
,
(constant) ulong gcd_source_read_pipe.DISPATCH_TIME_FOREVER = 18446744073709551615LU
DISPATCH_TIME_FOREVER
);
assert(
long core.atomic.atomicLoad!(MemoryOrder.seq, long)(ref return scope shared(const(long)) val) pure nothrow @nogc @trusted

Loads 'val' from memory and returns it. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq, and MemoryOrder.seq.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(long) gcd_source_read_pipe.Watch.lastAvailable
lastAvailable
) == 4, "second wakeup reported the wrong count");
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("state 3 — writer closes its end (the handler cancels the source):");
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) writeEnd
writeEnd
);
long gcd_source_read_pipe.dispatch_semaphore_wait(void* sema, ulong timeout) nothrow @nogc
dispatch_semaphore_wait
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.wakeup
wakeup
,
(constant) ulong gcd_source_read_pipe.DISPATCH_TIME_FOREVER = 18446744073709551615LU
DISPATCH_TIME_FOREVER
);
assert(
long core.atomic.atomicLoad!(MemoryOrder.seq, long)(ref return scope shared(const(long)) val) pure nothrow @nogc @trusted

Loads 'val' from memory and returns it. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq, and MemoryOrder.seq.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(long) gcd_source_read_pipe.Watch.lastAvailable
lastAvailable
) == 0, "EOF wakeup carried a non-zero byte count");
assert(
long core.atomic.atomicLoad!(MemoryOrder.seq, long)(ref return scope shared(const(long)) val) pure nothrow @nogc @trusted

Loads 'val' from memory and returns it. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq, and MemoryOrder.seq.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(long) gcd_source_read_pipe.Watch.lastRead
lastRead
) == 0, "read at EOF returned data");
// Cancellation is asynchronous even when requested from the handler: the // cancel handler is the completion signal, and the only point at which the // descriptor may be closed.
long gcd_source_read_pipe.dispatch_semaphore_wait(void* sema, ulong timeout) nothrow @nogc
dispatch_semaphore_wait
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.cancelled
cancelled
,
(constant) ulong gcd_source_read_pipe.DISPATCH_TIME_FOREVER = 18446744073709551615LU
DISPATCH_TIME_FOREVER
);
int core.sys.posix.unistd.close(int) nothrow @nogc @trusted
close
(
(local variable) const(int) readEnd
readEnd
);
void gcd_source_read_pipe.dispatch_release(void* object) nothrow @nogc
dispatch_release
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) void* gcd_source_read_pipe.Watch.source
source
);
void std.stdio.writeln!()() @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
();
void std.stdio.writefln!(char, int, long)(in char[] fmt, int __param_1, long __param_2) @safe

Equivalent to writef(fmt, args, '\n').

writefln
("handler invocations: %d, bytes delivered: %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
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(int) gcd_source_read_pipe.Watch.events
events
),
long core.atomic.atomicLoad!(MemoryOrder.seq, long)(ref return scope shared(const(long)) val) pure nothrow @nogc @trusted

Loads 'val' from memory and returns it. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq, and MemoryOrder.seq.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(long) gcd_source_read_pipe.Watch.totalRead
totalRead
));
assert(
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
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(int) gcd_source_read_pipe.Watch.events
events
) == 3, "expected exactly three wakeups");
assert(
long core.atomic.atomicLoad!(MemoryOrder.seq, long)(ref return scope shared(const(long)) val) pure nothrow @nogc @trusted

Loads 'val' from memory and returns it. The memory barrier specified by 'ms' is applied to the operation, which is fully sequenced by default. Valid memory orders are MemoryOrder.raw, MemoryOrder.acq, and MemoryOrder.seq.

@paramval The target variable.@returnsThe value of 'val'.
atomicLoad
(
(__gshared global) gcd_source_read_pipe.Watch gcd_source_read_pipe.watch
watch
.
(field) shared(long) gcd_source_read_pipe.Watch.totalRead
totalRead
) == 15, "expected 15 bytes across the two data wakeups");
return 0; }