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

Add ability to spawn Windows process with Proc Thread Attributes | Take 2 #114848

Merged
merged 1 commit into from
Aug 28, 2023

Conversation

michaelvanstraten
Copy link
Contributor

@michaelvanstraten michaelvanstraten commented Aug 15, 2023

This is the second attempt to merge pull request #88193 into the standard library.

This PR implements the ability to add arbitrary attributes to a command on Windows targets using a new raw_attribute method on the CommandExt trait.

@TyPR124 and my main motivation behind adding this feature is to enable the support of pseudo terminals in the std library, but there are many more applications. A good starting point to get into this topic is to head over to the Win32 API documentation.

@rustbot
Copy link
Collaborator

rustbot commented Aug 15, 2023

r? @ChrisDenton

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 15, 2023
@rust-log-analyzer

This comment has been minimized.

@michaelvanstraten michaelvanstraten force-pushed the spawn_with_attributes branch 2 times, most recently from ee8a884 to e035a33 Compare August 15, 2023 10:47
@michaelvanstraten
Copy link
Contributor Author

michaelvanstraten commented Aug 15, 2023

Okay the tracking issue has been created under #114854.

@michaelvanstraten
Copy link
Contributor Author

michaelvanstraten commented Aug 15, 2023

Before bringing this to review I would like to revisit the conversation about the parallels between proc attributes and thread attributes.

Since both support the attachment of attributes and the api is the same for both I think that the current implementation of this PR should be changed.

I believe we can make this work with threads by ether:

  • creating a ProcThreadAttribute trait implemented for std::thread::Builder and std::process::Command
    or
  • putting the implementation of the creation of ProcThreadAttributeList in a struct that both std::tread::Builder and std::process::Command can access

I think the later is more practical since windows states that a ProcThreadAttributeList can be used to crate multiple process/threads.

Second thing:

Removing the Pin since it doesn’t prevent use from moving the data anyway. I think a Box would be just fine.

@ChrisDenton
Copy link
Member

ChrisDenton commented Aug 15, 2023

putting the implementation of the creation of ProcThreadAttributeList in a struct that both std::thread::Builder and std::process::Command can access

I would tend to agree this is the better option but I think revisiting the old API would require a new ACPppropriate. It could explain the proposed public API for both Command and thread::Builder.

Alternatively we could start with merging what we have here and leave discussion on an improved API to the tracking issue.

@michaelvanstraten
Copy link
Contributor Author

michaelvanstraten commented Aug 15, 2023

@ChrisDenton I didn't exactly get what you were saying should I open a new ACP or not?

For now, I wouldn't change the public interface, except maybe the documentation.

@ChrisDenton
Copy link
Member

If you're not changing the API from the original then I think it's fine to go ahead with this.

Copy link
Member

@ChrisDenton ChrisDenton left a comment

Choose a reason for hiding this comment

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

This is looking good to me but the docs could have a bit more explanation.

library/std/src/os/windows/process.rs Outdated Show resolved Hide resolved
Copy link
Member

@ChrisDenton ChrisDenton left a comment

Choose a reason for hiding this comment

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

The lines in this file are sorted by doing a lowercase comparison. Hopefully this sorting will be better automated in the future.

library/std/src/sys/windows/c/windows_sys.lst Outdated Show resolved Hide resolved
library/std/src/sys/windows/c/windows_sys.lst Outdated Show resolved Hide resolved
@michaelvanstraten
Copy link
Contributor Author

@rustbot label -S-waiting-on-author +S-waiting-on-review

@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Aug 18, 2023
@michaelvanstraten
Copy link
Contributor Author

Somebody has to test this on a windows target, im only on Unix so i can't test this.

Comment on lines 900 to 901
let mut proc_thread_attribute_list =
ProcThreadAttributeList(vec![0u8; required_size as usize].into_boxed_slice());
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be MaybeUninit, but it's optional. Maybe adding fixme?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Whats the benifit of the MaybeUninit?

Copy link
Contributor

@TyPR124 TyPR124 Aug 19, 2023

Choose a reason for hiding this comment

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

MaybeUninit would allow the allocation to be faster, since we'd skip writing all 0's. Since we never directly read the memory, and the Win32 API is just fine with this memory being uninitialized (see example code here near the bottom of that page), we can do the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the clarification

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Happy with the current impl?

Comment on lines 467 to 468
child.kill().unwrap();
parent.kill().unwrap();
Copy link
Member

Choose a reason for hiding this comment

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

These kill calls will not be run if the test panics. This will result in the test process never exiting.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently not on my pc but I will fix that as soon as I get back.

Copy link
Contributor Author

@michaelvanstraten michaelvanstraten Aug 19, 2023

Choose a reason for hiding this comment

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

