{"action":"created","issue":{"url":"https://api.github.com/repos/wahern/cqueues/issues/35","repository_url":"https://api.github.com/repos/wahern/cqueues","labels_url":"https://api.github.com/repos/wahern/cqueues/issues/35/labels{/name}","comments_url":"https://api.github.com/repos/wahern/cqueues/issues/35/comments","events_url":"https://api.github.com/repos/wahern/cqueues/issues/35/events","html_url":"https://github.com/wahern/cqueues/issues/35","id":53297914,"number":35,"title":"Windows support","user":{"login":"daurnimator","id":127971,"avatar_url":"https://avatars.githubusercontent.com/u/127971?v=3","gravatar_id":"","url":"https://api.github.com/users/daurnimator","html_url":"https://github.com/daurnimator","followers_url":"https://api.github.com/users/daurnimator/followers","following_url":"https://api.github.com/users/daurnimator/following{/other_user}","gists_url":"https://api.github.com/users/daurnimator/gists{/gist_id}","starred_url":"https://api.github.com/users/daurnimator/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/daurnimator/subscriptions","organizations_url":"https://api.github.com/users/daurnimator/orgs","repos_url":"https://api.github.com/users/daurnimator/repos","events_url":"https://api.github.com/users/daurnimator/events{/privacy}","received_events_url":"https://api.github.com/users/daurnimator/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/wahern/cqueues/labels/packaging/portability","name":"packaging/portability","color":"006b75"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":10,"created_at":"2015-01-03T08:05:57Z","updated_at":"2016-03-08T02:52:57Z","closed_at":null,"body":"I've been mulling over how hard adding windows support to cqueues would be.\r\nLower level windows programming is not something I'm familar with, so please correct any incorrect assumptions I've made.\r\n\r\nI'd love to have cqueues be a library I can depend on everywhere: if I write a network client in cqueues, even windows developers should still be able to use it (though maybe not in a performant way, which is the approach many applications take, e.g. [nginx](http://nginx.org/en/docs/windows.html)).\r\n\r\nComments @wahern has made before:\r\n\r\n>  The concept is not portable to Windows because Windows lacks an analog to the pollable event queues of modern Unix systems. Libraries which try to abstract the two approaches—event readiness signaling versus event completion—invariably produce a pallid least common denominator library suffering all the weaknesses and enjoying none of the strengths of each approach.\r\n\r\n\r\n> Microsoft Windows support is basically out of the question<sup>1</sup>, for far too many reasons to put here.\r\nAside from the more technical reasons, Windows I/O and networking programming interfaces have\r\na fundamentally different character than on Unix. Unix historically relies on readiness polling, while\r\nWindows uses event completion callbacks. There are strengths and weaknesses to each approach.\r\nTrying to paper over the chasm between the two approaches invariably results in a framework with\r\nthe strengths of neither and the weaknesses of both. The purpose of cqueues is to leverage the\r\nstrengths of polling as well as address the weaknesses.\r\n\r\n> <sup>1</sup>  I have been toying with the idea of using an fd set in-place of a pollable descriptor on Windows, and taking the union of all fd sets when polling.\r\n\r\n-----------------------------------------------\r\n\r\n### Solution 1. Add `:pollset`\r\n\r\nOne possible route is catering to the lowest common denominator (which helps with other platforms, such as AIX) and use `select()`. This can be accomplished by iterating over the `fileno` LLRB and building a pollset; this could be done on demand in a `:pollset()` function, or inside of `fileno_ctl`.\r\n\r\n#### Issues\r\n\r\nselect does not expose a file handle we can wait on itself, and makes things much harder to nest/stack, :pollsets will need to be propogated up to the parent controller.\r\n\r\nOn windows, select boils down to a [WaitForMultipleObjectsEx](http://msdn.microsoft.com/en-us/library/windows/desktop/ms687028(v=vs.85).aspx) call, this has a maximum of 64 handles; which could easily be exceeded by a regular application. To get around this, you can spawn extra threads that each wait for events, and wait for them, and now we've recreated stackable event waiting.\r\n\r\n-----------------------------------------------\r\n\r\n### Solution 2. Use an [IOCP](https://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx) and `RegisterWaitForSingleObject`\r\n\r\n  - [Create an IOCP port](https://msdn.microsoft.com/en-us/library/aa363862(v=vs.85).aspx) for each cqueues object.\r\n  - To 'add' a file descriptor to it, use [`RegisterWaitForSingleObject`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms685061(v=vs.85).aspx) where the callback uses [`PostQueuedCompletionStatus`](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365458(v=vs.85).aspx)\r\n  - To cancel a file descriptor, use [UnregisterWaitEx](http://msdn.microsoft.com/en-us/library/windows/desktop/ms686876(v=vs.85).aspx)\r\n  - `kpoll_wait` uses [`GetQueuedCompletionStatusEx`](http://msdn.microsoft.com/en-us/library/windows/desktop/aa364988(v=vs.85).aspx)\r\n  - `:pollfd()` returns the IOCP handle\r\n\r\n#### Issues\r\n\r\nWindows potentially has more than just `readable` and `writable` events; you need to use [WSACreateEvent](http://msdn.microsoft.com/en-us/library/windows/desktop/ms741561(v=vs.85).aspx) + [WSAEventSelect](http://msdn.microsoft.com/en-us/library/windows/desktop/ms741576(v=vs.85).aspx) to manage a `HANDLE` that encapsulates the events being waited for.\r\n\r\n> It is not possible to specify different event objects for different network events. The following code will not work; the second call will cancel the effects of the first, and only the FD_WRITE network event will be associated with hEventObject2:\r\n> ```C++\r\n> rc = WSAEventSelect(s, hEventObject1, FD_READ);\r\n> rc = WSAEventSelect(s, hEventObject2, FD_WRITE); //bad\r\n> ```"},"comment":{"url":"https://api.github.com/repos/wahern/cqueues/issues/comments/193574273","html_url":"https://github.com/wahern/cqueues/issues/35#issuecomment-193574273","issue_url":"https://api.github.com/repos/wahern/cqueues/issues/35","id":193574273,"user":{"login":"wahern","id":6007976,"avatar_url":"https://avatars.githubusercontent.com/u/6007976?v=3","gravatar_id":"","url":"https://api.github.com/users/wahern","html_url":"https://github.com/wahern","followers_url":"https://api.github.com/users/wahern/followers","following_url":"https://api.github.com/users/wahern/following{/other_user}","gists_url":"https://api.github.com/users/wahern/gists{/gist_id}","starred_url":"https://api.github.com/users/wahern/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wahern/subscriptions","organizations_url":"https://api.github.com/users/wahern/orgs","repos_url":"https://api.github.com/users/wahern/repos","events_url":"https://api.github.com/users/wahern/events{/privacy}","received_events_url":"https://api.github.com/users/wahern/received_events","type":"User","site_admin":false},"created_at":"2016-03-08T02:52:57Z","updated_at":"2016-03-08T02:52:57Z","body":"On Mon, Mar 07, 2016 at 06:31:51PM -0800, daurnimator wrote:\n> @katlogic suggested using https://github.com/richardhundt/upoll\n> But it looks like upoll doesn't implement \"stacking\"; however it might not be hard to add.\n> \n\nIt's not doing anything that the existing code isn't already doing except\nfor a dozen or so lines for select. It'd be easier to add select to the\nexisting code than to add kqueue, ports, etc support to upoll.c. Likewise\nfor adding select stacking.\n\nI had an idea for supporting Windows overlapped I/O in a performant manner,\nbut it first involves properly breaking out the buffering code.\n\nBut simply supporting select on Windows is probably the best interim\nmeasure. Slightly easier (stacking notwithstanding) would be just supporting\nWSAPoll, available since Windows 2008.\n\n"}}