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 | |
30 | DWORD dwThreadId; /* consumer thread identifier */ |
31 | |
32 | HANDLE hThread; /* handle to consumer thread */ |
33 | |
34 | CRITICAL_SECTION CriticalSectionM; /* Critical Section Object (used as mutex) */ |
35 | |
36 | typedef struct Buffer |
37 | { |
38 | short readIndex; |
39 | short writeIndex; |
40 | CHAR message[_BUF_SIZE]; |
41 | |
42 | } BufferStructure; |
43 | |
44 | CHAR producerItems[PRODUCTION_TOTAL + 1]; |
45 | |
46 | CHAR 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 | */ |
52 | int |
53 | readBuf(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 | */ |
68 | int |
69 | writeBuf(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 | */ |
84 | VOID |
85 | consumerSleep(VOID) |
86 | { |
87 | Sleep(500); |
88 | } |
89 | |
90 | /* |
91 | * Sleep between 10 milleseconds. |
92 | */ |
93 | VOID |
94 | producerSleep(VOID) |
95 | { |
96 | Sleep(10); |
97 | } |
98 | |
99 | /* |
100 | * Produce a message and write the message to Buffer. |
101 | */ |
102 | VOID |
103 | producer(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 | */ |
132 | DWORD |
133 | PALAPI |
134 | consumer( 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 | |
160 | int __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 | |