IO Completion ports

Szymon Kulec



async intro

what is it?

public override IAsyncResult BeginRead(
	byte[] array,
	int offset,
	int numBytes,
	AsyncCallback userCallback,
	Object stateObject

public IAsyncResult BeginAccept(
	Socket acceptSocket,
	int receiveSize,
	AsyncCallback callback,
	Object state

async .NET API

Asynchronous .NET API for operations like

  • BeginXXX / EndXXX
  • SocketAsyncEventArgs

uses I/O Completion Ports

what is it?

I/O completion port

  • a threading model for IO on multicore machines
  • an object created for a given process
  • is extremely fast
  • a handle can be bound to a port. A handle can be:
    • file
    • socket
    • named pipe

I/O completion port flow

  • create a port
  • anytime, bind an object handle to the port. There's no unbinding
  • once, overlapped asynchronous operation is issued...
  • query completion port for its status...
  • finally you'll be given the result
  • use it massively, for each handle you want to work with in async way

functions working with completion ports

  • file & directory
    • ReadFile
    • ReadDirectoryChangesW
  • Sockets
    • WSASend
    • WSARecv

API - create & bind

HANDLE WINAPI CreateIoCompletionPort(
  _In_      HANDLE FileHandle,
  _In_opt_  HANDLE ExistingCompletionPort,
  _In_      ULONG_PTR CompletionKey,
  _In_      DWORD NumberOfConcurrentThreads

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateIoCompletionPort(
	IntPtr fileHandle, 
	IntPtr existingCompletionPort, 
	IntPtr completionKey, 
	uint numberOfConcurrentThreads

API - get status

BOOL WINAPI GetQueuedCompletionStatus(
  _In_   HANDLE CompletionPort,
  _Out_  LPDWORD lpNumberOfBytes,
  _Out_  PULONG_PTR lpCompletionKey,
  _Out_  LPOVERLAPPED *lpOverlapped,
  _In_   DWORD dwMilliseconds

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetQueuedCompletionStatus(
	IntPtr CompletionPort, 
	out uint numberOfTransferredBytes, 
	out IntPtr completionKey, 
	out NativeOverlapped* overlapped, 
	uint milisecondsTimeout

API - get status ex (1)

Windows Vista has introduced a new way of querying ports.

BOOL WINAPI GetQueuedCompletionStatusEx(
  _In_   HANDLE CompletionPort,
  _Out_  LPOVERLAPPED_ENTRY lpCompletionPortEntries,
  _In_   ULONG ulCount,
  _Out_  PULONG ulNumEntriesRemoved,
  _In_   DWORD dwMilliseconds,
  _In_   BOOL fAlertable

typedef struct _OVERLAPPED_ENTRY {
  ULONG_PTR    lpCompletionKey;
  LPOVERLAPPED lpOverlapped;
  ULONG_PTR    Internal;
  DWORD        dwNumberOfBytesTransferred;

API - get status ex (2)

public static extern bool GetQueuedCompletionStatusEx(
	IntPtr completionPort, 
	OverlappedEntry* entries, 
	uint count, 
	out uint entriesRemoved, 
	uint milisecondsTimeout, 
	bool alertable
public struct OverlappedEntry
    public IntPtr CompletionKey;
    public NativeOverlapped* Overlapped;
    public UIntPtr Internal;
    public uint NumberOfTransferredBytes;

API - post status

BOOL WINAPI PostQueuedCompletionStatus(
  _In_      HANDLE CompletionPort,
  _In_      DWORD dwNumberOfBytesTransferred,
  _In_      ULONG_PTR dwCompletionKey,
  _In_opt_  LPOVERLAPPED lpOverlapped

public static extern bool PostQueuedCompletionStatus(
	IntPtr completionPort,
	uint numberOfBytes,
	IntPtr completionKey,
	NativeOverlapped* overlapped


// assumes no errors
var sender = new IntPtr(1);
var overlapped = stackalloc NativeOverlapped[1];
var port = NativeMethods.CreateIoCompletionPort(
	InvalidHandle, IntPtr.Zero, IntPtr.Zero, 1);
	port, (uint) 1, sender, overlapped);

uint byteCount;
IntPtr completionKey;
Overlapped* resultOverlapped;
uint timeoutInMiliseconds = 1;
	port, out byteCount, out completionKey, 
	out resultOverlapped, timeoutInMiliseconds);


Szymon Kulec