-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add socket sendfile function #2311
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
Conversation
I'm so sorry, I should've checked before but this isn't actually how the sendfile method is implemented. It's implemented in the Python |
Oh, no problem. I will try to implement using low level functions. I saw that if the OS doesn't have |
Yup, pretty much. We don't even need to edit socket.py since it already checks that Line 343 in 3c9ad23
For examples, you can look at other functions in #[cfg(any(target_os = "linux", target_os = "otheros..."))]
#[pyfunction]
fn sendfile(out_fd: i32, in_fd: i32, offset: ...) -> PyResult<...> {
...
}
#[cfg(any(target_os = "macos", target_os = "otheros..."))]
#[pyfunction]
fn sendfile(out_fd: i32, in_fd: i32, ..., headers: PyObjectRef, trailers: PyObjectRef, flags: i32) -> PyResult<...> {
...
} You probably want to use the nix crate's sendfile wrappers, linux and macos; that would mean you wouldn't have to deal with the raw libc APIs yourself. |
Nice! I implemented the |
f4b9bd6
to
ca054c0
Compare
extra_tests/snippets/stdlib_os.py
Outdated
src_fd = os.open('README.md', os.O_RDONLY) | ||
dest_fd = os.open('destination.md', os.O_RDWR | os.O_CREAT) | ||
src_len = os.stat('README.md').st_size | ||
|
||
bytes_sent = os.sendfile(dest_fd, src_fd, 0, src_len) | ||
assert src_len == bytes_sent | ||
|
||
os.lseek(dest_fd, 0, 0) | ||
assert os.read(src_fd, src_len) == os.read(dest_fd, bytes_sent) | ||
os.close(src_fd) | ||
os.close(dest_fd) | ||
|
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.
You probably want to put this in a if hasattr(os, "sendfile"):
block
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.
Done!
vm/src/stdlib/os.rs
Outdated
headers.into_option(), | ||
trailers.into_option(), |
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.
You have to process these into an array of buffers (&[&[u8]]
) first -- something like
let headers = match headers.into_option() {
Some(x) => Some(vm.extract_elements::<PyBytesLike>(&x)?),
None => None,
};
let headers = headers.as_ref().map(|v| v.iter().map(|b| b.borrow_value()).collect::<Vec<_>>());
let headers = headers.as_ref().map(|v| v.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>());
let headers = headers.as_deref();
And then the same thing for trailers. That's really inefficient, what with creating like 3 different vecs, but I think I could submit a PR to nix
to allow sendfile to accept any IntoIterator
over AsRef<[u8]>
, and then we could make this more efficient later.
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.
So basically with those lines we are transforming PyObject into bytes? I put those lines and it worked, now the macos tests give me this error:
359 | pub(crate) fn sendfile(
| ^^^^^^^^ the trait `function::sealed::PyNativeFuncInternal<_, _, _>` is not implemented for `for<'r> fn(i32, i32, i64, i64, function::OptionalArg, function::OptionalArg, function::OptionalArg<i64>, &'r vm::VirtualMachine) -> std::result::Result<pyobjectrc::PyObjectRc, pyobject::PyRef<exceptions::PyBaseException>> {stdlib::os::_os::sendfile}`
|
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.
Oh, to fix that you can add another macro call (or 2?) after line 642 in vm/src/function.rs
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.
And yep, PyBytesLike
is anything that implements the buffer protocol (e.g. bytes
, bytearray
, memoryview
), PyBytesLike.borrow_value()
gets a read lock to the data, and then the &**
dereferences it to a &[u8]
.
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.
Done! Now that os
module has sendfile
function, a python test is broken because it uses a create_file
function that tries to open the file in xb
mode, and there's no implementation for this mode.
7707f5a
to
eda4f73
Compare
5c879b0
to
84227bb
Compare
I added a commit to skip the test that's failing because of an unrelated issue with |
Thanks! I loved to contribute to this project, what do you think are the next steps to keeping contributing to the project? |
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.
test_shutil also fails for now
count: i64, | ||
headers: OptionalArg<PyObjectRef>, | ||
trailers: OptionalArg<PyObjectRef>, | ||
flags: OptionalArg<i32>, |
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.
Adding _
prefix like _flags
will remove this warning
Looks great, thanks for contributing! re: continue contributing, one way you can do it is to find tests that are expectedFailures/skipped and fix them, or else just try to do stuff in rustpython that you might do usually in python and see if it works (heads up, anything that uses numpy isn't going to happen for a while, since we don't have a c-api) |
This article maybe helpful for test work: https://rustpython.github.io/guideline/2020/04/04/how-to-contribute-by-cpython-unittest.html |
Add socket function that sends all content of a file through the socket.