Skip to content

Commit

Permalink
provide GetLastError/FormatMessage as official functions of the [Wind…
Browse files Browse the repository at this point in the history
…ows] Libc module (also use them to provide better errors in the tests)

these belong in Libc since the are the windows counterparts to errno/strerror which are documented and exported in Libc
  • Loading branch information
vtjnash committed Jul 24, 2015
1 parent 84e969a commit 64c184b
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 63 deletions.
4 changes: 2 additions & 2 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -606,15 +606,15 @@ function munmap(viewhandle::Ptr, mmaphandle::Ptr)
status = ccall(:UnmapViewOfFile, stdcall, Cint, (Ptr{Void},), viewhandle)!=0
status |= ccall(:CloseHandle, stdcall, Cint, (Ptr{Void},), mmaphandle)!=0
if !status
error("could not unmap view: $(FormatMessage())")
error("could not unmap view: $(Libc.FormatMessage())")
end
end

function msync(p::Ptr, len::Integer)
depwarn("`msync` is deprecated, use `Mmap.sync!(array)` instead", :msync)
status = ccall(:FlushViewOfFile, stdcall, Cint, (Ptr{Void}, Csize_t), p, len)!=0
if !status
error("could not msync: $(FormatMessage())")
error("could not msync: $(Libc.FormatMessage())")
end
end

Expand Down
27 changes: 4 additions & 23 deletions base/env.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,16 @@
_getenv(var::AbstractString) = ccall(:getenv, Ptr{UInt8}, (Cstring,), var)
_hasenv(s::AbstractString) = _getenv(s) != C_NULL
end

@windows_only begin
const ERROR_ENVVAR_NOT_FOUND = UInt32(203)
const FORMAT_MESSAGE_ALLOCATE_BUFFER = UInt32(0x100)
const FORMAT_MESSAGE_FROM_SYSTEM = UInt32(0x1000)
const FORMAT_MESSAGE_IGNORE_INSERTS = UInt32(0x200)
const FORMAT_MESSAGE_MAX_WIDTH_MASK = UInt32(0xFF)
GetLastError() = ccall(:GetLastError,stdcall,UInt32,())
function FormatMessage(e=GetLastError())
lpMsgBuf = Array(Ptr{UInt16})
lpMsgBuf[1] = 0
len = ccall(:FormatMessageW,stdcall,UInt32,(Cint, Ptr{Void}, Cint, Cint, Ptr{Ptr{UInt16}}, Cint, Ptr{Void}),
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
C_NULL, e, 0, lpMsgBuf, 0, C_NULL)
p = lpMsgBuf[1]
len == 0 && return utf8("")
len = len + 1
buf = Array(UInt16, len)
unsafe_copy!(pointer(buf), p, len)
ccall(:LocalFree,stdcall,Ptr{Void},(Ptr{Void},),p)
return utf8(UTF16String(buf))
end

_getenvlen(var::AbstractString) = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Cwstring,Ptr{UInt8},UInt32),var,C_NULL,0)
_hasenv(s::AbstractString) = _getenvlen(s)!=0 || GetLastError()!=ERROR_ENVVAR_NOT_FOUND
_hasenv(s::AbstractString) = _getenvlen(s)!=0 || Libc.GetLastError()!=ERROR_ENVVAR_NOT_FOUND
function _jl_win_getenv(s::UTF16String,len::UInt32)
val=zeros(UInt16,len)
ret=ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Cwstring,Ptr{UInt16},UInt32),s,val,len)
if (ret == 0 && len != 1) || ret != len-1 || val[end] != 0
error(string("getenv: ", s, ' ', len, "-1 != ", ret, ": ", FormatMessage()))
error(string("getenv: ", s, ' ', len, "-1 != ", ret, ": ", Libc.FormatMessage()))
end
val
end
Expand All @@ -50,7 +31,7 @@ macro accessEnv(var,errorcase)
let var = utf16($(esc(var)))
len=_getenvlen(var)
if len == 0
if GetLastError() != ERROR_ENVVAR_NOT_FOUND
if Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND
return utf8("")
else
$(esc(errorcase))
Expand Down
4 changes: 2 additions & 2 deletions base/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ function tempdir()
temppath = Array(UInt16,32767)
lentemppath = ccall(:GetTempPathW,stdcall,UInt32,(UInt32,Ptr{UInt16}),length(temppath),temppath)
if lentemppath >= length(temppath) || lentemppath == 0
error("GetTempPath failed: $(FormatMessage())")
error("GetTempPath failed: $(Libc.FormatMessage())")
end
resize!(temppath,lentemppath+1)
return utf8(UTF16String(temppath))
Expand All @@ -186,7 +186,7 @@ function tempname(temppath::AbstractString,uunique::UInt32)
uunique = ccall(:GetTempFileNameW,stdcall,UInt32,(Cwstring,Ptr{UInt16},UInt32,Ptr{UInt16}), temppath,utf16("jul"),uunique,tname)
lentname = findfirst(tname,0)-1
if uunique == 0 || lentname <= 0
error("GetTempFileName failed: $(FormatMessage())")
error("GetTempFileName failed: $(Libc.FormatMessage())")
end
resize!(tname,lentname+1)
return utf8(UTF16String(tname))
Expand Down
23 changes: 23 additions & 0 deletions base/libc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Libc

