1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 /***********************************************************************
7 **
8 ** Name: sem.c
9 **
10 ** Description: Tests Semaphonre functions.
11 **
12 ** Modification History:
13 ** 20-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
14 **           The debug mode will print all of the printfs associated with this test.
15 **           The regress mode will be the default mode. Since the regress tool limits
16 **           the output to a one line status:PASS or FAIL,all of the printf statements
17 **           have been handled with an if (debug_mode) statement.
18 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
19 **          recognize the return code from tha main program.
20 ***********************************************************************/
21 
22 /***********************************************************************
23 ** Includes
24 ***********************************************************************/
25 /* Used to get the command line option */
26 #include "plgetopt.h"
27 
28 #include "nspr.h"
29 #include "prpriv.h"
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 PRIntn failed_already=0;
36 PRIntn debug_mode;
37 
38 /*
39     Since we don't have stdin, stdout everywhere, we will fake
40     it with our in-memory buffers called stdin and stdout.
41 */
42 
43 #define SBSIZE 1024
44 
45 #include "obsolete/prsem.h"
46 
47 static char stdinBuf[SBSIZE];
48 static char stdoutBuf[SBSIZE];
49 
50 static PRUintn stdinBufIdx = 0;
51 static PRUintn stdoutBufIdx = 0;
52 static PRStatus finalResult = PR_SUCCESS;
53 
54 
dread(PRUintn device,char * buf,size_t bufSize)55 static size_t dread (PRUintn device, char *buf, size_t bufSize)
56 {
57     PRUintn i;
58 
59     /* during first read call, initialize the stdinBuf buffer*/
60     if (stdinBufIdx == 0) {
61         for (i=0; i<SBSIZE; i++) {
62             stdinBuf[i] = i;
63         }
64     }
65 
66     /* now copy data from stdinBuf to the given buffer upto bufSize */
67     for (i=0; i<bufSize; i++) {
68         if (stdinBufIdx == SBSIZE) {
69             break;
70         }
71         buf[i] = stdinBuf[stdinBufIdx++];
72     }
73 
74     return i;
75 }
76 
dwrite(PRUintn device,char * buf,size_t bufSize)77 static size_t dwrite (PRUintn device, char *buf, size_t bufSize)
78 {
79     PRUintn i, j;
80 
81     /* copy data from the given buffer upto bufSize to stdoutBuf */
82     for (i=0; i<bufSize; i++) {
83         if (stdoutBufIdx == SBSIZE) {
84             break;
85         }
86         stdoutBuf[stdoutBufIdx++] = buf[i];
87     }
88 
89     /* during last write call, compare the two buffers */
90     if (stdoutBufIdx == SBSIZE)
91         for (j=0; j<SBSIZE; j++)
92             if (stdinBuf[j] != stdoutBuf[j]) {
93                 if (debug_mode) {
94                     printf("data mismatch for index= %d \n", j);
95                 }
96                 finalResult = PR_FAILURE;
97             }
98 
99     return i;
100 }
101 
102 /*------------------ Following is the real test program ---------*/
103 /*
104     Program to copy standard input to standard output.  The program
105     uses two threads.  One reads the input and puts the data in a
106     double buffer.  The other reads the buffer contents and writes
107     it to standard output.
108 */
109 
110 PRSemaphore *emptyBufs; /* number of empty buffers */
111 PRSemaphore *fullBufs;  /* number of buffers that are full */
112 
113 #define BSIZE   100
114 
115 struct {
116     char data[BSIZE];
117     PRUintn nbytes;     /* number of bytes in this buffer */
118 } buf[2];
119 
reader(void * arg)120 static void PR_CALLBACK reader(void *arg)
121 {
122     PRUintn i = 0;
123     size_t  nbytes;
124 
125     do {
126         (void) PR_WaitSem(emptyBufs);
127         nbytes = dread(0, buf[i].data, BSIZE);
128         buf[i].nbytes = nbytes;
129         PR_PostSem(fullBufs);
130         i = (i + 1) % 2;
131     } while (nbytes > 0);
132 }
133 
writer(void)134 static void writer(void)
135 {
136     PRUintn i = 0;
137     size_t  nbytes;
138 
139     do {
140         (void) PR_WaitSem(fullBufs);
141         nbytes = buf[i].nbytes;
142         if (nbytes > 0) {
143             nbytes = dwrite(1, buf[i].data, nbytes);
144             PR_PostSem(emptyBufs);
145             i = (i + 1) % 2;
146         }
147     } while (nbytes > 0);
148 }
149 
main(int argc,char ** argv)150 int main(int argc, char **argv)
151 {
152     PRThread *r;
153 
154     PR_STDIO_INIT();
155     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
156 
157     {
158         /* The command line argument: -d is used to determine if the test is being run
159         in debug mode. The regress tool requires only one line output:PASS or FAIL.
160         All of the printfs associated with this test has been handled with a if (debug_mode)
161         test.
162         Usage: test_name -d
163         */
164         PLOptStatus os;
165         PLOptState *opt = PL_CreateOptState(argc, argv, "d:");
166         while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
167         {
168             if (PL_OPT_BAD == os) {
169                 continue;
170             }
171             switch (opt->option)
172             {
173                 case 'd':  /* debug mode */
174                     debug_mode = 1;
175                     break;
176                 default:
177                     break;
178             }
179         }
180         PL_DestroyOptState(opt);
181     }
182 
183     /* main test */
184 
185     emptyBufs = PR_NewSem(2);   /* two empty buffers */
186 
187     fullBufs = PR_NewSem(0);    /* zero full buffers */
188 
189     /* create the reader thread */
190 
191     r = PR_CreateThread(PR_USER_THREAD,
192                         reader, 0,
193                         PR_PRIORITY_NORMAL,
194                         PR_LOCAL_THREAD,
195                         PR_UNJOINABLE_THREAD,
196                         0);
197 
198     /* Do the writer operation in this thread */
199     writer();
200 
201     PR_DestroySem(emptyBufs);
202     PR_DestroySem(fullBufs);
203 
204     if (finalResult == PR_SUCCESS) {
205         if (debug_mode) {
206             printf("sem Test Passed.\n");
207         }
208     }
209     else {
210         if (debug_mode) {
211             printf("sem Test Failed.\n");
212         }
213         failed_already=1;
214     }
215     PR_Cleanup();
216     if(failed_already) {
217         return 1;
218     }
219     else {
220         return 0;
221     }
222 }
223