-
Notifications
You must be signed in to change notification settings - Fork 306
Implement syscall ioctl
#1903
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
Implement syscall ioctl
#1903
Conversation
src/core/IronPython.Modules/fcntl.cs
Outdated
|
|
||
| ulong cmd = unchecked((ulong)request); | ||
|
|
||
| long data = arg switch { |
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 guess I should have suggested this in the last PR, but what about using PythonOps.Index(arg)?
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 looked at it too, but it doesn't do what is needed here:
- it doesn't handle
System.Reflection.Missing - it doesn't handle non-standard integer types like
uint,long,ulong - it returns
objectso aswitchis still needed to cast to an unmanaged type - it tries to call
__index__and this is not what Python does here
But now this code is being used in two places so I guess I might as well factor it out. I'm not sure it deserves to be promoted to PythonOps, but something similar is used in termios, except for the error message. Maybe I just leave it here and make internal; termios is already using some helper methods from fcntl, and these two modules are somewhat coupled.
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 doesn't handle non-standard integer types like
uint,long,ulong
They don't have a fast path since they're not typically expected in Python code, but they do end up being resolves via __index__ calls.
- it returns
objectso aswitchis still needed to cast to an unmanaged type
True. Could have an some helpers such as PythonOps.IndexAsLong.
- it tries to call
__index__and this is not what Python does here
In recent versions of Python, __index__ is supported pretty much everywhere. For example (only tried on 3.10.12, I guess it's always possible they reverted since):
import fcntl
import termios
class Index:
def __init__(self, idx):
self.idx = idx
def __index__(self):
return self.idx
fcntl.ioctl(0, Index(termios.TIOCGPGRP), b" ")
# not a valid call, but does throw TypeError: __index__ returned non-int (type bytes)
fcntl.ioctl(0, Index(termios.TIOCGPGRP), Index(b" "))Anyway, I don't have an objection to what you're proposing it just looked a lot like what index does.
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.
In recent versions of Python,
__index__is supported pretty much everywhere. For example (only tried on 3.10.12, I guess it's always possible they reverted since):
Ah, I see. On maxOS I am using 3.7 and on Linux 3.6 for testing (which are the oldest I could easily get, 3.4 is nowhere easily available anymore). I see that 3.8 – 3.12 all support __index__. It's moving target…
Could have an some helpers such as
PythonOps.IndexAsLong.
I like the idea. From my memory, this or a similar conversion is happening in more places. I think PythonOps.TryGetInt64 that doesn't do unnecessary try/catch would be more practical. Anyway, I'll keep it in mind, this is not something for this PR.
|
I forgot to mention, the code does not support |
|
Side note since I know nothing about these functions I looked up the Python docs and the example they give is using a fcntl.ioctl(0, termios.TIOCGPGRP, " ")
No problem for Mono. Feels like it's effectively abandoned anyway? |
It's a good point. I saw it but concluded that this is an artifact from the 2.x era — it used to be So ideally the doc should read: fcntl.ioctl(0, termios.TIOCGPGRP, b'\0' * 4)which clearly shows how many bytes the OS buffer should be (on macOS it's 4, on Linux 2 minimum). But when I tested the code, |
|
Another note about the misleading documentation. The part on
This is not correct. "Things" might not work. If |
This replaces the mock
ioctlimplementation with the actual syscall.The tricky part of it is that the
ioctlprototype is variadic, is not supported by the Mono.Unix shim, and .NET does not yet support variadic P/Invoke calls on POSIX. There is a long discussion on this topic (dotnet/runtime#48796) but after 4 years it does not seem to converge on any solution. As one of the commentators wrote: "perfect is the enemy of good". Hopefully in the next several years this will be sorted out, but in the meantime, an obscure workaround is needed to make a variadic P/Invoke work on ARM64. Too bad that we have to manage that level of calling convention detail and not the compiler, but I know of no alternative.I put pragma
#errorthere that gets triggered on any new .NET version we haven't tested yet as a remainder to check if the variadic P/Invokes are finally supported, and if not, just advance the .NET version to the next future one for the next round of checks.A similar solution could be applied to the
fcntlcall, which is also variadic, and unblock a bunch of newerF_*commands that are currently being rejected by Mono.Unix, but it is not my priority right now (unless I hit a roadblock there trying to run my favourite modules).