export FILE, TmStruct, strftime, strptime, getpid, gethostname, free, malloc, calloc, realloc,
errno, strerror, flush_cstdio, systemsleep, time
@windows_only export GetLastError, FormatMessage

include("errno.jl")

Expand Down Expand Up @@ -165,6 +166,28 @@ errno(e::Integer) = ccall(:jl_set_errno, Void, (Cint,), e)
strerror(e::Integer) = bytestring(ccall(:strerror, Ptr{UInt8}, (Int32,), e))
strerror() = strerror(errno())

@windows_only begin
GetLastError() = ccall(:GetLastError,stdcall,UInt32,())
function FormatMessage(e=GetLastError())
const FORMAT_MESSAGE_ALLOCATE_BUFFER = UInt32(0x100)
const FORMAT_MESSAGE_FROM_SYSTEM = UInt32(0x1000)
const FORMAT_MESSAGE_IGNORE_INSERTS = UInt32(0x200)
const FORMAT_MESSAGE_MAX_WIDTH_MASK = UInt32(0xFF)
lpMsgBuf = Array(Ptr{UInt16})
lpMsgBuf[1] = 0
len = ccall(:FormatMessageW,stdcall,UInt32,(Cint, Ptr{Void}, Cint, Cint, Ptr{Ptr{UInt16}}, Cint, Ptr{Void}),
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
C_NULL, e, 0, lpMsgBuf, 0, C_NULL)
p = lpMsgBuf[1]
len == 0 && return utf8("")
len = len + 1
buf = Array(UInt16, len)
unsafe_copy!(pointer(buf), p, len)
ccall(:LocalFree,stdcall,Ptr{Void},(Ptr{Void},),p)
return utf8(UTF16String(buf))
end
end

## Memory related ##

free(p::Ptr) = ccall(:free, Void, (Ptr{Void},), p)
Expand Down
10 changes: 5 additions & 5 deletions base/mmap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const FILE_MAP_EXECUTE = UInt32(0x20)

function gethandle(io::IO)
handle = Libc._get_osfhandle(RawFD(fd(io))).handle
systemerror("could not get handle for file to map: $(Base.FormatMessage())", handle == -1)
systemerror("could not get handle for file to map: $(Libc.FormatMessage())", handle == -1)
return Int(handle)
end

