-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JL_STD* vs ios_std* cleanup #9450
Conversation
Missing several Once it's working, seems like a good idea. |
looks like the Travis OSX build is stuck trying to download a new version of mpfr ?? |
cc @staticfloat for the Travis OS X problem |
I think it's a SourceForge problem, I doubt Elliot can do anything about it other than encourage the Homebrew maintainers to switch to S3. |
Hey well aside from the OSX Travis timeout, that seemed to work, no new warnings on Windows now and it passes tests (AppVeyor doing its job nicely there). I'm not so sure about the asserts and the fallback behavior in |
@@ -1306,7 +1306,7 @@ DLLEXPORT void jl_save_system_image(const char *fname) | |||
htable_reset(&backref_table, 250000); | |||
ios_t f; | |||
if (ios_file(&f, fname, 1, 1, 1, 1) == NULL) { | |||
JL_PRINTF(JL_STDERR, "Cannot open system image file \"%s\" for writing.\n", fname); | |||
jl_printf(JL_STDERR, "Cannot open system image file \"%s\" for writing.\n", fname); | |||
exit(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jl_exit
re static initializers: man stdio says:
|
Good catch. Use the numbers 0,1, 2 then (cast as pointers) |
@@ -125,7 +125,7 @@ void parse_opts(int *argcp, char ***argvp) | |||
jl_compileropts.cpu_target = strdup(optarg); | |||
break; | |||
case 'h': | |||
ios_printf(ios_stdout, "%s%s", usage, opts); | |||
jl_printf(JL_STDERR, "%s%s", usage, opts); | |||
exit(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you are calling jl_printf
, then you must call jl_exit
(even though we know that in this case it short-circuits and just calls fprintf
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling jl_exit() this early causes a segfault.
I guess there is not enough stuff initialised yet.
I'll look into making jl_exit() safe against early calls...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, i wondered if it might. jl_exit
assumes that you've successfully made it through julia_init
(although clearly there are cases where it gets called inside of julia_init
, so i'm not sure what would happen there)
My first implementation did use STDOUT_FILENO, ... (i.e. 0, 1, 2 & 3). I could always define some non-zero static constants and use them instead. |
some non-zero static constants sounds good then. it'll help it segfault faster if someone uses the wrong function on them |
Thanks @vtjnash for all your feedback. |
if (!jl_ExecutionEngine) { | ||
JL_PRINTF(JL_STDERR, "Critical error initializing llvm: ", ErrorStr.c_str()); | ||
jl_printf(JL_STDERR, "Critical error initializing llvm: ", ErrorStr.c_str()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jl_errorf ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would probably have the same effect.
However, per my note Jan 19, the time I can spend on this PR is now very limited.
I'll attempt to make things right if places are found where I've broken something.
But, I dont intend to add any more new changes on top of the existing refactoring.
bump - see comment Jan 19 |
Which one? It went conflict-stale again like I thought it would. Will you have time to rebase this, or will @vtjnash have to adopt the branch to get it rebased for merging? He's the main person qualified to make the final decision on it. |
rebased again... |
rebased again for review by @vtjnash |
Rationale: Unravel ios.c’s legacy role as debug io library for the runtime; vs current role as backend for iostream.jl. Clean up historical debug printf functions: Replace calls to ios_printf(), ios_puts(), JL_PRINTF, JL_PUTS etc with jl_printf(), jl_puts()... Replace exit() with jl_exit() in repl.c, dump.c and init.c. Make jl_printf() and jl_exit() safe in early initialisation. Remove ios.c dependance from ast.c and builtins.c: src/flisp/flisp.c: New fl_load_system_image_str(char*, size_t) Hides detail of ios_static_buffer from ast.c ios_* no longer used in ast.c. src/builtins.c In jl_errorf(), replace ios_vprintf() with vasprintf() (following the precedent set by src/jl_uv.c:663). Use free() not LLT_FREE() to clean up after vasprintf() in jl_uv.c: man vasprintf says “asprintf() and vasprintf() dynamically allocate a new string with malloc(3)” Refactor pairs of calls to jl_printf() & jl_exit(1) into calls to jl_error[f](), which does the same thing during early init. Dead code removal: jl_uv.c: jl_bufptr(), jl_ios_buf_base(), jl_putc(), jl_pututf8() sys.c: jl_ios_size() New jl_safe_printf(). jl_safe_printf() uses a statically allocated 1000 byte buffer to vnsprintf() a message then calls write(2) to send it to stderr. jl_safe_printf() is intended to be used in places where there is the potential for out of memory, corrupted stack, re-entrancy etc. The current jl_safe_printf() implementation is not 100% safe in all situations, but it should be pretty good most of the time, especially if the formatting is limited to %d. The safety of jl_safe_printf() could be improved later, but at least for now the places were safety might matter are identified by its use. jl_safe_printf() is used in: - sigdie_handler() - sigint_handler() - _exception_handler() - catch_exception_raise() - gdblookup() Thanks to @vtjnash for assistance and feedback with these changes. Dead code cleanup & jl_write() simplificaiton. Clean up dead code: stream.jl : write!() — My apologies if this is used somewhere, I could’t find any doc or callers. builtins.c : jl_print_symbol(), jl_print_int64() ccall.cpp : if(0 …) jl_puts() jl_uv.c : jl_puts Replace 2 remaining calls to jl_puts() with calls to jl_printf() for consistency. builtins.c : jl_error() repl.c : true_main() Move jl_uv_writecb() implementation from stream.jl to jl_uv.c. This callback is only used by jl_write(), which is only called from jl_vprintf() in runtime C code. This helps to de-tangle fs.jl and stream.jl from the runtime's printf(). Use jl_safe_printf() to attempt error message output in jl_uv_writecb(). If this callback is printing an error, there was a problem writing to JL_STDOUT or JL_STDERR, so its best to try the simpelest means possible to get the error out. update doc/devdocs/stdio.rst to remove reference to: jl_write(), jl_putc(), jl_puts(). Simplify handling of STDOUT and STDERR early in initialisation: Instead of calling fwrite(), just call uv_default_loop() to get the jl_io_loop and then call jl_fs_write as usual. This means that all jl_printf()s now go through uvlib. There is a chance that this won’t work in win32, AppVeyor will tell... Remove C interface for single character writes: - jl_fs_write_byte() - jl_putc_copy() - jl_pututf8_copy() Hadnle single character writes in Julia: - write(f::File, c::UInt8) = write(f, [c]) - write(s::AsyncStream, b::UInt8) = write(s, [b]) - write(s::AsyncStream, c::Char) = write(s, string(c)) Rationale: - Writing to a libuv stream involves: "Julia does C malloc, Julia calls C, C calls libuv, libuv calls C callback, C callback calls julia hook, C callcback does c_free". Having less special cases of this makes it easier to reason about correctness. - Whatever overhead there might be in creating the temporary 1 element array (or string); it is small compared to all the machinery in libuv, and the OS that actually makes the single character write happen. - If a user is doing single character writes to a libuv stream, they either don’t care about performance, or they should be buffering in Julia before calling write(). Inline jl_write_copy() into only remaining called: jl_write(): - This is now the only place that needs to know about the trick used to store a copy of the output string after the request struct (i.e. malloc(sizeof(uv_write_t) + n)); Removed dead code: - stream.jl : make_stdout_stream() - stream.jl : jl_write_copy() Rename: - jl_write_no_copy() -> jl_uv_write() Move common code from stream.jl write() functions into uv_write macro: - ccall to jl_uv_write() (was jl_write_no_copy). - wait for current task Simplify uv_write memory management: Try to keep all the state management in one place (in macto uv_write()). Move free() of uv_write_t request object from C callback jl_uv_writecb_task() to macro uv_write(). This puts the malloc() and the free() in the same place. Move uv_req_set_data(uvw,C_NULL) from C jl_uv_write() to macro uv_write(). In _uv_hook_writecb_task() assert that uv_req_data(req) is not NULL. libuv should not call the callback from within the call to uv_write(), libuv has an internal “write_completed_queue” that is pumped by the main loop.
Make uv_write() a function (was a macro) and do c_free in "finally" clause. Explicit null-termination in jl_safe_printf() to allow for win32's non-posix vsnprintf behaviour. See also JuliaLang#9624. Use jl_safe_printf() in profile thread. Send help message to jl_printf(JL_STDOUT,) was stderr.
uv_error("write",err) | ||
1 | ||
end | ||
write(f::File, c::UInt8) = write(f,[c]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would worry about the performance of allocating an array here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be handled by jl_fs_write
, passing &c
as the data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would argue that this is not the right layer to deal with performance of single-byte writes.
The OS implementation of the single-byte write involves a sys-call, maybe a network stack, etc... it is expensive.
If the caller needs to efficiently write lots of single bytes, they should write to a buffer interface that wraps the raw io interface.
Is there a particular use-pattern in current Julia code where single character writes to File are performance critical?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JeffBezanson you have to be careful there, since we could execute a task switch and invalid the stack slot before it gets written out
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @vtjnash,
Sorry, I'm afraid I don't quite understand.
Are you saying that the user of a buffered interface might write a character that does not get sent because it is left in the buffer? ... in that case they should call buffer.flush(). No?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that was addressed to Jeff's comment. just bad timing as we both typed replies at the same time
still conflict clean at this point... |
JL_STD* vs ios_std* cleanup
Thanks, very nice cleanup. |
👍 |
Use jl_printf(), jl_puts() etc instead of ios_printf(), JL_PRINTF(), fprintf() etc for consistency.
Make jl_printf(JL_STD*, ...), jl_puts() safe in very early stages of initialisation.
Try to remove miscellaneous ios.c dependencies.
Remaining ios.c dependencies are:
See detail in commit logs and discussion here:
https://groups.google.com/forum/?fromgroups=#!topic/julia-dev/UlfIRvX0_nw