printf() and stdio in the Julia runtime
Libuv wrappers for stdio
julia.h
يحدد libuv أغلفة لتدفقات stdio.h
:
uv_stream_t *JL_STDIN;
uv_stream_t *JL_STDOUT;
uv_stream_t *JL_STDERR;
... ودوال المخرجات المقابلة:
int jl_printf(uv_stream_t *s, const char *format, ...);
int jl_vprintf(uv_stream_t *s, const char *format, va_list args);
تُستخدم دوال printf
هذه من قبل ملفات .c
في دلائل src/
و cli/
حيثما كانت الحاجة إلى stdio لضمان معالجة تخزين المخرجات بطريقة موحدة.
In special cases, like signal handlers, where the full libuv infrastructure is too heavy, jl_safe_printf()
can be used to write(2)
directly to STDERR_FILENO
:
void jl_safe_printf(const char *str, ...);
Interface between JL_STD* and Julia code
Base.stdin
، Base.stdout
و Base.stderr
مرتبطة بـ JL_STD*
تدفقات libuv المعرفة في وقت التشغيل.
تقوم دالة __init__()
في base/sysimg.jl
باستدعاء reinit_stdio()
(في base/stream.jl
) لإنشاء كائنات جوليا لـ Base.stdin
، Base.stdout
و Base.stderr
.
reinit_stdio()
يستخدم ccall
لاسترجاع مؤشرات إلى JL_STD*
ويستدعي jl_uv_handle_type()
لفحص نوع كل دفق. ثم ينشئ كائن Base.IOStream
أو Base.TTY
أو Base.PipeEndpoint
في جوليا لتمثيل كل دفق، على سبيل المثال:
$ 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/null
Tuple{IOStream,Base.TTY,IOStream}
$ echo hello | julia -e 'println(typeof((stdin, stdout, stderr)))' | cat
Tuple{Base.PipeEndpoint,Base.PipeEndpoint,Base.TTY}
تستخدم طرق Base.read
و Base.write
لهذه التدفقات ccall
لاستدعاء أغلفة libuv في src/jl_uv.c
، على سبيل المثال:
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, ...)
printf() during initialization
تستند تدفقات libuv المستخدمة بواسطة jl_printf()
وما إلى ذلك، إلى أن تكون متاحة حتى منتصف عملية تهيئة وقت التشغيل (انظر init.c
، init_stdio()
). يتم توجيه رسائل الخطأ أو التحذيرات التي تحتاج إلى الطباعة قبل ذلك إلى دالة مكتبة C القياسية fwrite()
من خلال الآلية التالية:
في sys.c
، يتم تهيئة مؤشرات تدفق JL_STD*
بشكل ثابت إلى ثوابت عددية: STD*_FILENO (0 و 1 و 2)
. في jl_uv.c
، تتحقق دالة jl_uv_puts()
من وسيطها uv_stream_t* stream
وتستدعي fwrite()
إذا كان التدفق مضبوطًا على STDOUT_FILENO
أو STDERR_FILENO
.
هذا يسمح بالاستخدام الموحد لـ jl_printf()
طوال وقت التشغيل بغض النظر عما إذا كان أي جزء معين من الشيفرة قابلاً للوصول قبل اكتمال التهيئة.
Legacy ios.c
library
مكتبة src/support/ios.c
موروثة من femtolisp. إنها توفر إدخال/إخراج ملفات مؤقتة عبر الأنظمة الأساسية وذاكرات مؤقتة في الذاكرة.
ios.c
لا يزال يُستخدم من قبل:
src/flisp/*.c
src/dump.c
– لعمليات الإدخال والإخراج للملفات التسلسلية ولذاكرات التخزين.src/staticdata.c
– لعمليات الإدخال والإخراج للملفات التسلسلية ولذاكرات التخزين.base/iostream.jl
– لعمليات الإدخال والإخراج للملفات (انظرbase/fs.jl
لبديل libuv).
استخدام ios.c
في هذه الوحدات هو في الغالب مستقل ومفصول عن نظام الإدخال/الإخراج libuv. ومع ذلك، هناك one place حيث تستدعي femtolisp من خلال jl_printf()
مع دفق ios_t
قديم.
هناك اختراق في ios.h
يجعل حقل ios_t.bm
يتماشى مع uv_stream_t.type
ويضمن أن القيم المستخدمة لـ ios_t.bm
لا تتداخل مع قيم UV_HANDLE_TYPE
الصالحة. هذا يسمح لمؤشرات uv_stream_t
بالإشارة إلى تدفقات ios_t
.
هذا مطلوب لأن jl_printf()
المتصل بـ jl_static_show()
يتم تمرير دفق ios_t
بواسطة دالة fl_print()
في فمتوليسب. تحتوي دالة jl_uv_puts()
في جوليا على معالجة خاصة لذلك:
if (stream->type > UV_HANDLE_TYPE_MAX) {
return ios_write((ios_t*)stream, str, n);
}