1 #include "lib9.h" 2 #include "isa.h" 3 #include "interp.h" 4 #include "raise.h" 5 6 #define OP(fn) void fn(void) 7 #define W(p) *((WORD*)(p)) 8 9 #define CANGET(c) ((c)->size > 0) 10 #define CANPUT(c) ((c)->buf != H && (c)->size < (c)->buf->len) 11 12 extern OP(isend); 13 extern OP(irecv); 14 15 /* 16 * Count the number of ready channels in an array of channels 17 * Set each channel's alt pointer to the owning prog 18 */ 19 static int 20 altmark(Channel *c, Prog *p) 21 { 22 int nrdy; 23 Array *a; 24 Channel **ca, **ec; 25 26 nrdy = 0; 27 a = (Array*)c; 28 ca = (Channel**)a->data; 29 ec = ca + a->len; 30 while(ca < ec) { 31 c = *ca; 32 if(c != H) { 33 if(c->send->prog || CANGET(c)) 34 nrdy++; 35 cqadd(&c->recv, p); 36 } 37 ca++; 38 } 39 40 return nrdy; 41 } 42 43 /* 44 * Remove alt references to an array of channels 45 */ 46 static void 47 altunmark(Channel *c, WORD *ptr, Prog *p, int sr, Channel **sel, int dn) 48 { 49 int n; 50 Array *a; 51 Channel **ca, **ec; 52 53 n = 0; 54 a = (Array*)c; 55 ca = (Channel**)a->data; 56 ec = ca + a->len; 57 while(ca < ec) { 58 c = *ca; 59 if(c != H && c->recv->prog) 60 cqdelp(&c->recv, p); 61 if(sr == 1 && *sel == c) { 62 W(p->R.d) = dn; 63 p->ptr = ptr + 1; 64 ptr[0] = n; 65 *sel = nil; 66 } 67 ca++; 68 n++; 69 } 70 } 71 72 /* 73 * ALT Pass 1 - Count the number of ready channels and mark 74 * each channel as ALT by this prog 75 */ 76 static int 77 altrdy(Alt *a, Prog *p) 78 { 79 char *e; 80 Type *t; 81 int nrdy; 82 Channel *c; 83 Altc *ac, *eac; 84 85 e = nil; 86 nrdy = 0; 87 88 ac = a->ac + a->nsend; 89 eac = ac + a->nrecv; 90 while(ac < eac) { 91 c = ac->c; 92 ac++; 93 if(c == H) { 94 e = exNilref; 95 continue; 96 } 97 t = D2H(c)->t; 98 if(t == &Tarray) 99 nrdy += altmark(c, p); 100 else { 101 if(c->send->prog || CANGET(c)) 102 nrdy++; 103 cqadd(&c->recv, p); 104 } 105 } 106 107 ac = a->ac; 108 eac = ac + a->nsend; 109 while(ac < eac) { 110 c = ac->c; 111 ac++; 112 if(c == H) { 113 e = exNilref; 114 continue; 115 } 116 if(c->recv->prog || CANPUT(c)) { 117 if(c->recv->prog == p) { 118 e = exAlt; 119 continue; 120 } 121 nrdy++; 122 } 123 cqadd(&c->send, p); 124 } 125 126 if(e != nil) { 127 altdone(a, p, nil, -1); 128 error(e); 129 } 130 131 return nrdy; 132 } 133 134 /* 135 * ALT Pass 3 - Pull out of an ALT cancelling the channel pointers in each item 136 */ 137 void 138 altdone(Alt *a, Prog *p, Channel *sel, int sr) 139 { 140 int n; 141 Type *t; 142 Channel *c; 143 Altc *ac, *eac; 144 145 n = 0; 146 ac = a->ac; 147 eac = a->ac + a->nsend; 148 while(ac < eac) { 149 c = ac->c; 150 if(c != H) { 151 if(c->send->prog) 152 cqdelp(&c->send, p); 153 if(sr == 0 && c == sel) { 154 p->ptr = ac->ptr; 155 W(p->R.d) = n; 156 sel = nil; 157 } 158 } 159 ac++; 160 n++; 161 } 162 163 eac = a->ac + a->nsend + a->nrecv; 164 while(ac < eac) { 165 c = ac->c; 166 if(c != H) { 167 t = D2H(c)->t; 168 if(t == &Tarray) 169 altunmark(c, ac->ptr, p, sr, &sel, n); 170 else { 171 if(c->recv->prog) 172 cqdelp(&c->recv, p); 173 if(sr == 1 && c == sel) { 174 p->ptr = ac->ptr; 175 W(p->R.d) = n; 176 sel = nil; 177 } 178 } 179 } 180 ac++; 181 n++; 182 } 183 } 184 185 /* 186 * ALT Pass 2 - Perform the communication on the chosen channel 187 */ 188 static void 189 altcomm(Alt *a, int which) 190 { 191 Type *t; 192 Array *r; 193 int n, an; 194 WORD *ptr; 195 Altc *ac, *eac; 196 Channel *c, **ca, **ec; 197 198 n = 0; 199 ac = a->ac; 200 eac = ac + a->nsend; 201 while(ac < eac) { 202 c = ac->c; 203 if((c->recv->prog != nil || CANPUT(c)) && which-- == 0) { 204 W(R.d) = n; 205 R.s = ac->ptr; 206 R.d = &c; 207 isend(); 208 return; 209 } 210 ac++; 211 n++; 212 } 213 214 eac = eac + a->nrecv; 215 while(ac < eac) { 216 c = ac->c; 217 t = D2H(c)->t; 218 if(t == &Tarray) { 219 an = 0; 220 r = (Array*)c; 221 ca = (Channel**)r->data; 222 ec = ca + r->len; 223 while(ca < ec) { 224 c = *ca; 225 if(c != H && (c->send->prog != nil || CANGET(c)) && which-- == 0) { 226 W(R.d) = n; 227 R.s = &c; 228 ptr = ac->ptr; 229 R.d = ptr + 1; 230 ptr[0] = an; 231 irecv(); 232 return; 233 } 234 ca++; 235 an++; 236 } 237 } 238 else 239 if((c->send->prog != nil || CANGET(c)) && which-- == 0) { 240 W(R.d) = n; 241 R.s = &c; 242 R.d = ac->ptr; 243 irecv(); 244 return; 245 } 246 ac++; 247 n++; 248 } 249 return; 250 } 251 252 void 253 altgone(Prog *p) 254 { 255 Alt *a; 256 257 if (p->state == Palt) { 258 a = p->R.s; 259 altdone(a, p, nil, -1); 260 p->kill = "alt channel hungup"; 261 addrun(p); 262 } 263 } 264 265 void 266 xecalt(int block) 267 { 268 Alt *a; 269 Prog *p; 270 int nrdy; 271 static ulong xrand = 0x20342; 272 273 p = currun(); 274 275 a = R.s; 276 nrdy = altrdy(a, p); 277 if(nrdy == 0) { 278 if(block) { 279 delrun(Palt); 280 p->R.s = R.s; 281 p->R.d = R.d; 282 R.IC = 1; 283 R.t = 1; 284 return; 285 } 286 W(R.d) = a->nsend + a->nrecv; 287 altdone(a, p, nil, -1); 288 return; 289 } 290 291 xrand = xrand*1103515245 + 12345; 292 altcomm(a, (xrand>>8)%nrdy); 293 altdone(a, p, nil, -1); 294 } 295