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

Add exec option to mmap #53463

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 33 additions & 25 deletions stdlib/Mmap/src/Mmap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ if Sys.isunix()

const PROT_READ = Cint(1)
const PROT_WRITE = Cint(2)
const PROT_EXEC = Cint(4)
const MAP_SHARED = Cint(1)
const MAP_PRIVATE = Cint(2)
const MAP_ANONYMOUS = Cint(Sys.isbsd() ? 0x1000 : 0x20)
Expand All @@ -62,7 +63,7 @@ const F_GETFL = Cint(3)
gethandle(io::IO) = RawFD(fd(io))

# Determine a stream's read/write mode, and return prot & flags appropriate for mmap
function settings(s::RawFD, shared::Bool)
function settings(s::RawFD, shared::Bool, exec::Bool=false)
fatteneder marked this conversation as resolved.
Show resolved Hide resolved
flags = shared ? MAP_SHARED : MAP_PRIVATE
if s == INVALID_OS_HANDLE
flags |= MAP_ANONYMOUS
Expand All @@ -76,6 +77,7 @@ function settings(s::RawFD, shared::Bool)
throw(ArgumentError("mmap requires read permissions on the file (open with \"r+\" mode to override)"))
end
end
exec && (prot |= PROT_EXEC)
fatteneder marked this conversation as resolved.
Show resolved Hide resolved
return prot, flags, (prot & PROT_WRITE) > 0
end

Expand Down Expand Up @@ -125,7 +127,7 @@ end # os-test
# core implementation of mmap

