6fff9c75e0a438bd7097e8ae8f0aad12f1453f26
[openafs.git] / src / lwp / rw.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11         (Multiple) readers & writers test of LWP stuff.
12
13 Created: 11/1/83, J. Rosenberg
14
15 */
16
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20
21 #ifdef AFS_NT40_ENV
22 #include <malloc.h>
23 #include <stdlib.h>
24 #else
25 #include <sys/time.h>
26 extern char *calloc();
27 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include "lwp.h"
32 #include "lock.h"
33 #include "preempt.h"
34 #include <afs/afs_assert.h>
35
36 #define DEFAULT_READERS 5
37
38 #define STACK_SIZE      (16*1024)
39
40 /* The shared queue */
41 typedef struct QUEUE {
42     struct QUEUE *prev, *next;
43     char *data;
44     struct Lock lock;
45 } queue;
46
47 queue *
48 init()
49 {
50     queue *q;
51
52     q = (queue *) malloc(sizeof(queue));
53     q->prev = q->next = q;
54     return (q);
55 }
56
57 char
58 empty(queue *q)
59 {
60     return (q->prev == q && q->next == q);
61 }
62
63 void
64 insert(queue * q, char *s)
65 {
66     queue *new;
67
68     new = (queue *) malloc(sizeof(queue));
69     new->data = s;
70     new->prev = q->prev;
71     q->prev->next = new;
72     q->prev = new;
73     new->next = q;
74 }
75
76 char *
77 Remove(queue *q)
78 {
79     queue *old;
80     char *s;
81
82     if (empty(q)) {
83         printf("Remove from empty queue");
84         osi_Assert(0);
85     }
86
87     old = q->next;
88     q->next = old->next;
89     q->next->prev = q;
90     s = old->data;
91     free(old);
92     return (s);
93 }
94
95 queue *q;
96
97 int asleep;                     /* Number of processes sleeping -- used for
98                                  * clean termination */
99
100 static int
101 read_process(int *id)
102 {
103     printf("\t[Reader %d]\n", *id);
104     LWP_DispatchProcess();      /* Just relinquish control for now */
105
106     PRE_PreemptMe();
107     for (;;) {
108         int i;
109
110         /* Wait until there is something in the queue */
111         asleep++;
112         ObtainReadLock(&q->lock);
113         while (empty(q)) {
114             ReleaseReadLock(&q->lock);
115             LWP_WaitProcess(q);
116             ObtainReadLock(&q->lock);
117         }
118         asleep--;
119         for (i = 0; i < 10000; i++);
120         PRE_BeginCritical();
121         printf("[%d: %s]\n", *id, Remove(q));
122         PRE_EndCritical();
123         ReleaseReadLock(&q->lock);
124         LWP_DispatchProcess();
125     }
126     return 0;
127 }
128
129 static int
130 write_process()
131 {
132     static char *messages[] = {
133         "Mary had a little lamb,",
134         "Its fleece was white as snow,",
135         "And everywhere that Mary went,",
136         "The lamb was sure to go",
137         "Mary had a little lamb,",
138         "Its fleece was white as snow,",
139         "And everywhere that Mary went,",
140         "The lamb was sure to go",
141         "Mary had a little lamb,",
142         "Its fleece was white as snow,",
143         "And everywhere that Mary went,",
144         "The lamb was sure to go",
145         "Mary had a little lamb,",
146         "Its fleece was white as snow,",
147         "And everywhere that Mary went,",
148         "The lamb was sure to go",
149         "Mary had a little lamb,",
150         "Its fleece was white as snow,",
151         "And everywhere that Mary went,",
152         "The lamb was sure to go",
153         "Mary had a little lamb,",
154         "Its fleece was white as snow,",
155         "And everywhere that Mary went,",
156         "The lamb was sure to go",
157         "Mary had a little lamb,",
158         "Its fleece was white as snow,",
159         "And everywhere that Mary went,",
160         "The lamb was sure to go",
161         "Mary had a little lamb,",
162         "Its fleece was white as snow,",
163         "And everywhere that Mary went,",
164         "The lamb was sure to go",
165         "Mary had a little lamb,",
166         "Its fleece was white as snow,",
167         "And everywhere that Mary went,",
168         "The lamb was sure to go",
169         "Mary had a little lamb,",
170         "Its fleece was white as snow,",
171         "And everywhere that Mary went,",
172         "The lamb was sure to go",
173         0
174     };
175     char **mesg;
176
177     printf("\t[Writer]\n");
178     PRE_PreemptMe();
179
180     /* Now loop & write data */
181     for (mesg = messages; *mesg != 0; mesg++) {
182         ObtainWriteLock(&q->lock);
183         insert(q, *mesg);
184         ReleaseWriteLock(&q->lock);
185         LWP_SignalProcess(q);
186     }
187
188     asleep++;
189     return 0;
190 }
191
192 /*
193         Arguments:
194                 0:      Unix junk, ignore
195                 1:      Number of readers to create (default is DEFAULT_READERS)
196                 2:      # msecs for interrupt (to satisfy Larry)
197                 3:      Present if lwp_debug to be set
198 */
199
200 #include "AFS_component_version_number.c"
201
202 int
203 main(int argc, char **argv)
204 {
205     int nreaders, i;
206     PROCESS pid;
207     afs_int32 interval;         /* To satisfy Brad */
208     PROCESS *readers;
209     int *readerid;
210     PROCESS writer;
211     struct timeval tv;
212
213     printf("\n*Readers & Writers*\n\n");
214     setbuf(stdout, 0);
215
216     /* Determine # readers */
217     if (argc == 1)
218         nreaders = DEFAULT_READERS;
219     else
220         sscanf(*++argv, "%d", &nreaders);
221     printf("[There will be %d readers]\n", nreaders);
222
223     interval = (argc >= 3 ? atoi(*++argv) * 1000 : 50000);
224
225     if (argc == 4)
226         lwp_debug = 1;
227     LWP_InitializeProcessSupport(0, &pid);
228     printf("[Support initialized]\n");
229     tv.tv_sec = 0;
230     tv.tv_usec = interval;
231     PRE_InitPreempt(&tv);
232
233     /* Initialize queue */
234     q = init();
235
236     /* Initialize lock */
237     Lock_Init(&q->lock);
238
239     asleep = 0;
240     /* Now create readers */
241     printf("[Creating Readers...\n");
242     readers = (PROCESS *) calloc(nreaders, sizeof(PROCESS));
243     readerid = (int *)calloc(nreaders, sizeof(i));
244     for (i = 0; i < nreaders; i++)
245         LWP_CreateProcess(read_process, STACK_SIZE, 0, (void *)&readerid[i],
246                           "Reader", &readers[i]);
247     printf("done]\n");
248
249     printf("\t[Creating Writer...\n");
250     LWP_CreateProcess(write_process, STACK_SIZE, 1, 0, "Writer", &writer);
251     printf("done]\n");
252
253     /* Now loop until everyone's done */
254     while (asleep != nreaders + 1)
255         LWP_DispatchProcess();
256     /* Destroy the readers */
257     for (i = nreaders - 1; i >= 0; i--)
258         LWP_DestroyProcess(readers[i]);
259     printf("\n*Exiting*\n");
260 }