-
Notifications
You must be signed in to change notification settings - Fork 142
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move syscalls to a port of Posix enum. (#24)
Motivation: Right now we make a bunch of naked syscalls that don't correctly handle reporting errno or catching EINTR. We can't use the NIO Posix enum to fix this for us because it's internal, and because it doesn't have the function we need. Instead, we create a temporary port of those functions. Ideally we'd reconcile these at some time in the future. Modifications: Add a port of the Posix enum and its core functions. Improve wrapErrorIsNullReturnCall to be more useful. Adopt the posix functions. Result: Better safety in the face of EINTR. Better reporting of errnos.
- Loading branch information
Showing
8 changed files
with
134 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the SwiftNIO open source project | ||
// | ||
// Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors | ||
// Licensed under Apache License v2.0 | ||
// | ||
// See LICENSE.txt for license information | ||
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
// This file contains a version of the SwiftNIO Posix enum. This is necessary | ||
// because SwiftNIO's version is internal. Our version exists for the same reason: | ||
// to ensure errno is captured correctly when doing syscalls, and that no ARC traffic | ||
// can happen inbetween that *could* change the errno value before we were able to | ||
// read it. | ||
// | ||
// The code is an exact port from SwiftNIO, so if that version ever becomes public we | ||
// can lift anything missing from there and move it over without change. | ||
import NIO | ||
|
||
private let sysFopen: @convention(c) (UnsafePointer<CChar>?, UnsafePointer<CChar>?) -> UnsafeMutablePointer<FILE>? = fopen | ||
private let sysMlock: @convention(c) (UnsafeRawPointer?, size_t) -> CInt = mlock | ||
private let sysMunlock: @convention(c) (UnsafeRawPointer?, size_t) -> CInt = munlock | ||
|
||
// Sadly, stat has different signatures with glibc and macOS libc. | ||
#if os(Linux) || os(FreeBSD) || os(Android) | ||
private let sysStat: @convention(c) (UnsafePointer<CChar>, UnsafeMutablePointer<stat>) -> CInt = stat(_:_:) | ||
#elseif os(macOS) || os(iOS) || os(watchOS) || os(tvOS) | ||
private let sysStat: @convention(c) (UnsafePointer<CChar>?, UnsafeMutablePointer<stat>?) -> CInt = stat(_:_:) | ||
#endif | ||
|
||
|
||
// MARK:- Copied code from SwiftNIO | ||
private func isBlacklistedErrno(_ code: CInt) -> Bool { | ||
switch code { | ||
case EFAULT, EBADF: | ||
return true | ||
default: | ||
return false | ||
} | ||
} | ||
|
||
/* Sorry, we really try hard to not use underscored attributes. In this case however we seem to break the inlining threshold which makes a system call take twice the time, ie. we need this exception. */ | ||
@inline(__always) | ||
internal func wrapSyscall<T: FixedWidthInteger>(where function: StaticString = #function, _ body: () throws -> T) throws -> T { | ||
while true { | ||
let res = try body() | ||
if res == -1 { | ||
let err = errno | ||
if err == EINTR { | ||
continue | ||
} | ||
assert(!isBlacklistedErrno(err), "blacklisted errno \(err) \(strerror(err)!)") | ||
throw IOError(errnoCode: err, function: function) | ||
} | ||
return res | ||
} | ||
} | ||
|
||
/* Sorry, we really try hard to not use underscored attributes. In this case however we seem to break the inlining threshold which makes a system call take twice the time, ie. we need this exception. */ | ||
@inline(__always) | ||
internal func wrapErrorIsNullReturnCall<T>(where function: StaticString = #function, _ body: () throws -> T?) throws -> T { | ||
while true { | ||
guard let res = try body() else { | ||
let err = errno | ||
if err == EINTR { | ||
continue | ||
} | ||
assert(!isBlacklistedErrno(err), "blacklisted errno \(err) \(strerror(err)!)") | ||
throw IOError(errnoCode: err, function: function) | ||
} | ||
return res | ||
} | ||
} | ||
|
||
// MARK:- Our functions | ||
internal enum Posix { | ||
@inline(never) | ||
public static func fopen(file: UnsafePointer<CChar>, mode: UnsafePointer<CChar>) throws -> UnsafeMutablePointer<FILE> { | ||
return try wrapErrorIsNullReturnCall { | ||
sysFopen(file, mode) | ||
} | ||
} | ||
|
||
@inline(never) | ||
@discardableResult | ||
public static func stat(path: UnsafePointer<CChar>, buf: UnsafeMutablePointer<stat>) throws -> CInt { | ||
return try wrapSyscall { | ||
sysStat(path, buf) | ||
} | ||
} | ||
|
||
@inline(never) | ||
@discardableResult | ||
public static func mlock(addr: UnsafeRawPointer, len: size_t) throws -> CInt { | ||
return try wrapSyscall { | ||
sysMlock(addr, len) | ||
} | ||
} | ||
|
||
@inline(never) | ||
@discardableResult | ||
public static func munlock(addr: UnsafeRawPointer, len: size_t) throws -> CInt { | ||
return try wrapSyscall { | ||
sysMunlock(addr, len) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters