-
Notifications
You must be signed in to change notification settings - Fork 109
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
[DRAFT] ProcessID, Signal, SignalSet, TaskInfo, ResourceUsageInfo #20
base: main
Are you sure you want to change the base?
Changes from all commits
ad80d0f
0ebaa29
544fc8a
881a8ad
0c32e4e
c96a3e6
a051d71
153e5d3
e8b5ab4
9edaf16
5bc82a4
9830717
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* | ||
This source file is part of the Swift System open source project | ||
|
||
Copyright (c) 2020 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 | ||
*/ | ||
|
||
#ifdef __MACH__ | ||
#include "libproc.h" | ||
#else | ||
#error "whoops" | ||
#endif | ||
|
||
// |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,3 +16,7 @@ | |
#if defined(_WIN32) | ||
#include <CSystemWindows.h> | ||
#endif | ||
|
||
#ifdef __MACH__ | ||
#include <CSystemDarwin.h> | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
|
||
// FIXME(DO NOT MERGE): We need to find a way around this. We want to declare | ||
// a typealias to a struct from a header, but don't want downstream to import | ||
// Darwin or the whole header just for that. | ||
// | ||
import Darwin | ||
extension CInterop { | ||
public typealias PID = Int32 | ||
public typealias ProcTaskInfo = proc_taskinfo // FIXME | ||
public typealias RUsageInfo = rusage_info_current // FIXME | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have the option to just go with the original type names here, but I think it's still nice to have these typealiases. |
||
} | ||
|
||
public struct ProcessID: RawRepresentable, Hashable, Codable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems to me that this is more of a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This struct is the handle to the process, it's very much like a file descriptor. It's not "safe" to assume it's still valid after a process is torn down, etc. I've been thinking that a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think |
||
/// The raw C process id. | ||
@_alwaysEmitIntoClient | ||
public let rawValue: CInterop.PID | ||
|
||
/// Creates a strongly-typed process id from a raw C pid | ||
@_alwaysEmitIntoClient | ||
public init(rawValue: CInterop.PID) { self.rawValue = rawValue } | ||
|
||
fileprivate init(_ rawValue: CInterop.PID) { self.init(rawValue: rawValue) } | ||
|
||
} | ||
|
||
extension ProcessID { | ||
public static func current() -> ProcessID { | ||
ProcessID(getpid()) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
|
||
extension ProcessID { | ||
public struct ResourceUsageInfo: RawRepresentable/*, Hashable, Codable*/ { | ||
/// The raw C process id. | ||
@_alwaysEmitIntoClient | ||
public let rawValue: CInterop.RUsageInfo | ||
|
||
/// Creates a strongly-typed process id from a raw C pid | ||
@_alwaysEmitIntoClient | ||
public init(rawValue: CInterop.RUsageInfo) { self.rawValue = rawValue } | ||
|
||
fileprivate init(_ rawValue: CInterop.RUsageInfo) { | ||
self.init(rawValue: rawValue) | ||
} | ||
|
||
fileprivate static var blank: ResourceUsageInfo { | ||
ResourceUsageInfo(rusage_info_current()) | ||
} | ||
} | ||
} | ||
|
||
// FIXME(DO NOT MERGE): system_foo wrappers for these and mocking | ||
import CSystem | ||
extension ProcessID { | ||
public func getResourceUsageInfo() throws -> ResourceUsageInfo { | ||
var current = ResourceUsageInfo.blank | ||
try withUnsafeMutablePointer(to: ¤t) { | ||
try $0.withMemoryRebound(to: rusage_info_t?.self, capacity: 1) { | ||
guard 0 == proc_pid_rusage(self.rawValue, RUSAGE_INFO_CURRENT, $0) else { | ||
throw Errno(rawValue: errno) | ||
} | ||
} | ||
} | ||
return current | ||
} | ||
} | ||
|
||
// FIXME: docs or comments, the headers have none... | ||
// FIXME: names | ||
extension ProcessID.ResourceUsageInfo { | ||
// FIXME: UUID proper type | ||
public typealias UUID = ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Foundation already has a wrapper for |
||
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, | ||
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) | ||
|
||
/// `ri_uuid`: TBD | ||
public var uuid: UUID { rawValue.ri_uuid } | ||
|
||
/// `ri_user_time`: TBD | ||
public var userTime: UInt64 { rawValue.ri_user_time } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should specify units for all these dimensioned quantities, ideally at the type system level. Should these time intervals return whatever we end up using for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately the headers are not clear what even is here. It's like that |
||
|
||
/// `ri_system_time`: TBD | ||
public var systemTime: UInt64 { rawValue.ri_system_time } | ||
|
||
/// `ri_pkg_idle_wkups`: TBD | ||
public var pkgIdleWakeups: UInt64 { rawValue.ri_pkg_idle_wkups } | ||
|
||
/// `ri_interrupt_wkups`: TBD | ||
public var interruptWakeups: UInt64 { rawValue.ri_interrupt_wkups } | ||
|
||
/// `ri_pageins`: TBD | ||
public var pageIns: UInt64 { rawValue.ri_pageins } | ||
|
||
/// `ri_wired_size`: TBD | ||
public var wiredSize: UInt64 { rawValue.ri_wired_size } | ||
|
||
/// `ri_resident_size`: TBD | ||
public var residentSize: UInt64 { rawValue.ri_resident_size } | ||
|
||
/// `ri_phys_footprint`: TBD | ||
public var physicalFootprint: UInt64 { rawValue.ri_phys_footprint } | ||
|
||
/// `ri_proc_start_abstime`: TBD | ||
public var processStartAbsoluteTime: UInt64 { rawValue.ri_proc_start_abstime } | ||
|
||
/// `ri_proc_exit_abstime`: TBD | ||
public var processExitAbsoluteTime: UInt64 { rawValue.ri_proc_exit_abstime } | ||
|
||
/// `ri_child_user_time`: TBD | ||
public var childUserTime: UInt64 { rawValue.ri_child_user_time } | ||
|
||
/// `ri_child_system_time`: TBD | ||
public var childSystemTime: UInt64 { rawValue.ri_child_system_time } | ||
|
||
/// `ri_child_pkg_idle_wkups`: TBD | ||
public var childPkgIdleWakeups: UInt64 { rawValue.ri_child_pkg_idle_wkups } | ||
|
||
/// `ri_child_interrupt_wkups`: TBD | ||
public var childInterruptWakeups: UInt64 { rawValue.ri_child_interrupt_wkups } | ||
|
||
/// `ri_child_pageins`: TBD | ||
public var childPageIns: UInt64 { rawValue.ri_child_pageins } | ||
|
||
/// `ri_child_elapsed_abstime`: TBD | ||
public var childElapsedAbsoluteTime: UInt64 { rawValue.ri_child_elapsed_abstime } | ||
|
||
/// `ri_diskio_bytesread`: TBD | ||
public var diskIOBytesRead: UInt64 { rawValue.ri_diskio_bytesread } | ||
|
||
/// `ri_diskio_byteswritten`: TBD | ||
public var diskIOBytesWritten: UInt64 { rawValue.ri_diskio_byteswritten } | ||
|
||
/// `ri_cpu_time_qos_default`: TBD | ||
public var cpuTimeQOSDefault: UInt64 { rawValue.ri_cpu_time_qos_default } | ||
|
||
/// `ri_cpu_time_qos_maintenance`: TBD | ||
public var cpuTimeQOSMaintenance: UInt64 { rawValue.ri_cpu_time_qos_maintenance } | ||
|
||
/// `ri_cpu_time_qos_background`: TBD | ||
public var cpuTimeQOSBackground: UInt64 { rawValue.ri_cpu_time_qos_background } | ||
|
||
/// `ri_cpu_time_qos_utility`: TBD | ||
public var cpuTimeQOSUtility: UInt64 { rawValue.ri_cpu_time_qos_utility } | ||
|
||
/// `ri_cpu_time_qos_legacy`: TBD | ||
public var cpuTimeQOSLegacy: UInt64 { rawValue.ri_cpu_time_qos_legacy } | ||
|
||
/// `ri_cpu_time_qos_user_initiated`: TBD | ||
public var cpuTimeQOSUserInitiated: UInt64 { rawValue.ri_cpu_time_qos_user_initiated } | ||
|
||
/// `ri_cpu_time_qos_user_interactive`: TBD | ||
public var cpuTimeQOSUserInteractive: UInt64 { rawValue.ri_cpu_time_qos_user_interactive } | ||
|
||
/// `ri_billed_system_time`: TBD | ||
public var billedSystemTime: UInt64 { rawValue.ri_billed_system_time } | ||
|
||
/// `ri_serviced_system_time`: TBD | ||
public var servicedSystemTime: UInt64 { rawValue.ri_serviced_system_time } | ||
|
||
/// `ri_logical_writes`: TBD | ||
public var logicalWrites: UInt64 { rawValue.ri_logical_writes } | ||
|
||
/// `ri_lifetime_max_phys_footprint`: TBD | ||
public var lifetimeMaxPhysicalFootprint: UInt64 { rawValue.ri_lifetime_max_phys_footprint } | ||
|
||
/// `ri_instructions`: TBD | ||
public var instructions: UInt64 { rawValue.ri_instructions } | ||
|
||
/// `ri_cycles`: TBD | ||
public var cycles: UInt64 { rawValue.ri_cycles } | ||
|
||
/// `ri_billed_energy`: TBD | ||
public var billedEnergy: UInt64 { rawValue.ri_billed_energy } | ||
|
||
/// `ri_serviced_energy`: TBD | ||
public var servicedEnergy: UInt64 { rawValue.ri_serviced_energy } | ||
|
||
/// `ri_interval_max_phys_footprint`: TBD | ||
public var intervalMaxPhysicalFootprint: UInt64 { rawValue.ri_interval_max_phys_footprint } | ||
|
||
/// `ri_runnable_time`: TBD | ||
public var runnableTime: UInt64 { rawValue.ri_runnable_time } | ||
|
||
/// `ri_flags`: TBD | ||
public var flags: UInt64 { rawValue.ri_flags } | ||
|
||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,113 @@ | ||||||||||
|
||||||||||
public struct Signal: RawRepresentable, Hashable { | ||||||||||
public var rawValue: CInt | ||||||||||
public init(rawValue: CInt) { self.rawValue = rawValue } | ||||||||||
fileprivate init(_ rawValue: CInt) { self.init(rawValue: rawValue) } | ||||||||||
} | ||||||||||
|
||||||||||
// FIXME(DO NOT MERGE): Migrate these to the constants.swift file | ||||||||||
import Darwin | ||||||||||
|
||||||||||
extension Signal { | ||||||||||
#if os(Linux) | ||||||||||
public static var unused: Signal { Signal(SIGUNUSED) } | ||||||||||
#endif | ||||||||||
|
||||||||||
// TODO: better names | ||||||||||
|
||||||||||
/// SIGHUP (1): terminal line hangup (default behavior: terminate process) | ||||||||||
public static var hangup: Signal { Signal(SIGHUP) } | ||||||||||
lorentey marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
|
||||||||||
/// SIGINT (2): interrupt program (default behavior: terminate process) | ||||||||||
public static var interrupt: Signal { Signal(SIGINT) } | ||||||||||
|
||||||||||
/// SIGQUIT (3): quit program (default behavior: create core image) | ||||||||||
public static var quit: Signal { Signal(SIGQUIT) } | ||||||||||
|
||||||||||
/// SIGILL (4): illegal instruction (default behavior: create core image) | ||||||||||
public static var illegalInstruction: Signal { Signal(SIGILL) } | ||||||||||
|
||||||||||
/// SIGTRAP (5): trace trap (default behavior: create core image) | ||||||||||
public static var traceTrap: Signal { Signal(SIGTRAP) } | ||||||||||
|
||||||||||
/// SIGABRT (6): abort program (formerly SIGIOT) (default behavior: create core image) | ||||||||||
public static var abort: Signal { Signal(SIGABRT) } | ||||||||||
|
||||||||||
/// SIGEMT (7): emulate instruction executed (default behavior: create core image) | ||||||||||
public static var emulatorTrap: Signal { Signal(SIGEMT) } | ||||||||||
|
||||||||||
/// SIGFPE (8): floating-point exception (default behavior: create core image) | ||||||||||
public static var floatingPointException: Signal { Signal(SIGFPE) } | ||||||||||
|
||||||||||
/// SIGKILL (9): kill program (default behavior: terminate process) | ||||||||||
public static var kill: Signal { Signal(SIGKILL) } | ||||||||||
|
||||||||||
/// SIGBUS (10): bus error (default behavior: create core image) | ||||||||||
public static var busError: Signal { Signal(SIGBUS) } | ||||||||||
|
||||||||||
/// SIGSEGV (11): segmentation violation (default behavior: create core image) | ||||||||||
public static var segmentationViolation: Signal { Signal(SIGSEGV) } | ||||||||||
|
||||||||||
/// SIGSYS (12): non-existent system call invoked (default behavior: create core image) | ||||||||||
public static var unknownSystemCall: Signal { Signal(SIGSYS) } | ||||||||||
|
||||||||||
/// SIGPIPE (13): write on a pipe with no reader (default behavior: terminate process) | ||||||||||
public static var brokenPipe: Signal { Signal(SIGPIPE) } | ||||||||||
|
||||||||||
/// SIGALRM (14): real-time timer expired (default behavior: terminate process) | ||||||||||
public static var alarm: Signal { Signal(SIGALRM) } | ||||||||||
|
||||||||||
/// SIGTERM (15): software termination signal (default behavior: terminate process) | ||||||||||
public static var terminate: Signal { Signal(SIGTERM) } | ||||||||||
lorentey marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
|
||||||||||
/// SIGURG (16): urgent condition present on socket (default behavior: discard signal) | ||||||||||
public static var urgentCondition: Signal { Signal(SIGURG) } | ||||||||||
|
||||||||||
/// SIGSTOP (17): stop (cannot be caught or ignored) (default behavior: stop process) | ||||||||||
public static var stop: Signal { Signal(SIGSTOP) } | ||||||||||
|
||||||||||
/// SIGTSTP (18): stop signal generated from keyboard (default behavior: stop process) | ||||||||||
public static var temporaryStop: Signal { Signal(SIGTSTP) } | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the T is short for "terminal" in this case; this is a job control thing, generated on C-z. It's the polite way to request that a process suspend itself, so what if:
Suggested change
C.f. the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh god, this is a great argument for not renaming them from what they are. I know There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really don't think so. People who operate at this level know exactly what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Calling it Either There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, POSIX calls it "Terminal stop signal". That sort of settles it for me.
Suggested change
|
||||||||||
|
||||||||||
/// SIGCONT (19): continue after stop (default behavior: discard signal) | ||||||||||
public static var `continue`: Signal { Signal(SIGCONT) } | ||||||||||
|
||||||||||
/// SIGCHLD (20): child status has changed (default behavior: discard signal) | ||||||||||
public static var childProcessStatusChange: Signal { Signal(SIGCHLD) } | ||||||||||
|
||||||||||
/// SIGTTIN (21): background read attempted from control terminal (default behavior: stop process) | ||||||||||
public static var backgroundReadFromControllingTerminal: Signal { Signal(SIGTTIN) } | ||||||||||
|
||||||||||
/// SIGTTOU (22): background write attempted to control terminal (default behavior: stop process) | ||||||||||
public static var backgroundWriteToControllingTerminal: Signal { Signal(SIGTTOU) } | ||||||||||
|
||||||||||
/// SIGIO (23): I/O is possible on a descriptor (see fcntl(2)) (default behavior: discard signal) | ||||||||||
public static var ioAvailable: Signal { Signal(SIGIO) } | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the |
||||||||||
|
||||||||||
/// SIGXCPU (24): cpu time limit exceeded (see setrlimit(2)) (default behavior: terminate process) | ||||||||||
public static var cpuLimitExceeded: Signal { Signal(SIGXCPU) } | ||||||||||
|
||||||||||
/// SIGXFSZ (25): file size limit exceeded (see setrlimit(2)) (default behavior: terminate process) | ||||||||||
public static var fileSizeLimitExceeded: Signal { Signal(SIGXFSZ) } | ||||||||||
|
||||||||||
/// SIGVTALRM (26): virtual time alarm (see setitimer(2)) (default behavior: terminate process) | ||||||||||
public static var virtualAlarm: Signal { Signal(SIGVTALRM) } | ||||||||||
|
||||||||||
/// SIGPROF (27): profiling timer alarm (see setitimer(2)) (default behavior: terminate process) | ||||||||||
public static var profilingAlarm: Signal { Signal(SIGPROF) } | ||||||||||
|
||||||||||
/// SIGWINCH (28): Window size change (default behavior: discard signal) | ||||||||||
public static var windowSizeChange: Signal { Signal(SIGWINCH) } | ||||||||||
|
||||||||||
/// SIGINFO (29): status request from keyboard (default behavior: discard signal) | ||||||||||
public static var info: Signal { Signal(SIGINFO) } | ||||||||||
|
||||||||||
/// SIGUSR1 (30): User defined signal 1 (default behavior: terminate process) | ||||||||||
public static var user1: Signal { Signal(SIGUSR1) } | ||||||||||
|
||||||||||
/// SIGUSR2 (31): User defined signal 2 (default behavior: terminate process) | ||||||||||
public static var user2: Signal { Signal(SIGUSR2) } | ||||||||||
|
||||||||||
} | ||||||||||
|
||||||||||
// TODO: unavailable renamed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turns out we should just import Darwin! Since System isn't an overlay, it doesn't need to reexport the module, and merely importing it won't pollute the client namespace with C junk. 🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use
Darwin
's types though? Also, can we do this with ourCSystem
module as well (which is needed for Linux, sincelibC
isn'tlibSystem
).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so -- if people only import System, they will still be able to refer to these types by one of their System typealiases (such as the ones in CInterop or RawValue). (They can't spell
Darwin.foo
unless they import it.)CSystem
is trickier, because it shouldn't be a public module, so we should continue to import it@_implementationOnly
.