Expand Down Expand Up @@ -127,18 +127,18 @@ function mmap{T,N}(io::IO,
file_desc, C_NULL, readonly ? PAGE_READONLY : PAGE_READWRITE, szfile >> 32, szfile & typemax(UInt32), name) :
ccall(:OpenFileMappingW, stdcall, Ptr{Void}, (Cint, Cint, Cwstring),
readonly ? FILE_MAP_READ : FILE_MAP_WRITE, true, name)
handle == C_NULL && error("could not create file mapping: $(Base.FormatMessage())")
handle == C_NULL && error("could not create file mapping: $(Libc.FormatMessage())")
ptr = ccall(:MapViewOfFile, stdcall, Ptr{Void}, (Ptr{Void}, Cint, Cint, Cint, Csize_t),
handle, readonly ? FILE_MAP_READ : FILE_MAP_WRITE, offset_page >> 32, offset_page & typemax(UInt32), (offset - offset_page) + len)
ptr == C_NULL && error("could not create mapping view: $(Base.FormatMessage())")
ptr == C_NULL && error("could not create mapping view: $(Libc.FormatMessage())")
end # @windows_only
# convert mmapped region to Julia Array at `ptr + (offset - offset_page)` since file was mapped at offset_page
A = pointer_to_array(convert(Ptr{T}, UInt(ptr) + UInt(offset - offset_page)), dims)
@unix_only finalizer(A, x -> systemerror("munmap", ccall(:munmap,Cint,(Ptr{Void},Int),ptr,mmaplen) != 0))
@windows_only finalizer(A, x -> begin
status = ccall(:UnmapViewOfFile, stdcall, Cint, (Ptr{Void},), ptr)!=0
status |= ccall(:CloseHandle, stdcall, Cint, (Ptr{Void},), handle)!=0
status || error("could not unmap view: $(Base.FormatMessage())")
status || error("could not unmap view: $(Libc.FormatMessage())")
end)
return A
end
Expand Down Expand Up @@ -202,7 +202,7 @@ const MS_SYNC = 4

function sync!{T}(m::Array{T}, flags::Integer=MS_SYNC)
@unix_only systemerror("msync", ccall(:msync, Cint, (Ptr{Void}, Csize_t, Cint), pointer(m), length(m)*sizeof(T), flags) != 0)
@windows_only systemerror("could not FlushViewOfFile: $(Base.FormatMessage())",
@windows_only systemerror("could not FlushViewOfFile: $(Libc.FormatMessage())",
ccall(:FlushViewOfFile, stdcall, Cint, (Ptr{Void}, Csize_t), pointer(m), length(m)) == 0)
end
sync!(B::BitArray, flags::Integer=MS_SYNC) = sync!(B.chunks, flags)
Expand Down
10 changes: 9 additions & 1 deletion doc/stdlib/libc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,18 @@
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)
.. function:: strerror(n=errno())

Convert a system call error code to a descriptive string

.. function:: GetLastError()

Call the Win32 ``GetLastError`` function [only available on Windows].

.. function:: FormatMessage(n=GetLastError())

Convert a Win32 system call error code to a descriptive string [only available on Windows].

.. function:: time(t::TmStruct)

Converts a ``TmStruct`` struct to a number of seconds since the epoch.
Expand Down
39 changes: 26 additions & 13 deletions src/support/wsasocketpair.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,41 +29,54 @@ __declspec(dllexport) int wsasocketpair(int domain, int type, int protocol, SOCK
return -1;
}
name.sin_family = AF_INET;
name.sin_addr.s_addr = INADDR_LOOPBACK;
name.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
name.sin_port = 0;
err = bind(server, (SOCKADDR*)&name, sizeof(name));
if (err == SOCKET_ERROR) {
closesocket(server);
return -1;
int lasterr = WSAGetLastError();
closesocket(server);
WSASetLastError(lasterr);
return -1;
}
err = listen(server, 1);
if (err == SOCKET_ERROR) {
closesocket(server);
return -1;
int lasterr = WSAGetLastError();
closesocket(server);
WSASetLastError(lasterr);
return -1;
}
namelen = sizeof(name);
err = getsockname(server, (SOCKADDR*)&name, &namelen);
if (err == SOCKET_ERROR) {
closesocket(server);
return -1;
int lasterr = WSAGetLastError();
closesocket(server);
WSASetLastError(lasterr);
return -1;
}
client0 = socket(AF_INET, type, protocol);
if (client0 == INVALID_SOCKET) {
int lasterr = WSAGetLastError();
closesocket(server);
WSASetLastError(lasterr);
return -1;
}
err = connect(client0, (SOCKADDR*)&name, sizeof(name));
if (err == SOCKET_ERROR) {
closesocket(client0);
closesocket(server);
return -1;
int lasterr = WSAGetLastError();
closesocket(client0);
closesocket(server);
WSASetLastError(lasterr);
return -1;
}
client1 = accept(server, NULL, NULL);
closesocket(server);
if (err == INVALID_SOCKET) {
closesocket(client0);
return -1;
int lasterr = WSAGetLastError();
closesocket(server);
closesocket(client0);
WSASetLastError(lasterr);
return -1;
}
closesocket(server);
socket_vector[0] = client0;
socket_vector[1] = client1;
return 0;
Expand Down
33 changes: 16 additions & 17 deletions test/pollfd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@ intvls = [2, .2, .1, .002]

