Ccons.c 7.0 KB

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