-
Notifications
You must be signed in to change notification settings - Fork 190
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
Winio #559
base: master
Are you sure you want to change the base?
Winio #559
Conversation
So this version doesn't do much yet. It was just me marking what needs updating. I have a bigger branch locally that I was working on where I started functional change or separating out the Fd typ which is the hard part. But didn't get around to finishing it. I'll push it here tomorrow when I'm home for you to see. |
OK. If I understand correctly, an async mechanism should be introduced to make use of WINIO. |
Short answer no, long answer: While for efficiency network should eventually have an async interface, it's not required for the use of WinIO. WINIO is async only, but provides mechanisms for you to implement synchronous APIs on top. primarely using
That's how e.g. For this to work, the FFI call should never block itself. How does that work? I/O calls are wrapped into a helper function that will provide a You also provide a second function to tell it how to interpret results of the API call, e.g, is it done, did it error etc. https://github.com/ghc/ghc/blob/07f858eb1ff419b5190f6999f0d4dd5ba275b40c/libraries/base/GHC/Event/Windows/FFI.hsc#L398 The I/O manager then handles the rest. The issue is that some of the API calls in Network are in the C file. and so we make an FFI call to this C file. We don't want that and instead the call should be made from Haskell land. This removes one FFI call indirection, but also allows the scheduler to see what's running. I think @coot said he will have time to help here. |
@Mistuke we're discussing this internally in IOG, we might indeed find time to work on this. |
If you guys kindly list up things to do, I could help. |
@kazu-yamamoto will do, I'll write up a todo this weekend. Need to go over things again. |
Ok, so the first thing to do is
After that we can hook things up to WinIO. So here's a quick overview of how WinIO works (simplified to what is important for this work): The easiest way to think about WinIO is that it's a As an example I'll use how So typically, a blocking call to ret <- c_ReadFile handle (castPtr outBuffer) (fromIntegral numBytes) nullPtr nullPtr Where the program will block until the I/O finishes. Typically a block on an I/O function is handled specially by the RTS and there's a bit of book keeping that says that an I/O action is being performed. With regards to Now if we look at the documentation for Luckily network already makes the right API calls and passes Line 53 in e4444fb
network/Network/Socket/Buffer.hsc Line 290 in e4444fb
However for other functions, like This is an issue as this API can't be made asynchronous. So for WinIO we need to switch to using the native APIs on Windows: https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsarecv This mapping should be reasonably easy to do, the POSIX functions are just wrappers around the native ones. Now if you've looked at the docs for these functions, the A pointer to a WSAOVERLAPPED structure (ignored for nonoverlapped sockets). So how do we get an overlapped socket? (Haddock doesn't render Windows specific docs so I'll point to src instead). Well to get one after we create a socket, we need to set an overlapped flag, so network/Network/Socket/Syscall.hs Line 86 in e4444fb
socket https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket to the native WSASocket https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsasocketw where (only when WinIO is being used) do we need to pass WSA_FLAG_OVERLAPPED as a flag. This creates the socket in overlapped mode, but it needs to be registered with WinIO.
This can be done through the helper functions After this the I/O manager can track requests on this So how do you get an The difference between The helper function looks like this withOverlappedEx :: forall a.
Manager -- ^ The scheduling manager to use.
-> String -- ^ Handle name
-> HANDLE -- ^ Windows handle associated with the operation.
-> Bool -- ^ whether we should force the application to be synchronous
-> Word64 -- ^ Value to use for the @OVERLAPPED@
-- structure's Offset/OffsetHigh members, determines the offset of which to start reading from
-> StartIOCallback Int -- ^ wrapper around the native I/O function you wish to invoke, this will queue a message.
-> CompletionCallback (IOResult a) -- ^ A utility to tell the I/O manager how to interpret the result of the I/O call.
-> IO (IOResult a) Putting it all together, hwndRead :: Io NativeHandle -> Ptr Word8 -> Word64 -> Int -> IO Int
hwndRead hwnd ptr offset bytes = do
mngr <- Mgr.getSystemManager
fmap fromIntegral $ Mgr.withException "hwndRead" $
withOverlappedEx mngr "hwndRead" (toHANDLE hwnd) (isAsynchronous hwnd)
offset (startCB ptr) completionCB
where
startCB outBuf lpOverlapped = do
debugIO ":: hwndRead"
-- See Note [ReadFile/WriteFile].
ret <- c_ReadFile (toHANDLE hwnd) (castPtr outBuf)
(fromIntegral bytes) nullPtr lpOverlapped
return $ Mgr.CbNone ret
completionCB err dwBytes
| err == #{const ERROR_SUCCESS} = Mgr.ioSuccess $ fromIntegral dwBytes
| err == #{const ERROR_HANDLE_EOF} = Mgr.ioSuccess 0
| err == #{const STATUS_END_OF_FILE} = Mgr.ioSuccess 0
| err == #{const ERROR_BROKEN_PIPE} = Mgr.ioSuccess 0
| err == #{const STATUS_PIPE_BROKEN} = Mgr.ioSuccess 0
| err == #{const ERROR_NO_MORE_ITEMS} = Mgr.ioSuccess $ fromIntegral dwBytes
| err == #{const ERROR_MORE_DATA} = Mgr.ioSuccess $ fromIntegral dwBytes
| otherwise = Mgr.ioFailed err this shows you how everything is tied together, to make an I/O call you call For a list of options see https://github.com/ghc/ghc/blob/182df90e4d1f652c3d078294921805b9b982671b/libraries/base/GHC/Event/Windows.hsc#L465 Once a result is ready or error has occurred your Note that the behaviour of Lastly we also need to support bot MIO and WinIO. to make this easier we expose helper functions https://github.com/ghc/ghc/blob/182df90e4d1f652c3d078294921805b9b982671b/libraries/base/GHC/IO/SubSystem.hs#L44 but of course these are only available in GHCs which support WinIO. To make it work with older GHCs we export a CPP define Does this all make sense to both of you @kazu-yamamoto @coot ? I'm happy to explain over a call if easier as well. |
@Mistuke We don't have to support old GHCs in v3.2. |
@Mistuke One confirmation: we keep Mio-based code as is and create new code with |
That's right, mio will be removed at some point when we know WinIO covers
everything.
…Sent from my Mobile
On Mon, Jun 12, 2023, 02:03 Kazu Yamamoto ***@***.***> wrote:
@Mistuke <https://github.com/Mistuke> One confirmation: we keep Mio-based
code as is and create new code with withOverlappedEx for WinIO, then
chose proper one for the OS with conditional. Is this understanding
correct?
—
Reply to this email directly, view it on GitHub
<#559 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAI7OKM7KWY737MTV6NOZC3XKZTEJANCNFSM6AAAAAAYTN6NX4>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
We can use |
Due to complicated mechanism of hsc2hs and CPP, I can only use |
@Mistuke Could you provide WinIO-version of |
I can, but it won't run. Not without socket and accept beikg converted. In
any case I'll do so this weekend.
…Sent from my Mobile
On Mon, Jun 12, 2023, 07:20 Kazu Yamamoto ***@***.***> wrote:
@Mistuke <https://github.com/Mistuke> Could you provide WinIO-version of
recvMsg first?
—
Reply to this email directly, view it on GitHub
<#559 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAI7OKIBVRQKXXEAQ4L4PO3XK2YKXANCNFSM6AAAAAAYTN6NX4>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Gentle ping. |
Sorry had been too busy. I have pushed a branch Not that for it to work, the thing that creates the sockets needs to register the socket. I think the easiest way to support this is what wrapper helper functions like I'm happy to answer any questions any time but don't know when I'll have time to code again on it. Is this enough to give you an idea of what's needed? |
@kazu-yamamoto hmm what happened? |
Sorry. My bad. I restored the branch. |
@kazu-yamamoto that branch is in your fork. The one I updated is https://github.com/haskell/network/tree/win-io I thought you just wanted me to convert one API call so you'd know what to do. That one has a framework started to convert the calls. |
I'm confused because |
Never mind. I was really confused last night. |
Will do, also working on getting the initialization done so others can be
plugged in more easily.
But after family easter time :)
…On Tue, Mar 26, 2024 at 1:06 AM Kazu Yamamoto ***@***.***> wrote:
Never mind. I was really confused last night.
I just re-opened this PR.
@Mistuke <https://github.com/Mistuke> If you like, please rebase this PR
onto master and push -f. (This is not required)
—
Reply to this email directly, view it on GitHub
<#559 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAI7OKJ4N7FXV2BDHP3LIWTY2DCYPAVCNFSM6AAAAAAYTN6NX6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMJZGIYDIMZUGY>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
I would like to merge your WIP branch.
This PR is a rebased version.
However, even with
unsafe
call,recv
cannot be interrupted.I tested with my
http2
anddnsext
libraries.What is the expected behavior?