kernel32/tests: Add additional tests for multithreaded partial reads from named pipes.
This commit is contained in:
parent
e65a618538
commit
652f5d9b87
|
@ -43,6 +43,72 @@ static void CALLBACK user_apc(ULONG_PTR param)
|
||||||
user_apc_ran = TRUE;
|
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)
|
static void test_CreateNamedPipe(int pipemode)
|
||||||
{
|
{
|
||||||
HANDLE hnp;
|
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(readden == sizeof(obuf) - 4, "read got %d bytes 8\n", readden);
|
||||||
ok(memcmp(obuf, ibuf, written) == 0, "content check 8\n");
|
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 */
|
/* Picky conformance tests */
|
||||||
|
|
Loading…
Reference in New Issue