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/*.csrc/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.16.0 onThursday 20 November 2025. Using Julia version 1.12.2.