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/*.csrc/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);
}