Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Sources/CSystem/include/CSystemLinux.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/sysinfo.h>
#include <sys/ioctl.h>
#include <sys/timerfd.h>
#include <sys/types.h>
#include <errno.h>
Expand Down
47 changes: 47 additions & 0 deletions Sources/System/InputOutput/IOControl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
This source file is part of the Swift System open source project

Copyright (c) 2021 Apple Inc. and the Swift System project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
*/

/// Input / Output Request identifier for manipulating underlying device parameters of special files.
public protocol IOControlID: RawRepresentable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a protocol?


/// Create a strongly-typed I/O request from a raw C IO request.
init?(rawValue: CUnsignedLong)

/// The raw C IO request ID.
var rawValue: CUnsignedLong { get }
}

#if os(Linux)
public extension IOControlID {

@_alwaysEmitIntoClient
init(type: IOType, direction: IODirection, code: CInt, size: CInt) {
self.init(rawValue: _IOC(direction, type, nr, size))
}
}
#endif

public protocol IOControlInteger {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, why is this a protocol?


associatedtype ID: IOControlID

static var id: ID { get }

var intValue: Int32 { get }
}

public protocol IOControlValue {

associatedtype ID: IOControlID

static var id: ID { get }

mutating func withUnsafeMutablePointer<Result>(_ body: (UnsafeMutableRawPointer) throws -> (Result)) rethrows -> Result
}

40 changes: 40 additions & 0 deletions Sources/System/InputOutput/IODirection.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
This source file is part of the Swift System open source project

Copyright (c) 2021 Apple Inc. and the Swift System project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
*/

#if os(Linux)

/// `ioctl` Data Direction
@frozen
public struct IODirection: OptionSet, Hashable, Codable {

/// The raw C file permissions.
@_alwaysEmitIntoClient
public let rawValue: CInt

/// Create a strongly-typed file permission from a raw C value.
@_alwaysEmitIntoClient
public init(rawValue: CInt) { self.rawValue = rawValue }

@_alwaysEmitIntoClient
private init(_ raw: CInt) { self.init(rawValue: raw) }
}

public extension IODirection {

@_alwaysEmitIntoClient
static var none: IODirection { IODirection(0x00) }

@_alwaysEmitIntoClient
static var read: IODirection { IODirection(0x01) }

@_alwaysEmitIntoClient
static var write: IODirection { IODirection(0x02) }
}

#endif
73 changes: 73 additions & 0 deletions Sources/System/InputOutput/IOOperations.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
This source file is part of the Swift System open source project

Copyright (c) 2021 Apple Inc. and the Swift System project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
*/

extension FileDescriptor {

/// Manipulates the underlying device parameters of special files.
@_alwaysEmitIntoClient
public func inputOutput<T: IOControlID>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you consider a related descriptor type for special device files?

_ request: T,
retryOnInterrupt: Bool = true
) throws {
try _inputOutput(request, retryOnInterrupt: true).get()
}

/// Manipulates the underlying device parameters of special files.
@usableFromInline
internal func _inputOutput<T: IOControlID>(
_ request: T,
retryOnInterrupt: Bool
) -> Result<(), Errno> {
nothingOrErrno(retryOnInterrupt: retryOnInterrupt) {
system_ioctl(self.rawValue, request.rawValue)
}
}

/// Manipulates the underlying device parameters of special files.
@_alwaysEmitIntoClient
public func inputOutput<T: IOControlInteger>(
_ request: T,
retryOnInterrupt: Bool = true
) throws {
try _inputOutput(request, retryOnInterrupt: retryOnInterrupt).get()
}

/// Manipulates the underlying device parameters of special files.
@usableFromInline
internal func _inputOutput<T: IOControlInteger>(
_ request: T,
retryOnInterrupt: Bool
) -> Result<(), Errno> {
nothingOrErrno(retryOnInterrupt: retryOnInterrupt) {
system_ioctl(self.rawValue, T.id.rawValue, request.intValue)
}
}

/// Manipulates the underlying device parameters of special files.
@_alwaysEmitIntoClient
public func inputOutput<T: IOControlValue>(
_ request: inout T,
retryOnInterrupt: Bool = true
) throws {
try _inputOutput(&request, retryOnInterrupt: retryOnInterrupt).get()
}

/// Manipulates the underlying device parameters of special files.
@usableFromInline
internal func _inputOutput<T: IOControlValue>(
_ request: inout T,
retryOnInterrupt: Bool
) -> Result<(), Errno> {
nothingOrErrno(retryOnInterrupt: retryOnInterrupt) {
request.withUnsafeMutablePointer { pointer in
system_ioctl(self.rawValue, T.id.rawValue, pointer)
}
}
}
}
91 changes: 91 additions & 0 deletions Sources/System/InputOutput/IOType.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
This source file is part of the Swift System open source project

Copyright (c) 2021 Apple Inc. and the Swift System project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
*/

#if os(Linux)

/// `ioctl` Device driver identifier code
@frozen
public struct IOType: RawRepresentable, Equatable, Hashable {

@_alwaysEmitIntoClient
public let rawValue: CInt

@_alwaysEmitIntoClient
public init(rawValue: CInt) {
self.rawValue = rawValue
}
}

// MARK: - ExpressibleByUnicodeScalarLiteral

