diff options
Diffstat (limited to 'src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore')
10 files changed, 957 insertions, 0 deletions
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/CMakeLists.txt new file mode 100644 index 0000000000..1962ade358 --- /dev/null +++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(test1) +add_subdirectory(test2) +add_subdirectory(test3) + diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CMakeLists.txt new file mode 100644 index 0000000000..b40f2695bc --- /dev/null +++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + CreateSemaphore.c +) + +add_executable(paltest_createsemaphorew_releasesemaphore_test1 + ${SOURCES} +) + +add_dependencies(paltest_createsemaphorew_releasesemaphore_test1 coreclrpal) + +target_link_libraries(paltest_createsemaphorew_releasesemaphore_test1 + pthread + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c new file mode 100644 index 0000000000..854d16d0ef --- /dev/null +++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c @@ -0,0 +1,323 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================ +** +** Source: CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c +** +** Purpose: Test Semaphore operation using classic IPC problem: +** "Producer-Consumer Problem". +** +** Dependencies: CreateThread +** ReleaseSemaphore +** WaitForSingleObject +** Sleep +** fflush +** + +** +**=========================================================*/ + +#define UNICODE +#include <palsuite.h> + +#define PRODUCTION_TOTAL 26 + +#define _BUF_SIZE 10 + +DWORD dwThreadId; /* consumer thread identifier */ + +HANDLE hThread; /* handle to consumer thread */ + +HANDLE hSemaphoreM; /* handle to mutual exclusion semaphore */ + +HANDLE hSemaphoreE; /* handle to semaphore that counts empty buffer slots */ + +HANDLE hSemaphoreF; /* handle to semaphore that counts full buffer slots */ + +typedef struct Buffer +{ + short readIndex; + short writeIndex; + CHAR message[_BUF_SIZE]; + +} BufferStructure; + +CHAR producerItems[PRODUCTION_TOTAL + 1]; + +CHAR consumerItems[PRODUCTION_TOTAL + 1]; + +/* + * Read next message from the Buffer into provided pointer. + * Returns: 0 on failure, 1 on success. + */ +int +readBuf(BufferStructure *Buffer, char *c) +{ + if( Buffer -> writeIndex == Buffer -> readIndex ) + { + return 0; + } + *c = Buffer -> message[Buffer -> readIndex++]; + Buffer -> readIndex %= _BUF_SIZE; + return 1; +} + +/* + * Write message generated by the producer to Buffer. + * Returns: 0 on failure, 1 on success. + */ +int +writeBuf(BufferStructure *Buffer, CHAR c) +{ + if( ( ((Buffer -> writeIndex) + 1) % _BUF_SIZE) == + (Buffer -> readIndex) ) + { + return 0; + } + Buffer -> message[Buffer -> writeIndex++] = c; + Buffer -> writeIndex %= _BUF_SIZE; + return 1; +} + +/* + * Atomic decrement of semaphore value. + */ +VOID +down(HANDLE hSemaphore) +{ + switch ( (WaitForSingleObject ( + hSemaphore, + 10000))) /* Wait 10 seconds */ + { + case WAIT_OBJECT_0: /* + * Semaphore was signaled. OK to access + * semaphore. + */ + break; + case WAIT_ABANDONED: /* + * Object was mutex object whose owning + * thread has terminated. Shouldn't occur. + */ + Fail("WaitForSingleObject call returned 'WAIT_ABANDONED'.\n" + "Failing Test.\n"); + break; + case WAIT_FAILED: /* WaitForSingleObject function failed */ + Fail("WaitForSingleObject call returned 'WAIT_FAILED'.\n" + "GetLastError returned %d\nFailing Test.\n",GetLastError()); + break; + default: + Fail("WaitForSingleObject call returned an unexpected value.\n" + "Failing Test.\n"); + break; + } + +} + +/* + * Atomic increment of semaphore value. + */ +VOID +up(HANDLE hSemaphore) +{ + if (!ReleaseSemaphore ( + hSemaphore, + 1, + NULL) + ) + { + Fail("ReleaseSemaphore call failed. GetLastError returned %d\n", + GetLastError()); + } +} + +/* + * Sleep 500 milleseconds. + */ +VOID +consumerSleep(VOID) +{ + Sleep(500); +} + +/* + * Sleep between 10 milleseconds. + */ +VOID +producerSleep(VOID) +{ + Sleep(10); +} + +/* + * Produce a message and write the message to Buffer. + */ +VOID +producer(BufferStructure *Buffer) +{ + + int n = 0; + char c; + + while (n < PRODUCTION_TOTAL) + { + c = 'A' + n ; /* Produce Item */ + + down(hSemaphoreE); + down(hSemaphoreM); + + if (writeBuf(Buffer, c)) + { + Trace("Producer produces %c.\n", c); + fflush(stdout); + producerItems[n++] = c; + } + + up(hSemaphoreM); + up(hSemaphoreF); + + producerSleep(); + } + + return; +} + +/* + * Read and "Consume" the messages in Buffer. + */ +DWORD +PALAPI +consumer( LPVOID lpParam ) +{ + int n = 0; + char c; + + consumerSleep(); + + while (n < PRODUCTION_TOTAL) + { + + down(hSemaphoreF); + down(hSemaphoreM); + + if (readBuf((BufferStructure*)lpParam, &c)) + { + Trace("\tConsumer consumes %c.\n", c); + fflush(stdout); + consumerItems[n++] = c; + } + + up(hSemaphoreM); + up(hSemaphoreE); + + consumerSleep(); + } + + return 0; +} + +int __cdecl main (int argc, char **argv) +{ + + BufferStructure Buffer, *pBuffer; + + pBuffer = &Buffer; + + if(0 != (PAL_Initialize(argc, argv))) + { + return ( FAIL ); + } + + /* + * Create Semaphores + */ + hSemaphoreM = CreateSemaphoreW ( + NULL, + 1, + 1, + NULL); + + if ( NULL == hSemaphoreM ) + { + Fail ( "hSemaphoreM = CreateSemaphoreW () - returned NULL\n" + "Failing Test.\nGetLastError returned %d\n", GetLastError()); + } + + + hSemaphoreE = CreateSemaphoreW ( + NULL, + _BUF_SIZE , + _BUF_SIZE , + NULL); + + if ( NULL == hSemaphoreE ) + { + Fail ( "hSemaphoreE = CreateSemaphoreW () - returned NULL\n" + "Failing Test.\nGetLastError returned %d\n", GetLastError()); + } + + hSemaphoreF = CreateSemaphoreW ( + NULL, + 0, + _BUF_SIZE , + NULL); + + if ( NULL == hSemaphoreF ) + { + Fail ( "hSemaphoreF = CreateSemaphoreW () - returned NULL\n" + "Failing Test.\nGetLastError returned %d\n", GetLastError()); + } + + + /* + * Initialize Buffer + */ + pBuffer->writeIndex = pBuffer->readIndex = 0; + + /* + * Create Consumer + */ + hThread = CreateThread( + NULL, + 0, + consumer, + &Buffer, + 0, + &dwThreadId); + + if ( NULL == hThread ) + { + Fail ( "CreateThread() returned NULL. Failing test.\n" + "GetLastError returned %d\n", GetLastError()); + } + + /* + * Start producing + */ + producer(pBuffer); + + /* + * Wait for consumer to complete + */ + WaitForSingleObject (hThread, INFINITE); + + /* + * Compare items produced vs. items consumed + */ + if ( 0 != strncmp (producerItems, consumerItems, PRODUCTION_TOTAL) ) + { + Fail("The producerItems string %s\n and the consumerItems string " + "%s\ndo not match. This could be a problem with the strncmp()" + " function\n FailingTest\nGetLastError() returned %d\n", + producerItems, consumerItems, GetLastError()); + } + + Trace ("producerItems and consumerItems arrays match. All %d\nitems " + "were produced and consumed in order.\nTest passed.\n", + PRODUCTION_TOTAL); + + PAL_Terminate(); + return ( PASS ); + +} diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/testinfo.dat new file mode 100644 index 0000000000..9127589333 --- /dev/null +++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/testinfo.dat @@ -0,0 +1,18 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = threading +Function = CreateSemaphoreW / ReleaseSemaphore +Name = Positive Test for CreateSemaphoreW and ReleaseSemaphore +TYPE = DEFAULT +EXE1 = createsemaphore +Description += Implementation of Producer / Consumer IPC problem using CreateSemaphoreW += and ReleaseSemaphore functions. This test case exercises CreateSemaphoreW += , ReleaseSemaphore, CreateThread and WaitForSingleObject functions. += Since there is no way to currently create "pseudo" random events in the += pal, this example does not behave as classic bounded buffers would. This += test case is designed to starve the consumer and have the producer fill += the buffer. diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CMakeLists.txt new file mode 100644 index 0000000000..b14284d08f --- /dev/null +++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + CreateSemaphore.c +) + +add_executable(paltest_createsemaphorew_releasesemaphore_test2 + ${SOURCES} +) + +add_dependencies(paltest_createsemaphorew_releasesemaphore_test2 coreclrpal) + +target_link_libraries(paltest_createsemaphorew_releasesemaphore_test2 + pthread + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.c b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.c new file mode 100644 index 0000000000..62532737ac --- /dev/null +++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.c @@ -0,0 +1,314 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================ +** +** Source: CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c +** +** Purpose: Test Semaphore operation using classic IPC problem: +** "Producer-Consumer Problem". +** +** Dependencies: CreateThread +** ReleaseSemaphore +** WaitForSingleObject +** Sleep +** fflush +** + +** +**=========================================================*/ + +#define UNICODE +#include <palsuite.h> + +#define PRODUCTION_TOTAL 26 + +#define _BUF_SIZE 10 + +DWORD dwThreadId; /* consumer thread identifier */ + +HANDLE hThread; /* handle to consumer thread */ + +HANDLE hSemaphoreM; /* handle to mutual exclusion semaphore */ + +HANDLE hSemaphoreE; /* handle to semaphore that counts empty buffer slots */ + +HANDLE hSemaphoreF; /* handle to semaphore that counts full buffer slots */ + +typedef struct Buffer +{ + short readIndex; + short writeIndex; + CHAR message[_BUF_SIZE]; + +} BufferStructure; + +CHAR producerItems[PRODUCTION_TOTAL + 1]; + +CHAR consumerItems[PRODUCTION_TOTAL + 1]; + +/* + * Read next message from the Buffer into provided pointer. + * Returns: 0 on failure, 1 on success. + */ +int +readBuf(BufferStructure *Buffer, char *c) +{ + if( Buffer -> writeIndex == Buffer -> readIndex ) + { + return 0; + } + *c = Buffer -> message[Buffer -> readIndex++]; + Buffer -> readIndex %= _BUF_SIZE; + return 1; +} + +/* + * Write message generated by the producer to Buffer. + * Returns: 0 on failure, 1 on success. + */ +int +writeBuf(BufferStructure *Buffer, CHAR c) +{ + if( ( ((Buffer -> writeIndex) + 1) % _BUF_SIZE) == + (Buffer -> readIndex) ) + { + return 0; + } + Buffer -> message[Buffer -> writeIndex++] = c; + Buffer -> writeIndex %= _BUF_SIZE; + return 1; +} + +/* + * Atomic decrement of semaphore value. + */ +VOID +down(HANDLE hSemaphore) +{ + switch ( (WaitForSingleObject ( + hSemaphore, + 10000))) + { + case WAIT_OBJECT_0: /* + * Semaphore was signaled. OK to access semaphore. + */ + break; + case WAIT_ABANDONED: /* + * Object was mutex object whose owning + * thread has terminated. Shouldn't occur. + */ + Fail("WaitForSingleObject call returned 'WAIT_ABANDONED'.\n" + "Failing Test.\n"); + break; + case WAIT_FAILED: /* WaitForSingleObject function failed */ + Fail("WaitForSingleObject call returned 'WAIT_FAILED'.\n" + "GetLastError returned %d\nFailing Test.\n",GetLastError()); + break; + default: + Fail("WaitForSingleObject call returned an unexpected value.\n" + "Failing Test.\n"); + break; + } + +} + +/* + * Atomic increment of semaphore value. + */ +VOID +up(HANDLE hSemaphore) +{ + if (!ReleaseSemaphore ( + hSemaphore, + 1, + NULL) + ) + { + Fail("ReleaseSemaphore call failed. GetLastError returned %d\n", + GetLastError()); + } +} + +/* + * Sleep 10 milleseconds. + */ +VOID +consumerSleep(VOID) +{ + Sleep(10); +} + +/* + * Sleep 500 milleseconds. + */ +VOID +producerSleep(VOID) +{ + Sleep(500); +} + +/* + * Produce a message and write the message to Buffer. + */ +VOID +producer(BufferStructure *Buffer) +{ + + int n = 0; + char c; + + while (n < PRODUCTION_TOTAL) + { + c = 'A' + n ; /* Produce Item */ + + down(hSemaphoreE); + down(hSemaphoreM); + + if (writeBuf(Buffer, c)) + { + Trace("Producer produces %c.\n", c); + fflush(stdout); + producerItems[n++] = c; + } + + up(hSemaphoreM); + up(hSemaphoreF); + + producerSleep(); + } + return; +} + +/* + * Read and "Consume" the messages in Buffer. + */ +DWORD +PALAPI +consumer( LPVOID lpParam ) +{ + int n = 0; + char c; + + consumerSleep(); + + while (n < PRODUCTION_TOTAL) + { + + down(hSemaphoreF); + down(hSemaphoreM); + + if (readBuf((BufferStructure*)lpParam, &c)) + { + Trace("\tConsumer consumes %c.\n", c); + fflush(stdout); + consumerItems[n++] = c; + } + + up(hSemaphoreM); + up(hSemaphoreE); + + consumerSleep(); + } + return 0; +} + +int __cdecl main (int argc, char **argv) +{ + + BufferStructure Buffer, *pBuffer; + + pBuffer = &Buffer; + + if(0 != (PAL_Initialize(argc, argv))) + { + return (FAIL); + } + + /* + * Create Semaphores + */ + hSemaphoreM = CreateSemaphoreW ( + NULL, + 1, + 1, + NULL); + + if ( NULL == hSemaphoreM ) + { + Fail ( "hSemaphoreM = CreateSemaphoreW () - returned NULL\n" + "Failing Test.\n"); + } + + hSemaphoreE = CreateSemaphoreW ( + NULL, + _BUF_SIZE , + _BUF_SIZE , + NULL); + + if ( NULL == hSemaphoreE ) + { + Fail ( "hSemaphoreE = CreateSemaphoreW () - returned NULL\n" + "Failing Test.\n"); + } + + hSemaphoreF = CreateSemaphoreW ( + NULL, + 0, + _BUF_SIZE , + NULL); + + if ( NULL == hSemaphoreF ) + { + Fail ( "hSemaphoreF = CreateSemaphoreW () - returned NULL\n" + "Failing Test.\n"); + } + + /* + * Initialize Buffer + */ + pBuffer->writeIndex = pBuffer->readIndex = 0; + + /* + * Create Consumer + */ + hThread = CreateThread( + NULL, + 0, + consumer, + &Buffer, + 0, + &dwThreadId); + + if ( NULL == hThread ) + { + Fail ( "CreateThread() returned NULL. Failing test.\n"); + } + + /* + * Start producing + */ + producer(pBuffer); + + /* + * Wait for consumer to complete + */ + WaitForSingleObject (hThread, INFINITE); + + if ( 0 != strncmp (producerItems, consumerItems, PRODUCTION_TOTAL) ) + { + Fail("The producerItems string %s\n and the consumerItems string " + "%s\ndo not match. This could be a problem with the strncmp()" + " function\n FailingTest\nGetLastError() returned %d\n", + producerItems, consumerItems, GetLastError()); + } + + Trace ("producerItems and consumerItems arrays match. All %d\nitems " + "were produced and consumed in order.\nTest passed.\n", + PRODUCTION_TOTAL); + + PAL_Terminate(); + return ( PASS ); + +} diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/testinfo.dat new file mode 100644 index 0000000000..32b107fd9e --- /dev/null +++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/testinfo.dat @@ -0,0 +1,18 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = threading +Function = CreateSemaphoreW / ReleaseSemaphore +Name = Positive Test for CreateSemaphoreW and ReleaseSemaphore +TYPE = DEFAULT +EXE1 = createsemaphore +Description += Implementation of Producer / Consumer IPC problem using CreateSemaphoreW += and ReleaseSemaphore functions. This test case exercises CreateSemaphoreW += , ReleaseSemaphore, CreateThread and WaitForSingleObject functions. += Since there is no way to currently create "pseudo" random events in the += pal, this example does not behave as classic bounded buffers would. This += test case is designed to starve the producer and have the consumer fill += the buffer. diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/CMakeLists.txt new file mode 100644 index 0000000000..f7f0905761 --- /dev/null +++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + createsemaphore.c +) + +add_executable(paltest_createsemaphorew_releasesemaphore_test3 + ${SOURCES} +) + +add_dependencies(paltest_createsemaphorew_releasesemaphore_test3 coreclrpal) + +target_link_libraries(paltest_createsemaphorew_releasesemaphore_test3 + pthread + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.c b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.c new file mode 100644 index 0000000000..ea0a5e0846 --- /dev/null +++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.c @@ -0,0 +1,201 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================================ +** +** Source: createsemaphorew_releasesemaphore/test3/createsemaphore.c +** +** Purpose: Test attributes of CreateSemaphoreW and ReleaseSemaphore. +** Insure for CreateSemaphore that lInitialCount and lMaximumCount +** constraints are respected. Validate that CreateSemaphore rejects +** conditions where initial count and / or maximum count are negative +** and conditions where the initial count is greater than the maximum +** count. For ReleaseSemaphore validate that lpPreviousCount gets set +** to the previous semaphore count and lpPreviousCount can be NULL. +** Also establish ReleaseSemaphore fails when called in a semaphore +** with count equal to lMaximumCount. +** +** +**==========================================================================*/ + +#include <palsuite.h> + +struct testcase +{ + LPSECURITY_ATTRIBUTES lpSemaphoreAttributes; + LONG lInitialCount; + LONG lMaximumCount; + LPCWSTR lpName; + BOOL bNegativeTest; +}; + +struct testcase testCases[] = +{ + {NULL, -1, 1, NULL, TRUE}, + {NULL, 1, -1, NULL, TRUE}, + {NULL, -1, -1, NULL, TRUE}, + {NULL, 2, 1, NULL, TRUE}, + {NULL, 1, 2, NULL, FALSE}, + {NULL, 0, 10, NULL, FALSE}, + {NULL, INT_MAX - 1, INT_MAX, NULL, FALSE}, + {NULL, INT_MAX, INT_MAX, NULL, FALSE} +}; + +HANDLE hSemaphore[sizeof(testCases)/sizeof(struct testcase)]; + +BOOL cleanup(int index) +{ + int i; + BOOL bRet = TRUE; + for (i = 0; i < index; i++) + { + if (!CloseHandle(hSemaphore[i])) + { + bRet = FALSE; + Trace("PALSUITE ERROR: CloseHandle(%p) call failed for index %d\n", + hSemaphore[i], i); + } + } + return(bRet); +} + +int __cdecl main (int argc, char **argv) +{ + int i; + int j; + + if(0 != (PAL_Initialize(argc, argv))) + { + return (FAIL); + } + /* create semaphores */ + for (i = 0; i < sizeof(testCases)/sizeof(struct testcase); i++) + { + hSemaphore[i] = CreateSemaphoreW (testCases[i].lpSemaphoreAttributes, + testCases[i].lInitialCount, + testCases[i].lMaximumCount, + testCases[i].lpName); + + if (NULL == hSemaphore[i]) + { + if (!testCases[i].bNegativeTest) + { + Trace("PALSUITE ERROR: CreateSemaphoreW('%p' '%ld' '%ld' " + "'%p') returned NULL at index %d.\nGetLastError " + "returned %d.\n", testCases[i].lpSemaphoreAttributes, + testCases[i].lInitialCount, testCases[i].lMaximumCount, + testCases[i].lpName, i, GetLastError()); + if (i > 0) + { + cleanup(i - 1); + } + Fail(""); + } + else + { + continue; + } + } + + /* increment semaphore count to lMaximumCount */ + for (j = testCases[i].lInitialCount; (ULONG)j <= (ULONG)testCases[i].lMaximumCount; + j++) + { + if (testCases[i].lMaximumCount == j) + { + /* Call ReleaseSemaphore once more to ensure ReleaseSemaphore + fails */ + if(ReleaseSemaphore(hSemaphore[i], 1, NULL)) + { + Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') " + "call returned %d\nwhen it should have returned " + "%d.\nThe semaphore's count was %d.\nGetLastError " + "returned %d.\n", hSemaphore[i], 1, NULL, TRUE, + FALSE, j, GetLastError()); + cleanup(i); + Fail(""); + } + } + else + { + int previous; + BOOL bRet = ReleaseSemaphore(hSemaphore[i], 1, &previous); + DWORD dwError = GetLastError(); + + if(!bRet) + { + Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') " + "call returned %d\nwhen it should have returned " + "%d.\nThe semaphore count was %d and it's " + "lMaxCount was %d.\nGetLastError returned %d.\n", + hSemaphore[i], 1, &previous, bRet, TRUE, j, + testCases[i].lMaximumCount, dwError); + cleanup(i); + Fail(""); + } + if (previous != j) + { + Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') " + "call set %p to %d instead of %d.\n The semaphore " + "count was %d and GetLastError returned %d.\n", + hSemaphore[i], 1, &previous, &previous, previous, + j, j, dwError); + cleanup(i); + Fail(""); + } + } + } + + // Skip exhaustive decrement tests for too large an initial count + if(testCases[i].lInitialCount >= INT_MAX - 1) + { + continue; + } + + /* decrement semaphore count to 0 */ + for (j = testCases[i].lMaximumCount; j >= 0; j--) + { + DWORD dwRet = WaitForSingleObject(hSemaphore[i], 0); + DWORD dwError = GetLastError(); + + if (0 == j) + { + /* WaitForSingleObject should report that the + semaphore is nonsignaled */ + if (WAIT_TIMEOUT != dwRet) + { + Trace("PALSUITE ERROR: WaitForSingleObject('%p' '%u') " + "call returned %d\nwhen it should have returned " + "%d.\nThe semaphore's count was %d.\nGetLastError " + "returned %d.\n", hSemaphore[i], 0, dwRet, + WAIT_TIMEOUT, j, dwError); + cleanup(i); + Fail(""); + } + } + else + { + /* WaitForSingleObject should report that the + semaphore is signaled */ + if (WAIT_OBJECT_0 != dwRet) + { + Trace("PALSUITE ERROR: WaitForSingleObject('%p' '%u') " + "call returned %d\nwhen it should have returned " + "%d.\nThe semaphore's count was %d.\nGetLastError " + "returned %d.\n", hSemaphore[i], 0, dwRet, + WAIT_OBJECT_0, j, dwError); + cleanup(i); + Fail(""); + } + } + } + } + PAL_Terminate(); + return (PASS); +} + + + + + diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/testinfo.dat b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/testinfo.dat new file mode 100644 index 0000000000..beaac95f97 --- /dev/null +++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/testinfo.dat @@ -0,0 +1,20 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = threading +Function = CreateSemaphoreW / ReleaseSemaphore +Name = Positive Test for CreateSemaphoreW and ReleaseSemaphore +TYPE = DEFAULT +EXE1 = createsemaphore +Description += Test attributes of CreateSemaphoreW and ReleaseSemaphore. += Insure for CreateSemaphore that lInitialCount and lMaximumCount += constraints are respected. Validate that CreateSemaphore rejects += conditions where, initial count and / or maximum count are negative += and conditions where the initial count is greater than the maximum += count. For ReleaseSemaphore validate that lpPreviousCount gets set += to the previous semaphore count and lpPreviousCount can be NULL. += Also establish ReleaseSemaphore fails when called in a semaphore += with count equal to lMaximumCount. |