49db7271214e157833bcef75b2d12575216d5dea
[vlp.git] / src / int / rpcall.c
1 #include "depend.h"
2 #include "genint.h"
3 #include "int.h"
4 #include "process.h"
5 #include "intproto.h"
6
7
8 #ifndef NO_PROTOTYPES
9 static bool isenabled(word,word);
10 static bool rpcready(word);
11 static void bitaccess(word, word, int *, char *);
12 static void dupmask(word);
13 #else
14 static bool isenabled();
15 static bool rpcready();
16 static void bitaccess();
17 static void dupmask();
18 #endif
19
20 /**
21  * preprocess RPC request
22  */
23 void rpc1(message *msg)
24 {
25         word pix, prot;
26         procdescr *p;
27         message *msg1;
28
29         pix = msg->control.receiver.pix;
30         p = &process[pix];
31         if (p->mark != msg->control.receiver.mark)
32                 senderr(RTEREFTN, &msg->control.sender);
33
34         msg1 = (message *) ballocate(sizeof(message));
35
36         if (msg1 == NULL)
37                 errsignal(RTEMEMOV);
38
39         moveblock((char *) msg, (char *) msg1, (word) sizeof(message));
40         prot = msg->control.par;
41         if (isenabled(pix, prot)) {
42                 p->msgqueue = minsert(p->msgqueue, msg1);
43
44                 if (p->status == ACCEPTING)
45                         activate(pix);
46         }
47         else
48                 p->rpcwait = minsert(p->rpcwait, msg1);
49 }
50
51
52 void rpc2()
53 {
54         if (rpcready(thispix))
55                 rpc3();
56 }
57
58 /**
59  * Actual remote procedure call
60  */
61 void rpc3()
62 {
63         word prot, ah, am;
64         message *msg;
65
66         /* remove first RPC message (enabled) */
67         msg = mfront(thisp->msgqueue);
68
69         /*
70         fprintf(stderr, "rpc(thisp=%d) from: node=%d, pix=%d, mark=%d\n",
71                 thispix,
72                 msg->control.sender.node,
73                 msg->control.sender.pix,
74                 msg->control.sender.mark
75         );*/
76
77         thisp->msgqueue = qremove(thisp->msgqueue);
78         /* disable all procedures */
79         pushmask(thispix);
80         prot = msg->control.par;
81
82         /* open procedure object */
83         slopen(prot, &thisp->procref, &ah, &am);
84
85         {
86                 virtaddr v;
87                 mess2obj(thisp, &(msg->control.sender), &v);
88                 /* set up remote DL */
89                 storevirt(v, am + M[am] + RPCDL);
90         }
91
92         moveparams(thispix, am, msg, PARIN, SAVEPAR);
93
94         /* transfer control to procedure */
95         go(ah, am);
96
97         free(msg);
98 }
99
100 /* After return from RPC */
101 void rpcend(message *msg)
102 {
103         word pix, am;
104         procdescr *p;
105
106         pix = msg->control.receiver.pix;
107
108
109         p = &process[pix];
110         /* template physical address */
111         am = p->M[temporary];
112         moveparams(pix, am, msg, PAROUT, SAVEPAR);
113         /* resume process waiting for RPC */
114         activate(pix);
115 }
116
117
118 static void bitaccess(word pix, word prot, int *bytenr, char *bitmask)
119 {
120         int bitnr;
121
122         bitnr = prot-prototype[process[pix].prot]->maskbase;
123         *bytenr = bitnr / 8;
124         *bitmask = (char)(unsigned char)(1 << (bitnr % 8));
125 }
126
127 /* Enable remote procedure */
128 void enable(word pix, word prot)
129 {
130         mask m;
131         int bytenr;
132         char bitmask;
133
134         m = top(process[pix].rpcmask);
135         bitaccess(pix, prot, &bytenr, &bitmask);
136         m[bytenr] |= bitmask;
137 }
138
139 /**
140  * Disable remote procedure
141  */
142 void disable(word pix, word prot)
143 {
144         mask m;
145         int bytenr;
146         char bitmask;
147
148         m = top(process[pix].rpcmask);
149         bitaccess(pix, prot, &bytenr, &bitmask);
150         m[bytenr] &= ~ bitmask;
151 }
152
153 /**
154  * Check if RPC allowed
155  */
156 static bool isenabled(word pix, word prot)
157 {
158         mask m;
159         int bytenr;
160         char bitmask;
161
162         m = top(process[pix].rpcmask);
163         bitaccess(pix, prot, &bytenr, &bitmask);
164         return m[bytenr] & bitmask;
165 }
166
167 /**
168  * Push empty RPC mask onto stack
169  */
170 void pushmask(word pix)
171 {
172         mask m;
173         int i, size;
174
175         size = prototype[process[pix].prot]->masksize;
176         m = (mask) ballocate(size);
177         if (m == NULL)
178                 errsignal(RTEMEMOV);
179         for (i = 0; i < size; i++) {
180                 /* disable all */
181                 m[i] = '\0';
182         }
183         process[pix].rpcmask = push(process[pix].rpcmask, m);
184 }
185
186 /**
187  * Duplicate RPC mask from stack top
188  */
189 static void dupmask(word pix)
190 {
191         mask m;
192         int size;
193
194         size = prototype[process[pix].prot]->masksize;
195         m = (mask) ballocate(size);
196         if (m == NULL)
197                 errsignal(RTEMEMOV);
198         moveblock(top(process[pix].rpcmask), m, (word) size);
199         process[pix].rpcmask = push(process[pix].rpcmask, m);
200 }
201
202 /**
203  * Pop RPC mask from stack (restore)
204  */
205 void popmask(word pix)
206 {
207         mask m;
208
209         m = top(process[pix].rpcmask);
210         process[pix].rpcmask = pop(process[pix].rpcmask);
211         free((char *) m);
212 }
213
214 /**
215  * Check if any waiting RPC is enabled
216  */
217 void evaluaterpc(word pix)
218 {
219         queue q;
220         message *msg;
221
222         q = process[pix].rpcwait;
223         if (!qempty(q)) {
224                 do {
225                         msg = mfront(q);
226                         if (isenabled(pix, msg->control.par)) {
227                                 process[pix].msgqueue =
228                                         mpush(process[pix].msgqueue, msg);
229                                 process[pix].rpcwait =
230                                         mdelete(process[pix].rpcwait, msg);
231                                 return;
232                         }
233                         q = qrotate(q);
234                 } while (q != process[pix].rpcwait);
235         }
236 }
237
238 /**
239  * Accept remote procedure call
240  */
241 void rpc_accept(word length)
242 {
243         int i;
244
245         dupmask(thispix);
246         for (i = 0;  i < length;  i++)
247                 enable(thispix, virtprot(M[ic++]));
248
249         evaluaterpc(thispix);
250
251         if (!rpcready(thispix))
252                 passivate(ACCEPTING);
253 }
254
255
256 static bool rpcready(word pix)
257 {
258         procdescr *p;
259         message *msg;
260         word prot;
261
262         p = &process[pix];
263         while (!qempty(p->msgqueue)) {
264                 msg = mfront(p->msgqueue);
265                 prot = msg->control.par;
266                 if (isenabled(pix, prot))
267                         return TRUE;
268                 p->msgqueue = qremove(p->msgqueue);
269                 p->rpcwait = minsert(p->rpcwait, msg);
270         }
271         return FALSE;
272 }
273
274 /**
275  * Get actual prototype for virtual
276  */
277 word virtprot(word prot)
278 {
279         bool sign;
280         word virtnr;
281
282         sign = (prot < 0);
283         prot = absolute(prot);
284         virtnr = prototype[ prot ]->virtnumber;
285         if (virtnr != -1)
286                 prot = M[prototype[thisp->prot]->virtlist + virtnr];
287
288         if (sign)
289                 return -prot;
290         else
291                 return prot;
292 }
293
294