extension IOType: ExpressibleByUnicodeScalarLiteral {

@_alwaysEmitIntoClient
public init(unicodeScalarLiteral character: Unicode.Scalar) {
self.init(rawValue: CInt(character.value))
}
}

// MARK: - ExpressibleByIntegerLiteral

extension IOType: ExpressibleByIntegerLiteral {

@_alwaysEmitIntoClient
public init(integerLiteral value: Int32) {
self.init(rawValue: value)
}
}

// MARK: - Definitions

// https://01.org/linuxgraphics/gfx-docs/drm/ioctl/ioctl-number.html
public extension IOType {

/// Floppy Disk
@_alwaysEmitIntoClient
static var floppyDisk: IOType { 0x02 } // linux/fd.h

/// InfiniBand Subsystem
@_alwaysEmitIntoClient
static var infiniBand: IOType { 0x1b }

/// IEEE 1394 Subsystem Block for the entire subsystem
@_alwaysEmitIntoClient
static var ieee1394: IOType { "#" }

/// Performance counter
@_alwaysEmitIntoClient
static var performance: IOType { "$" } // linux/perf_counter.h, linux/perf_event.h

/// System Trace Module subsystem
@_alwaysEmitIntoClient
static var systemTrace: IOType { "%" } // include/uapi/linux/stm.h

/// Kernel-based Virtual Machine
@_alwaysEmitIntoClient
static var kvm: IOType { 0xAF } // linux/kvm.h

/// Freescale hypervisor
@_alwaysEmitIntoClient
static var freescaleHypervisor: IOType { 0xAF } // linux/fsl_hypervisor.h

/// GPIO
@_alwaysEmitIntoClient
static var gpio: IOType { 0xB4 } // linux/gpio.h

/// Linux FUSE
@_alwaysEmitIntoClient
static var fuse: IOType { 0xE5 } // linux/fuse.h

/// ChromeOS EC driver
@_alwaysEmitIntoClient
static var chromeEC: IOType { 0xEC } // drivers/platform/chrome/cros_ec_dev.h
}

#endif
105 changes: 105 additions & 0 deletions Sources/System/InputOutput/TerminalIO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
This source file is part of the Swift System open source project

Copyright (c) 2021 Apple Inc. and the Swift System project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
*/

#if os(macOS) || os(Linux) || os(FreeBSD) || os(Android)
/// Terminal `ioctl` definitions
@frozen
public struct TerminalIO: IOControlID, Equatable, Hashable {

public let rawValue: CUnsignedLong

public init(rawValue: CUnsignedLong) {
self.rawValue = rawValue
}

@_alwaysEmitIntoClient
private init(_ rawValue: CUnsignedLong) {
self.init(rawValue: rawValue)
}
}

public extension TerminalIO {

/// Turn break on, that is, start sending zero bits.
@_alwaysEmitIntoClient
static var setBreakBit: TerminalIO { TerminalIO(_TIOCSBRK) }

/// Turn break off, that is, stop sending zero bits.
@_alwaysEmitIntoClient
static var clearBreakBit: TerminalIO { TerminalIO(_TIOCCBRK) }

/// Put the terminal into exclusive mode.
@_alwaysEmitIntoClient
static var setExclusiveMode: TerminalIO { TerminalIO(_TIOCEXCL) }

/// Reset exclusive use of tty.
@_alwaysEmitIntoClient
static var resetExclusiveMode: TerminalIO { TerminalIO(_TIOCNXCL) }

/// Get the line discipline of the terminal.
@_alwaysEmitIntoClient
static var getLineDiscipline: TerminalIO { TerminalIO(_TIOCGETD) }

/// Set the line discipline of the terminal.
@_alwaysEmitIntoClient
static var setLineDiscipline: TerminalIO { TerminalIO(_TIOCSETD) }
}

public extension TerminalIO {

/// Get the line discipline of the terminal.
@frozen
struct GetLineDiscipline: Equatable, Hashable, IOControlValue {

@_alwaysEmitIntoClient
public static var id: TerminalIO { .getLineDiscipline }

public private(set) var lineDiscipline: Int

public init() {
self.lineDiscipline = 0
}

public mutating func withUnsafeMutablePointer<Result>(_ body: (UnsafeMutableRawPointer) throws -> (Result)) rethrows -> Result {
// Argument: int *argp
var value: CInt = numericCast(self.lineDiscipline)
let result = try Swift.withUnsafeMutableBytes(of: &value) { buffer in
try body(buffer.baseAddress!)
}
self.lineDiscipline = numericCast(value)
return result
}
}

/// Set the line discipline of the terminal.
@frozen
struct SetLineDiscipline: Equatable, Hashable, IOControlValue {

@_alwaysEmitIntoClient
public static var id: TerminalIO { .setLineDiscipline }

public let lineDiscipline: Int

public init(lineDiscipline: Int) {
self.lineDiscipline = lineDiscipline
}

public mutating func withUnsafeMutablePointer<Result>(_ body: (UnsafeMutableRawPointer) throws -> (Result)) rethrows -> Result {
// Argument: const int *argp
var value: CInt = numericCast(self.lineDiscipline)
let result = try Swift.withUnsafeMutableBytes(of: &value) { buffer in
try body(buffer.baseAddress!)
}
assert(numericCast(value) == self.lineDiscipline, "Value changed")
return result
}
}
}

#endif
Loading