summaryrefslogtreecommitdiff
path: root/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CreateSemaphore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CreateSemaphore.cpp')
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CreateSemaphore.cpp313
1 files changed, 313 insertions, 0 deletions
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CreateSemaphore.cpp b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CreateSemaphore.cpp
new file mode 100644
index 0000000000..bff5b51c33
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CreateSemaphore.cpp
@@ -0,0 +1,313 @@
+// 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: CreateSemaphoreA_ReleaseSemaphore/test2/createsemaphore.c
+**
+** Purpose: Test Semaphore operation using classic IPC problem:
+** "Producer-Consumer Problem".
+**
+** Dependencies: CreateThread
+** ReleaseSemaphore
+** WaitForSingleObject
+** Sleep
+** fflush
+**
+
+**
+**=========================================================*/
+
+#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 = CreateSemaphoreA (
+ NULL,
+ 1,
+ 1,
+ NULL);
+
+ if ( NULL == hSemaphoreM )
+ {
+ Fail ( "hSemaphoreM = CreateSemaphoreA () - returned NULL\n"
+ "Failing Test.\n");
+ }
+
+ hSemaphoreE = CreateSemaphoreA (
+ NULL,
+ _BUF_SIZE ,
+ _BUF_SIZE ,
+ NULL);
+
+ if ( NULL == hSemaphoreE )
+ {
+ Fail ( "hSemaphoreE = CreateSemaphoreA () - returned NULL\n"
+ "Failing Test.\n");
+ }
+
+ hSemaphoreF = CreateSemaphoreA (
+ NULL,
+ 0,
+ _BUF_SIZE ,
+ NULL);
+
+ if ( NULL == hSemaphoreF )
+ {
+ Fail ( "hSemaphoreF = CreateSemaphoreA () - 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 );
+
+}