Skip to content
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

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

milseman
Copy link
Contributor

@milseman milseman commented Feb 5, 2021

Just a draft of low-level strongly typed wrappers for getting the current PID, querying usage information of a processes, and wrappers for signals and signal sets.

@milseman milseman mentioned this pull request Feb 15, 2021

// 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.
Copy link
Member

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. 🎉

Copy link
Contributor Author

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 our CSystem module as well (which is needed for Linux, since libC isn't libSystem).

Copy link
Member

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.

Sources/System/Process/Signal.swift Outdated Show resolved Hide resolved
Sources/System/Process/Signal.swift Outdated Show resolved Hide resolved
public static var busError: Signal { Signal(SIGBUS) }

/// SIGSEGV (11): segmentation violation (default behavior: create core image)
public static var segfault: Signal { Signal(SIGSEGV) }
Copy link
Member

Choose a reason for hiding this comment

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

Segfault is a colloquialism; segmentationFault or segmentationViolation seems like a better fit.

Suggested change
public static var segfault: Signal { Signal(SIGSEGV) }
public static var segmentationViolation: Signal { Signal(SIGSEGV) }

Copy link
Member

Choose a reason for hiding this comment

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

not super how I feel about this. We're not using segmentation anymore but paging, so spelling "segfault" out may not make it easier to find?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Having an unavailable-renamed entry for SIGSEGV would hopefully help point to whatever name we choose.

Copy link
Member

Choose a reason for hiding this comment

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

That's true. But segmentationViolation is still not what this will be sent for so I'd be inclined to leave the as a "term of art".

Copy link
Member

@lorentey lorentey Feb 26, 2021

Choose a reason for hiding this comment

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

Yeah, this is sort of like hangup in that the name has somehow outlived its original meaning, which is now a complete anachronism. SIGSEGV is defined as "segmentation violation" in the man pages, so at least this expansion isn't likely to confuse anyone.

@weissi, what would you propose as a replacement? Note that System is supposed to follow the Swift naming conventions, so the original arbitrary abbreviations need to be replaced, no matter how well known.

Copy link
Member

Choose a reason for hiding this comment

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

FWIW, POSIX describes SIGSEGV as "Invalid memory reference". Would we be willing to name it invalidMemoryReference?

SEGV is such an (in)famous signal, it may be worth spending a term-of-art card on segmentationViolation, no matter how far it is from the current meaning...

Copy link
Member

Choose a reason for hiding this comment

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

invalidMemoryReference is IMHO much better than segmentationViolation. Both names however aren't as good as SIGSEGV or sigsegv IMHO. If you want to program your operating system directly, I think any translation of names is counterproductive and will lead to avoidable bugs, imprecise reviews, etc.

Sources/System/Process/Signal.swift Outdated Show resolved Hide resolved
extension CInterop {
public typealias PID = Int32
public typealias ProcTaskInfo = proc_taskinfo // FIXME
public typealias RUsageInfo = rusage_info_current // FIXME
Copy link
Member

Choose a reason for hiding this comment

The 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.

// FIXME: names
extension ProcessID.ResourceUsageInfo {
// FIXME: UUID proper type
public typealias UUID = (
Copy link
Member

Choose a reason for hiding this comment

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

Foundation already has a wrapper for uuid_t -- perhaps we should investigate shrinking it into System.

public var uuid: UUID { rawValue.ri_uuid }

/// `ri_user_time`: TBD
public var userTime: UInt64 { rawValue.ri_user_time }
Copy link
Member

Choose a reason for hiding this comment

The 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 timespec_t?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 ResourceUsageInfo will be split off from this PR eventually.

}


public struct SignalSet: Hashable, Codable {
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if Codable conformance is a good idea here -- sigset_t values aren't necessarily portable between platforms/architectures.

Copy link
Member

Choose a reason for hiding this comment

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

They are definitely not. Neither are signal numbers, errno codes, or so.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's true, they would have to be encoded/decoded as the string of function calls.

Copy link
Member

Choose a reason for hiding this comment

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

I don't suppose there is a portable/easy way to list the full contents of a signal set, is there? (If we had one, we could maybe add Collection and/or SetAlgebra conformance. OTOH, that'd probably be gilding the lily...)

1 == withUnsafePointer { sigismember($0, sig.rawValue) }
}

public static var empty: SignalSet {
Copy link
Member

Choose a reason for hiding this comment

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

We should also provide a no-argument initializer that creates the empty set.

Copy link
Member

@weissi weissi left a comment

Choose a reason for hiding this comment

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

random drive by

public static var badSyscall: Signal { Signal(SIGSYS) }

/// SIGPIPE (13): write on a pipe with no reader (default behavior: terminate process)
public static var pipe: Signal { Signal(SIGPIPE) }
Copy link
Member

Choose a reason for hiding this comment

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

hmm, you can also get them on sockets...

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) }
Copy link
Member

Choose a reason for hiding this comment

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

I think SIGSTOP is uncatchable so it's not a request.

public typealias RUsageInfo = rusage_info_current // FIXME
}

public struct ProcessID: RawRepresentable, Hashable, Codable {
Copy link

Choose a reason for hiding this comment

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

It seems to me that this is more of a Process (i.e. a system object identified by a pid) than a ProcessID - related APIs such as resource usage are really properties of the process more than the ID.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 Process type would probably be more like an actor with interfaces for interprocess communication. Similarly with a proper File type (though that might be a moveonly buffered struct). ProcessID here is the lower-level systems model of that where we can communicate using descriptors or other forms of IPC.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think Process will be part of SystemPackage or layered on top? If it is part of SystemPackage is there a way to make a stub Process type so that this type could be Process.ID? I'm not sure if this will work for ABI stability (though I also can't say that it won't), but maybe we can create an enum Process that we then upgrade to an actor (or whatever).

@milseman
Copy link
Contributor Author

milseman commented Oct 3, 2021

I think shipping this requires that we finish fleshing out posix_spawn functionality, otherwise we wouldn't have a good vetting of some of the design here.

@GeorgeLyon GeorgeLyon mentioned this pull request Nov 13, 2021
}
}
return TaskInfo(result)
}

Choose a reason for hiding this comment

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

I don't know what the intended scope is for this pull request, but a common need is to get the path and name for a PID. proc_pidpath and proc_name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants