1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
//===----------------------------------------------------------------------===//
//
// 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
#if os(Android)
internal typealias FILEPointer = OpaquePointer
#else
internal typealias FILEPointer = UnsafeMutablePointer<FILE>
#endif
private let sysFopen: @convention(c) (UnsafePointer<CChar>?, UnsafePointer<CChar>?) -> FILEPointer? = fopen
private let sysMlock: @convention(c) (UnsafeRawPointer?, size_t) -> CInt = mlock
private let sysMunlock: @convention(c) (UnsafeRawPointer?, size_t) -> CInt = munlock
private let sysFclose = fclose
// Sadly, stat has different signatures with glibc and macOS libc.
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(Android)
private let sysStat: @convention(c) (UnsafePointer<CChar>?, UnsafeMutablePointer<stat>?) -> CInt = stat(_:_:)
#elseif os(Linux) || os(FreeBSD)
private let sysStat: @convention(c) (UnsafePointer<CChar>, UnsafeMutablePointer<stat>) -> CInt = stat(_:_:)
#endif
// MARK:- Copied code from SwiftNIO
private func isUnacceptableErrno(_ 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: String = #function, _ body: () throws -> T) throws -> T {
while true {
let res = try body()
if res == -1 {
let err = errno
if err == EINTR {
continue
}
assert(!isUnacceptableErrno(err), "unacceptable errno \(err) \(strerror(err)!)")
throw IOError(errnoCode: err, reason: 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: String = #function, _ body: () throws -> T?) throws -> T {
while true {
guard let res = try body() else {
let err = errno
if err == EINTR {
continue
}
assert(!isUnacceptableErrno(err), "unacceptable errno \(err) \(strerror(err)!)")
throw IOError(errnoCode: err, reason: function)
}
return res
}
}
// MARK:- Our functions
internal enum Posix {
@inline(never)
internal static func fopen(file: UnsafePointer<CChar>, mode: UnsafePointer<CChar>) throws -> FILEPointer {
return try wrapErrorIsNullReturnCall {
sysFopen(file, mode)
}
}
@inline(never)
internal static func fclose(file: FILEPointer) throws -> CInt {
return try wrapSyscall {
sysFclose(file)
}
}
@inline(never)
@discardableResult
internal static func stat(path: UnsafePointer<CChar>, buf: UnsafeMutablePointer<stat>) throws -> CInt {
return try wrapSyscall {
sysStat(path, buf)
}
}
@inline(never)
@discardableResult
internal static func mlock(addr: UnsafeRawPointer, len: size_t) throws -> CInt {
return try wrapSyscall {
sysMlock(addr, len)
}
}
@inline(never)
@discardableResult
internal static func munlock(addr: UnsafeRawPointer, len: size_t) throws -> CInt {
return try wrapSyscall {
sysMunlock(addr, len)
}
}
}
|