Skip to content
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

Merged
merged 2 commits into from
Feb 16, 2015
Merged

Commits on Feb 10, 2015

  1. Refactor to reduce dependancy on ios.c

    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.
    samoconnor committed Feb 10, 2015
    Configuration menu
    Copy the full SHA
    b75971b View commit details
    Browse the repository at this point in the history
  2. Refinement per @vtjnash comments.

    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.
    samoconnor committed Feb 10, 2015
    24 Configuration menu
    Copy the full SHA
    2af73dd View commit details
    Browse the repository at this point in the history