f814fd8220356b55463f88fc45432d79c1b3ce1c
[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/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(q)
59      queue *q;
60 {
61     return (q->prev == q && q->next == q);
62 }
63
64 void
65 insert(queue * q, char *s)
66 {
67     queue *new;
68
69     new = (queue *) malloc(sizeof(queue));
70     new->data = s;
71     new->prev = q->prev;
72     q->prev->next = new;
73     q->prev = new;
74     new->next = q;
75 }
76
77 char *
78 Remove(q)
79      queue *q;
80 {
81     queue *old;
82     char *s;
83
84     if (empty(q)) {
85         printf("Remove from empty queue");
86         assert(0);
87     }
88
89     old = q->next;
90     q->next = old->next;
91     q->next->prev = q;
92     s = old->data;
93     free(old);
94     return (s);
95 }
96
97 queue *q;
98
99 int asleep;                     /* Number of processes sleeping -- used for
100                                  * clean termination */
101
102 static int
103 read_process(id)
104      int *id;
105 {
106     printf("\t[Reader %d]\n", *id);
107     LWP_DispatchProcess();      /* Just relinquish control for now */
108
109     PRE_PreemptMe();
110     for (;;) {
111         int i;
112
113         /* Wait until there is something in the queue */
114         asleep++;
115         ObtainReadLock(&q->lock);
116         while (empty(q)) {
117             ReleaseReadLock(&q->lock);
118             LWP_WaitProcess(q);
119             ObtainReadLock(&q->lock);
120         }
121         asleep--;
122         for (i = 0; i < 10000; i++);
123         PRE_BeginCritical();
124         printf("[%d: %s]\n", *id, Remove(q));
125         PRE_EndCritical();
126         ReleaseReadLock(&q->lock);
127         LWP_DispatchProcess();
128     }
129     return 0;
130 }
131
132 static int
133 write_process()
134 {
135     static char *messages[] = {
136         "Mary had a little lamb,",
137         "Its fleece was white as snow,",
138         "And everywhere that Mary went,",
139         "The lamb was sure to go",
140         "Mary had a little lamb,",
141         "Its fleece was white as snow,",
142         "And everywhere that Mary went,",
143         "The lamb was sure to go",
144         "Mary had a little lamb,",
145         "Its fleece was white as snow,",
146         "And everywhere that Mary went,",
147         "The lamb was sure to go",
148         "Mary had a little lamb,",
149         "Its fleece was white as snow,",
150         "And everywhere that Mary went,",
151         "The lamb was sure to go",
152         "Mary had a little lamb,",
153         "Its fleece was white as snow,",
154         "And everywhere that Mary went,",
155         "The lamb was sure to go",
156         "Mary had a little lamb,",
157         "Its fleece was white as snow,",
158         "And everywhere that Mary went,",
159         "The lamb was sure to go",
160         "Mary had a little lamb,",
161         "Its fleece was white as snow,",
162         "And everywhere that Mary went,",
163         "The lamb was sure to go",
164         "Mary had a little lamb,",
165         "Its fleece was white as snow,",
166         "And everywhere that Mary went,",
167         "The lamb was sure to go",
168         "Mary had a little lamb,",
169         "Its fleece was white as snow,",
170         "And everywhere that Mary went,",
171         "The lamb was sure to go",
172         "Mary had a little lamb,",
173         "Its fleece was white as snow,",
174         "And everywhere that Mary went,",
175         "The lamb was sure to go",
176         0
177     };
178     char **mesg;
179
180     printf("\t[Writer]\n");
181     PRE_PreemptMe();
182
183     /* Now loop & write data */
184     for (mesg = messages; *mesg != 0; mesg++) {
185         ObtainWriteLock(&q->lock);
186         insert(q, *mesg);
187         ReleaseWriteLock(&q->lock);
188         LWP_SignalProcess(q);
189     }
190
191     asleep++;
192     return 0;
193 }
194
195 /*
196         Arguments:
197                 0:      Unix junk, ignore
198                 1:      Number of readers to create (default is DEFAULT_READERS)
199                 2:      # msecs for interrupt (to satisfy Larry)
200                 3:      Present if lwp_debug to be set
201 */
202
203 #include "AFS_component_version_number.c"
204
205 main(argc, argv)
206      int argc;
207      char **argv;
208 {
209     int nreaders, i;
210     PROCESS pid;
211     afs_int32 interval;         /* To satisfy Brad */
212     PROCESS *readers;
213     int *readerid;
214     PROCESS writer;
215     struct timeval tv;
216
217     printf("\n*Readers & Writers*\n\n");
218     setbuf(stdout, 0);
219
220     /* Determine # readers */
221     if (argc == 1)
222         nreaders = DEFAULT_READERS;
223     else
224         sscanf(*++argv, "%d", &nreaders);
225     printf("[There will be %d readers]\n", nreaders);
226
227     interval = (argc >= 3 ? atoi(*++argv) * 1000 : 50000);
228
229     if (argc == 4)
230         lwp_debug = 1;
231     LWP_InitializeProcessSupport(0, &pid);
232     printf("[Support initialized]\n");
233     tv.tv_sec = 0;
234     tv.tv_usec = interval;
235     PRE_InitPreempt(&tv);
236
237     /* Initialize queue */
238     q = init();
239
240     /* Initialize lock */
241     Lock_Init(&q->lock);
242
243     asleep = 0;
244     /* Now create readers */
245     printf("[Creating Readers...\n");
246     readers = (PROCESS *) calloc(nreaders, sizeof(PROCESS));
247     readerid = (int *)calloc(nreaders, sizeof(i));
248     for (i = 0; i < nreaders; i++)
249         LWP_CreateProcess(read_process, STACK_SIZE, 0, (void *)&readerid[i],
250                           "Reader", &readers[i]);
251     printf("done]\n");
252
253     printf("\t[Creating Writer...\n");
254     LWP_CreateProcess(write_process, STACK_SIZE, 1, 0, "Writer", &writer);
255     printf("done]\n");
256
257     /* Now loop until everyone's done */
258     while (asleep != nreaders + 1)
259         LWP_DispatchProcess();
260     /* Destroy the readers */
261     for (i = nreaders - 1; i >= 0; i--)
262         LWP_DestroyProcess(readers[i]);
263     printf("\n*Exiting*\n");
264 }