Okay, in 0e84161 I prevented the test from leaking the process if the spawn of the child fails. But the call to wnic could still fail if it doesn't find the process_id or the binary simply doesn't exist.

Copy link
Contributor Author

@michaelvanstraten michaelvanstraten Aug 19, 2023

Choose a reason for hiding this comment

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

I found the following snippet on Stack Overflow, it locates a parent process using the win32 API:

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>

int main(int argc, char *argv[]) 
{
    int pid = -1;
    HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe = { 0 };
    pe.dwSize = sizeof(PROCESSENTRY32);

    //assume first arg is the PID to get the PPID for, or use own PID
    if (argc > 1) {
        pid = atoi(argv[1]);
    } else {
        pid = GetCurrentProcessId();
    }

    if( Process32First(h, &pe)) {
        do {
            if (pe.th32ProcessID == pid) {
                printf("PID: %i; PPID: %i\n", pid, pe.th32ParentProcessID);
            }
        } while( Process32Next(h, &pe));
    }

    CloseHandle(h);
}

Maybe this could be more stable?

All functions are loaded through Kernel32.dll and are available since Windows XP and Windows Server 2003.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@TyPR124 what are your thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

The easiest way to ensure a process is killed would be to wrap the spawned Child in a tuple struct that implements drop. E.g.:

struct Process(crate::process::Child);
impl Drop for Process {
    fn drop(&mut self) {
        let _ = self.0.kill();
    }
}
let parent = Process(Command::new("cmd.exe").spawn().unwrap());

Copy link
Member

@ChrisDenton ChrisDenton Aug 20, 2023

Choose a reason for hiding this comment

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

I do think it's also useful to also use the winapi directly instead of wmic though. The wmic utility is marked as deprecated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, I will try to test the win32 API version on a windows target as soon as possible.

Copy link
Contributor Author

@michaelvanstraten michaelvanstraten left a comment

Choose a reason for hiding this comment

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

Okay, this is a mock-up implementation for now. If this is unwanted, I will revert the change tomorrow.

library/std/src/process/tests.rs Outdated Show resolved Hide resolved
library/std/src/process/tests.rs Outdated Show resolved Hide resolved
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. O-windows Operating system: Windows S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 22, 2023
Copy link
Member

@ChrisDenton ChrisDenton left a comment

Choose a reason for hiding this comment

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

Ok, this is looking ready to merge. Just one small thing then please squish your commits when you're ready.

You might also want to update your opening post to reflect the current state of this PR.

library/std/src/sys/windows/process.rs Outdated Show resolved Hide resolved
@michaelvanstraten
Copy link
Contributor Author

Okay, I will squash all commit now, or @TyPR124 should I keep yours at the base?

@ChrisDenton
Copy link
Member

Squish your commits but make sure that the commit message has Co-authored-by: lines at the end to give proper credit

This implements the ability to add arbitrary attributes to a command on Windows targets using a new `raw_attribute` method on the [`CommandExt`](https://doc.rust-lang.org/stable/std/os/windows/process/trait.CommandExt.html) trait. Setting these attributes provides extended configuration options for Windows processes.

Co-authored-by: Tyler Ruckinger <[email protected]>
@michaelvanstraten
Copy link
Contributor Author

@ChrisDenton Is there anything left for me to do ?

@ChrisDenton
Copy link
Member

Nope, just waiting on me to take a final look at the code. Which I've now done, so let's see if CI is happy with it.

@bors r+

@bors
Copy link
Contributor

bors commented Aug 28, 2023

📌 Commit edefa8b has been approved by ChrisDenton

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 28, 2023
@bors
Copy link
Contributor

bors commented Aug 28, 2023

⌛ Testing commit edefa8b with merge 9847c64...

@bors
Copy link
Contributor

bors commented Aug 28, 2023

☀️ Test successful - checks-actions
Approved by: ChrisDenton
Pushing 9847c64 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Aug 28, 2023
@bors bors merged commit 9847c64 into rust-lang:master Aug 28, 2023
11 checks passed
@rustbot rustbot added this to the 1.74.0 milestone Aug 28, 2023
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (9847c64): comparison URL.

Overall result: no relevant changes - no action needed

@rustbot label: -perf-regression

Instruction count

This benchmark run did not return any relevant results for this metric.

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-1.9% [-2.2%, -1.7%] 2
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -1.9% [-2.2%, -1.7%] 2

Cycles

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-1.8% [-2.1%, -1.5%] 2
All ❌✅ (primary) - - 0

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 630.025s -> 630.448s (0.07%)
Artifact size: 316.26 MiB -> 316.23 MiB (-0.01%)

jsturtevant added a commit to jsturtevant/power-process that referenced this pull request Aug 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merged-by-bors This PR was explicitly merged by bors. O-windows Operating system: Windows S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants