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

process: implement getpid #30013

Merged
merged 1 commit into from
Nov 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ New library functions

* `splitpath(p::String)` function, which is the opposite of `joinpath(parts...)`: it splits a filepath into its components ([#28156]).
* `isnothing(::Any)` function, to check whether something is a `Nothing`, returns a `Bool` ([#29679]).
* `getpid(::Process)` method ([#24064]).


Standard library changes
------------------------
Expand Down
19 changes: 17 additions & 2 deletions base/process.jl
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ function uv_return_spawn(p::Ptr{Cvoid}, exit_status::Int64, termsignal::Int32)
proc.exitcode = exit_status
proc.termsignal = termsignal
ccall(:jl_close_uv, Cvoid, (Ptr{Cvoid},), proc.handle)
proc.handle = C_NULL
notify(proc.exitnotify)
nothing
end
Expand Down Expand Up @@ -682,7 +683,7 @@ function test_success(proc::Process)
#TODO: this codepath is not currently tested
throw(_UVError("could not start process $(string(proc.cmd))", proc.exitcode))
end
proc.exitcode == 0 && (proc.termsignal == 0 || proc.termsignal == SIGPIPE)
return proc.exitcode == 0 && (proc.termsignal == 0 || proc.termsignal == SIGPIPE)
end

function success(x::Process)
Expand Down Expand Up @@ -744,6 +745,20 @@ kill(ps::Vector{Process}) = foreach(kill, ps)
kill(ps::ProcessChain) = foreach(kill, ps.processes)
kill(p::Process) = kill(p, SIGTERM)

"""
getpid(process) -> Int32

Get the child process ID, if it still exists.
"""
function Libc.getpid(p::Process)
ppid = Int32(0)
if p.handle != C_NULL
ppid = ccall(:jl_uv_process_pid, Int32, (Ptr{Cvoid},), p.handle)
end
ppid <= 0 && throw(_UVError("getpid", UV_ESRCH))
return ppid
end

function _contains_newline(bufptr::Ptr{Cvoid}, len::Int32)
return (ccall(:memchr, Ptr{Cvoid}, (Ptr{Cvoid},Int32,Csize_t), bufptr, '\n', len) != C_NULL)
end
Expand All @@ -755,7 +770,7 @@ end

Determine whether a process is currently running.
"""
process_running(s::Process) = s.exitcode == typemin(fieldtype(Process, :exitcode))
process_running(s::Process) = s.handle != C_NULL
process_running(s::Vector{Process}) = any(process_running, s)
process_running(s::ProcessChain) = process_running(s.processes)

Expand Down
7 changes: 4 additions & 3 deletions src/jl_uv.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ void jl_uv_flush(uv_stream_t *stream)
return;
while (uv_is_writable(stream) && stream->write_queue_size != 0) {
int fired = 0;
uv_buf_t buf;
buf.base = (char*)(&buf + 1);
buf.len = 0;
uv_buf_t buf;
buf.base = (char*)(&buf + 1);
buf.len = 0;
uv_write_t *write_req = (uv_write_t*)malloc(sizeof(uv_write_t));
write_req->data = (void*)&fired;
if (uv_write(write_req, stream, &buf, 1, uv_flush_callback) != 0)
Expand All @@ -165,6 +165,7 @@ void jl_uv_flush(uv_stream_t *stream)
}

// getters and setters
JL_DLLEXPORT int jl_uv_process_pid(uv_process_t *p) { return p->pid; }
JL_DLLEXPORT void *jl_uv_process_data(uv_process_t *p) { return p->data; }
JL_DLLEXPORT void *jl_uv_buf_base(const uv_buf_t *buf) { return buf->base; }
JL_DLLEXPORT size_t jl_uv_buf_len(const uv_buf_t *buf) { return buf->len; }
Expand Down
8 changes: 6 additions & 2 deletions test/spawn.jl
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,14 @@ if valgrind_off
end

# setup_stdio for AbstractPipe
let out = Pipe(), proc = run(pipeline(`$echocmd "Hello World"`, stdout=IOContext(out,stdout)), wait=false)
let out = Pipe(),
proc = run(pipeline(`$exename --startup-file=no -e 'println(getpid())'`, stdout=IOContext(out, :foo => :bar)), wait=false)
# < don't block here before getpid call >
pid = getpid(proc)
close(out.in)
@test read(out, String) == "Hello World\n"
@test parse(Int32, read(out, String)) === pid > 1
@test success(proc)
@test_throws Base.IOError getpid(proc)
end

# issue #5904
Expand Down