├── README.md ├── .gitignore ├── RIOServerSample ├── stdafx.cpp ├── targetver.h ├── stdafx.h ├── RIOServerSample.vcxproj.filters ├── ReadMe.txt ├── RIOServerSample.vcxproj └── RIOServerSample.cpp ├── LICENSE └── RIOServerSample.sln /README.md: -------------------------------------------------------------------------------- 1 | === RIOEchoServer === 2 | 3 | * UDP Echo Server using Windows Registered I/O 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | -------------------------------------------------------------------------------- /RIOServerSample/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // RIOServerSample.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /RIOServerSample/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /RIOServerSample/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | 23 | 24 | // TODO: reference additional headers your program requires here 25 | -------------------------------------------------------------------------------- /RIOServerSample/RIOServerSample.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | RIOServer 15 | 16 | 17 | RIOServer 18 | 19 | 20 | 21 | 22 | RIOServer 23 | 24 | 25 | RIOServer 26 | 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 zeliard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /RIOServerSample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RIOServerSample", "RIOServerSample\RIOServerSample.vcxproj", "{0CD52283-2129-42C9-9461-B76D044314B9}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {0CD52283-2129-42C9-9461-B76D044314B9}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {0CD52283-2129-42C9-9461-B76D044314B9}.Debug|Win32.Build.0 = Debug|Win32 18 | {0CD52283-2129-42C9-9461-B76D044314B9}.Debug|x64.ActiveCfg = Debug|x64 19 | {0CD52283-2129-42C9-9461-B76D044314B9}.Debug|x64.Build.0 = Debug|x64 20 | {0CD52283-2129-42C9-9461-B76D044314B9}.Release|Win32.ActiveCfg = Release|Win32 21 | {0CD52283-2129-42C9-9461-B76D044314B9}.Release|Win32.Build.0 = Release|Win32 22 | {0CD52283-2129-42C9-9461-B76D044314B9}.Release|x64.ActiveCfg = Release|x64 23 | {0CD52283-2129-42C9-9461-B76D044314B9}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /RIOServerSample/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : RIOServerSample Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this RIOServerSample application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your RIOServerSample application. 9 | 10 | 11 | RIOServerSample.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | RIOServerSample.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | RIOServerSample.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named RIOServerSample.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /RIOServerSample/RIOServerSample.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {0CD52283-2129-42C9-9461-B76D044314B9} 23 | Win32Proj 24 | RIOServerSample 25 | 26 | 27 | 28 | Application 29 | true 30 | v120 31 | Unicode 32 | 33 | 34 | Application 35 | true 36 | v120 37 | Unicode 38 | 39 | 40 | Application 41 | false 42 | v120 43 | true 44 | Unicode 45 | 46 | 47 | Application 48 | false 49 | v120 50 | true 51 | Unicode 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | true 71 | 72 | 73 | true 74 | 75 | 76 | false 77 | 78 | 79 | false 80 | 81 | 82 | 83 | Use 84 | Level3 85 | Disabled 86 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 87 | true 88 | 89 | 90 | Console 91 | true 92 | 93 | 94 | 95 | 96 | Use 97 | Level3 98 | Disabled 99 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 100 | true 101 | 102 | 103 | Console 104 | true 105 | 106 | 107 | 108 | 109 | Level3 110 | Use 111 | MaxSpeed 112 | true 113 | true 114 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 115 | true 116 | 117 | 118 | Console 119 | true 120 | true 121 | true 122 | 123 | 124 | 125 | 126 | Level3 127 | Use 128 | MaxSpeed 129 | true 130 | true 131 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Console 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | Create 152 | Create 153 | Create 154 | Create 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /RIOServerSample/RIOServerSample.cpp: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************* 2 | * Windows Registered I/O (RIO) Sample Code (Echo Server) 3 | * Minimum requirement: Windows 8 or Windows Server 2012 4 | * Author: @sm9kr 5 | * 6 | * Notice 7 | * AllocateBufferSpace() from http://www.serverframework.com/asynchronousevents/rio/ 8 | *********************************************************************************************************/ 9 | 10 | #include "stdafx.h" 11 | 12 | #pragma comment(lib, "ws2_32.lib") 13 | 14 | 15 | RIO_EXTENSION_FUNCTION_TABLE g_rio; 16 | RIO_CQ g_completionQueue = 0; 17 | RIO_RQ g_requestQueue = 0; 18 | 19 | HANDLE g_hIOCP = NULL; 20 | 21 | SOCKET g_socket; 22 | 23 | CRITICAL_SECTION g_criticalSection; 24 | 25 | RIO_BUFFERID g_sendBufferId; 26 | RIO_BUFFERID g_recvBufferId; 27 | RIO_BUFFERID g_addrBufferId; 28 | 29 | char* g_sendBufferPointer = NULL; 30 | char* g_recvBufferPointer = NULL; 31 | char* g_addrBufferPointer = NULL; 32 | 33 | 34 | static const unsigned short PORTNUM = 5050; 35 | 36 | static const DWORD RIO_PENDING_RECVS = 100000; 37 | static const DWORD RIO_PENDING_SENDS = 10000; 38 | 39 | static const DWORD RECV_BUFFER_SIZE = 1024; 40 | static const DWORD SEND_BUFFER_SIZE = 1024; 41 | 42 | static const DWORD ADDR_BUFFER_SIZE = 64; 43 | 44 | static const DWORD NUM_IOCP_THREADS = 4; 45 | 46 | static const DWORD RIO_MAX_RESULTS = 1000; 47 | 48 | HANDLE g_threads[NUM_IOCP_THREADS] = { NULL, }; 49 | 50 | 51 | enum COMPLETION_KEY 52 | { 53 | CK_STOP = 0, 54 | CK_START = 1 55 | }; 56 | 57 | enum OPERATION_TYPE 58 | { 59 | OP_NONE = 0, 60 | OP_RECV = 1, 61 | OP_SEND = 2 62 | }; 63 | 64 | struct EXTENDED_RIO_BUF : public RIO_BUF 65 | { 66 | OPERATION_TYPE operation; 67 | }; 68 | 69 | 70 | /// RIO_BUF for SEND (circular) 71 | EXTENDED_RIO_BUF* g_sendRioBufs = NULL; 72 | DWORD g_sendRioBufTotalCount = 0; 73 | __int64 g_sendRioBufIndex = 0; 74 | 75 | /// RIO_BUF for ADDR (circular) 76 | EXTENDED_RIO_BUF* g_addrRioBufs = NULL; 77 | DWORD g_addrRioBufTotalCount = 0; 78 | __int64 g_addrRioBufIndex = 0; 79 | 80 | char* AllocateBufferSpace(const DWORD bufSize, const DWORD bufCount, DWORD& totalBufferSize, DWORD& totalBufferCount); 81 | unsigned int __stdcall IOThread(void *pV); 82 | 83 | int _tmain(int argc, _TCHAR* argv[]) 84 | { 85 | WSADATA data; 86 | InitializeCriticalSectionAndSpinCount(&g_criticalSection, 4000); 87 | 88 | if (0 != ::WSAStartup(0x202, &data)) 89 | { 90 | printf_s("WSAStartup Error: %d\n", GetLastError()); 91 | exit(0); 92 | } 93 | 94 | /// RIO socket 95 | g_socket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_REGISTERED_IO); 96 | if (g_socket == INVALID_SOCKET) 97 | { 98 | printf_s("WSASocket Error: %d\n", GetLastError()); 99 | exit(0); 100 | } 101 | 102 | /// port binding 103 | sockaddr_in addr; 104 | addr.sin_family = AF_INET; 105 | addr.sin_port = htons(PORTNUM); 106 | addr.sin_addr.s_addr = INADDR_ANY; 107 | 108 | if (SOCKET_ERROR == ::bind(g_socket, reinterpret_cast(&addr), sizeof(addr))) 109 | { 110 | printf_s("Bind Error: %d\n", GetLastError()); 111 | exit(0); 112 | } 113 | 114 | /// RIO function table 115 | GUID functionTableId = WSAID_MULTIPLE_RIO; 116 | DWORD dwBytes = 0; 117 | 118 | if (NULL != WSAIoctl(g_socket, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER, &functionTableId, sizeof(GUID), 119 | (void**)&g_rio, sizeof(g_rio), &dwBytes, NULL, NULL)) 120 | { 121 | printf_s("WSAIoctl Error: %d\n", GetLastError()); 122 | exit(0); 123 | } 124 | 125 | /// rio's completion manner: iocp 126 | g_hIOCP = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); 127 | if (NULL == g_hIOCP) 128 | { 129 | printf_s("CreateIoCompletionPort Error: %d\n", GetLastError()); 130 | exit(0); 131 | } 132 | 133 | 134 | OVERLAPPED overlapped; 135 | 136 | RIO_NOTIFICATION_COMPLETION completionType; 137 | 138 | completionType.Type = RIO_IOCP_COMPLETION; 139 | completionType.Iocp.IocpHandle = g_hIOCP; 140 | completionType.Iocp.CompletionKey = (void*)CK_START; 141 | completionType.Iocp.Overlapped = &overlapped; 142 | 143 | /// creating RIO CQ, which is bigger than (or equal to) RQ size 144 | g_completionQueue = g_rio.RIOCreateCompletionQueue(RIO_PENDING_RECVS + RIO_PENDING_SENDS, &completionType); 145 | if (g_completionQueue == RIO_INVALID_CQ) 146 | { 147 | printf_s("RIOCreateCompletionQueue Error: %d\n", GetLastError()); 148 | exit(0); 149 | } 150 | 151 | /// creating RIO RQ 152 | /// SEND and RECV within one CQ (you can do with two CQs, seperately) 153 | g_requestQueue = g_rio.RIOCreateRequestQueue(g_socket, RIO_PENDING_RECVS, 1, RIO_PENDING_SENDS, 1, g_completionQueue, g_completionQueue, NULL); 154 | if (g_requestQueue == RIO_INVALID_RQ) 155 | { 156 | printf_s("RIOCreateRequestQueue Error: %d\n", GetLastError()); 157 | exit(0); 158 | } 159 | 160 | 161 | /// registering RIO buffers for SEND 162 | { 163 | DWORD totalBufferCount = 0; 164 | DWORD totalBufferSize = 0; 165 | 166 | g_sendBufferPointer = AllocateBufferSpace(SEND_BUFFER_SIZE, RIO_PENDING_SENDS, totalBufferSize, totalBufferCount); 167 | g_sendBufferId = g_rio.RIORegisterBuffer(g_sendBufferPointer, static_cast(totalBufferSize)); 168 | 169 | if (g_sendBufferId == RIO_INVALID_BUFFERID) 170 | { 171 | printf_s("RIORegisterBuffer Error: %d\n", GetLastError()); 172 | exit(0); 173 | } 174 | 175 | DWORD offset = 0; 176 | 177 | g_sendRioBufs = new EXTENDED_RIO_BUF[totalBufferCount]; 178 | g_sendRioBufTotalCount = totalBufferCount; 179 | 180 | for (DWORD i = 0; i < g_sendRioBufTotalCount; ++i) 181 | { 182 | /// split g_sendRioBufs to SEND_BUFFER_SIZE for each RIO operation 183 | EXTENDED_RIO_BUF* pBuffer = g_sendRioBufs + i; 184 | 185 | pBuffer->operation = OP_SEND; 186 | pBuffer->BufferId = g_sendBufferId; 187 | pBuffer->Offset = offset; 188 | pBuffer->Length = SEND_BUFFER_SIZE; 189 | 190 | offset += SEND_BUFFER_SIZE; 191 | 192 | } 193 | 194 | } 195 | 196 | 197 | /// registering RIO buffers for ADDR 198 | { 199 | DWORD totalBufferCount = 0; 200 | DWORD totalBufferSize = 0; 201 | 202 | g_addrBufferPointer = AllocateBufferSpace(ADDR_BUFFER_SIZE, RIO_PENDING_RECVS, totalBufferSize, totalBufferCount); 203 | g_addrBufferId = g_rio.RIORegisterBuffer(g_addrBufferPointer, static_cast(totalBufferSize)); 204 | 205 | if (g_addrBufferId == RIO_INVALID_BUFFERID) 206 | { 207 | printf_s("RIORegisterBuffer Error: %d\n", GetLastError()); 208 | exit(0); 209 | } 210 | 211 | DWORD offset = 0; 212 | 213 | g_addrRioBufs = new EXTENDED_RIO_BUF[totalBufferCount]; 214 | g_addrRioBufTotalCount = totalBufferCount; 215 | 216 | for (DWORD i = 0; i < totalBufferCount; ++i) 217 | { 218 | EXTENDED_RIO_BUF* pBuffer = g_addrRioBufs + i; 219 | 220 | pBuffer->operation = OP_NONE; 221 | pBuffer->BufferId = g_addrBufferId; 222 | pBuffer->Offset = offset; 223 | pBuffer->Length = ADDR_BUFFER_SIZE; 224 | 225 | offset += ADDR_BUFFER_SIZE; 226 | } 227 | } 228 | 229 | /// registering RIO buffers for RECV and then, post pre-RECV 230 | { 231 | DWORD totalBufferCount = 0; 232 | DWORD totalBufferSize = 0; 233 | 234 | g_recvBufferPointer = AllocateBufferSpace(RECV_BUFFER_SIZE, RIO_PENDING_RECVS, totalBufferSize, totalBufferCount); 235 | 236 | g_recvBufferId = g_rio.RIORegisterBuffer(g_recvBufferPointer, static_cast(totalBufferSize)); 237 | if (g_recvBufferId == RIO_INVALID_BUFFERID) 238 | { 239 | printf_s("RIORegisterBuffer Error: %d\n", GetLastError()); 240 | exit(0); 241 | } 242 | 243 | 244 | DWORD offset = 0; 245 | 246 | EXTENDED_RIO_BUF* pBufs = new EXTENDED_RIO_BUF[totalBufferCount]; 247 | 248 | for (DWORD i = 0; i < totalBufferCount; ++i) 249 | { 250 | EXTENDED_RIO_BUF* pBuffer = pBufs + i; 251 | 252 | pBuffer->operation = OP_RECV; 253 | pBuffer->BufferId = g_recvBufferId; 254 | pBuffer->Offset = offset; 255 | pBuffer->Length = RECV_BUFFER_SIZE; 256 | 257 | offset += RECV_BUFFER_SIZE; 258 | 259 | /// posting pre RECVs 260 | if (!g_rio.RIOReceiveEx(g_requestQueue, pBuffer, 1, NULL, &g_addrRioBufs[g_addrRioBufIndex++], NULL, 0, 0, pBuffer)) 261 | { 262 | printf_s("RIOReceive Error: %d\n", GetLastError()); 263 | exit(0); 264 | } 265 | } 266 | 267 | printf_s("%d total receives pending\n", totalBufferCount); 268 | } 269 | 270 | 271 | /// creating IO threads 272 | for (DWORD i = 0; i < NUM_IOCP_THREADS; ++i) 273 | { 274 | unsigned int notUsed; 275 | const uintptr_t result = ::_beginthreadex(0, 0, IOThread, (void*)i, 0, ¬Used); 276 | if (result == 0) 277 | { 278 | printf_s("_beginthreadex Error: %d\n", GetLastError()); 279 | exit(0); 280 | } 281 | 282 | g_threads[i] = (HANDLE)result; 283 | } 284 | 285 | /// notify completion-ready 286 | INT notifyResult = g_rio.RIONotify(g_completionQueue); 287 | if (notifyResult != ERROR_SUCCESS) 288 | { 289 | printf_s("RIONotify Error: %d\n", GetLastError()); 290 | exit(0); 291 | } 292 | 293 | 294 | /// terminating i/o to press any key 295 | printf_s("Press Any Key to Stop\n"); 296 | getchar(); 297 | 298 | 299 | 300 | /// completion key CK_STOP: to stop I/O threads 301 | for (DWORD i = 0; i < NUM_IOCP_THREADS; ++i) 302 | { 303 | if (0 == ::PostQueuedCompletionStatus(g_hIOCP, 0, CK_STOP, 0)) 304 | { 305 | printf_s("PostQueuedCompletionStatus Error: %d\n", GetLastError()); 306 | exit(0); 307 | } 308 | } 309 | 310 | /// thread join 311 | for (DWORD i = 0; i < NUM_IOCP_THREADS; ++i) 312 | { 313 | HANDLE hThread = g_threads[i]; 314 | 315 | if (WAIT_OBJECT_0 != ::WaitForSingleObject(hThread, INFINITE)) 316 | { 317 | printf_s("WaitForSingleObject (thread join) Error: %d\n", GetLastError()); 318 | exit(0); 319 | } 320 | 321 | ::CloseHandle(hThread); 322 | } 323 | 324 | 325 | if (SOCKET_ERROR == ::closesocket(g_socket)) 326 | { 327 | printf_s("closesocket Error: %d\n", GetLastError()); 328 | } 329 | 330 | g_rio.RIOCloseCompletionQueue(g_completionQueue); 331 | 332 | g_rio.RIODeregisterBuffer(g_sendBufferId); 333 | g_rio.RIODeregisterBuffer(g_recvBufferId); 334 | g_rio.RIODeregisterBuffer(g_addrBufferId); 335 | 336 | DeleteCriticalSection(&g_criticalSection); 337 | 338 | return 0; 339 | } 340 | 341 | 342 | unsigned int __stdcall IOThread(void *pV) 343 | { 344 | DWORD numberOfBytes = 0; 345 | 346 | ULONG_PTR completionKey = 0; 347 | OVERLAPPED* pOverlapped = 0; 348 | 349 | RIORESULT results[RIO_MAX_RESULTS]; 350 | 351 | while (true) 352 | { 353 | if (!::GetQueuedCompletionStatus(g_hIOCP, &numberOfBytes, &completionKey, &pOverlapped, INFINITE)) 354 | { 355 | printf_s("GetQueuedCompletionStatus Error: %d\n", GetLastError()); 356 | exit(0); 357 | } 358 | 359 | /// exit when CK_STOP 360 | if (completionKey == CK_STOP) 361 | break; 362 | 363 | memset(results, 0, sizeof(results)); 364 | 365 | ULONG numResults = g_rio.RIODequeueCompletion(g_completionQueue, results, RIO_MAX_RESULTS); 366 | if (0 == numResults || RIO_CORRUPT_CQ == numResults) 367 | { 368 | printf_s("RIODequeueCompletion Error: %d\n", GetLastError()); 369 | exit(0); 370 | } 371 | 372 | /// Notify after Dequeueing 373 | INT notifyResult = g_rio.RIONotify(g_completionQueue); 374 | if (notifyResult != ERROR_SUCCESS) 375 | { 376 | printf_s("RIONotify Error: %d\n", GetLastError()); 377 | exit(0); 378 | } 379 | 380 | for (DWORD i = 0; i < numResults; ++i) 381 | { 382 | EXTENDED_RIO_BUF* pBuffer = reinterpret_cast(results[i].RequestContext); 383 | 384 | if (OP_RECV == pBuffer->operation) 385 | { 386 | /// error when total packet is not arrived because this is UDP 387 | if (results[i].BytesTransferred != RECV_BUFFER_SIZE) 388 | break; 389 | 390 | ///// ECHO TEST 391 | const char* offset = g_recvBufferPointer + pBuffer->Offset; 392 | 393 | /// RQ is not thread-safe (need to be optimized...) 394 | ::EnterCriticalSection(&g_criticalSection); 395 | { 396 | 397 | EXTENDED_RIO_BUF* sendBuf = &(g_sendRioBufs[g_sendRioBufIndex++ % g_sendRioBufTotalCount]); 398 | char* sendOffset = g_sendBufferPointer + sendBuf->Offset; 399 | memcpy_s(sendOffset, RECV_BUFFER_SIZE, offset, pBuffer->Length); 400 | 401 | 402 | 403 | if (!g_rio.RIOSendEx(g_requestQueue, sendBuf, 1, NULL, &g_addrRioBufs[g_addrRioBufIndex % g_addrRioBufTotalCount], NULL, NULL, 0, sendBuf)) 404 | { 405 | printf_s("RIOSend Error: %d\n", GetLastError()); 406 | exit(0); 407 | } 408 | 409 | } 410 | ::LeaveCriticalSection(&g_criticalSection); 411 | 412 | 413 | } 414 | else if (OP_SEND == pBuffer->operation) 415 | { 416 | /// RQ is not thread-safe 417 | ::EnterCriticalSection(&g_criticalSection); 418 | { 419 | if (!g_rio.RIOReceiveEx(g_requestQueue, pBuffer, 1, NULL, &g_addrRioBufs[g_addrRioBufIndex % g_addrRioBufTotalCount], NULL, 0, 0, pBuffer)) 420 | { 421 | printf_s("RIOReceive Error: %d\n", GetLastError()); 422 | exit(0);; 423 | } 424 | 425 | g_addrRioBufIndex++; 426 | 427 | } 428 | ::LeaveCriticalSection(&g_criticalSection); 429 | 430 | } 431 | else 432 | break; 433 | 434 | } 435 | } 436 | 437 | 438 | return 0; 439 | } 440 | 441 | 442 | template 443 | inline TV RoundDown(TV Value, TM Multiple) 444 | { 445 | return((Value / Multiple) * Multiple); 446 | } 447 | 448 | template 449 | inline TV RoundUp(TV Value, TM Multiple) 450 | { 451 | return(RoundDown(Value, Multiple) + (((Value % Multiple) > 0) ? Multiple : 0)); 452 | } 453 | 454 | 455 | char* AllocateBufferSpace(const DWORD bufSize, const DWORD bufCount, DWORD& totalBufferSize, DWORD& totalBufferCount) 456 | { 457 | SYSTEM_INFO systemInfo; 458 | 459 | ::GetSystemInfo(&systemInfo); 460 | 461 | const unsigned __int64 granularity = systemInfo.dwAllocationGranularity; 462 | 463 | const unsigned __int64 desiredSize = bufSize * bufCount; 464 | 465 | unsigned __int64 actualSize = RoundUp(desiredSize, granularity); 466 | 467 | if (actualSize > UINT_MAX ) 468 | { 469 | actualSize = (UINT_MAX / granularity) * granularity; 470 | } 471 | 472 | totalBufferCount = min(bufCount, static_cast(actualSize / bufSize)); 473 | 474 | totalBufferSize = static_cast(actualSize); 475 | 476 | char* pBuffer = reinterpret_cast(VirtualAllocEx(GetCurrentProcess(), 0, totalBufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); 477 | 478 | if (pBuffer == 0) 479 | { 480 | printf_s("VirtualAllocEx Error: %d\n", GetLastError()); 481 | exit(0); 482 | } 483 | 484 | return pBuffer; 485 | } --------------------------------------------------------------------------------