Skip to content

Commit

Permalink
Dup FD when converting an IO object to a FILE*
Browse files Browse the repository at this point in the history
@JeffBezanson and I decided that was the best way to go about handling the issue that
fdopen wants to take ownership of the file descriptor. In this way the two objects
are independent and everything should work in the general case. Also add a close method
to Libc.FILE, which can now always be safely called (assuming of course that it isn't
closed by the C function it gets passed to).

Finally, move RawFD and dup to Libc, since they're part of the C library anyway.
  • Loading branch information
Keno committed Mar 19, 2015
1 parent 8d21ac8 commit 20497c1
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 17 deletions.
21 changes: 20 additions & 1 deletion base/libc.jl
Expand Up @@ -6,6 +6,22 @@ export FILE, TmStruct, strftime, strptime, getpid, gethostname, free, malloc, ca

include("errno.jl")

## RawFD ##

#Wrapper for an OS file descriptor (on both Unix and Windows)
immutable RawFD
fd::Int32
RawFD(fd::Integer) = new(fd)
RawFD(fd::RawFD) = fd
end

Base.convert(::Type{Int32}, fd::RawFD) = fd.fd

dup(x::RawFD) = RawFD(ccall((@windows? :_dup : :dup),Int32,(Int32,),x.fd))
dup(src::RawFD,target::RawFD) = systemerror("dup",-1==
ccall((@windows? :_dup2 : :dup2),Int32,
(Int32,Int32),src.fd,target.fd))

## FILE ##

immutable FILE
Expand All @@ -23,10 +39,13 @@ function FILE(fd, mode)
end

function FILE(s::IO)
f = FILE(fd(s),modestr(s))
f = FILE(dup(RawFD(fd(s))),modestr(s))
seek(f, position(s))
f
end

Base.unsafe_convert(T::Union(Type{Ptr{Void}},Type{Ptr{FILE}}), f::FILE) = convert(T, f.ptr)
Base.close(f::FILE) = systemerror("fclose", ccall(:fclose, Cint, (Ptr{Void},), f.ptr) != 0)
Base.convert(::Type{FILE}, s::IO) = FILE(s)

function Base.seek(h::FILE, offset::Integer)
Expand Down
16 changes: 2 additions & 14 deletions base/stream.jl
@@ -1,6 +1,8 @@
#TODO: Move stdio detection from C to Julia (might require some Clang magic)
include("uv_constants.jl")

import .Libc: RawFD, dup

## types ##
typealias Callback Union(Function,Bool)

Expand All @@ -17,15 +19,6 @@ const uvhandles = ObjectIdDict()
preserve_handle(x) = uvhandles[x] = get(uvhandles,x,0)+1
unpreserve_handle(x) = (v = uvhandles[x]; v == 1 ? pop!(uvhandles,x) : (uvhandles[x] = v-1); nothing)

#Wrapper for an OS file descriptor (on both Unix and Windows)
immutable RawFD
fd::Int32
RawFD(fd::Integer) = new(fd)
RawFD(fd::RawFD) = fd
end

convert(::Type{Int32}, fd::RawFD) = fd.fd

function uv_sizeof_handle(handle)
if !(UV_UNKNOWN_HANDLE < handle < UV_HANDLE_TYPE_MAX)
throw(DomainError())
Expand Down Expand Up @@ -944,11 +937,6 @@ end

connect(path::AbstractString) = connect(Pipe(),path)

dup(x::RawFD) = RawFD(ccall((@windows? :_dup : :dup),Int32,(Int32,),x.fd))
dup(src::RawFD,target::RawFD) = systemerror("dup",-1==
ccall((@windows? :_dup2 : :dup2),Int32,
(Int32,Int32),src.fd,target.fd))

_fd(x::IOStream) = RawFD(fd(x))
@unix_only _fd(x::AsyncStream) = RawFD(ccall(:jl_uv_handle,Int32,(Ptr{Void},),x.handle))
@windows_only _fd(x::AsyncStream) = WindowsRawSocket(
Expand Down
4 changes: 2 additions & 2 deletions test/file.jl
Expand Up @@ -388,11 +388,12 @@ rm(cfile)

function test_LibcFILE(FILEp)
buf = Array(UInt8, 8)
str = ccall(:fread, Csize_t, (Ptr{Void}, Csize_t, Csize_t, Ptr{Void}), buf, 1, 8, FILEp.ptr)
str = ccall(:fread, Csize_t, (Ptr{Void}, Csize_t, Csize_t, Ptr{Void}), buf, 1, 8, FILEp)
@test bytestring(buf) == "Hello, w"
@test position(FILEp) == 8
seek(FILEp, 5)
@test position(FILEp) == 5
close(FILEp)
end

f = open(file, "w")
Expand All @@ -404,7 +405,6 @@ close(f)
@unix_only f = RawFD(ccall(:open, Cint, (Ptr{Uint8}, Cint), file, Base.FS.JL_O_RDONLY))
@windows_only f = RawFD(ccall(:_open, Cint, (Ptr{Uint8}, Cint), file, Base.FS.JL_O_RDONLY))
test_LibcFILE(Libc.FILE(f,Libc.modestr(true,false)))
ccall(:close, Void, (Cint,), f)

############
# Clean up #
Expand Down

0 comments on commit 20497c1

Please sign in to comment.