"""
mmap(io::Union{IOStream,AbstractString,Mmap.AnonymousMmap}[, type::Type{Array{T,N}}, dims, offset]; grow::Bool=true, shared::Bool=true)
mmap(io::Union{IOStream,AbstractString,Mmap.AnonymousMmap}[, type::Type{Array{T,N}}, dims, offset]; grow::Bool=true, shared::Bool=true, exec::Bool=false)
mmap(type::Type{Array{T,N}}, dims)
fatteneder marked this conversation as resolved.
Show resolved Hide resolved

Create an `Array` whose values are linked to a file, using memory-mapping. This provides a
Expand Down Expand Up @@ -155,6 +157,8 @@ privileges are required to grow the file.
The `shared` keyword argument specifies whether the resulting `Array` and changes made to it
will be visible to other processes mapping the same file.

The `exec` keyword argument specifies whether the underlying mmap data will be executale.
fatteneder marked this conversation as resolved.
Show resolved Hide resolved

For example, the following code

```julia
Expand Down Expand Up @@ -186,7 +190,8 @@ like HDF5 (which can be used with memory-mapping).
function mmap(io::IO,
::Type{Array{T,N}}=Vector{UInt8},
dims::NTuple{N,Integer}=(div(filesize(io)-position(io),sizeof(T)),),
offset::Integer=position(io); grow::Bool=true, shared::Bool=true) where {T,N}
offset::Integer=position(io); grow::Bool=true, shared::Bool=true,
exec::Bool=false) where {T,N}
# check inputs
isopen(io) || throw(ArgumentError("$io must be open to mmap"))
isbitstype(T) || throw(ArgumentError("unable to mmap $T; must satisfy isbitstype(T) == true"))
Expand Down Expand Up @@ -217,7 +222,7 @@ function mmap(io::IO,
end
# platform-specific mmapping
@static if Sys.isunix()
prot, flags, iswrite = settings(file_desc, shared)
prot, flags, iswrite = settings(file_desc, shared, exec)
if requestedSizeLarger
if iswrite
if grow
Expand Down Expand Up @@ -245,13 +250,16 @@ function mmap(io::IO,
throw(ArgumentError("requested size $szfile larger than file size $(filesize(io)), but requested not to grow"))
end
end
page_flag = exec ? (readonly ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE) : (readonly ? PAGE_READONLY : PAGE_READWRITE)
file_flag = readonly ? FILE_MAP_READ : FILE_MAP_WRITE
exec && (file_flag |= FILE_MAP_EXECUTE)
handle = create ? ccall(:CreateFileMappingW, stdcall, Ptr{Cvoid}, (OS_HANDLE, Ptr{Cvoid}, DWORD, DWORD, DWORD, Cwstring),
file_desc, C_NULL, readonly ? PAGE_READONLY : PAGE_READWRITE, szfile >> 32, szfile & typemax(UInt32), name) :
file_desc, C_NULL, page_flag, szfile >> 32, szfile & typemax(UInt32), name) :
ccall(:OpenFileMappingW, stdcall, Ptr{Cvoid}, (DWORD, Cint, Cwstring),
readonly ? FILE_MAP_READ : FILE_MAP_WRITE, true, name)
page_flag, true, name)
fatteneder marked this conversation as resolved.
Show resolved Hide resolved
Base.windowserror(:mmap, handle == C_NULL)
ptr = ccall(:MapViewOfFile, stdcall, Ptr{Cvoid}, (Ptr{Cvoid}, DWORD, DWORD, DWORD, Csize_t),
handle, readonly ? FILE_MAP_READ : FILE_MAP_WRITE, offset_page >> 32, offset_page & typemax(UInt32), mmaplen)
handle, file_flag, offset_page >> 32, offset_page & typemax(UInt32), mmaplen)
Base.windowserror(:mmap, ptr == C_NULL)
end # os-test
# convert mmapped region to Julia Array at `ptr + (offset - offset_page)` since file was mapped at offset_page
Expand All @@ -271,18 +279,18 @@ end
mmap(file::AbstractString,
::Type{T}=Vector{UInt8},
dims::NTuple{N,Integer}=(div(filesize(file),sizeof(eltype(T))),),
offset::Integer=Int64(0); grow::Bool=true, shared::Bool=true) where {T<:Array,N} =
open(io->mmap(io, T, dims, offset; grow=grow, shared=shared), file, isfile(file) ? "r" : "w+")::Array{eltype(T),N}
offset::Integer=Int64(0); grow::Bool=true, shared::Bool=true, exec::Bool=false) where {T<:Array,N} =
open(io->mmap(io, T, dims, offset; grow=grow, shared=shared, exec=exec), file, isfile(file) ? "r" : "w+")::Array{eltype(T),N}

# using a length argument instead of dims
mmap(io::IO, ::Type{T}, len::Integer, offset::Integer=position(io); grow::Bool=true, shared::Bool=true) where {T<:Array} =
mmap(io, T, (len,), offset; grow=grow, shared=shared)
mmap(file::AbstractString, ::Type{T}, len::Integer, offset::Integer=Int64(0); grow::Bool=true, shared::Bool=true) where {T<:Array} =
open(io->mmap(io, T, (len,), offset; grow=grow, shared=shared), file, isfile(file) ? "r" : "w+")::Vector{eltype(T)}
mmap(io::IO, ::Type{T}, len::Integer, offset::Integer=position(io); grow::Bool=true, shared::Bool=true, exec::Bool=false) where {T<:Array} =
mmap(io, T, (len,), offset; grow=grow, shared=shared, exec=exec)
mmap(file::AbstractString, ::Type{T}, len::Integer, offset::Integer=Int64(0); grow::Bool=true, shared::Bool=true, exec::Bool=false) where {T<:Array} =
open(io->mmap(io, T, (len,), offset; grow=grow, shared=shared, exec=exec), file, isfile(file) ? "r" : "w+")::Vector{eltype(T)}

# constructors for non-file-backed (anonymous) mmaps
mmap(::Type{T}, dims::NTuple{N,Integer}; shared::Bool=true) where {T<:Array,N} = mmap(Anonymous(), T, dims, Int64(0); shared=shared)
mmap(::Type{T}, i::Integer...; shared::Bool=true) where {T<:Array} = mmap(Anonymous(), T, convert(Tuple{Vararg{Int}},i), Int64(0); shared=shared)
mmap(::Type{T}, dims::NTuple{N,Integer}; shared::Bool=true, exec::Bool=false) where {T<:Array,N} = mmap(Anonymous(), T, dims, Int64(0); shared=shared, exec=exec)
mmap(::Type{T}, i::Integer...; shared::Bool=true, exec::Bool=false) where {T<:Array} = mmap(Anonymous(), T, convert(Tuple{Vararg{Int}},i), Int64(0); shared=shared, exec=exec)

"""
mmap(io, BitArray, [dims, offset])
Expand Down Expand Up @@ -322,10 +330,10 @@ julia> rm("mmap.bin")
This creates a 25-by-30000 `BitArray`, linked to the file associated with stream `io`.
"""
function mmap(io::IOStream, ::Type{<:BitArray}, dims::NTuple{N,Integer},
offset::Int64=position(io); grow::Bool=true, shared::Bool=true) where N
offset::Int64=position(io); grow::Bool=true, shared::Bool=true, exec::Bool=false) where N
n = prod(dims)
nc = Base.num_bit_chunks(n)
chunks = mmap(io, Vector{UInt64}, (nc,), offset; grow=grow, shared=shared)
chunks = mmap(io, Vector{UInt64}, (nc,), offset; grow=grow, shared=shared, exec=exec)
if !isreadonly(io)
chunks[end] &= Base._msk_end(n)
else
Expand All @@ -342,18 +350,18 @@ function mmap(io::IOStream, ::Type{<:BitArray}, dims::NTuple{N,Integer},
return B
end

mmap(file::AbstractString, ::Type{T}, dims::NTuple{N,Integer}, offset::Integer=Int64(0);grow::Bool=true, shared::Bool=true) where {T<:BitArray,N} =
open(io->mmap(io, T, dims, offset; grow=grow, shared=shared), file, isfile(file) ? "r" : "w+")::BitArray{N}
mmap(file::AbstractString, ::Type{T}, dims::NTuple{N,Integer}, offset::Integer=Int64(0);grow::Bool=true, shared::Bool=true, exec::Bool=false) where {T<:BitArray,N} =
open(io->mmap(io, T, dims, offset; grow=grow, shared=shared, exec=exec), file, isfile(file) ? "r" : "w+")::BitArray{N}

# using a length argument instead of dims
mmap(io::IO, ::Type{T}, len::Integer, offset::Integer=position(io); grow::Bool=true, shared::Bool=true) where {T<:BitArray} =
mmap(io, T, (len,), offset; grow=grow, shared=shared)
mmap(file::AbstractString, ::Type{T}, len::Integer, offset::Integer=Int64(0); grow::Bool=true, shared::Bool=true) where {T<:BitArray} =
open(io->mmap(io, T, (len,), offset; grow=grow, shared=shared), file, isfile(file) ? "r" : "w+")::BitVector
mmap(io::IO, ::Type{T}, len::Integer, offset::Integer=position(io); grow::Bool=true, shared::Bool=true, exec::Bool=false) where {T<:BitArray} =
mmap(io, T, (len,), offset; grow=grow, shared=shared, exec=exec)
mmap(file::AbstractString, ::Type{T}, len::Integer, offset::Integer=Int64(0); grow::Bool=true, shared::Bool=true, exec::Bool=false) where {T<:BitArray} =
open(io->mmap(io, T, (len,), offset; grow=grow, shared=shared, exec=exec), file, isfile(file) ? "r" : "w+")::BitVector

# constructors for non-file-backed (anonymous) mmaps
mmap(::Type{T}, dims::NTuple{N,Integer}; shared::Bool=true) where {T<:BitArray,N} = mmap(Anonymous(), T, dims, Int64(0); shared=shared)
mmap(::Type{T}, i::Integer...; shared::Bool=true) where {T<:BitArray} = mmap(Anonymous(), T, convert(Tuple{Vararg{Int}},i), Int64(0); shared=shared)
mmap(::Type{T}, dims::NTuple{N,Integer}; shared::Bool=true, exec::Bool=false) where {T<:BitArray,N} = mmap(Anonymous(), T, dims, Int64(0); shared=shared, exec=exec)
mmap(::Type{T}, i::Integer...; shared::Bool=true, exec::Bool=false) where {T<:BitArray} = mmap(Anonymous(), T, convert(Tuple{Vararg{Int}},i), Int64(0); shared=shared, exec=exec)

# msync flags for unix
const MS_ASYNC = 1
Expand Down
5 changes: 5 additions & 0 deletions stdlib/Mmap/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,25 @@ finalize(m); m=nothing; GC.gc()
@test length(@inferred mmap(file, Matrix{Int8}, (12,1), 0)) == 12
@test length(@inferred mmap(file, Matrix{Int8}, (12,1), 0; grow=false)) == 12
@test length(@inferred mmap(file, Matrix{Int8}, (12,1), 0; shared=false)) == 12
@test length(@inferred mmap(file, Matrix{Int8}, (12,1), 0; exec=true)) == 12
@test length(@inferred mmap(file, Vector{Int8}, 12)) == 12
@test length(@inferred mmap(file, Vector{Int8}, 12, 0)) == 12
@test length(@inferred mmap(file, Vector{Int8}, 12, 0; grow=false)) == 12
@test length(@inferred mmap(file, Vector{Int8}, 12, 0; shared=false)) == 12
@test length(@inferred mmap(file, Vector{Int8}, 12, 0; exec=true)) == 12
s = open(file)
@test length(@inferred mmap(s)) == 12
@test length(@inferred mmap(s, Vector{Int8})) == 12
@test length(@inferred mmap(s, Matrix{Int8}, (12,1))) == 12
@test length(@inferred mmap(s, Matrix{Int8}, (12,1), 0)) == 12
@test length(@inferred mmap(s, Matrix{Int8}, (12,1), 0; grow=false)) == 12
@test length(@inferred mmap(s, Matrix{Int8}, (12,1), 0; shared=false)) == 12
@test length(@inferred mmap(s, Matrix{Int8}, (12,1), 0; exec=true)) == 12
@test length(@inferred mmap(s, Vector{Int8}, 12)) == 12
@test length(@inferred mmap(s, Vector{Int8}, 12, 0)) == 12
@test length(@inferred mmap(s, Vector{Int8}, 12, 0; grow=false)) == 12
@test length(@inferred mmap(s, Vector{Int8}, 12, 0; shared=false)) == 12
@test length(@inferred mmap(s, Vector{Int8}, 12, 0; exec=true)) == 12
close(s)
@test_throws ErrorException mmap(file, Vector{Ref}) # must be bit-type
GC.gc(); GC.gc()
Expand Down Expand Up @@ -292,6 +296,7 @@ m[1] = 0x0a
Mmap.sync!(m)
@test m[1] === 0x0a
m = mmap(Vector{UInt8}, 12; shared=false)
m = mmap(Vector{UInt8}, 12; exec=true)
m = mmap(Vector{Int}, 12)
@test length(m) == 12
@test all(m .== 0)
Expand Down