summaryrefslogtreecommitdiff
path: root/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore')
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c323
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.c314
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.c201
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/testinfo.dat20
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.