pipe_fds = cell(n)
for i in 1:n
@test 0 ==
@windows ? begin
pipe_fds[i] = Array(Libc.WindowsRawSocket, 2)
ccall(:wsasocketpair, Cint, (Cint, Cuint, Cint, Ptr{Libc.WindowsRawSocket}), 1, 1, 6, pipe_fds[i])
end : begin
pipe_fds[i] = Array(RawFD, 2)
ccall(:pipe, Cint, (Ptr{RawFD},), pipe_fds[i])
end
@windows ? begin
pipe_fds[i] = Array(Libc.WindowsRawSocket, 2)
0 == ccall(:wsasocketpair, Cint, (Cint, Cuint, Cint, Ptr{Libc.WindowsRawSocket}), 1, 1, 6, pipe_fds[i]) || error(Libc.FormatMessage())
end : begin
pipe_fds[i] = Array(RawFD, 2)
@test 0 == ccall(:pipe, Cint, (Ptr{RawFD},), pipe_fds[i])
end
end

function pfd_tst_reads(idx, intvl)
Expand All @@ -38,10 +37,10 @@ function pfd_tst_reads(idx, intvl)
@test t_elapsed <= (intvl + 1)

dout = Array(UInt8, 1)
@test 1 == @windows ? (
ccall(:recv, stdcall, Cint, (Ptr{Void}, Ptr{UInt8}, Cint, Cint), pipe_fds[idx][1], dout, 1, 0)
@windows ? (
1 == ccall(:recv, stdcall, Cint, (Ptr{Void}, Ptr{UInt8}, Cint, Cint), pipe_fds[idx][1], dout, 1, 0) || error(Libc.FormatMessage())
) : (
ccall(:read, Csize_t, (Cint, Ptr{UInt8}, Csize_t), pipe_fds[idx][1], dout, 1)
@test 1 == ccall(:read, Csize_t, (Cint, Ptr{UInt8}, Csize_t), pipe_fds[idx][1], dout, 1)
)
@test dout[1] == Int8('A')
end
Expand Down Expand Up @@ -87,10 +86,10 @@ for (i, intvl) in enumerate(intvls)
@test event.writable

if isodd(idx)
@test 1 == @windows ? (
ccall(:send, stdcall, Cint, (Ptr{Void}, Ptr{UInt8}, Cint, Cint), pipe_fds[idx][2], "A", 1, 0)
@windows ? (
1 == ccall(:send, stdcall, Cint, (Ptr{Void}, Ptr{UInt8}, Cint, Cint), pipe_fds[idx][2], "A", 1, 0) || error(Libc.FormatMessage())
) : (
ccall(:write, Csize_t, (Cint, Ptr{UInt8}, Csize_t), pipe_fds[idx][2], "A", 1)
@test 1 == ccall(:write, Csize_t, (Cint, Ptr{UInt8}, Csize_t), pipe_fds[idx][2], "A", 1)
)
end
end
Expand All @@ -100,10 +99,10 @@ end

for i in 1:n
for j = 1:2
@test 0 == @windows ? (
ccall(:closesocket, stdcall, Cint, (Ptr{Void},), pipe_fds[i][j])
@windows ? (
0 == ccall(:closesocket, stdcall, Cint, (Ptr{Void},), pipe_fds[i][j]) || error(Libc.FormatMessage())
) : (
ccall(:close, Cint, (Cint,), pipe_fds[i][j])
@test 0 == ccall(:close, Cint, (Cint,), pipe_fds[i][j])
)
end
end

0 comments on commit 64c184b

Please sign in to comment.