devpipe.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. #include "netif.h"
  8. typedef struct Pipe Pipe;
  9. struct Pipe
  10. {
  11. QLock;
  12. Pipe *next;
  13. int ref;
  14. ulong path;
  15. Queue *q[2];
  16. int qref[2];
  17. };
  18. struct
  19. {
  20. Lock;
  21. ulong path;
  22. } pipealloc;
  23. enum
  24. {
  25. Qdir,
  26. Qdata0,
  27. Qdata1,
  28. };
  29. Dirtab pipedir[] =
  30. {
  31. ".", {Qdir,0,QTDIR}, 0, DMDIR|0500,
  32. "data", {Qdata0}, 0, 0600,
  33. "data1", {Qdata1}, 0, 0600,
  34. };
  35. #define NPIPEDIR 3
  36. static void
  37. pipeinit(void)
  38. {
  39. if(conf.pipeqsize == 0){
  40. if(conf.nmach > 1)
  41. conf.pipeqsize = 256*1024;
  42. else
  43. conf.pipeqsize = 32*1024;
  44. }
  45. }
  46. /*
  47. * create a pipe, no streams are created until an open
  48. */
  49. static Chan*
  50. pipeattach(char *spec)
  51. {
  52. Pipe *p;
  53. Chan *c;
  54. c = devattach('|', spec);
  55. p = malloc(sizeof(Pipe));
  56. if(p == 0)
  57. exhausted("memory");
  58. p->ref = 1;
  59. p->q[0] = qopen(conf.pipeqsize, 0, 0, 0);
  60. if(p->q[0] == 0){
  61. free(p);
  62. exhausted("memory");
  63. }
  64. p->q[1] = qopen(conf.pipeqsize, 0, 0, 0);
  65. if(p->q[1] == 0){
  66. free(p->q[0]);
  67. free(p);
  68. exhausted("memory");
  69. }
  70. lock(&pipealloc);
  71. p->path = ++pipealloc.path;
  72. unlock(&pipealloc);
  73. mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
  74. c->aux = p;
  75. c->dev = 0;
  76. return c;
  77. }
  78. static int
  79. pipegen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp)
  80. {
  81. Qid q;
  82. if(i == DEVDOTDOT){
  83. devdir(c, c->qid, "#|", 0, eve, DMDIR|0555, dp);
  84. return 1;
  85. }
  86. i++; /* skip . */
  87. if(tab==0 || i>=ntab)
  88. return -1;
  89. tab += i;
  90. mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE);
  91. devdir(c, q, tab->name, 0, eve, tab->perm, dp);
  92. return 1;
  93. }
  94. static Walkqid*
  95. pipewalk(Chan *c, Chan *nc, char **name, int nname)
  96. {
  97. Walkqid *wq;
  98. Pipe *p;
  99. wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen);
  100. if(wq != nil && wq->clone != nil && wq->clone != c){
  101. p = c->aux;
  102. qlock(p);
  103. p->ref++;
  104. if(c->flag & COPEN){
  105. print("channel open in pipewalk\n");
  106. switch(NETTYPE(c->qid.path)){
  107. case Qdata0:
  108. p->qref[0]++;
  109. break;
  110. case Qdata1:
  111. p->qref[1]++;
  112. break;
  113. }
  114. }
  115. qunlock(p);
  116. }
  117. return wq;
  118. }
  119. static int
  120. pipestat(Chan *c, uchar *db, int n)
  121. {
  122. Dir dir;
  123. switch(NETTYPE(c->qid.path)){
  124. case Qdir:
  125. devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
  126. break;
  127. case Qdata0:
  128. devdir(c, c->qid, "data", 0, eve, 0600, &dir);
  129. break;
  130. case Qdata1:
  131. devdir(c, c->qid, "data1", 0, eve, 0600, &dir);
  132. break;
  133. default:
  134. panic("pipestat");
  135. }
  136. n = convD2M(&dir, db, n);
  137. if(n < BIT16SZ)
  138. error(Eshortstat);
  139. return n;
  140. }
  141. /*
  142. * if the stream doesn't exist, create it
  143. */
  144. static Chan*
  145. pipeopen(Chan *c, int omode)
  146. {
  147. Pipe *p;
  148. if(c->qid.type & QTDIR){
  149. if(omode != OREAD)
  150. error(Ebadarg);
  151. c->mode = omode;
  152. c->flag |= COPEN;
  153. c->offset = 0;
  154. return c;
  155. }
  156. p = c->aux;
  157. qlock(p);
  158. switch(NETTYPE(c->qid.path)){
  159. case Qdata0:
  160. p->qref[0]++;
  161. break;
  162. case Qdata1:
  163. p->qref[1]++;
  164. break;
  165. }
  166. qunlock(p);
  167. c->mode = openmode(omode);
  168. c->flag |= COPEN;
  169. c->offset = 0;
  170. c->iounit = qiomaxatomic;
  171. return c;
  172. }
  173. static void
  174. pipeclose(Chan *c)
  175. {
  176. Pipe *p;
  177. p = c->aux;
  178. qlock(p);
  179. if(c->flag & COPEN){
  180. /*
  181. * closing either side hangs up the stream
  182. */
  183. switch(NETTYPE(c->qid.path)){
  184. case Qdata0:
  185. p->qref[0]--;
  186. if(p->qref[0] == 0){
  187. qhangup(p->q[1], 0);
  188. qclose(p->q[0]);
  189. }
  190. break;
  191. case Qdata1:
  192. p->qref[1]--;
  193. if(p->qref[1] == 0){
  194. qhangup(p->q[0], 0);
  195. qclose(p->q[1]);
  196. }
  197. break;
  198. }
  199. }
  200. /*
  201. * if both sides are closed, they are reusable
  202. */
  203. if(p->qref[0] == 0 && p->qref[1] == 0){
  204. qreopen(p->q[0]);
  205. qreopen(p->q[1]);
  206. }
  207. /*
  208. * free the structure on last close
  209. */
  210. p->ref--;
  211. if(p->ref == 0){
  212. qunlock(p);
  213. free(p->q[0]);
  214. free(p->q[1]);
  215. free(p);
  216. } else
  217. qunlock(p);
  218. }
  219. static long
  220. piperead(Chan *c, void *va, long n, vlong)
  221. {
  222. Pipe *p;
  223. p = c->aux;
  224. switch(NETTYPE(c->qid.path)){
  225. case Qdir:
  226. return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen);
  227. case Qdata0:
  228. return qread(p->q[0], va, n);
  229. case Qdata1:
  230. return qread(p->q[1], va, n);
  231. default:
  232. panic("piperead");
  233. }
  234. return -1; /* not reached */
  235. }
  236. static Block*
  237. pipebread(Chan *c, long n, ulong offset)
  238. {
  239. Pipe *p;
  240. p = c->aux;
  241. switch(NETTYPE(c->qid.path)){
  242. case Qdata0:
  243. return qbread(p->q[0], n);
  244. case Qdata1:
  245. return qbread(p->q[1], n);
  246. }
  247. return devbread(c, n, offset);
  248. }
  249. /*
  250. * a write to a closed pipe causes a note to be sent to
  251. * the process.
  252. */
  253. static long
  254. pipewrite(Chan *c, void *va, long n, vlong)
  255. {
  256. Pipe *p;
  257. if(!islo())
  258. print("pipewrite hi %lux\n", getcallerpc(&c));
  259. if(waserror()) {
  260. /* avoid notes when pipe is a mounted queue */
  261. if((c->flag & CMSG) == 0)
  262. postnote(up, 1, "sys: write on closed pipe", NUser);
  263. nexterror();
  264. }
  265. p = c->aux;
  266. switch(NETTYPE(c->qid.path)){
  267. case Qdata0:
  268. n = qwrite(p->q[1], va, n);
  269. break;
  270. case Qdata1:
  271. n = qwrite(p->q[0], va, n);
  272. break;
  273. default:
  274. panic("pipewrite");
  275. }
  276. poperror();
  277. return n;
  278. }
  279. static long
  280. pipebwrite(Chan *c, Block *bp, ulong)
  281. {
  282. long n;
  283. Pipe *p;
  284. if(waserror()) {
  285. /* avoid notes when pipe is a mounted queue */
  286. if((c->flag & CMSG) == 0)
  287. postnote(up, 1, "sys: write on closed pipe", NUser);
  288. nexterror();
  289. }
  290. p = c->aux;
  291. switch(NETTYPE(c->qid.path)){
  292. case Qdata0:
  293. n = qbwrite(p->q[1], bp);
  294. break;
  295. case Qdata1:
  296. n = qbwrite(p->q[0], bp);
  297. break;
  298. default:
  299. n = 0;
  300. panic("pipebwrite");
  301. }
  302. poperror();
  303. return n;
  304. }
  305. Dev pipedevtab = {
  306. '|',
  307. "pipe",
  308. devreset,
  309. pipeinit,
  310. devshutdown,
  311. pipeattach,
  312. pipewalk,
  313. pipestat,
  314. pipeopen,
  315. devcreate,
  316. pipeclose,
  317. piperead,
  318. pipebread,
  319. pipewrite,
  320. pipebwrite,
  321. devremove,
  322. devwstat,
  323. };