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