-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Windows Process API #8518
Windows Process API #8518
Conversation
this looks like a lot of work. Thank you for pushing forward Windows support. |
This is really awesome. Thank you very much! It's also quite a lot of code and a huge task to review. The overall design looks good to me. But we'll certainly have to talk about the public API in detail. We should try to split this feature into smaller bites of self-contained changes, to separate commits and preferably even separate PRs. I assume some parts can be extracted and merged on their own. This makes it easier to review and discuss each individual feature without getting lost. Skimming over it, I could think of a few ideas:
|
Thanks for initiating this! I think the one thing I dont like are the Signal changes. The only reason we need them with Process is to know and report when a spawned process has terminated on POSIX (SIGCHLD), which is achieved differently on Windows. The sigset is only there because of how we receive/handle signals with the EventLoop and fork/exec semantics; it's not needed on Windows. I would leave Signal alone for the time being, not abstracting it into System (yet) and obviously not requiring it on win32. This would help to focus the pull request on Process itself for Win32. It only needs Signal on POSIX. Last but not least, having focused commits, instead of one big commit, as proposed by @straight-shoota would be very appreciated. |
ccf6142
to
0a7a12d
Compare
0a7a12d
to
ff1c4fe
Compare
@ysbaddaden, @straight-shoota thank you for first feedback. I made these changes:
|
@jan-zajic Only to add to what others already said: this is excellent, thank you so much! With efforts like these Windows support is closer and closer. I'll try to review the commits during these days if I can, though I'll admit I'm a bit clueless regarding OS processes, fork, signals, and of course the Windows API. But at this point I think it's better to get something working and being able to bootstrap the compiler to Windows. At that point development becomes much easier and we can worry more about the small details or performance matters. Again, thank you! ❤️❤️❤️ |
It would also be nice if you could add some comments explaining the reasoning behind some changes. For example when some code is excluded on @Sija Please don't suggest circumstantial style improvements while we still haven't discussed the overall API and implementation. This is just unnecessary noise at the moment. |
The most important feature is the public API design for All documentation for public API should be directly in
Relevant precursor PR: #6744 |
@straight-shoota, @asterite and all other - i was thinking very much about that and here (#8524) is my proposal how I think it's the best to deal with public platform dependent apis. Please let's discuss it there, before we continue our work on this Process related PR .. |
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.
Looking at Go, it looks like both Process.pid
and .ppid
can be implemented on Windows with and getCurrentProcessId
(already did)GetProcessEntry
for PPID which look compatible with POSIX (just integers). Other methods like .pgid
(and uid
, gid
, euid
, egid
) are dummies returning -1. See https://golang.org/pkg/os.
I propose to:
- keep most methods into Process itself (instead of crystal/system/process) and follow up on Go with
(already done)pid_system
,ppid_system
andpgid_system
methods; - keep
fork
buried in crystal/system/process, we're leaning on removing it anyway (withexec
,exec_internal
,fork_internal
this becoming internal API for POSIX); - remove most
LibC
type constraints (e.g.LibC::PidT
) and always return an Int64 —pid_t
is always an Int32 andgid_t
andpid_t
always an UInt32 anyway — I don't know about Windows PID, but Go merely casts them all to the target specificint
, that would stop leaking LibC types to the stdlib;
Maybe:
- use
Process#terminate
instead of#terminate_gracefully
andProcess#kill
instead of#terminate_immediately
; they look simpler to me, yet explicit; - rename
Process#kill(Signal)
toProcess#signal(Signal)
that we can eventually implement on Windows (if needed) with a deprecation notice.
This is mostly details to start shaping the public API. I hope we can agree and quickly merge the Windows implementation of Process!
Sounds good. So do we agree the system implementation should provide the following interface: self.exit_system(status : Int32) : NoReturn
self.pid_system : Int64
self.pgid_system : Int64
self.ppid_system : Int64
self.exist_system?(pid : Int64) : Bool
self.signal_system(pid : Int64, signal : Signal) : Nil
self.terminate_system(pid : Int64) : Nil
self.kill_system(pid : Int64) : Nil
system_close : Nil
create_and_exec(*args) : Int64
self.prepare_shell(command : String, args : Enumerable(String)) : {String, Enumerable(String)}
self.wait(pid : Int64) All these methods should probably be private or protected. Those with One issue exists for sending signals to or kill/terminate to arbitrary processes (by process id). On POSIX this works fine one process id but the windows implementations need process handle or thread id. When there are only class methods receiving pid, the windows implementation needs to lookup the handle/thread id and can't re-use the one from an instance. Alternatively, we could implement both class methods receiving pid and instance methods which can use available information. Another solution might be to re-purpose |
I can implement ppid, but please be aware that pid will be reused by other process if parent terminates and we don't open handle to the parent process. It's different from Linux behavior. Regarding kill methods - i'm fine with kill/terminate if we rename existing kill method and you ok with breaking change. I try named them different to just to differentiate from that current Unix kill method which means send any signal and not send kill signal in accordance with Unix kill command. |
Btw @ysbaddaden i forget to say you that i really don't known about some GetProcessEntry windows api, it's only name of the function in go where it is implemented.. NtQueryInformationProcess must be involved. Strictly speaking, the parent process (the process which created the child process) is not actually recorded. InheritedFromUniqueProcessId just gives you the process from which attributes were inherited. This is very rarely a problem, but is controllable from the CreateProcess call, and can be something other than parent. |
We can surely defer the implementation of |
c0e8eb9
to
4c10d90
Compare
According to that non-portable apis, as it is last remaining design decision necessary to do: i currently keep pgid, signal, fork and chroot as public methods in file unix/process. They are added to reopened class Process. We can (please decide per-method):
|
4c10d90
to
e55bdad
Compare
It's okay to not implement the methods in question for win32. Regarding Could you document the internal interface for |
Splitting this PR into commits is good, but I think it's better to split this into smaller PRs. Reviewing 31 files changed and 1000 lines of code is a task I can't handle right now, maybe it's the same for others. Also, because it's so big many discussions are all discussed in a single place and it's not easy to follow. |
I know everyone wants to get stuck into the code as soon as possible, but to prevent this in the future, please open an issue before sending a PR. We have that in the contribution guide, but it's worth repeating: always make an issue about API changes before sending a PR. Whether you've written the code or not. |
The remainder of this PR merged with master is https://github.com/oprypin/crystal/compare/winapi#files_bucket (504bcc6 as of writing this) I am still planning to try to get that merged, but to be fair I don't quite understand it. FYI @kubo. If you want to take that instead, let me know in advance. |
Replace Fork–exec Unix technique with CreateProcess API on MS Win. As Windows processes don't use the *nix fork idiom, there is no analogue in Windows to forking. Therefore fork without exec on Win is not implemented (it's almost impossible and not so useful on Windows).
Personally tested and working.
Little bit problematic because of currently win implementation of Crystal::EventLoop, but works, so will simplify further development of windows fork. (raise "No runnables in scheduler" must be removed, see changes, then wait on Process result using Channel works, otherwise it hang).
At the same time Signal API reduced to minimal Win supported signals. Also Signal api is not so useful on Win platform.
Part of #5430.
Existing discussion to signals is here: #7339.
There is lot of necessary magic on Win platform when calling CreateProcessW and related apis..