1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*============================================================
6**
7** Source: criticalsectionfunctions/test1/initializecriticalsection.c
8**
9** Purpose: Test Semaphore operation using classic IPC problem:
10** "Producer-Consumer Problem".
11**
12** Dependencies: CreateThread
13** InitializeCriticalSection
14** EnterCriticalSection
15** LeaveCriticalSection
16** DeleteCriticalSection
17** WaitForSingleObject
18** Sleep
19**
20
21**
22**=========================================================*/
23
24#include <palsuite.h>
25
26#define PRODUCTION_TOTAL 26
27
28#define _BUF_SIZE 10
29
30DWORD dwThreadId; /* consumer thread identifier */
31
32HANDLE hThread; /* handle to consumer thread */
33
34CRITICAL_SECTION CriticalSectionM; /* Critical Section Object (used as mutex) */
35
36typedef struct Buffer
37{
38 short readIndex;
39 short writeIndex;
40 CHAR message[_BUF_SIZE];
41
42} BufferStructure;
43
44CHAR producerItems[PRODUCTION_TOTAL + 1];
45
46CHAR consumerItems[PRODUCTION_TOTAL + 1];
47
48/*
49 * Read next message from the Buffer into provided pointer.
50 * Returns: 0 on failure, 1 on success.
51 */
52int
53readBuf(BufferStructure *Buffer, char *c)
54{
55 if( Buffer -> writeIndex == Buffer -> readIndex )
56 {
57 return 0;
58 }
59 *c = Buffer -> message[Buffer -> readIndex++];
60 Buffer -> readIndex %= _BUF_SIZE;
61 return 1;
62}
63
64/*
65 * Write message generated by the producer to Buffer.
66 * Returns: 0 on failure, 1 on success.
67 */
68int
69writeBuf(BufferStructure *Buffer, CHAR c)
70{
71 if( ( ((Buffer -> writeIndex) + 1) % _BUF_SIZE) ==
72 (Buffer -> readIndex) )
73 {
74 return 0;
75 }
76 Buffer -> message[Buffer -> writeIndex++] = c;
77 Buffer -> writeIndex %= _BUF_SIZE;
78 return 1;
79}
80
81/*
82 * Sleep 500 milleseconds.
83 */
84VOID
85consumerSleep(VOID)
86{
87 Sleep(500);
88}
89
90/*
91 * Sleep between 10 milleseconds.
92 */
93VOID
94producerSleep(VOID)
95{
96 Sleep(10);
97}
98
99/*
100 * Produce a message and write the message to Buffer.
101 */
102VOID
103producer(BufferStructure *Buffer)
104{
105
106 int n = 0;
107 char c;
108
109 while (n < PRODUCTION_TOTAL)
110 {
111 c = 'A' + n ; /* Produce Item */
112
113 EnterCriticalSection(&CriticalSectionM);
114
115 if (writeBuf(Buffer, c))
116 {
117 printf("Producer produces %c.\n", c);
118 producerItems[n++] = c;
119 }
120
121 LeaveCriticalSection(&CriticalSectionM);
122
123 producerSleep();
124 }
125
126 return;
127}
128
129/*
130 * Read and "Consume" the messages in Buffer.
131 */
132DWORD
133PALAPI
134consumer( LPVOID lpParam )
135{
136 int n = 0;
137 char c;
138
139 consumerSleep();
140
141 while (n < PRODUCTION_TOTAL)
142 {
143
144 EnterCriticalSection(&CriticalSectionM);
145
146 if (readBuf((BufferStructure*)lpParam, &c))
147 {
148 printf("\tConsumer consumes %c.\n", c);
149 consumerItems[n++] = c;
150 }
151
152 LeaveCriticalSection(&CriticalSectionM);
153
154 consumerSleep();
155 }
156
157 return 0;
158}
159
160int __cdecl main (int argc, char **argv)
161{
162
163 BufferStructure Buffer, *pBuffer;
164
165 pBuffer = &Buffer;
166
167 if(0 != (PAL_Initialize(argc, argv)))
168 {
169 return FAIL;
170 }
171
172 /*
173 * Create mutual exclusion mechanisms
174 */
175
176 InitializeCriticalSection ( &CriticalSectionM );
177
178 /*
179 * Initialize Buffer
180 */
181 pBuffer->writeIndex = pBuffer->readIndex = 0;
182
183
184
185 /*
186 * Create Consumer
187 */
188 hThread = CreateThread(
189 NULL,
190 0,
191 consumer,
192 &Buffer,
193 0,
194 &dwThreadId);
195
196 if ( NULL == hThread )
197 {
198 Fail ( "CreateThread() returned NULL. Failing test.\n"
199 "GetLastError returned %d\n", GetLastError());
200 }
201
202 /*
203 * Start producing
204 */
205 producer(pBuffer);
206
207 /*
208 * Wait for consumer to complete
209 */
210 WaitForSingleObject (hThread, INFINITE);
211
212 /*
213 * Compare items produced vs. items consumed
214 */
215 if ( 0 != strncmp (producerItems, consumerItems, PRODUCTION_TOTAL) )
216 {
217 Fail("The producerItems string %s\n and the consumerItems string "
218 "%s\ndo not match. This could be a problem with the strncmp()"
219 " function\n FailingTest\nGetLastError() returned %d\n",
220 producerItems, consumerItems, GetLastError());
221 }
222
223 /*
224 * Clean up Critical Section object
225 */
226 DeleteCriticalSection(&CriticalSectionM);
227
228 Trace("producerItems and consumerItems arrays match. All %d\nitems "
229 "were produced and consumed in order.\nTest passed.\n",
230 PRODUCTION_TOTAL);
231
232 PAL_Terminate();
233 return (PASS);
234
235}
236