-
Notifications
You must be signed in to change notification settings - Fork 114
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
让rust程序支持Windows XP RTM(rust程序兼容性问题请统一在此帖回复) #80
Comments
@wapznw |
好像是mio中调用WSAIoctl传递的SIO_BASE_HANDLE在Windows XP中不支持。 |
已经更新需求,因为rust的人比较少所以暂时只记录问题(目前也还有很多其他API缺失问题需要处理,人力不足)。 如果你有解决方案也可以提交PR到YY-Thunks。 |
mio不支持xp系统。目前也没有人做这方面的移植工作,所以所有与async相关的net io库都不能用。std的应该还是可以用的。 |
这些信息我们知道,所以需要做的是在yY-Thunks里重新支持上那些不支持的功能,这样mio就可以正常在XP使用了。 |
原因: 如何解决: 副作用:
|
@zhuxiujia 注释掉肯定是不行的,wsaloctl相当于是获取一个可异步操作的socket句柄,如果没有这一步,等于是在异步环境中使用一个同步的socket。 |
用ioctlsocket 调用FIONBIO 还是不行的,tokio还是会出现 “由于线程退出或应用程序请求,已放弃 I/O 操作。” |
应该和SIO_BASE_HANDLE 没关系,在win11上 注释掉SIO_BASE_HANDLE 这些代码直接使用base_socket 也不影响正常运行 |
我的测试步骤是 结论: |
Related: tokio-rs/mio#735. I'm so close to getting a pure Rust TLS1.3 implementation running on Windows XP with async support... |
I made it! I can finally run reqwest on a fresh Windows XP SP3 system out of the box without any kernel patches! #[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Error> {
let _ = rustls_rustcrypto::provider().install_default();
let _ = tokio::spawn(async move {
let exec = async {
Ok::<_, Error>(reqwest::get("https://www.rust-lang.org").await?.text().await?)
}.await;
match exec {
Ok(data) => println!("{data}"),
Err(e) => println!("{e:?}")
}
})
.await;
press_btn_continue::wait("Press any key to continue...")?;
Ok(())
} Notice how I have to use This is because NtCancelIoFileEx does this
This means if we can pin the cancellation request to the same thread the request was created on, then we can use NtCancelIoFile as an alternative for NtCancelIoFileEx (since there are no other threads requests to cancel). Keep in mind using |
@stevefan1999-personal This is works because the entire tokenization has become single threaded, sacrificing performance. |
Yes, and that's how you do it right now: #[tokio::main]
async fn main() -> Result<(), Error> {
let _ = rustls_rustcrypto::provider().install_default();
tokio::task::spawn_blocking(|| {
Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(async {
loop {
let _ = tokio::spawn(async move {
let exec = async {
Ok::<_, Error>(
reqwest::get("https://www.rust-lang.org")
.await?
.text()
.await?,
)
}
.await;
match exec {
Ok(data) => println!("{data}"),
Err(e) => println!("{e:?}"),
}
})
.await;
}
})
});
press_btn_continue::wait("Press any key to continue...")?;
Ok(())
} We use a spawn_blocking to pin a specific thread for I/O operations, and we still can have other worker threads to do their job. The problem is that mio uses file cancellation to notify other threads for completed job cleanup (marked as deletion), so if any mio cancel operation is used outside of the single-threaded context, it will also break all the event poll ongoing in other worker threads as well which causes a panic. Also, |
Not sure if we can use APC to work around the limitations of NtCancelIoFile https://learn.microsoft.com/en-us/windows/win32/sync/asynchronous-procedure-calls |
@stevefan1999-personal If you are using Hyper or Axum, it accepts in a thread and then uses TikTok:: spawn to handle it. We know that TikTok:: spawn will submit a task to the runtime, which can be stolen by any worker thread and executed. That is to say, migrating from one thread to another thread。 so.... Why not design an IO management scheduler in MIO to cancel the IO generated by the corresponding thread itself。 The key to implementing a task stealing mechanism similar to SMOL in MIO is to design a system that can track and manage I/O requests across threads, as there is no precise I/O cancellation API like NtCancelIoFileEx on Windows XP. By using a global I/O request table and task migration tracking logic, combined with the use of I/O completion ports, you can achieve cross threaded I/O operation tracking and "simulated cancellation", although the underlying layer cannot accurately cancel specific I/O requests like modern Windows. |
Oh it looks like NtCancelIoFileEx accepts an overlapped I/O filtering request and the second parameter for NtCancelIoFile is actually not it. |
Yes, the IO should be cancelled according to LPOVERLAPPED |
Yep...after experimenting I noticed that if I do nothing at all with NtCancelIoFileEx and just return STATUS_NOT_FOUND, that actually fared much better thatn calling NtCancelIoFile. The problem exactly come from the lack of passing of LPOVERLAPPED, so it cancels every outstanding I/O requests on that is on the current calling thread. Using NtCancelIoFile alone is simply cooked. |
Ah, god damn it, they have a major redesign of Overlapped I/O in Vista:
Reference: https://lenholgate.com/blog/2008/02/major-vista-overlapped-io-change.html So, that's the whole reason NtCancelIoFileEx was introduced exactly since Vista. I guess there is no help that there is no solution to NtCancelIoFileEx at the moment for mio right now unless we do kernel patches and deliberately add that to the syscall, and so you either fall back to single-threaded I/O in Tokio, or threaded I/O without using IOCP. It's simply not worth the trouble I would argue. |
No, if you just return You can try using two browsers open #[tokio::main]
async fn main() {
// build our application with a route
let app = Router::new().route("/", get(handler));
// run it
let listener = tokio::net::TcpListener::bind("0.0.0.0:8000")
.await
.unwrap();
println!("listening on http://127.0.0.1:8000");
axum::serve(listener, app).await.unwrap();
}
async fn handler() -> Html<&'static str> {
Html("<h1>Hello, World!</h1>")
} |
Tokio, and by extension mio, should work after the patches above in single threaded mode, sadly but for Tokio to truly work in a multithreaded environment with work stealing, you need at least Windows Vista because there is a fundamental change in overlapped I/O since Vista, specifically that the IO request is no longer bound to the lifetime of the thread, and can continue working after the thread that created it completed, meaning the overlapped I/O operation is independent of the thread, and there is no need for the creator thread to clean it up. If you want to, you can spawn a new thread for the async I/O operation if you don't mind the Send+Sync requirement. Fun fact: Windows 7 is just a Vista reskin and the kernel itself did not have many significant changes after Vista, except Hyper-V, Windows Container, and some confidential computing stuff I think. |
@stevefan1999-personal @zhuxiujia 新版本中对SetFileCompletionNotificationModes函数进行了小幅度调整,可能对tokio产生影响。如果可能请帮忙做一些测试,有问题也及时发现。 谢谢 |
背景
rust也放弃了兼容Windows 7或者XP,需要YY-Thunks统一支持。如果您遇到rust相关项目API缺失,请在此帖统一回复。
如果你的程序提示找不到API,请使用YY-Thunk内置的YY.Depends.Analyzer扫描你的应用程序。扫描程序将检查所有缺失的API,并且整理成报告,这样可以极减少遗漏的概率。
缺失或者功能不全的函数
Ws2_32.dll
KERNEL32.DLL
The text was updated successfully, but these errors were encountered: