Ccons.c (6722B)
1 #include "stdinc.h" 2 3 #include "9.h" 4 5 enum { 6 Nl = 256, /* max. command line length */ 7 Nq = 8*1024, /* amount of I/O buffered */ 8 }; 9 10 typedef struct Q { 11 QLock lock; 12 Rendez full; 13 Rendez empty; 14 15 char q[Nq]; 16 int n; 17 int r; 18 int w; 19 } Q; 20 21 typedef struct Cons { 22 QLock lock; 23 int ref; 24 int closed; 25 int fd; 26 int srvfd; 27 int ctlfd; 28 Q* iq; /* points to console.iq */ 29 Q* oq; /* points to console.oq */ 30 } Cons; 31 32 char *currfsysname; 33 34 static struct { 35 Q* iq; /* input */ 36 Q* oq; /* output */ 37 char l[Nl]; /* command line assembly */ 38 int nl; /* current line length */ 39 int nopens; 40 41 char* prompt; 42 int np; 43 } console; 44 45 static void 46 consClose(Cons* cons) 47 { 48 qlock(&cons->lock); 49 cons->closed = 1; 50 51 cons->ref--; 52 if(cons->ref > 0){ 53 qlock(&cons->iq->lock); 54 rwakeup(&cons->iq->full); 55 qunlock(&cons->iq->lock); 56 qlock(&cons->oq->lock); 57 rwakeup(&cons->oq->empty); 58 qunlock(&cons->oq->lock); 59 qunlock(&cons->lock); 60 return; 61 } 62 63 if(cons->ctlfd != -1){ 64 close(cons->ctlfd); 65 cons->srvfd = -1; 66 } 67 if(cons->srvfd != -1){ 68 close(cons->srvfd); 69 cons->srvfd = -1; 70 } 71 if(cons->fd != -1){ 72 close(cons->fd); 73 cons->fd = -1; 74 } 75 qunlock(&cons->lock); 76 vtfree(cons); 77 console.nopens--; 78 } 79 80 static void 81 consIProc(void* v) 82 { 83 Q *q; 84 Cons *cons; 85 int n, w; 86 char buf[Nq/4]; 87 88 threadsetname("consI"); 89 90 cons = v; 91 q = cons->iq; 92 for(;;){ 93 /* 94 * Can't tell the difference between zero-length read 95 * and eof, so keep calling read until we get an error. 96 */ 97 if(cons->closed || (n = read(cons->fd, buf, Nq/4)) < 0) 98 break; 99 qlock(&q->lock); 100 while(Nq - q->n < n && !cons->closed) 101 rsleep(&q->full); 102 w = Nq - q->w; 103 if(w < n){ 104 memmove(&q->q[q->w], buf, w); 105 memmove(&q->q[0], buf + w, n - w); 106 } 107 else 108 memmove(&q->q[q->w], buf, n); 109 q->w = (q->w + n) % Nq; 110 q->n += n; 111 rwakeup(&q->empty); 112 qunlock(&q->lock); 113 } 114 consClose(cons); 115 } 116 117 static void 118 consOProc(void* v) 119 { 120 Q *q; 121 Cons *cons; 122 char buf[Nq]; 123 int lastn, n, r; 124 125 threadsetname("consO"); 126 127 cons = v; 128 q = cons->oq; 129 qlock(&q->lock); 130 lastn = 0; 131 for(;;){ 132 while(lastn == q->n && !cons->closed) 133 rsleep(&q->empty); 134 if((n = q->n - lastn) > Nq) 135 n = Nq; 136 if(n > q->w){ 137 r = n - q->w; 138 memmove(buf, &q->q[Nq - r], r); 139 memmove(buf+r, &q->q[0], n - r); 140 } 141 else 142 memmove(buf, &q->q[q->w - n], n); 143 lastn = q->n; 144 qunlock(&q->lock); 145 if(cons->closed || write(cons->fd, buf, n) < 0) 146 break; 147 qlock(&q->lock); 148 rwakeup(&q->empty); 149 } 150 consClose(cons); 151 } 152 153 int 154 consOpen(int fd, int srvfd, int ctlfd) 155 { 156 Cons *cons; 157 158 cons = vtmallocz(sizeof(Cons)); 159 cons->fd = fd; 160 cons->srvfd = srvfd; 161 cons->ctlfd = ctlfd; 162 cons->iq = console.iq; 163 cons->oq = console.oq; 164 console.nopens++; 165 166 qlock(&cons->lock); 167 cons->ref = 2; 168 cons->closed = 0; 169 if(proccreate(consOProc, cons, STACK) < 0){ 170 cons->ref--; 171 qunlock(&cons->lock); 172 consClose(cons); 173 return 0; 174 } 175 qunlock(&cons->lock); 176 177 if(ctlfd >= 0) 178 consIProc(cons); 179 else if(proccreate(consIProc, cons, STACK) < 0){ 180 consClose(cons); 181 return 0; 182 } 183 184 return 1; 185 } 186 187 static int 188 qWrite(Q* q, char* p, int n) 189 { 190 int w; 191 192 qlock(&q->lock); 193 if(n > Nq - q->w){ 194 w = Nq - q->w; 195 memmove(&q->q[q->w], p, w); 196 memmove(&q->q[0], p + w, n - w); 197 q->w = n - w; 198 } 199 else{ 200 memmove(&q->q[q->w], p, n); 201 q->w += n; 202 } 203 q->n += n; 204 rwakeup(&q->empty); 205 qunlock(&q->lock); 206 207 return n; 208 } 209 210 static Q* 211 qAlloc(void) 212 { 213 Q *q; 214 215 q = vtmallocz(sizeof(Q)); 216 q->full.l = &q->lock; 217 q->empty.l = &q->lock; 218 q->n = q->r = q->w = 0; 219 220 return q; 221 } 222 223 static void 224 consProc(void* v) 225 { 226 USED(v); 227 Q *q; 228 int argc, i, n, r; 229 char *argv[20], buf[Nq], *lp, *wbuf; 230 char procname[64]; 231 232 snprint(procname, sizeof procname, "cons %s", currfsysname); 233 threadsetname(procname); 234 235 q = console.iq; 236 qWrite(console.oq, console.prompt, console.np); 237 qlock(&q->lock); 238 for(;;){ 239 while((n = q->n) == 0) 240 rsleep(&q->empty); 241 r = Nq - q->r; 242 if(r < n){ 243 memmove(buf, &q->q[q->r], r); 244 memmove(buf + r, &q->q[0], n - r); 245 } 246 else 247 memmove(buf, &q->q[q->r], n); 248 q->r = (q->r + n) % Nq; 249 q->n -= n; 250 rwakeup(&q->full); 251 qunlock(&q->lock); 252 253 for(i = 0; i < n; i++){ 254 switch(buf[i]){ 255 case '\004': /* ^D */ 256 if(console.nl == 0){ 257 qWrite(console.oq, "\n", 1); 258 break; 259 } 260 /*FALLTHROUGH*/ 261 default: 262 if(console.nl < Nl-1){ 263 qWrite(console.oq, &buf[i], 1); 264 console.l[console.nl++] = buf[i]; 265 } 266 continue; 267 case '\b': 268 if(console.nl != 0){ 269 qWrite(console.oq, &buf[i], 1); 270 console.nl--; 271 } 272 continue; 273 case '\n': 274 qWrite(console.oq, &buf[i], 1); 275 break; 276 case '\025': /* ^U */ 277 qWrite(console.oq, "^U\n", 3); 278 console.nl = 0; 279 break; 280 case '\027': /* ^W */ 281 console.l[console.nl] = '\0'; 282 wbuf = vtmalloc(console.nl+1); 283 memmove(wbuf, console.l, console.nl+1); 284 argc = tokenize(wbuf, argv, nelem(argv)); 285 if(argc > 0) 286 argc--; 287 console.nl = 0; 288 lp = console.l; 289 for(i = 0; i < argc; i++) 290 lp += sprint(lp, "%q ", argv[i]); 291 console.nl = lp - console.l; 292 vtfree(wbuf); 293 qWrite(console.oq, "^W\n", 3); 294 if(console.nl == 0) 295 break; 296 qWrite(console.oq, console.l, console.nl); 297 continue; 298 case '\177': 299 qWrite(console.oq, "\n", 1); 300 console.nl = 0; 301 break; 302 } 303 304 console.l[console.nl] = '\0'; 305 if(console.nl != 0) 306 cliExec(console.l); 307 308 console.nl = 0; 309 qWrite(console.oq, console.prompt, console.np); 310 } 311 312 qlock(&q->lock); 313 } 314 } 315 316 int 317 consWrite(char* buf, int len) 318 { 319 if(console.oq == nil) 320 return write(2, buf, len); 321 if(console.nopens == 0) 322 write(2, buf, len); 323 return qWrite(console.oq, buf, len); 324 } 325 326 int 327 consPrompt(char* prompt) 328 { 329 char buf[ERRMAX]; 330 331 if(prompt == nil) 332 prompt = "prompt"; 333 334 vtfree(console.prompt); 335 console.np = snprint(buf, sizeof(buf), "%s: ", prompt); 336 console.prompt = vtstrdup(buf); 337 338 return console.np; 339 } 340 341 int 342 consTTY(void) 343 { 344 int ctl, fd; 345 char *name, *p; 346 347 name = "/dev/cons"; 348 if((fd = open(name, ORDWR)) < 0){ 349 #ifdef PLAN9PORT 350 name = "/dev/tty"; 351 #else 352 name = "#c/cons"; 353 #endif 354 if((fd = open(name, ORDWR)) < 0){ 355 werrstr("consTTY: open %s: %r", name); 356 return 0; 357 } 358 } 359 360 #ifdef PLAN9PORT 361 USED(p); 362 ctl = 0; 363 #else 364 p = smprint("%sctl", name); 365 if((ctl = open(p, OWRITE)) < 0){ 366 close(fd); 367 werrstr("consTTY: open %s: %r", p); 368 free(p); 369 return 0; 370 } 371 if(write(ctl, "rawon", 5) < 0){ 372 close(ctl); 373 close(fd); 374 werrstr("consTTY: write %s: %r", p); 375 free(p); 376 return 0; 377 } 378 free(p); 379 #endif 380 381 if(consOpen(fd, fd, ctl) == 0){ 382 close(ctl); 383 close(fd); 384 return 0; 385 } 386 387 return 1; 388 } 389 390 int 391 consInit(void) 392 { 393 console.iq = qAlloc(); 394 console.oq = qAlloc(); 395 console.nl = 0; 396 397 consPrompt(nil); 398 399 if(proccreate(consProc, nil, STACK) < 0){ 400 sysfatal("can't start console proc"); 401 return 0; 402 } 403 404 return 1; 405 }