Sebastian Lackner : kernel32/tests: Add additional tests for multithreaded partial reads from named pipes.
Alexandre Julliard
julliard at wine.codeweavers.com
Thu Sep 4 14:48:40 CDT 2014
Module: wine
Branch: master
Commit: 652f5d9b8715fb71b15cfb93fa741474ac3b757d
URL: http://source.winehq.org/git/wine.git/?a=commit;h=652f5d9b8715fb71b15cfb93fa741474ac3b757d
Author: Sebastian Lackner <sebastian at fds-team.de>
Date: Thu Sep 4 17:24:12 2014 +0200
kernel32/tests: Add additional tests for multithreaded partial reads from named pipes.
---
dlls/kernel32/tests/pipe.c | 159 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 159 insertions(+)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index eeeaa32..3f89086 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -43,6 +43,72 @@ static void CALLBACK user_apc(ULONG_PTR param)
user_apc_ran = TRUE;
}
+
+enum rpcThreadOp
+{
+ RPC_READFILE
+};
+
+struct rpcThreadArgs
+{
+ ULONG_PTR returnValue;
+ DWORD lastError;
+ enum rpcThreadOp op;
+ ULONG_PTR args[5];
+};
+
+static DWORD CALLBACK rpcThreadMain(LPVOID arg)
+{
+ struct rpcThreadArgs *rpcargs = (struct rpcThreadArgs *)arg;
+ trace("rpcThreadMain starting\n");
+ SetLastError( rpcargs->lastError );
+
+ switch (rpcargs->op)
+ {
+ case RPC_READFILE:
+ rpcargs->returnValue = (ULONG_PTR)ReadFile( (HANDLE)rpcargs->args[0], /* hFile */
+ (LPVOID)rpcargs->args[1], /* buffer */
+ (DWORD)rpcargs->args[2], /* bytesToRead */
+ (LPDWORD)rpcargs->args[3], /* bytesRead */
+ (LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */
+ break;
+
+ default:
+ SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
+ rpcargs->returnValue = 0;
+ break;
+ }
+
+ rpcargs->lastError = GetLastError();
+ trace("rpcThreadMain returning\n");
+ return 0;
+}
+
+/* Runs ReadFile(...) from a different thread */
+static BOOL RpcReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead, LPOVERLAPPED overlapped)
+{
+ struct rpcThreadArgs rpcargs;
+ HANDLE thread;
+ DWORD threadId;
+
+ rpcargs.returnValue = 0;
+ rpcargs.lastError = GetLastError();
+ rpcargs.op = RPC_READFILE;
+ rpcargs.args[0] = (ULONG_PTR)hFile;
+ rpcargs.args[1] = (ULONG_PTR)buffer;
+ rpcargs.args[2] = (ULONG_PTR)bytesToRead;
+ rpcargs.args[3] = (ULONG_PTR)bytesRead;
+ rpcargs.args[4] = (ULONG_PTR)overlapped;
+
+ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId);
+ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError());
+ ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed with %d.\n", GetLastError());
+ CloseHandle(thread);
+
+ SetLastError(rpcargs.lastError);
+ return (BOOL)rpcargs.returnValue;
+}
+
static void test_CreateNamedPipe(int pipemode)
{
HANDLE hnp;
@@ -372,6 +438,99 @@ static void test_CreateNamedPipe(int pipemode)
ok(readden == sizeof(obuf) - 4, "read got %d bytes 8\n", readden);
ok(memcmp(obuf, ibuf, written) == 0, "content check 8\n");
+ /* The following test shows that when doing a partial read of a message, the rest
+ * is still in the pipe, and can be received from a second thread. This shows
+ * especially that the content is _not_ stored in thread-local-storage until it is
+ * completely transmitted. The same method works even across multiple processes. */
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile 9\n");
+ ok(written == sizeof(obuf), "write file len 9\n");
+ ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 9\n");
+ ok(written == sizeof(obuf2), "write file len 9\n");
+ SetLastError(0xdeadbeef);
+ todo_wine
+ ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 9\n");
+ todo_wine
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
+ ok(readden == 4, "read got %d bytes 9\n", readden);
+ SetLastError(0xdeadbeef);
+ ret = RpcReadFile(hFile, ibuf + 4, 4, &readden, NULL);
+ todo_wine
+ ok(!ret, "RpcReadFile 9\n");
+ todo_wine
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
+ ok(readden == 4, "read got %d bytes 9\n", readden);
+ ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL);
+ ok(ret, "RpcReadFile 9\n");
+ todo_wine
+ ok(readden == sizeof(obuf) - 8, "read got %d bytes 9\n", readden);
+ ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 9\n");
+ if (readden <= sizeof(obuf) - 8) /* blocks forever if second part was already received */
+ {
+ memset(ibuf, 0, sizeof(ibuf));
+ SetLastError(0xdeadbeef);
+ ret = RpcReadFile(hFile, ibuf, 4, &readden, NULL);
+ ok(!ret, "RpcReadFile 9\n");
+ todo_wine
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
+ ok(readden == 4, "read got %d bytes 9\n", readden);
+ SetLastError(0xdeadbeef);
+ todo_wine
+ ok(!ReadFile(hFile, ibuf + 4, 4, &readden, NULL), "ReadFile 9\n");
+ todo_wine
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n");
+ ok(readden == 4, "read got %d bytes 9\n", readden);
+ ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL);
+ ok(ret, "RpcReadFile 9\n");
+ ok(readden == sizeof(obuf2) - 8, "read got %d bytes 9\n", readden);
+ ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 9\n");
+ }
+
+ /* Now the reverse direction */
+ memset(ibuf, 0, sizeof(ibuf));
+ ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 10\n");
+ ok(written == sizeof(obuf2), "write file len 10\n");
+ ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile 10\n");
+ ok(written == sizeof(obuf), "write file len 10\n");
+ SetLastError(0xdeadbeef);
+ todo_wine
+ ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 10\n");
+ todo_wine
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
+ ok(readden == 4, "read got %d bytes 10\n", readden);
+ SetLastError(0xdeadbeef);
+ ret = RpcReadFile(hnp, ibuf + 4, 4, &readden, NULL);
+ todo_wine
+ ok(!ret, "RpcReadFile 10\n");
+ todo_wine
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
+ ok(readden == 4, "read got %d bytes 10\n", readden);
+ ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL);
+ ok(ret, "RpcReadFile 10\n");
+ todo_wine
+ ok(readden == sizeof(obuf2) - 8, "read got %d bytes 10\n", readden);
+ ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 10\n");
+ if (readden <= sizeof(obuf2) - 8) /* blocks forever if second part was already received */
+ {
+ memset(ibuf, 0, sizeof(ibuf));
+ SetLastError(0xdeadbeef);
+ ret = RpcReadFile(hnp, ibuf, 4, &readden, NULL);
+ ok(!ret, "RpcReadFile 10\n");
+ todo_wine
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
+ ok(readden == 4, "read got %d bytes 10\n", readden);
+ SetLastError(0xdeadbeef);
+ todo_wine
+ ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile 10\n");
+ todo_wine
+ ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n");
+ ok(readden == 4, "read got %d bytes 10\n", readden);
+ ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL);
+ ok(ret, "RpcReadFile 10\n");
+ ok(readden == sizeof(obuf) - 8, "read got %d bytes 10\n", readden);
+ ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 10\n");
+ }
+
}
/* Picky conformance tests */
More information about the wine-cvs
mailing list