[libdispatch-dev] Updates regarding the status of libdispatch on Windows
Mark Heily
mark at heily.com
Sun May 8 21:29:46 PDT 2011
On 05/08/2011 08:47 PM, DrPizza wrote:
>
> I've taken a different tack than you for several parts of the code. Although
> it would be nice to ensure that a common codebase works everywhere, the
> platforms I'm interested in are Windows and Mac OS X (I've not yet built my
> fork on my Mac, but it's on my todo list...), and I want the library to feel
> as native as possible on both platforms. This has led me to do a few things:
>
> 1) Not even try to emulate kevent/kqueue, and instead use an I/O Completion
> Port
Hi Peter,
You may be interested to know that on Windows, libkqueue uses an IO
completion port as the underlying mechanism for kqueue(). These functions
are roughly equivalent:
kqueue() == CreateIoCompletionPort()
kevent() == GetQueuedCompletionStatus()
When a native Windows event is recieved by one of the filters' callback
routines, it is translated into a kevent and delivered via
PostQueuedCompletionStatus() to the IOCP.
> 2) Create a new OIO source type for overlapped I/O
In libkqueue, we are planning to create a Windows-specific filter named
EVFILT_IOCP to support overlapped I/O. This could be exposed via libdispatch
as a dispatch_source type.
In addition to the platform-specific dispatch sources, I think it would be
helpful to have a platform-agnostic libdispatch I/O subsystem. The basic
idea would be to enqueue a block onto a dispatch queue when an I/O operation
is completed. This is similar to IOCP on Windows, but could be implemented
using readiness notification on Unix.
Imagine there was a <dispatch/io.h> header that provided dispatch-aware
alternatives to socket and file I/O functions such as:
---------------------
#ifdef WIN32
#define dispatch_file_t HANDLE
#define dispatch_socket_t SOCKET
#else
#define dispatch_file_t int
#define dispatch_socket_t int
#endif
void
dispatch_read(dispatch_file_t fd, void *buf, size_t count,
dispatch_queue_t dq, void (^block)(ssize_t));
void
dispatch_recv(dispatch_socket_t sockfd, void *buf, size_t len,
int flags, dispatch_queue_t dq, void (^block)(ssize_t));
dispatch_write() ...
dispatch_send() ...
dispatch_connect() ...
etc ...
---------------------
Here is an example of how dispatch_recv() would work on Unix.. this assumes
that the socket has previously been made non-blocking via
setsockopt(O_NONBLOCK...):
1. Call recv() and attempt to read from the socket.
2a. If the return value is positive, add the block to the dispatch queue,
and return.
2b. If the return value is negative and errno is EAGAIN, then create a
oneshot EVFILT_READ kevent for the socket descriptor. Associate this with a
block that will perform the recv(), and then enqueue the user-supplied block.
On Windows, dispatch_recv() would be implemented like this:
1. Add a oneshot EVFILT_IOCP kevent with the SOCKET as the ident.
2. Set the handler to call the user-defined block when the kevent is
recieved.
3. Call WSARecv() using overlapped IO.
Here's an example of how someone might use dispatch_read() to read some data
from STDIN.
#define BUFSZ 100
int main() {
char *buf;
buf = malloc(BUFSZ);
fcntl(0, F_SETFL, O_NONBLOCK);
dispatch_read(0, buf, BUFSZ,
dispatch_get_main_queue(), ^(ssize_t bytes){
printf("I read %zu bytes, buf contains '%s'\n", bytes, buf);
});
dispatch_main();
}
More information about the libdispatch-dev
mailing list