julia.h
defineslibuv wrappers for thestdio.h
streams:
uv_stream_t *JL_STDIN;uv_stream_t *JL_STDOUT;uv_stream_t *JL_STDERR;
... and corresponding output functions:
int jl_printf(uv_stream_t *s, const char *format, ...);int jl_vprintf(uv_stream_t *s, const char *format, va_list args);
Theseprintf
functions are used by the.c
files in thesrc/
andcli/
directories wherever stdio is needed to ensure that output buffering is handled in a unified way.
In special cases, like signal handlers, where the full libuv infrastructure is too heavy,jl_safe_printf()
can be used towrite(2)
directly toSTDERR_FILENO
:
void jl_safe_printf(const char *str, ...);
Base.stdin
,Base.stdout
andBase.stderr
are bound to theJL_STD*
libuv streams defined in the runtime.
Julia's__init__()
function (inbase/sysimg.jl
) callsreinit_stdio()
(inbase/stream.jl
) to create Julia objects forBase.stdin
,Base.stdout
andBase.stderr
.
reinit_stdio()
usesccall
to retrieve pointers toJL_STD*
and callsjl_uv_handle_type()
to inspect the type of each stream. It then creates a JuliaBase.IOStream
,Base.TTY
orBase.PipeEndpoint
object to represent each stream, e.g.:
$ julia -e 'println(typeof((stdin, stdout, stderr)))'Tuple{Base.TTY,Base.TTY,Base.TTY}$ julia -e 'println(typeof((stdin, stdout, stderr)))' < /dev/null 2>/dev/nullTuple{IOStream,Base.TTY,IOStream}$ echo hello | julia -e 'println(typeof((stdin, stdout, stderr)))' | catTuple{Base.PipeEndpoint,Base.PipeEndpoint,Base.TTY}
TheBase.read
andBase.write
methods for these streams useccall
to call libuv wrappers insrc/jl_uv.c
, e.g.:
stream.jl: function write(s::IO, p::Ptr, nb::Integer) -> ccall(:jl_uv_write, ...) jl_uv.c: -> int jl_uv_write(uv_stream_t *stream, ...) -> uv_write(uvw, stream, buf, ...)
The libuv streams relied upon byjl_printf()
etc., are not available until midway through initialization of the runtime (seeinit.c
,init_stdio()
). Error messages or warnings that need to be printed before this are routed to the standard C libraryfwrite()
function by the following mechanism:
Insys.c
, theJL_STD*
stream pointers are statically initialized to integer constants:STD*_FILENO (0, 1 and 2)
. Injl_uv.c
thejl_uv_puts()
function checks itsuv_stream_t* stream
argument and callsfwrite()
if stream is set toSTDOUT_FILENO
orSTDERR_FILENO
.
This allows for uniform use ofjl_printf()
throughout the runtime regardless of whether or not any particular piece of code is reachable before initialization is complete.
ios.c
libraryThesrc/support/ios.c
library is inherited fromfemtolisp. It provides cross-platform buffered file IO and in-memory temporary buffers.
ios.c
is still used by:
src/flisp/*.c
src/dump.c
– for serialization file IO and for memory buffers.src/staticdata.c
– for serialization file IO and for memory buffers.base/iostream.jl
– for file IO (seebase/fs.jl
for libuv equivalent).Use ofios.c
in these modules is mostly self-contained and separated from the libuv I/O system. However, there isone place where femtolisp calls through tojl_printf()
with a legacyios_t
stream.
There is a hack inios.h
that makes theios_t.bm
field line up with theuv_stream_t.type
and ensures that the values used forios_t.bm
to not overlap with validUV_HANDLE_TYPE
values. This allowsuv_stream_t
pointers to point toios_t
streams.
This is needed becausejl_printf()
callerjl_static_show()
is passed anios_t
stream by femtolisp'sfl_print()
function. Julia'sjl_uv_puts()
function has special handling for this:
if (stream->type > UV_HANDLE_TYPE_MAX) { return ios_write((ios_t*)stream, str, n);}
Settings
This document was generated withDocumenter.jl version 1.8.0 onWednesday 9 July 2025. Using Julia version 1.11.6.