Landin library reference discuss source

Hosted targets only.

The hosted provider whose waiting operations block the thread, written once over platform/posix: the provider host, made by new, imported as blocking with no alias. It is what an ordinary hosted program imports.

Call What it does
blocking.new() The process's provider: a host handle that borrows nothing.
blocking.over(space) A provider that keeps its last errno in a space the caller declares.
blocking.last_errno(host) The errno number of the last failing call.
blocking.last_signal(host) The signal that ended the last child waited for.

host supplies every concept of core/io, core/time and core/net: the shared I/O concepts and so world, directories, environment, programs, network, file_system, terminals, clock, wall_clock and entropy. It is also a fibre.scheduler that runs each task to its end before admit returns, as fibre.whole does, and so is no provider of fibre.turns: its calls block the thread.

It is built over a hosted/system handle, which new makes, and hands that handle everything that does not wait: opening and closing files, the standard streams' descriptors and the arguments, the environment, directories, the rest of the file system, terminals, entropy and the wall clock. What waits is its own: read, write and write_some, running programs, the network, and the monotonic clock with its sleep. A child is started by the system handle's start, which does not wait; reading and writing its pipes and waiting for it are this provider's. Both report through the system handle's one last-error cell, so last_errno says the same whichever of them failed. Its files are the system's: hosted/system's descriptor_of, file_of and socket_of convert them.

What the provider promises

Call Promise
write Writes the whole slice, or fails. Bytes written before a failure stay written.
write_some Makes one attempt and returns a positive count, which may be short. A failed attempt writes nothing.
either, on an empty slice Succeeds without asking the system; write_some returns zero.
open, read, write Retried after a signal interrupts them only when the system guarantees the attempt made no progress: completed progress is never repeated.
close Consumes the file once, even when it fails, and is never retried blindly.
same_file(left, right) Follows symbolic links and recognises hard links. The left path must exist; a missing right path gives false, and any other failure is an error. The check is not atomic: the names must stay put until the open that follows.
the arguments Begin after the program's name: neither this provider nor the memory world includes argv[0].

The network

network runs over platform/posix's sockets. A socket is a descriptor and a file of the provider like any other, so read and write take a connection.

  • A write to a socket the provider made is a send, which raises no SIGPIPE beside a C handler on any system.
  • A listener reuses its address.
  • An IPv6 socket takes IPv6 alone on every system, which BSD does from the start and Linux does not.
  • Up to 128 connections wait to be accepted.

Interruptions and partial results are handled for you:

  • an interrupted call is made again;
  • a connection a signal interrupted is waited out with poll, and its outcome read from the socket;
  • an accept refused because its connection was reset before it was taken accepts the next;
  • a send goes on after a short one until every byte is sent.

A send to a peer that has gone is disconnected, EPIPE or ECONNRESET kept as the last errno, and a write to it is io_failed with EPIPE. The process ignores SIGPIPE, so neither ends it.

The clock

Call On the hosted provider
now platform/posix's monotonic clock, in nanoseconds since the system started.
sleep Takes its deadline from the monotonic clock, and asks the system to sleep for what is left until that clock has reached it.

A clock the system cannot read ends the program, since no hosted system fails to.

A sleep a signal interrupts, or the system ends early, sleeps on: it never returns before the deadline as now reads it.

Items

Types 2

Also on this page

public host: type = blocking_value

Hosted implementation of all four I/O capabilities and so of io.world, of io.programs, net.network, the monotonic time.clock and fibre.scheduler, whose waits block the thread, and of every concept hosted/system supplies, which it hands the system's handle it is built over: io.directories, io.environment, io.file_system, io.terminals, io.entropy and time.wall_clock. A child is started by that handle's start, which does not wait (D479). A handle: copies share the process's descriptors, arguments and environment, and the last-error and last-signal cells they were made with. Its files are the system's, as hosted/system's descriptor_of and file_of give them; borrowed arguments and variables refer to process storage.

public space: type = system.space

The system's last-error and last-signal cells of the caller's own, hosted/system's space, for over.

public last_errno: (handle: host) -> (number: i32)

Return errno captured for the terminal failing provider call, as hosted/system's last_errno does: the cell is the system handle's, which this provider's own calls report through too. Zero means the handle's most recent call of any concept did not fail with an errno.

public last_signal: (handle: host) -> (number: i32)

Return the number of the signal that ended the child this handle's cell last saw end through io.wait, as hosted/system's last_signal does; zero when it exited with a code or none was waited for.

public new: () -> (handle: host)

Return a handle to the hosted provider whose waits block the thread, over a new hosted/system handle: the process's arguments, the three standard streams, descriptors 0, 1 and 2, and the process's last-error cell. Regular open-write operations create or truncate files; close regular files explicitly. The handle borrows nothing. Use over for a cell of the caller's own.

Calling this before the hosted entry has established the process's arguments traps, as hosted/system's new does.

public over: (inout state: space) -> (handle: host from state)

Fill state and return a handle that records its last error there rather than in the process's cell, over hosted/system's over. It shares the process's arguments and descriptors like any other handle; calling this before any root exists traps, as new does.

Example program

The program prints the arguments blocking.new()'s provider lends, one to a line after its index. It then looks for a settings file that is not there and prints why it could not be opened, in failure.words' phrase and by blocking.last_errno's number, before going on with its defaults.

This complete program is one of the compiler's runtime tests. View source.

compiler/tests/fixtures/runtime/library-system-arguments/main.ldn38 lines
--  Print the arguments the program was given, one to a line after its
--  index, then look for a settings file.  When it cannot be opened the
--  program says why, in the library's words and by the system's own error
--  number, and goes on with its defaults.
import core/failure
import core/io
import core/text
import hosted/blocking

public main: () -> (code: i32) =
    host := blocking.new()
    mut storage: [256]u8 = zeroed
    mut out := io.buffered_over(host, io.out(host), storage)
    defer io.flush(out) else none
    code = 1
    count: usize = io.argument_count(host)
    io.format(out, "{} arguments\n", [any(addr count)]) else none
    for index in 0..<count do
        argument := io.argument_at(host, index) else (problem)
            return
        end
        io.format(out, "{}: {}\n", [any(addr index), any(addr argument)])
            else none
    end for
    path: []u8 = "settings.conf"
    file := io.open_read(host, text.host_over(path)) else (problem)
        reason: []u8 = failure.words(problem)
        number: i32 = blocking.last_errno(host)
        io.format(out, "{}: {} (errno {}), so the defaults apply\n",
                  [any(addr path), any(addr reason), any(addr number)])
            else none
        code = 0
        return
    end
    io.close(host, file) else none
    io.format(out, "{}: opened\n", [any(addr path)]) else none
    code = 0
end main
in a terminalprints on standard output
$ refine compile main.ldn -o system-arguments && ./system-arguments hello world
2 arguments
0: hello
1: world
settings.conf: not found (errno 2), so the defaults apply