async-win32-test.c++ (4844B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #if _WIN32 23 24 #include "async-win32.h" 25 #include "thread.h" 26 #include "test.h" 27 #include "mutex.h" 28 29 namespace kj { 30 namespace { 31 32 KJ_TEST("Win32IocpEventPort I/O operations") { 33 Win32IocpEventPort port; 34 EventLoop loop(port); 35 WaitScope waitScope(loop); 36 37 auto pipeName = kj::str("\\\\.\\Pipe\\kj-async-win32-test.", GetCurrentProcessId()); 38 39 HANDLE readEnd_, writeEnd_; 40 KJ_WIN32(readEnd_ = CreateNamedPipeA(pipeName.cStr(), 41 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 42 PIPE_TYPE_BYTE | PIPE_WAIT, 43 1, 0, 0, 0, NULL)); 44 AutoCloseHandle readEnd(readEnd_); 45 46 KJ_WIN32(writeEnd_ = CreateFileA(pipeName.cStr(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 47 FILE_ATTRIBUTE_NORMAL, NULL)); 48 AutoCloseHandle writeEnd(writeEnd_); 49 50 auto observer = port.observeIo(readEnd); 51 auto op = observer->newOperation(0); 52 53 byte buffer[256]; 54 55 KJ_ASSERT(!ReadFile(readEnd, buffer, sizeof(buffer), NULL, op->getOverlapped())); 56 DWORD error = GetLastError(); 57 if (error != ERROR_IO_PENDING) { 58 KJ_FAIL_WIN32("ReadFile()", error); 59 } 60 61 bool done = false; 62 auto promise = op->onComplete().then([&](Win32EventPort::IoResult result) { 63 done = true; 64 return result; 65 }).eagerlyEvaluate(nullptr); 66 67 KJ_EXPECT(!done); 68 69 evalLater([]() {}).wait(waitScope); 70 evalLater([]() {}).wait(waitScope); 71 evalLater([]() {}).wait(waitScope); 72 evalLater([]() {}).wait(waitScope); 73 evalLater([]() {}).wait(waitScope); 74 75 KJ_EXPECT(!done); 76 77 DWORD bytesWritten; 78 KJ_WIN32(WriteFile(writeEnd, "foo", 3, &bytesWritten, NULL)); 79 KJ_EXPECT(bytesWritten == 3); 80 81 auto result = promise.wait(waitScope); 82 KJ_EXPECT(result.errorCode == ERROR_SUCCESS); 83 KJ_EXPECT(result.bytesTransferred == 3); 84 85 KJ_EXPECT(kj::str(kj::arrayPtr(buffer, 3).asChars()) == "foo"); 86 } 87 88 KJ_TEST("Win32IocpEventPort::wake()") { 89 Win32IocpEventPort port; 90 91 Thread thread([&]() { 92 Sleep(10); 93 port.wake(); 94 }); 95 96 KJ_EXPECT(port.wait()); 97 } 98 99 KJ_TEST("Win32IocpEventPort::wake() on poll()") { 100 Win32IocpEventPort port; 101 volatile bool woken = false; 102 103 Thread thread([&]() { 104 Sleep(10); 105 port.wake(); 106 woken = true; 107 }); 108 109 KJ_EXPECT(!port.poll()); 110 while (!woken) Sleep(10); 111 KJ_EXPECT(port.poll()); 112 } 113 114 KJ_TEST("Win32IocpEventPort timer") { 115 Win32IocpEventPort port; 116 EventLoop loop(port); 117 WaitScope waitScope(loop); 118 119 auto start = port.getTimer().now(); 120 121 bool done = false; 122 auto promise = port.getTimer().afterDelay(10 * MILLISECONDS).then([&]() { 123 done = true; 124 }).eagerlyEvaluate(nullptr); 125 126 KJ_EXPECT(!done); 127 128 evalLater([]() {}).wait(waitScope); 129 evalLater([]() {}).wait(waitScope); 130 evalLater([]() {}).wait(waitScope); 131 evalLater([]() {}).wait(waitScope); 132 evalLater([]() {}).wait(waitScope); 133 134 KJ_EXPECT(!done); 135 136 promise.wait(waitScope); 137 KJ_EXPECT(done); 138 KJ_EXPECT(port.getTimer().now() - start >= 10 * MILLISECONDS); 139 } 140 141 VOID CALLBACK testApcProc(ULONG_PTR dwParam) { 142 reinterpret_cast<kj::PromiseFulfiller<void>*>(dwParam)->fulfill(); 143 } 144 145 KJ_TEST("Win32IocpEventPort APC") { 146 if (GetProcAddress(GetModuleHandle("ntdll.dll"), "wine_get_version") != nullptr) { 147 // TODO(cleanup): Periodically check if Wine supports this yet. 148 KJ_LOG(WARNING, "detected that we're running under wine and this test won't work; skipping"); 149 return; 150 } 151 152 Win32IocpEventPort port; 153 EventLoop loop(port); 154 WaitScope waitScope(loop); 155 156 port.allowApc(); 157 158 auto paf = kj::newPromiseAndFulfiller<void>(); 159 160 KJ_WIN32(QueueUserAPC(&testApcProc, GetCurrentThread(), 161 reinterpret_cast<ULONG_PTR>(paf.fulfiller.get()))); 162 163 paf.promise.wait(waitScope); 164 } 165 166 } // namespace 167 } // namespace kj 168 169 #endif // _WIN32