From b87ab6084f3bd1ff5cb05cd40986f8162a45e469 Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 18 Nov 2018 13:57:12 -0500 Subject: [PATCH] process: implement `getpid` (#30013) Closes #4752 --- NEWS.md | 2 ++ base/process.jl | 19 +++++++++++++++++-- src/jl_uv.c | 7 ++++--- test/spawn.jl | 8 ++++++-- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/NEWS.md b/NEWS.md index 851575c3d0702..035b3ffd6094a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 ------------------------ diff --git a/base/process.jl b/base/process.jl index b78dd2cc6db82..0c703eacdd312 100644 --- a/base/process.jl +++ b/base/process.jl @@ -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 @@ -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) @@ -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 @@ -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) diff --git a/src/jl_uv.c b/src/jl_uv.c index 27d1e3de6cd06..b2081a7f2eac8 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -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) @@ -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; } diff --git a/test/spawn.jl b/test/spawn.jl index aa2c4001752ce..9ebdcdef3a505 100644 --- a/test/spawn.jl +++ b/test/spawn.jl @@ -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