diff --git a/NEWS.md b/NEWS.md index 2c639df77898a..55640e6516b93 100644 --- a/NEWS.md +++ b/NEWS.md @@ -284,6 +284,9 @@ Deprecated or removed `Array{T}(x)`, `map(T,x)`, or `round(T,x)`. To parse a string as an integer or floating-point number, use `parseint` or `parsefloat` ([#1470], [#6211]). + * Low-level functions from the C library and dynamic linker have been moved to + modules `Libc` and `Libdl`, respectively ([#10328]). + Julia v0.3.0 Release Notes ========================== diff --git a/base/REPL.jl b/base/REPL.jl index d4faf005a2758..5b16221278564 100644 --- a/base/REPL.jl +++ b/base/REPL.jl @@ -361,7 +361,7 @@ function add_history(hist::REPLHistoryProvider, s) push!(hist.history, str) hist.history_file == nothing && return entry = """ - # time: $(strftime("%Y-%m-%d %H:%M:%S %Z", time())) + # time: $(Libc.strftime("%Y-%m-%d %H:%M:%S %Z", time())) # mode: $mode $(replace(str, r"^"ms, "\t")) """ diff --git a/base/base.jl b/base/base.jl index c3ad12722383b..5940c40099257 100644 --- a/base/base.jl +++ b/base/base.jl @@ -74,7 +74,7 @@ type SystemError <: Exception prefix::AbstractString errnum::Int32 SystemError(p::AbstractString, e::Integer) = new(p, e) - SystemError(p::AbstractString) = new(p, errno()) + SystemError(p::AbstractString) = new(p, Libc.errno()) end type TypeError <: Exception diff --git a/base/c.jl b/base/c.jl index 872414be19bc0..4138b8d7161ae 100644 --- a/base/c.jl +++ b/base/c.jl @@ -2,42 +2,7 @@ import Core.Intrinsics.cglobal -# constants to match JL_RTLD_* in src/julia.h -const RTLD_LOCAL = 0x00000000 -const RTLD_GLOBAL = 0x00000001 -const RTLD_LAZY = 0x00000002 -const RTLD_NOW = 0x00000004 -const RTLD_NODELETE = 0x00000008 -const RTLD_NOLOAD = 0x00000010 -const RTLD_DEEPBIND = 0x00000020 -const RTLD_FIRST = 0x00000040 - -function dlsym(hnd::Ptr, s::Union(Symbol,AbstractString)) - hnd == C_NULL && error("NULL library handle") - ccall(:jl_dlsym, Ptr{Void}, (Ptr{Void}, Ptr{UInt8}), hnd, s) -end - -function dlsym_e(hnd::Ptr, s::Union(Symbol,AbstractString)) - hnd == C_NULL && error("NULL library handle") - ccall(:jl_dlsym_e, Ptr{Void}, (Ptr{Void}, Ptr{UInt8}), hnd, s) -end - -dlopen(s::Symbol, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = - dlopen(string(s), flags) - -dlopen(s::AbstractString, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = - ccall(:jl_load_dynamic_library, Ptr{Void}, (Ptr{UInt8},UInt32), s, flags) - -dlopen_e(s::AbstractString, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = - ccall(:jl_load_dynamic_library_e, Ptr{Void}, (Ptr{UInt8},UInt32), s, flags) - -dlopen_e(s::Symbol, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = - dlopen_e(string(s), flags) - -dlclose(p::Ptr) = if p!=C_NULL; ccall(:uv_dlclose,Void,(Ptr{Void},),p); end - -cfunction(f::Function, r, a) = - ccall(:jl_function_ptr, Ptr{Void}, (Any, Any, Any), f, r, a) +cfunction(f::Function, r, a) = ccall(:jl_function_ptr, Ptr{Void}, (Any, Any, Any), f, r, a) if ccall(:jl_is_char_signed, Any, ()) typealias Cchar Int8 @@ -90,28 +55,6 @@ sigatomic_end() = ccall(:jl_sigatomic_end, Void, ()) disable_sigint(f::Function) = try sigatomic_begin(); f(); finally sigatomic_end(); end reenable_sigint(f::Function) = try sigatomic_end(); f(); finally sigatomic_begin(); end -# flush C stdio output from external libraries -flush_cstdio() = ccall(:jl_flush_cstdio, Void, ()) - -function find_library{T<:ByteString, S<:ByteString}(libnames::Array{T,1}, extrapaths::Array{S,1}=ASCIIString[]) - for lib in libnames - for path in extrapaths - l = joinpath(path, lib) - p = dlopen_e(l, RTLD_LAZY) - if p != C_NULL - dlclose(p) - return l - end - end - p = dlopen_e(lib, RTLD_LAZY) - if p != C_NULL - dlclose(p) - return lib - end - end - return "" -end - function ccallable(f::Function, rt::Type, argt::(Type...), name::Union(AbstractString,Symbol)=string(f)) ccall(:jl_extern_c, Void, (Any, Any, Any, Ptr{UInt8}), f, rt, argt, name) end diff --git a/base/dates/conversions.jl b/base/dates/conversions.jl index 36528a954e1f9..d4da50dc60f97 100644 --- a/base/dates/conversions.jl +++ b/base/dates/conversions.jl @@ -18,7 +18,7 @@ end # Returns unix seconds since 1970-01-01T00:00:00 datetime2unix(dt::DateTime) = (value(dt) - UNIXEPOCH)/1000.0 function now() - tm = TmStruct(time()) + tm = Libc.TmStruct(time()) return DateTime(tm.year+1900,tm.month+1,tm.mday,tm.hour,tm.min,tm.sec) end today() = Date(now()) diff --git a/base/deprecated.jl b/base/deprecated.jl index 3c36ef8b19ec8..35740aa52db0f 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -100,8 +100,6 @@ const Range1 = UnitRange @deprecate set_bigfloat_rounding(r::RoundingMode) set_rounding(BigFloat,r) @deprecate get_bigfloat_rounding() get_rounding(BigFloat) @deprecate with_bigfloat_rounding(f::Function, r::RoundingMode) with_rounding(f::Function, BigFloat, r) -eval(Sys, :(@deprecate shlib_list dllist)) -# Sys.shlib_ext is deprecated, renamed to Sys.dlext. Remove alias before release @deprecate degrees2radians deg2rad @deprecate radians2degrees rad2deg @@ -423,6 +421,24 @@ end @deprecate flipud(A::AbstractArray) flipdim(A, 1) @deprecate fliplr(A::AbstractArray) flipdim(A, 2) +@deprecate strftime Libc.strftime +@deprecate strptime Libc.strptime +@deprecate flush_cstdio Libc.flush_cstdio +@deprecate mmap Libc.mmap +@deprecate c_free Libc.free +@deprecate c_malloc Libc.malloc +@deprecate c_calloc Libc.calloc +@deprecate c_realloc Libc.realloc +@deprecate errno Libc.errno +@deprecate strerror Libc.strerror + +@deprecate dlclose Libdl.dlclose +@deprecate dlopen Libdl.dlopen +@deprecate dlopen_e Libdl.dlopen_e +@deprecate dlsym Libdl.dlsym +@deprecate dlsym_e Libdl.dlsym_e +@deprecate find_library Libdl.find_library + # 0.4 discontinued functions @noinline function subtypetree(x::DataType, level=-1) diff --git a/base/env.jl b/base/env.jl index 13adfe3e201e8..8355ba4583822 100644 --- a/base/env.jl +++ b/base/env.jl @@ -1,5 +1,3 @@ -## core libc calls ## - @unix_only begin _getenv(var::AbstractString) = ccall(:getenv, Ptr{UInt8}, (Ptr{UInt8},), var) _hasenv(s::AbstractString) = _getenv(s) != C_NULL diff --git a/base/error.jl b/base/error.jl index f2ca82c27e61d..b1da72a6418f7 100644 --- a/base/error.jl +++ b/base/error.jl @@ -33,10 +33,6 @@ kwerr(kw) = error("unrecognized keyword argument \"", kw, "\"") ## system error handling ## -errno() = ccall(:jl_errno, Cint, ()) -errno(e::Integer) = ccall(:jl_set_errno, Void, (Cint,), e) -strerror(e::Integer) = bytestring(ccall(:strerror, Ptr{UInt8}, (Int32,), e)) -strerror() = strerror(errno()) systemerror(p, b::Bool) = b ? throw(SystemError(string(p))) : nothing ## assertion functions and macros ## diff --git a/base/exports.jl b/base/exports.jl index 07fe6b9b3b4a2..f8cd1de2fa4f9 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -9,6 +9,8 @@ export Dates, Sys, Test, + Libc, + Libdl, LinAlg, BLAS, LAPACK, @@ -34,7 +36,6 @@ export BufferStream, CartesianIndex, CartesianRange, - CFILE, Cmd, Colon, Complex, @@ -108,7 +109,6 @@ export Symmetric, SymTridiagonal, Timer, - TmStruct, Tridiagonal, UnitRange, UpperTriangular, @@ -164,7 +164,6 @@ export ARGS, C_NULL, CPU_CORES, - DL_LOAD_PATH, ENDIAN_BOM, ENV, Inf, @@ -172,21 +171,10 @@ export Inf32, JULIA_HOME, LOAD_PATH, - MS_ASYNC, - MS_INVALIDATE, - MS_SYNC, NaN, NaN16, NaN32, OS_NAME, - RTLD_DEEPBIND, - RTLD_FIRST, - RTLD_GLOBAL, - RTLD_LAZY, - RTLD_LOCAL, - RTLD_NODELETE, - RTLD_NOLOAD, - RTLD_NOW, STDERR, STDIN, STDOUT, @@ -1022,8 +1010,6 @@ export # time sleep, - strftime, - strptime, tic, time, time_ns, @@ -1132,7 +1118,6 @@ export fd, fdio, flush, - flush_cstdio, getaddrinfo, gethostname, getipaddr, @@ -1145,7 +1130,6 @@ export listenany, ltoh, mark, - mmap, mmap_array, mmap_bitarray, msync, @@ -1317,25 +1301,13 @@ export success, # C interface - c_free, - c_malloc, - c_calloc, - c_realloc, cfunction, cglobal, disable_sigint, - dlclose, - dlopen, - dlopen_e, - dlsym, - dlsym_e, - errno, - find_library, pointer, pointer_from_objref, pointer_to_array, reenable_sigint, - strerror, unsafe_copy!, unsafe_load, unsafe_pointer_to_objref, diff --git a/base/file.jl b/base/file.jl index 5b517f7c47a6b..285157b27ec18 100644 --- a/base/file.jl +++ b/base/file.jl @@ -104,7 +104,7 @@ function tempname() p = ccall(:tempnam, Ptr{UInt8}, (Ptr{UInt8},Ptr{UInt8}), d, "julia") systemerror(:tempnam, p == C_NULL) s = bytestring(p) - c_free(p) + Libc.free(p) return s end @@ -164,7 +164,7 @@ function mktempdir() if ret == 0 return filename end - systemerror(:mktempdir, errno()!=EEXIST) + systemerror(:mktempdir, Libc.errno()!=EEXIST) seed += 1 end end diff --git a/base/fs.jl b/base/fs.jl index 9a372eb4cd57d..442f2373f6040 100644 --- a/base/fs.jl +++ b/base/fs.jl @@ -70,12 +70,12 @@ uvtype(::File) = Base.UV_RAW_FD _uv_fs_result(req) = ccall(:jl_uv_fs_result,Int32,(Ptr{Void},),req) function open(f::File,flags::Integer,mode::Integer) - req = c_malloc(_sizeof_uv_fs) + req = Libc.malloc(_sizeof_uv_fs) ret = ccall(:uv_fs_open,Int32,(Ptr{Void},Ptr{Void},Ptr{UInt8},Int32,Int32,Ptr{Void}), eventloop(), req, f.path, flags,mode, C_NULL) f.handle = _uv_fs_result(req) ccall(:uv_fs_req_cleanup,Void,(Ptr{Void},),req) - c_free(req) + Libc.free(req) uv_error("open",ret) f.open = true f @@ -189,19 +189,19 @@ function write{T}(f::File, a::Array{T}) end function truncate(f::File, n::Integer) - req = Base.c_malloc(_sizeof_uv_fs) + req = Base.Libc.malloc(_sizeof_uv_fs) err = ccall(:uv_fs_ftruncate,Int32,(Ptr{Void},Ptr{Void},Int32,Int64,Ptr{Void}), eventloop(),req,f.handle,n,C_NULL) - c_free(req) + Libc.free(req) uv_error("ftruncate", err) f end function futime(f::File, atime::Float64, mtime::Float64) - req = Base.c_malloc(_sizeof_uv_fs) + req = Base.Libc.malloc(_sizeof_uv_fs) err = ccall(:uv_fs_futime,Int32,(Ptr{Void},Ptr{Void},Int32,Float64,Float64,Ptr{Void}), eventloop(),req,f.handle,atime,mtime,C_NULL) - c_free(req) + Libc.free(req) uv_error("futime", err) f end diff --git a/base/iostream.jl b/base/iostream.jl index 058aa09952287..0e4c2c41efead 100644 --- a/base/iostream.jl +++ b/base/iostream.jl @@ -36,8 +36,6 @@ function flush(s::IOStream) end iswritable(s::IOStream) = Bool(ccall(:ios_get_writable, Cint, (Ptr{Void},), s.ios)) isreadable(s::IOStream) = Bool(ccall(:ios_get_readable, Cint, (Ptr{Void},), s.ios)) -modestr(s::IO) = modestr(isreadable(s), iswritable(s)) -modestr(r::Bool, w::Bool) = r ? (w ? "r+" : "r") : (w ? "w" : throw(ArgumentError("neither readable nor writable"))) function truncate(s::IOStream, n::Integer) systemerror("truncate", ccall(:ios_trunc, Int32, (Ptr{Void}, UInt), s.ios, n) != 0) @@ -73,30 +71,6 @@ end eof(s::IOStream) = ccall(:ios_eof_blocking, Int32, (Ptr{Void},), s.ios)!=0 -# For interfacing with C FILE* functions - - -immutable CFILE - ptr::Ptr{Void} -end - -function CFILE(s::IO) - @unix_only FILEp = ccall(:fdopen, Ptr{Void}, (Cint, Ptr{UInt8}), convert(Cint, fd(s)), modestr(s)) - @windows_only FILEp = ccall(:_fdopen, Ptr{Void}, (Cint, Ptr{UInt8}), convert(Cint, fd(s)), modestr(s)) - systemerror("fdopen", FILEp == C_NULL) - seek(CFILE(FILEp), position(s)) -end - -convert(::Type{CFILE}, s::IO) = CFILE(s) - -function seek(h::CFILE, offset::Integer) - systemerror("fseek", ccall(:fseek, Cint, (Ptr{Void}, Clong, Cint), - h.ptr, offset, 0) != 0) - h -end - -position(h::CFILE) = ccall(:ftell, Clong, (Ptr{Void},), h.ptr) - ## constructing and opening streams ## # "own" means the descriptor will be closed with the IOStream diff --git a/base/libc.jl b/base/libc.jl index 9aaa26a346c51..1d1ba0ea8bf05 100644 --- a/base/libc.jl +++ b/base/libc.jl @@ -1,3 +1,40 @@ +module Libc + +export FILE, TmStruct, strftime, strptime, getpid, gethostname, free, malloc, calloc, realloc, + errno, strerror, flush_cstdio, systemsleep, time, + MS_ASYNC, MS_INVALIDATE, MS_SYNC, mmap, munmap, msync + +include("errno.jl") + +## FILE ## + +immutable FILE + ptr::Ptr{Void} +end + +modestr(s::IO) = modestr(isreadable(s), iswritable(s)) +modestr(r::Bool, w::Bool) = r ? (w ? "r+" : "r") : (w ? "w" : throw(ArgumentError("neither readable nor writable"))) + +function FILE(s::IO) + @unix_only FILEp = ccall(:fdopen, Ptr{Void}, (Cint, Ptr{UInt8}), convert(Cint, fd(s)), modestr(s)) + @windows_only FILEp = ccall(:_fdopen, Ptr{Void}, (Cint, Ptr{UInt8}), convert(Cint, fd(s)), modestr(s)) + systemerror("fdopen", FILEp == C_NULL) + seek(FILE(FILEp), position(s)) +end + +Base.convert(::Type{FILE}, s::IO) = FILE(s) + +function Base.seek(h::FILE, offset::Integer) + systemerror("fseek", ccall(:fseek, Cint, (Ptr{Void}, Clong, Cint), + h.ptr, offset, 0) != 0) + h +end + +Base.position(h::FILE) = ccall(:ftell, Clong, (Ptr{Void},), h.ptr) + +# flush C stdio output from external libraries +flush_cstdio() = ccall(:jl_flush_cstdio, Void, ()) + ## time-related functions ## # TODO: check for usleep errors? @@ -68,7 +105,9 @@ function strptime(fmt::AbstractString, timestr::AbstractString) tm end +# system date in seconds time(tm::TmStruct) = Float64(ccall(:mktime, Int, (Ptr{TmStruct},), &tm)) +time() = ccall(:clock_now, Float64, ()) ## process-related functions ## @@ -84,9 +123,78 @@ function gethostname() bytestring(pointer(hn)) end +## system error handling ## + +errno() = ccall(:jl_errno, Cint, ()) +errno(e::Integer) = ccall(:jl_set_errno, Void, (Cint,), e) +strerror(e::Integer) = bytestring(ccall(:strerror, Ptr{UInt8}, (Int32,), e)) +strerror() = strerror(errno()) + ## Memory related ## -c_free(p::Ptr) = ccall(:free, Void, (Ptr{Void},), p) -c_malloc(size::Integer) = ccall(:malloc, Ptr{Void}, (Csize_t,), size) -c_realloc(p::Ptr, size::Integer) = ccall(:realloc, Ptr{Void}, (Ptr{Void}, Csize_t), p, size) -c_calloc(num::Integer, size::Integer) = ccall(:calloc, Ptr{Void}, (Csize_t, Csize_t), num, size) +free(p::Ptr) = ccall(:free, Void, (Ptr{Void},), p) +malloc(size::Integer) = ccall(:malloc, Ptr{Void}, (Csize_t,), size) +realloc(p::Ptr, size::Integer) = ccall(:realloc, Ptr{Void}, (Ptr{Void}, Csize_t), p, size) +calloc(num::Integer, size::Integer) = ccall(:calloc, Ptr{Void}, (Csize_t, Csize_t), num, size) + +## mmap ## + +msync{T}(A::Array{T}) = msync(pointer(A), length(A)*sizeof(T)) + +msync(B::BitArray) = msync(pointer(B.chunks), length(B.chunks)*sizeof(UInt64)) + +@unix_only begin +# Low-level routines +# These are needed for things like MAP_ANONYMOUS +function mmap(len::Integer, prot::Integer, flags::Integer, fd, offset::Integer) + const pagesize::Int = ccall(:jl_getpagesize, Clong, ()) + # Check that none of the computations will overflow + if len < 0 + throw(ArgumentError("requested size must be ≥ 0, got $len")) + end + if len > typemax(Int)-pagesize + throw(ArgumentError("requested size must be ≤ $(typemax(Int)-pagesize), got $len")) + end + # Set the offset to a page boundary + offset_page::FileOffset = floor(Integer,offset/pagesize)*pagesize + len_page::Int = (offset-offset_page) + len + # Mmap the file + p = ccall(:jl_mmap, Ptr{Void}, (Ptr{Void}, Csize_t, Cint, Cint, Cint, FileOffset), C_NULL, len_page, prot, flags, fd, offset_page) + systemerror("memory mapping failed", reinterpret(Int,p) == -1) + # Also return a pointer that compensates for any adjustment in the offset + return p, Int(offset-offset_page) +end + +function munmap(p::Ptr,len::Integer) + systemerror("munmap", ccall(:munmap,Cint,(Ptr{Void},Int),p,len) != 0) +end + +const MS_ASYNC = 1 +const MS_INVALIDATE = 2 +const MS_SYNC = 4 +function msync(p::Ptr, len::Integer, flags::Integer) + systemerror("msync", ccall(:msync, Cint, (Ptr{Void}, Csize_t, Cint), p, len, flags) != 0) +end +msync(p::Ptr, len::Integer) = msync(p, len, MS_SYNC) +end + + +@windows_only begin +function munmap(viewhandle::Ptr, mmaphandle::Ptr) + status = Bool(ccall(:UnmapViewOfFile, stdcall, Cint, (Ptr{Void},), viewhandle)) + status |= Bool(ccall(:CloseHandle, stdcall, Cint, (Ptr{Void},), mmaphandle)) + if !status + error("could not unmap view: $(FormatMessage())") + end +end + +function msync(p::Ptr, len::Integer) + status = Bool(ccall(:FlushViewOfFile, stdcall, Cint, (Ptr{Void}, Csize_t), p, len)) + if !status + error("could not msync: $(FormatMessage())") + end +end + +end + +end # module diff --git a/base/libdl.jl b/base/libdl.jl new file mode 100644 index 0000000000000..3547efe295a35 --- /dev/null +++ b/base/libdl.jl @@ -0,0 +1,137 @@ +module Libdl + +export DL_LOAD_PATH, RTLD_DEEPBIND, RTLD_FIRST, RTLD_GLOBAL, RTLD_LAZY, RTLD_LOCAL, + RTLD_NODELETE, RTLD_NOLOAD, RTLD_NOW, dlclose, dlopen, dlopen_e, dlsym, dlsym_e, + dlpath, find_library, dlext, dllist + +const DL_LOAD_PATH = ByteString[] +@osx_only push!(DL_LOAD_PATH, "@executable_path/../lib/julia") +@osx_only push!(DL_LOAD_PATH, "@executable_path/../lib") + +# constants to match JL_RTLD_* in src/julia.h +const RTLD_LOCAL = 0x00000000 +const RTLD_GLOBAL = 0x00000001 +const RTLD_LAZY = 0x00000002 +const RTLD_NOW = 0x00000004 +const RTLD_NODELETE = 0x00000008 +const RTLD_NOLOAD = 0x00000010 +const RTLD_DEEPBIND = 0x00000020 +const RTLD_FIRST = 0x00000040 + +function dlsym(hnd::Ptr, s::Union(Symbol,AbstractString)) + hnd == C_NULL && error("NULL library handle") + ccall(:jl_dlsym, Ptr{Void}, (Ptr{Void}, Ptr{UInt8}), hnd, s) +end + +function dlsym_e(hnd::Ptr, s::Union(Symbol,AbstractString)) + hnd == C_NULL && error("NULL library handle") + ccall(:jl_dlsym_e, Ptr{Void}, (Ptr{Void}, Ptr{UInt8}), hnd, s) +end + +dlopen(s::Symbol, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = dlopen(string(s), flags) + +dlopen(s::AbstractString, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = + ccall(:jl_load_dynamic_library, Ptr{Void}, (Ptr{UInt8},UInt32), s, flags) + +dlopen_e(s::AbstractString, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = + ccall(:jl_load_dynamic_library_e, Ptr{Void}, (Ptr{UInt8},UInt32), s, flags) + +dlopen_e(s::Symbol, flags::Integer = RTLD_LAZY | RTLD_DEEPBIND) = dlopen_e(string(s), flags) + +dlclose(p::Ptr) = if p!=C_NULL; ccall(:uv_dlclose,Void,(Ptr{Void},),p); end + +function find_library{T<:ByteString, S<:ByteString}(libnames::Array{T,1}, extrapaths::Array{S,1}=ASCIIString[]) + for lib in libnames + for path in extrapaths + l = joinpath(path, lib) + p = dlopen_e(l, RTLD_LAZY) + if p != C_NULL + dlclose(p) + return l + end + end + p = dlopen_e(lib, RTLD_LAZY) + if p != C_NULL + dlclose(p) + return lib + end + end + return "" +end + +function dlpath( handle::Ptr{Void} ) + p = ccall( :jl_pathname_for_handle, Ptr{UInt8}, (Ptr{Void},), handle ) + s = bytestring(p) + @windows_only Libc.free(p) + return s +end + +function dlpath(libname::Union(AbstractString, Symbol)) + handle = dlopen(libname) + path = dlpath(handle) + dlclose(handle) + return path +end + +if OS_NAME === :Darwin + const dlext = "dylib" +elseif OS_NAME === :Windows + const dlext = "dll" +else + #assume OS_NAME === :Linux, or similar + const dlext = "so" +end + +@linux_only begin + immutable dl_phdr_info + # Base address of object + addr::Cuint + + # Null-terminated name of object + name::Ptr{UInt8} + + # Pointer to array of ELF program headers for this object + phdr::Ptr{Void} + + # Number of program headers for this object + phnum::Cshort + end + + # This callback function called by dl_iterate_phdr() on Linux + function dl_phdr_info_callback(di::dl_phdr_info, size::Csize_t, dynamic_libraries::Array{AbstractString,1}) + # Skip over objects without a path (as they represent this own object) + name = bytestring(di.name) + if !isempty(name) + push!(dynamic_libraries, name) + end + return convert(Cint, 0)::Cint + end +end #@linux_only + +function dllist() + dynamic_libraries = Array(AbstractString,0) + + @linux_only begin + const callback = cfunction(dl_phdr_info_callback, Cint, + (Ref{dl_phdr_info}, Csize_t, Ref{Array{AbstractString,1}} )) + ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Array{AbstractString,1}}), callback, dynamic_libraries) + end + + @osx_only begin + numImages = ccall(:_dyld_image_count, Cint, (), ) + + # start at 1 instead of 0 to skip self + for i in 1:numImages-1 + name = bytestring(ccall(:_dyld_get_image_name, Ptr{UInt8}, (UInt32,), i)) + push!(dynamic_libraries, name) + end + end + + @windows_only begin + ccall(:jl_dllist, Cint, (Any,), dynamic_libraries) + end + + dynamic_libraries +end + +end # module diff --git a/base/mmap.jl b/base/mmap.jl index 39452351f7f98..bd87b80faccbd 100644 --- a/base/mmap.jl +++ b/base/mmap.jl @@ -3,39 +3,16 @@ # Arrays mmap_array{T,N}(::Type{T}, dims::NTuple{N,Integer}, s::IO) = mmap_array(T, dims, s, position(s)) -msync{T}(A::Array{T}) = msync(pointer(A), length(A)*sizeof(T)) - # BitArrays mmap_bitarray{N}(::Type{Bool}, dims::NTuple{N,Integer}, s::IOStream, offset::FileOffset) = mmap_bitarray(dims, s, offset) mmap_bitarray{N}(::Type{Bool}, dims::NTuple{N,Integer}, s::IOStream) = mmap_bitarray(dims, s, position(s)) mmap_bitarray{N}(dims::NTuple{N,Integer}, s::IOStream) = mmap_bitarray(dims, s, position(s)) -msync(B::BitArray) = msync(pointer(B.chunks), length(B.chunks)*sizeof(UInt64)) - ### UNIX implementation ### @unix_only begin -# Low-level routines -# These are needed for things like MAP_ANONYMOUS -function mmap(len::Integer, prot::Integer, flags::Integer, fd, offset::Integer) - const pagesize::Int = ccall(:jl_getpagesize, Clong, ()) - # Check that none of the computations will overflow - if len < 0 - throw(ArgumentError("requested size must be ≥ 0, got $len")) - end - if len > typemax(Int)-pagesize - throw(ArgumentError("requested size must be ≤ $(typemax(Int)-pagesize), got $len")) - end - # Set the offset to a page boundary - offset_page::FileOffset = floor(Integer,offset/pagesize)*pagesize - len_page::Int = (offset-offset_page) + len - # Mmap the file - p = ccall(:jl_mmap, Ptr{Void}, (Ptr{Void}, Csize_t, Cint, Cint, Cint, FileOffset), C_NULL, len_page, prot, flags, fd, offset_page) - systemerror("memory mapping failed", reinterpret(Int,p) == -1) - # Also return a pointer that compensates for any adjustment in the offset - return p, Int(offset-offset_page) -end +# Higher-level functions # Before mapping, grow the file to sufficient size # (Required if you're going to write to a new memory-mapped file) @@ -56,22 +33,9 @@ function mmap_grow(len::Integer, prot::Integer, flags::Integer, fd::Integer, off end cpos = ccall(:jl_lseek, FileOffset, (Cint, FileOffset, Cint), fd, cpos, SEEK_SET) systemerror("lseek", cpos < 0) - return mmap(len, prot, flags, fd, offset) -end - -function munmap(p::Ptr,len::Integer) - systemerror("munmap", ccall(:munmap,Cint,(Ptr{Void},Int),p,len) != 0) -end - -const MS_ASYNC = 1 -const MS_INVALIDATE = 2 -const MS_SYNC = 4 -function msync(p::Ptr, len::Integer, flags::Integer) - systemerror("msync", ccall(:msync, Cint, (Ptr{Void}, Csize_t, Cint), p, len, flags) != 0) + return Libc.mmap(len, prot, flags, fd, offset) end -msync(p::Ptr, len::Integer) = msync(p, len, MS_SYNC) -# Higher-level functions # Determine a stream's read/write mode, and return prot & flags # appropriate for mmap # We could use isreadonly here, but it's worth checking that it's readable too @@ -107,10 +71,10 @@ function mmap_array{T,N}(::Type{T}, dims::NTuple{N,Integer}, s::IO, offset::File if iswrite && grow pmap, delta = mmap_grow(len, prot, flags, fd(s), offset) else - pmap, delta = mmap(len, prot, flags, fd(s), offset) + pmap, delta = Libc.mmap(len, prot, flags, fd(s), offset) end A = pointer_to_array(convert(Ptr{T}, UInt(pmap)+delta), dims) - finalizer(A,x->munmap(pmap,len+delta)) + finalizer(A,x->Libc.munmap(pmap,len+delta)) return A end @@ -172,25 +136,10 @@ function mmap_array{T,N}(::Type{T}, dims::NTuple{N,Integer}, s::Union(IO,SharedM error("could not create mapping view: $(FormatMessage())") end A = pointer_to_array(convert(Ptr{T}, viewhandle+offset-offset_page), dims) - finalizer(A, x->munmap(viewhandle, mmaphandle)) + finalizer(A, x->Libc.munmap(viewhandle, mmaphandle)) return A end -function munmap(viewhandle::Ptr, mmaphandle::Ptr) - status = Bool(ccall(:UnmapViewOfFile, stdcall, Cint, (Ptr{Void},), viewhandle)) - status |= Bool(ccall(:CloseHandle, stdcall, Cint, (Ptr{Void},), mmaphandle)) - if !status - error("could not unmap view: $(FormatMessage())") - end -end - -function msync(p::Ptr, len::Integer) - status = Bool(ccall(:FlushViewOfFile, stdcall, Cint, (Ptr{Void}, Csize_t), p, len)) - if !status - error("could not msync: $(FormatMessage())") - end -end - end # Mmapped-bitarray constructor diff --git a/base/multi.jl b/base/multi.jl index 86b0e15bafdbf..8b292705cf46f 100644 --- a/base/multi.jl +++ b/base/multi.jl @@ -1571,7 +1571,7 @@ function disable_nagle(sock) @linux_only begin # tcp_quickack is a linux only option if ccall(:jl_tcp_quickack, Cint, (Ptr{Void}, Cint), sock.handle, 1) < 0 - warn_once("Parallel networking unoptimized ( Error enabling TCP_QUICKACK : ", strerror(errno()), " )") + warn_once("Parallel networking unoptimized ( Error enabling TCP_QUICKACK : ", Libc.strerror(Libc.errno()), " )") end end end diff --git a/base/path.jl b/base/path.jl index ed21c4a8d9373..c5984e04e0e0f 100644 --- a/base/path.jl +++ b/base/path.jl @@ -127,7 +127,7 @@ end p = ccall(:realpath, Ptr{UInt8}, (Ptr{UInt8}, Ptr{UInt8}), path, C_NULL) systemerror(:realpath, p == C_NULL) s = bytestring(p) - c_free(p) + Libc.free(p) return s end diff --git a/base/poll.jl b/base/poll.jl index 1b595c6fea7cc..2a9a2b62b16dc 100644 --- a/base/poll.jl +++ b/base/poll.jl @@ -4,7 +4,7 @@ type FileMonitor open::Bool notify::Condition function FileMonitor(cb, file) - handle = c_malloc(_sizeof_uv_fs_event) + handle = Libc.malloc(_sizeof_uv_fs_event) err = ccall(:jl_fs_event_init,Int32, (Ptr{Void}, Ptr{Void}, Ptr{UInt8}, Int32), eventloop(),handle,file,0) if err < 0 ccall(:uv_fs_event_stop, Int32, (Ptr{Void},), handle) @@ -74,10 +74,10 @@ type PollingFileWatcher <: UVPollingWatcher notify::Condition cb::Callback function PollingFileWatcher(cb, file) - handle = c_malloc(_sizeof_uv_fs_poll) + handle = Libc.malloc(_sizeof_uv_fs_poll) err = ccall(:uv_fs_poll_init,Int32,(Ptr{Void},Ptr{Void}),eventloop(),handle) if err < 0 - c_free(handle) + Libc.free(handle) throw(UVError("PollingFileWatcher",err)) end this = new(handle, file, false, Condition(), cb) @@ -106,14 +106,14 @@ type FDWatcher <: UVPollingWatcher new(handle,_get_osfhandle(fd),open,notify,cb,events) end function FDWatcher(fd::RawFD) - handle = c_malloc(_sizeof_uv_poll) + handle = Libc.malloc(_sizeof_uv_poll) @unix_only if ccall(:jl_uv_unix_fd_is_watched,Int32,(Int32,Ptr{Void},Ptr{Void}),fd.fd,handle,eventloop()) == 1 - c_free(handle) + Libc.free(handle) throw(ArgumentError("file descriptor $(fd.fd) is already being watched by another watcher")) end err = ccall(:uv_poll_init,Int32,(Ptr{Void},Ptr{Void},Int32),eventloop(),handle,fd.fd) if err < 0 - c_free(handle) + Libc.free(handle) throw(UVError("FDWatcher",err)) end this = FDWatcher(handle,fd,false,Condition(),false,FDEvent()) @@ -122,11 +122,11 @@ function FDWatcher(fd::RawFD) this end @windows_only function FDWatcher(fd::WindowsRawSocket) - handle = c_malloc(_sizeof_uv_poll) + handle = Libc.malloc(_sizeof_uv_poll) err = ccall(:uv_poll_init_socket,Int32,(Ptr{Void}, Ptr{Void}, Ptr{Void}), eventloop(), handle, fd.handle) if err < 0 - c_free(handle) + Libc.free(handle) throw(UVError("FDWatcher",err)) end this = FDWatcher(handle,fd,false,Condition(),false,FDEvent()) diff --git a/base/precompile.jl b/base/precompile.jl index c0c9d78bed2b0..7609aebf21915 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -151,7 +151,7 @@ precompile(Base.Terminals.TTYTerminal, (ASCIIString, Base.TTY, Base.TTY, Base.TT precompile(Base.Terminals.beep, (Base.Terminals.TTYTerminal,)) precompile(Base.Terminals.raw!, (Base.Terminals.TTYTerminal, Bool)) precompile(Base.Terminals.write, (Base.Terminals.TTYTerminal, Array{UInt8, 1})) -precompile(Base.TmStruct, (Float64,)) +precompile(Libc.TmStruct, (Float64,)) precompile(Base.VersionNumber, (Int, Int, Int, (), (ASCIIString,))) precompile(Base._atexit, ()) precompile(Base._deleteat!, (Array{UInt8, 1}, Int, Int)) @@ -405,7 +405,7 @@ precompile(Base.start, (Dict{Symbol,Any},)) precompile(Base.start, (UnitRange{Int},)) precompile(Base.start_reading, (Base.TTY,)) precompile(Base.stop_reading, (Base.TTY,)) -precompile(Base.strftime, (ASCIIString, Base.TmStruct)) +precompile(Libc.strftime, (ASCIIString, Libc.TmStruct)) precompile(Base.string, (Int,)) precompile(Base.strip, (ASCIIString,)) precompile(Base.strwidth, (ASCIIString,)) diff --git a/base/process.jl b/base/process.jl index d1abae6285e5a..580672466ebfb 100644 --- a/base/process.jl +++ b/base/process.jl @@ -200,7 +200,7 @@ typealias ProcessChainOrNot Union(Bool,ProcessChain) function _jl_spawn(cmd, argv, loop::Ptr{Void}, pp::Process, in, out, err) - proc = c_malloc(_sizeof_uv_process) + proc = Libc.malloc(_sizeof_uv_process) error = ccall(:jl_spawn, Int32, (Ptr{UInt8}, Ptr{Ptr{UInt8}}, Ptr{Void}, Ptr{Void}, Any, Int32, Ptr{Void}, Int32, Ptr{Void}, Int32, Ptr{Void}, Int32, Ptr{Ptr{UInt8}}, Ptr{UInt8}), @@ -245,8 +245,8 @@ end function spawn(pc::ProcessChainOrNot, cmds::OrCmds, stdios::StdIOSet, exitcb::Callback, closecb::Callback) out_pipe = box(Ptr{Void}, Intrinsics.jl_alloca(_sizeof_uv_named_pipe)) in_pipe = box(Ptr{Void}, Intrinsics.jl_alloca(_sizeof_uv_named_pipe)) - #out_pipe = c_malloc(_sizeof_uv_named_pipe) - #in_pipe = c_malloc(_sizeof_uv_named_pipe) + #out_pipe = Libc.malloc(_sizeof_uv_named_pipe) + #in_pipe = Libc.malloc(_sizeof_uv_named_pipe) link_pipe(in_pipe, false, out_pipe, false) if pc == false pc = ProcessChain(stdios) @@ -267,8 +267,8 @@ end function spawn(pc::ProcessChainOrNot, cmds::ErrOrCmds, stdios::StdIOSet, exitcb::Callback, closecb::Callback) out_pipe = box(Ptr{Void}, Intrinsics.jl_alloca(_sizeof_uv_named_pipe)) in_pipe = box(Ptr{Void}, Intrinsics.jl_alloca(_sizeof_uv_named_pipe)) - #out_pipe = c_malloc(_sizeof_uv_named_pipe) - #in_pipe = c_malloc(_sizeof_uv_named_pipe) + #out_pipe = Libc.malloc(_sizeof_uv_named_pipe) + #in_pipe = Libc.malloc(_sizeof_uv_named_pipe) link_pipe(in_pipe, false, out_pipe, false) if pc == false pc = ProcessChain(stdios) diff --git a/base/replutil.jl b/base/replutil.jl index 010150ec5dc62..0e79b2e342798 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -109,7 +109,7 @@ function showerror(io::IO, ex::DomainError, bt) show_backtrace(io, bt) end -showerror(io::IO, ex::SystemError) = print(io, "SystemError: $(ex.prefix): $(strerror(ex.errnum))") +showerror(io::IO, ex::SystemError) = print(io, "SystemError: $(ex.prefix): $(Libc.strerror(ex.errnum))") showerror(io::IO, ::DivideError) = print(io, "DivideError: integer division error") showerror(io::IO, ::StackOverflowError) = print(io, "StackOverflowError:") showerror(io::IO, ::UndefRefError) = print(io, "UndefRefError: access to undefined reference") diff --git a/base/socket.jl b/base/socket.jl index 97d696ad478e3..72763c0ac0fd8 100644 --- a/base/socket.jl +++ b/base/socket.jl @@ -1,7 +1,6 @@ ## IP ADDRESS HANDLING ## abstract IPAddr - Base.isless{T<:IPAddr}(a::T, b::T) = isless(a.host, b.host) immutable IPv4 <: IPAddr @@ -275,14 +274,14 @@ type TCPSocket <: Socket ) end function TCPSocket() - this = TCPSocket(c_malloc(_sizeof_uv_tcp)) + this = TCPSocket(Libc.malloc(_sizeof_uv_tcp)) associate_julia_struct(this.handle,this) finalizer(this,uvfinalize) err = ccall(:uv_tcp_init,Cint,(Ptr{Void},Ptr{Void}), eventloop(),this.handle) if err != 0 #TODO: this codepath is not currently tested - c_free(this.handle) + Libc.free(this.handle) this.handle = C_NULL throw(UVError("failed to create tcp socket",err)) end @@ -306,14 +305,14 @@ type TCPServer <: UVServer ) end function TCPServer() - this = TCPServer(c_malloc(_sizeof_uv_tcp)) + this = TCPServer(Libc.malloc(_sizeof_uv_tcp)) associate_julia_struct(this.handle, this) finalizer(this,uvfinalize) err = ccall(:uv_tcp_init,Cint,(Ptr{Void},Ptr{Void}), eventloop(),this.handle) if err != 0 #TODO: this codepath is not currently tested - c_free(this.handle) + Libc.free(this.handle) this.handle = C_NULL throw(UVError("failed to create tcp server",err)) end @@ -375,14 +374,14 @@ type UDPSocket <: Socket ) end function UDPSocket() - this = UDPSocket(c_malloc(_sizeof_uv_udp)) + this = UDPSocket(Libc.malloc(_sizeof_uv_udp)) associate_julia_struct(this.handle, this) err = ccall(:uv_udp_init,Cint,(Ptr{Void},Ptr{Void}), eventloop(),this.handle) finalizer(this, uvfinalize) if err != 0 #TODO: this codepath is not currently tested - c_free(this.handle) + Libc.free(this.handle) this.handle = C_NULL throw(UVError("failed to create udp socket",err)) end @@ -472,7 +471,7 @@ function setopt(sock::UDPSocket; multicast_loop = nothing, multicast_ttl=nothing end end -_uv_hook_alloc_buf(sock::UDPSocket,size::UInt) = (c_malloc(size),size) +_uv_hook_alloc_buf(sock::UDPSocket,size::UInt) = (Libc.malloc(size),size) function _recv_start(sock::UDPSocket) if ccall(:uv_is_active,Cint,(Ptr{Void},),sock.handle) == 0 @@ -501,7 +500,7 @@ end function _uv_hook_recv(sock::UDPSocket, nread::Int, buf_addr::Ptr{Void}, buf_size::UInt, addr::Ptr{Void}, flags::Int32) # C signature documented as (*uv_udp_recv_cb)(...) if flags & UV_UDP_PARTIAL > 0 - c_free(buf_addr) + Libc.free(buf_addr) notify_error(sock.recvnotify,"Partial message received") end diff --git a/base/sparse/cholmod.jl b/base/sparse/cholmod.jl index 26e7fc9483317..610560fdb8080 100644 --- a/base/sparse/cholmod.jl +++ b/base/sparse/cholmod.jl @@ -50,7 +50,7 @@ for Ti in IndexTypes end const version_array = Array(Cint, 3) -if dlsym(dlopen("libcholmod"), :cholmod_version) != C_NULL +if Libdl.dlsym(Libdl.dlopen("libcholmod"), :cholmod_version) != C_NULL ccall((:cholmod_version, :libcholmod), Cint, (Ptr{Cint},), version_array) else ccall((:jl_cholmod_version, :libsuitesparse_wrapper), Cint, (Ptr{Cint},), version_array) @@ -58,7 +58,7 @@ end const version = VersionNumber(version_array...) function __init__() - if dlsym(dlopen("libcholmod"), :cholmod_version) == C_NULL + if Libdl.dlsym(Libdl.dlopen("libcholmod"), :cholmod_version) == C_NULL warn(""" CHOLMOD version incompatibility @@ -652,7 +652,7 @@ for Ti in IndexTypes end # Autodetects the types - function read_sparse(file::CFILE, ::Type{$Ti}) + function read_sparse(file::Libc.FILE, ::Type{$Ti}) ptr = ccall((@cholmod_name("read_sparse", $Ti), :libcholmod), Ptr{C_SparseVoid}, (Ptr{Void}, Ptr{UInt8}), file.ptr, common($Ti)) @@ -791,7 +791,7 @@ Sparse(A::Dense) = dense_to_sparse(A, Cint) Sparse(L::Factor) = factor_to_sparse!(copy(L)) function Sparse(filename::ByteString) open(filename) do f - return read_sparse(CFILE(f), SuiteSparse_long) + return read_sparse(Libc.FILE(f), SuiteSparse_long) end end diff --git a/base/stream.jl b/base/stream.jl index 6e8c073493df3..30155e5ae70e7 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -121,14 +121,14 @@ type Pipe <: AsyncStream nothing,nothing,Condition()) end function Pipe() - handle = c_malloc(_sizeof_uv_named_pipe) + handle = Libc.malloc(_sizeof_uv_named_pipe) try ret = Pipe(handle) associate_julia_struct(ret.handle,ret) finalizer(ret,uvfinalize) return init_pipe!(ret;readable=true) catch - c_free(handle) + Libc.free(handle) rethrow() end end @@ -159,15 +159,15 @@ function init_pipe!(pipe::Union(Pipe,PipeServer);readable::Bool=false,writable=f end function PipeServer() - handle = c_malloc(_sizeof_uv_named_pipe) + handle = Libc.malloc(_sizeof_uv_named_pipe) try ret = PipeServer(handle) associate_julia_struct(ret.handle,ret) finalizer(ret,uvfinalize) return init_pipe!(ret;readable=true) catch - c_free(handle) - c_free(handle-1) + Libc.free(handle) + Libc.free(handle-1) rethrow() end end @@ -204,7 +204,7 @@ type TTY <: AsyncStream end function TTY(fd::RawFD; readable::Bool = false) - handle = c_malloc(_sizeof_uv_tty) + handle = Libc.malloc(_sizeof_uv_tty) ret = TTY(handle) associate_julia_struct(handle,ret) finalizer(ret,uvfinalize) @@ -440,7 +440,7 @@ type SingleAsyncWork <: AsyncWork handle::Ptr{Void} cb::Function function SingleAsyncWork(cb::Function) - this = new(c_malloc(_sizeof_uv_async), cb) + this = new(Libc.malloc(_sizeof_uv_async), cb) associate_julia_struct(this.handle, this) preserve_handle(this) err = ccall(:uv_async_init,Cint,(Ptr{Void},Ptr{Void},Ptr{Void}),eventloop(),this.handle,uv_jl_asynccb::Ptr{Void}) @@ -452,7 +452,7 @@ type Timer <: AsyncWork handle::Ptr{Void} cb::Function function Timer(cb::Function) - this = new(c_malloc(_sizeof_uv_timer), cb) + this = new(Libc.malloc(_sizeof_uv_timer), cb) # We don't want to set a julia struct, but we also # want to make sure there's no garbage data in the # ->data field @@ -460,7 +460,7 @@ type Timer <: AsyncWork err = ccall(:uv_timer_init,Cint,(Ptr{Void},Ptr{Void}),eventloop(),this.handle) if err != 0 #TODO: this codepath is currently not tested - c_free(this.handle) + Libc.free(this.handle) this.handle = C_NULL throw(UVError("uv_make_timer",err)) end @@ -548,7 +548,7 @@ end ## pipe functions ## function malloc_julia_pipe(x) - x.handle = c_malloc(_sizeof_uv_named_pipe) + x.handle = Libc.malloc(_sizeof_uv_named_pipe) associate_julia_struct(x.handle,x) finalizer(x,uvfinalize) end @@ -734,7 +734,7 @@ end function uv_write(s::AsyncStream, p, n::Integer) check_open(s) - uvw = c_malloc(_sizeof_uv_write) + uvw = Libc.malloc(_sizeof_uv_write) try uv_req_set_data(uvw,C_NULL) err = ccall(:jl_uv_write, @@ -750,7 +750,7 @@ function uv_write(s::AsyncStream, p, n::Integer) ct.state = :waiting stream_wait(ct) finally - c_free(uvw) + Libc.free(uvw) end return Int(n) end @@ -929,7 +929,7 @@ end function connect!(sock::Pipe, path::AbstractString) @assert sock.status == StatusInit - req = c_malloc(_sizeof_uv_connect) + req = Libc.malloc(_sizeof_uv_connect) uv_req_set_data(req,C_NULL) ccall(:uv_pipe_connect, Void, (Ptr{Void}, Ptr{Void}, Ptr{UInt8}, Ptr{Void}), req, sock.handle, path, uv_jl_connectcb::Ptr{Void}) sock.status = StatusConnecting diff --git a/base/sysimg.jl b/base/sysimg.jl index c3a90ff207fb6..1f4e2ec77fad2 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -81,10 +81,6 @@ include("inference.jl") # For OS specific stuff in I/O include("osutils.jl") -const DL_LOAD_PATH = ByteString[] -@osx_only push!(DL_LOAD_PATH, "@executable_path/../lib/julia") -@osx_only push!(DL_LOAD_PATH, "@executable_path/../lib") - # strings & printing include("char.jl") include("ascii.jl") @@ -105,9 +101,9 @@ include("iostream.jl") # system & environment include("libc.jl") +using .Libc: getpid, gethostname, time, msync +include("libdl.jl") include("env.jl") -include("errno.jl") -using .Errno include("path.jl") include("intfuncs.jl") diff --git a/base/sysinfo.jl b/base/sysinfo.jl index ca270064bd90e..e9a178b40b74c 100644 --- a/base/sysinfo.jl +++ b/base/sysinfo.jl @@ -11,11 +11,7 @@ export CPU_CORES, uptime, loadavg, free_memory, - total_memory, - dlext, - shlib_ext, - dllist, - dlpath + total_memory import ..Base: WORD_SIZE, OS_NAME, ARCH, MACHINE import ..Base: show, uv_error @@ -137,84 +133,6 @@ end free_memory() = ccall(:uv_get_free_memory, UInt64, ()) total_memory() = ccall(:uv_get_total_memory, UInt64, ()) -if OS_NAME === :Darwin - const dlext = "dylib" -elseif OS_NAME === :Windows - const dlext = "dll" -else - #assume OS_NAME === :Linux, or similar - const dlext = "so" -end - -# This is deprecated! use dlext instead! -const shlib_ext = dlext - -@linux_only begin - immutable dl_phdr_info - # Base address of object - addr::Cuint - - # Null-terminated name of object - name::Ptr{UInt8} - - # Pointer to array of ELF program headers for this object - phdr::Ptr{Void} - - # Number of program headers for this object - phnum::Cshort - end - - # This callback function called by dl_iterate_phdr() on Linux - function dl_phdr_info_callback(di::dl_phdr_info, size::Csize_t, dynamic_libraries::Array{AbstractString,1}) - # Skip over objects without a path (as they represent this own object) - name = bytestring(di.name) - if !isempty(name) - push!(dynamic_libraries, name) - end - return convert(Cint, 0)::Cint - end -end #@linux_only - -function dllist() - dynamic_libraries = Array(AbstractString,0) - - @linux_only begin - const callback = cfunction(dl_phdr_info_callback, Cint, - (Ref{dl_phdr_info}, Csize_t, Ref{Array{AbstractString,1}} )) - ccall(:dl_iterate_phdr, Cint, (Ptr{Void}, Ref{Array{AbstractString,1}}), callback, dynamic_libraries) - end - - @osx_only begin - numImages = ccall(:_dyld_image_count, Cint, (), ) - - # start at 1 instead of 0 to skip self - for i in 1:numImages-1 - name = bytestring(ccall(:_dyld_get_image_name, Ptr{UInt8}, (UInt32,), i)) - push!(dynamic_libraries, name) - end - end - - @windows_only begin - ccall(:jl_dllist, Cint, (Any,), dynamic_libraries) - end - - return dynamic_libraries -end - -function dlpath( handle::Ptr{Void} ) - p = ccall( :jl_pathname_for_handle, Ptr{UInt8}, (Ptr{Void},), handle ) - s = bytestring(p) - @windows_only c_free(p) - return s -end - -function dlpath(libname::Union(AbstractString,Symbol)) - handle = dlopen(libname) - path = dlpath(handle) - dlclose(handle) - return path -end - function get_process_title() buf = zeros(Uint8, 512) err = ccall(:uv_get_process_title, Cint, (Ptr{Uint8}, Cint), buf, 512) diff --git a/base/util.jl b/base/util.jl index 445418f388bbb..e6659f9dae3c1 100644 --- a/base/util.jl +++ b/base/util.jl @@ -1,7 +1,6 @@ # timing -# system date in seconds -time() = ccall(:clock_now, Float64, ()) +# time() in libc.jl # high-resolution relative time, in nanoseconds time_ns() = ccall(:jl_hrtime, UInt64, ()) diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index 4dfe1a1052d15..891a13322411c 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -713,26 +713,14 @@ System Get julia's process ID. -.. function:: time([t::TmStruct]) +.. function:: time() - Get the system time in seconds since the epoch, with fairly high (typically, microsecond) resolution. When passed a ``TmStruct``, converts it to a number of seconds since the epoch. + Get the system time in seconds since the epoch, with fairly high (typically, microsecond) resolution. .. function:: time_ns() Get the time in nanoseconds. The time corresponding to 0 is undefined, and wraps every 5.8 years. -.. function:: strftime([format], time) - - Convert time, given as a number of seconds since the epoch or a ``TmStruct``, to a formatted string using the given format. Supported formats are the same as those in the standard C library. - -.. function:: strptime([format], timestr) - - Parse a formatted time string into a ``TmStruct`` giving the seconds, minute, hour, date, etc. Supported formats are the same as those in the standard C library. On some platforms, timezones will not be parsed correctly. If the result of this function will be passed to ``time`` to convert it to seconds since the epoch, the ``isdst`` field should be filled in manually. Setting it to ``-1`` will tell the C library to use the current system settings to determine the timezone. - -.. function:: TmStruct([seconds]) - - Convert a number of seconds since the epoch to broken-down format, with fields ``sec``, ``min``, ``hour``, ``mday``, ``month``, ``year``, ``wday``, ``yday``, and ``isdst``. - .. function:: tic() Set a timer to be read by the next call to :func:`toc` or :func:`toq`. The macro call ``@time expr`` can also be used to time evaluation. diff --git a/doc/stdlib/c.rst b/doc/stdlib/c.rst index 375e5ec96be6e..a142a5c9056de 100644 --- a/doc/stdlib/c.rst +++ b/doc/stdlib/c.rst @@ -36,104 +36,6 @@ bar = cfunction(foo, Float64, ()) - -.. function:: dlopen(library_file::AbstractString [, flags::Integer]) - - Load a shared library, returning an opaque handle. - - The optional flags argument is a bitwise-or of zero or more of - ``RTLD_LOCAL``, ``RTLD_GLOBAL``, ``RTLD_LAZY``, ``RTLD_NOW``, ``RTLD_NODELETE``, - ``RTLD_NOLOAD``, ``RTLD_DEEPBIND``, and ``RTLD_FIRST``. These are converted to - the corresponding flags of the POSIX (and/or GNU libc and/or MacOS) - dlopen command, if possible, or are ignored if the specified - functionality is not available on the current platform. The - default is ``RTLD_LAZY|RTLD_DEEPBIND|RTLD_LOCAL``. An important usage - of these flags, on POSIX platforms, is to specify - ``RTLD_LAZY|RTLD_DEEPBIND|RTLD_GLOBAL`` in order for the library's - symbols to be available for usage in other shared libraries, in - situations where there are dependencies between shared libraries. - -.. function:: dlopen_e(library_file::AbstractString [, flags::Integer]) - - Similar to :func:`dlopen`, except returns a ``NULL`` pointer instead of raising errors. - -.. data:: RTLD_DEEPBIND - - Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. - -.. data:: RTLD_FIRST - - Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. - -.. data:: RTLD_GLOBAL - - Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. - -.. data:: RTLD_LAZY - - Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. - -.. data:: RTLD_LOCAL - - Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. - -.. data:: RTLD_NODELETE - - Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. - -.. data:: RTLD_NOLOAD - - Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. - -.. data:: RTLD_NOW - - Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. - -.. function:: dlsym(handle, sym) - - Look up a symbol from a shared library handle, return callable function pointer on success. - -.. function:: dlsym_e(handle, sym) - - Look up a symbol from a shared library handle, silently return NULL pointer on lookup failure. - -.. function:: dlclose(handle) - - Close shared library referenced by handle. - -.. function:: find_library(names, locations) - - Searches for the first library in ``names`` in the paths in the ``locations`` list, ``DL_LOAD_PATH``, or system - library paths (in that order) which can successfully be dlopen'd. On success, the return value will be one of - the names (potentially prefixed by one of the paths in locations). This string can be assigned to a ``global const`` - and used as the library name in future ``ccall``'s. On failure, it returns the empty string. - -.. data:: DL_LOAD_PATH - - When calling ``dlopen``, the paths in this list will be searched first, in order, before searching the - system locations for a valid library handle. - -.. function:: c_malloc(size::Integer) -> Ptr{Void} - - Call ``malloc`` from the C standard library. - -.. function:: c_calloc(num::Integer, size::Integer) -> Ptr{Void} - - Call ``calloc`` from the C standard library. - -.. function:: c_realloc(addr::Ptr, size::Integer) -> Ptr{Void} - - Call ``realloc`` from the C standard library. - - See warning in ``c_free`` documentation regarding only using this on memory originally obtained from ``c_malloc``. - -.. function:: c_free(addr::Ptr) - - Call ``free`` from the C standard library. Only use this on memory obtained from ``c_malloc``, - not on pointers retrieved from other C libraries. - ``Ptr`` objects obtained from C libraries should be freed by the free functions defined in that library, - to avoid assertion failures if multiple ``libc`` libraries exist on the system. - .. function:: unsafe_convert(T,x) Convert "x" to a value of type "T" @@ -162,7 +64,6 @@ .. function:: unsafe_load(p::Ptr{T},i::Integer) - Load a value of type ``T`` from the address of the ith element (1-indexed) starting at ``p``. This is equivalent to the C expression ``p[i-1]``. @@ -249,23 +150,10 @@ Re-enable Ctrl-C handler during execution of a function. Temporarily reverses the effect of ``disable_sigint``. -.. function:: errno([code]) - - Get the value of the C library's ``errno``. If an argument is specified, it is - used to set the value of ``errno``. - - The value of ``errno`` is only valid immediately after a ``ccall`` to a C - library routine that sets it. Specifically, you cannot call ``errno`` at the next - prompt in a REPL, because lots of code is executed between prompts. - .. function:: systemerror(sysfunc, iftrue) Raises a ``SystemError`` for ``errno`` with the descriptive string ``sysfunc`` if ``bool`` is true -.. function:: strerror(errno) - - Convert a system call error code to a descriptive string - .. data:: Ptr{T} A memory address referring to data of type ``T``. diff --git a/doc/stdlib/index.rst b/doc/stdlib/index.rst index 43d2e38c62531..f655bca911ade 100644 --- a/doc/stdlib/index.rst +++ b/doc/stdlib/index.rst @@ -25,4 +25,6 @@ collections test c + libc + libdl profile diff --git a/doc/stdlib/io-network.rst b/doc/stdlib/io-network.rst index 47dd60828a3d2..3bf644e59ca23 100644 --- a/doc/stdlib/io-network.rst +++ b/doc/stdlib/io-network.rst @@ -77,11 +77,6 @@ General I/O Commit all currently buffered writes to the given stream. -.. function:: flush_cstdio() - - Flushes the C ``stdout`` and ``stderr`` streams (which may have been - written to by external C code). - .. function:: close(stream) Close an I/O stream. Performs a ``flush`` first. @@ -659,33 +654,6 @@ Memory-mapped I/O Forces synchronization between the in-memory version of a memory-mapped ``Array`` or ``BitArray`` and the on-disk version. -.. function:: msync(ptr, len, [flags]) - - Forces synchronization of the :func:`mmap`\ ped memory region from ``ptr`` to ``ptr+len``. Flags defaults to ``MS_SYNC``, but can be a combination of ``MS_ASYNC``, ``MS_SYNC``, or ``MS_INVALIDATE``. See your platform man page for specifics. The flags argument is not valid on Windows. - - You may not need to call ``msync``, because synchronization is performed at intervals automatically by the operating system. However, you can call this directly if, for example, you are concerned about losing the result of a long-running calculation. - -.. data:: MS_ASYNC - - Enum constant for :func:`msync`. See your platform man page for details. (not available on Windows). - -.. data:: MS_SYNC - - Enum constant for :func:`msync`. See your platform man page for details. (not available on Windows). - -.. data:: MS_INVALIDATE - - Enum constant for :func:`msync`. See your platform man page for details. (not available on Windows). - -.. function:: mmap(len, prot, flags, fd, offset) - - Low-level interface to the ``mmap`` system call. See the man page. - -.. function:: munmap(pointer, len) - - Low-level interface for unmapping memory (see the man page). With :func:`mmap_array` you do not need to call this directly; the memory is unmapped for you when the array goes out of scope. - - Network I/O ----------- diff --git a/doc/stdlib/libc.rst b/doc/stdlib/libc.rst new file mode 100644 index 0000000000000..12d8a6f33d562 --- /dev/null +++ b/doc/stdlib/libc.rst @@ -0,0 +1,86 @@ +.. module:: Libc + +******************** + C Standard Library +******************** + +.. function:: malloc(size::Integer) -> Ptr{Void} + + Call ``malloc`` from the C standard library. + +.. function:: calloc(num::Integer, size::Integer) -> Ptr{Void} + + Call ``calloc`` from the C standard library. + +.. function:: realloc(addr::Ptr, size::Integer) -> Ptr{Void} + + Call ``realloc`` from the C standard library. + + See warning in the documentation for ``free`` regarding only using this on memory originally obtained from ``malloc``. + +.. function:: free(addr::Ptr) + + Call ``free`` from the C standard library. Only use this on memory obtained from ``malloc``, + not on pointers retrieved from other C libraries. + ``Ptr`` objects obtained from C libraries should be freed by the free functions defined in that library, + to avoid assertion failures if multiple ``libc`` libraries exist on the system. + +.. function:: errno([code]) + + Get the value of the C library's ``errno``. If an argument is specified, it is + used to set the value of ``errno``. + + The value of ``errno`` is only valid immediately after a ``ccall`` to a C + library routine that sets it. Specifically, you cannot call ``errno`` at the next + prompt in a REPL, because lots of code is executed between prompts. + +.. function:: strerror(n) + + Convert a system call error code to a descriptive string + +.. function:: time(t::TmStruct) + + Converts a ``TmStruct`` struct to a number of seconds since the epoch. + +.. function:: strftime([format], time) + + Convert time, given as a number of seconds since the epoch or a ``TmStruct``, to a formatted string using the given format. Supported formats are the same as those in the standard C library. + +.. function:: strptime([format], timestr) + + Parse a formatted time string into a ``TmStruct`` giving the seconds, minute, hour, date, etc. Supported formats are the same as those in the standard C library. On some platforms, timezones will not be parsed correctly. If the result of this function will be passed to ``time`` to convert it to seconds since the epoch, the ``isdst`` field should be filled in manually. Setting it to ``-1`` will tell the C library to use the current system settings to determine the timezone. + +.. function:: TmStruct([seconds]) + + Convert a number of seconds since the epoch to broken-down format, with fields ``sec``, ``min``, ``hour``, ``mday``, ``month``, ``year``, ``wday``, ``yday``, and ``isdst``. + +.. function:: flush_cstdio() + + Flushes the C ``stdout`` and ``stderr`` streams (which may have been + written to by external C code). + +.. function:: msync(ptr, len, [flags]) + + Forces synchronization of the :func:`mmap`\ ped memory region from ``ptr`` to ``ptr+len``. Flags defaults to ``MS_SYNC``, but can be a combination of ``MS_ASYNC``, ``MS_SYNC``, or ``MS_INVALIDATE``. See your platform man page for specifics. The flags argument is not valid on Windows. + + You may not need to call ``msync``, because synchronization is performed at intervals automatically by the operating system. However, you can call this directly if, for example, you are concerned about losing the result of a long-running calculation. + +.. data:: MS_ASYNC + + Enum constant for :func:`msync`. See your platform man page for details. (not available on Windows). + +.. data:: MS_SYNC + + Enum constant for :func:`msync`. See your platform man page for details. (not available on Windows). + +.. data:: MS_INVALIDATE + + Enum constant for :func:`msync`. See your platform man page for details. (not available on Windows). + +.. function:: mmap(len, prot, flags, fd, offset) + + Low-level interface to the ``mmap`` system call. See the man page. + +.. function:: munmap(pointer, len) + + Low-level interface for unmapping memory (see the man page). With :func:`mmap_array` you do not need to call this directly; the memory is unmapped for you when the array goes out of scope. diff --git a/doc/stdlib/libdl.rst b/doc/stdlib/libdl.rst new file mode 100644 index 0000000000000..5620978db9d49 --- /dev/null +++ b/doc/stdlib/libdl.rst @@ -0,0 +1,81 @@ +.. module:: Libdl + +**************** + Dynamic Linker +**************** + +.. function:: dlopen(libfile::AbstractString [, flags::Integer]) + + Load a shared library, returning an opaque handle. + + The optional flags argument is a bitwise-or of zero or more of + ``RTLD_LOCAL``, ``RTLD_GLOBAL``, ``RTLD_LAZY``, ``RTLD_NOW``, ``RTLD_NODELETE``, + ``RTLD_NOLOAD``, ``RTLD_DEEPBIND``, and ``RTLD_FIRST``. These are converted to + the corresponding flags of the POSIX (and/or GNU libc and/or MacOS) + dlopen command, if possible, or are ignored if the specified + functionality is not available on the current platform. The + default is ``RTLD_LAZY|RTLD_DEEPBIND|RTLD_LOCAL``. An important usage + of these flags, on POSIX platforms, is to specify + ``RTLD_LAZY|RTLD_DEEPBIND|RTLD_GLOBAL`` in order for the library's + symbols to be available for usage in other shared libraries, in + situations where there are dependencies between shared libraries. + +.. function:: dlopen_e(libfile::AbstractString [, flags::Integer]) + + Similar to :func:`dlopen`, except returns a ``NULL`` pointer instead of raising errors. + +.. data:: RTLD_DEEPBIND + + Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. + +.. data:: RTLD_FIRST + + Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. + +.. data:: RTLD_GLOBAL + + Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. + +.. data:: RTLD_LAZY + + Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. + +.. data:: RTLD_LOCAL + + Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. + +.. data:: RTLD_NODELETE + + Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. + +.. data:: RTLD_NOLOAD + + Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. + +.. data:: RTLD_NOW + + Enum constant for :func:`dlopen`. See your platform man page for details, if applicable. + +.. function:: dlsym(handle, sym) + + Look up a symbol from a shared library handle, return callable function pointer on success. + +.. function:: dlsym_e(handle, sym) + + Look up a symbol from a shared library handle, silently return NULL pointer on lookup failure. + +.. function:: dlclose(handle) + + Close shared library referenced by handle. + +.. function:: find_library(names, locations) + + Searches for the first library in ``names`` in the paths in the ``locations`` list, ``DL_LOAD_PATH``, or system + library paths (in that order) which can successfully be dlopen'd. On success, the return value will be one of + the names (potentially prefixed by one of the paths in locations). This string can be assigned to a ``global const`` + and used as the library name in future ``ccall``'s. On failure, it returns the empty string. + +.. data:: DL_LOAD_PATH + + When calling ``dlopen``, the paths in this list will be searched first, in order, before searching the + system locations for a valid library handle. diff --git a/test/backtrace.jl b/test/backtrace.jl index 8fc058eacda92..bef07cf1e3ecf 100644 --- a/test/backtrace.jl +++ b/test/backtrace.jl @@ -13,11 +13,11 @@ end # these could fail on an embedded installation # but for now, we don't handle that case -dlls = Sys.dllist() +dlls = Libdl.dllist() @test !isempty(dlls) @test length(dlls) > 3 # at a bare minimum, probably have some version of libstdc, libgcc, libjulia, ... -@test Base.samefile(Sys.dlpath(dlls[1]), dlls[1]) -@test Base.samefile(Sys.dlpath(dlls[end]), dlls[end]) +@test Base.samefile(Libdl.dlpath(dlls[1]), dlls[1]) +@test Base.samefile(Libdl.dlpath(dlls[end]), dlls[end]) @test length(filter(dlls) do dl - return ismatch(Regex("^libjulia(?:.*)\.$(Sys.dlext)(?:\..+)?\$"), basename(dl)) + return ismatch(Regex("^libjulia(?:.*)\.$(Libdl.dlext)(?:\..+)?\$"), basename(dl)) end) == 1 # look for something libjulia-like (but only one) diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index e0d35c3a6594a..9f332ed840633 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -58,7 +58,7 @@ let exename = joinpath(JULIA_HOME, Base.julia_exename()) # NOTE: this test only holds true when there is a sys.{dll,dylib,so} shared library present. # The tests are also limited to unix platforms at the moment because loading the system image # not turned on for Window's binary builds at the moment. - @unix_only if dlopen_e(splitext(bytestring(Base.JLOptions().image_file))[1]) != C_NULL + @unix_only if Libdl.dlopen_e(splitext(bytestring(Base.JLOptions().image_file))[1]) != C_NULL @test !success(`$exename -C invalidtarget`) @test !success(`$exename --cpu-target=invalidtarget`) end diff --git a/test/file.jl b/test/file.jl index 11b51b214de3a..5db311cd5104c 100644 --- a/test/file.jl +++ b/test/file.jl @@ -194,7 +194,7 @@ s = open(file, "r+") @test isreadonly(s) == false c = mmap_array(UInt8, (11,), s) c[5] = UInt8('x') -msync(c) +Libc.msync(c) close(s) s = open(file, "r") str = readline(s) @@ -217,7 +217,7 @@ close(s) s = open(file, "r+") b = mmap_bitarray((17,19), s) rand!(b) -msync(b) +Libc.msync(b) b0 = copy(b) close(s) s = open(file, "r") @@ -390,7 +390,7 @@ f = open(file, "w") write(f, "Hello, world!") close(f) f = open(file, "r") -FILEp = convert(CFILE, f) +FILEp = convert(Libc.FILE, f) buf = Array(UInt8, 8) str = ccall(:fread, Csize_t, (Ptr{Void}, Csize_t, Csize_t, Ptr{Void}), buf, 1, 8, FILEp.ptr) @test bytestring(buf) == "Hello, w"