Blob


1 #include "stdinc.h"
3 #include "9.h"
5 enum {
6 Nl = 256, /* max. command line length */
7 Nq = 8*1024, /* amount of I/O buffered */
8 };
10 typedef struct Q {
11 QLock lock;
12 Rendez full;
13 Rendez empty;
15 char q[Nq];
16 int n;
17 int r;
18 int w;
19 } Q;
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;
32 char *currfsysname;
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;
41 char* prompt;
42 int np;
43 } console;
45 static void
46 consClose(Cons* cons)
47 {
48 qlock(&cons->lock);
49 cons->closed = 1;
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 }
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 }
80 static void
81 consIProc(void* v)
82 {
83 Q *q;
84 Cons *cons;
85 int n, w;
86 char buf[Nq/4];
88 threadsetname("consI");
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);
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);
114 consClose(cons);
117 static void
118 consOProc(void* v)
120 Q *q;
121 Cons *cons;
122 char buf[Nq];
123 int lastn, n, r;
125 threadsetname("consO");
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);
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);
150 consClose(cons);
153 int
154 consOpen(int fd, int srvfd, int ctlfd)
156 Cons *cons;
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++;
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;
175 qunlock(&cons->lock);
177 if(ctlfd >= 0)
178 consIProc(cons);
179 else if(proccreate(consIProc, cons, STACK) < 0){
180 consClose(cons);
181 return 0;
184 return 1;
187 static int
188 qWrite(Q* q, char* p, int n)
190 int w;
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;
199 else{
200 memmove(&q->q[q->w], p, n);
201 q->w += n;
203 q->n += n;
204 rwakeup(&q->empty);
205 qunlock(&q->lock);
207 return n;
210 static Q*
211 qAlloc(void)
213 Q *q;
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;
220 return q;
223 static void
224 consProc(void* v)
226 USED(v);
227 Q *q;
228 int argc, i, n, r;
229 char *argv[20], buf[Nq], *lp, *wbuf;
230 char procname[64];
232 snprint(procname, sizeof procname, "cons %s", currfsysname);
233 threadsetname(procname);
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);
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);
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;
260 /*FALLTHROUGH*/
261 default:
262 if(console.nl < Nl-1){
263 qWrite(console.oq, &buf[i], 1);
264 console.l[console.nl++] = buf[i];
266 continue;
267 case '\b':
268 if(console.nl != 0){
269 qWrite(console.oq, &buf[i], 1);
270 console.nl--;
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;
304 console.l[console.nl] = '\0';
305 if(console.nl != 0)
306 cliExec(console.l);
308 console.nl = 0;
309 qWrite(console.oq, console.prompt, console.np);
312 qlock(&q->lock);
316 int
317 consWrite(char* buf, int len)
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);
326 int
327 consPrompt(char* prompt)
329 char buf[ERRMAX];
331 if(prompt == nil)
332 prompt = "prompt";
334 vtfree(console.prompt);
335 console.np = snprint(buf, sizeof(buf), "%s: ", prompt);
336 console.prompt = vtstrdup(buf);
338 return console.np;
341 int
342 consTTY(void)
344 int ctl, fd;
345 char *name, *p;
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;
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;
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;
378 free(p);
379 #endif
381 if(consOpen(fd, fd, ctl) == 0){
382 close(ctl);
383 close(fd);
384 return 0;
387 return 1;
390 int
391 consInit(void)
393 console.iq = qAlloc();
394 console.oq = qAlloc();
395 console.nl = 0;
397 consPrompt(nil);
399 if(proccreate(consProc, nil, STACK) < 0){
400 sysfatal("can't start console proc");
401 return 0;
404 return 1;