13e12c5d1SDavid du Colombier #include "u.h" 23e12c5d1SDavid du Colombier #include "../port/lib.h" 33e12c5d1SDavid du Colombier #include "mem.h" 43e12c5d1SDavid du Colombier #include "dat.h" 53e12c5d1SDavid du Colombier #include "fns.h" 63e12c5d1SDavid du Colombier #include "../port/error.h" 73e12c5d1SDavid du Colombier 83e12c5d1SDavid du Colombier #include "devtab.h" 93e12c5d1SDavid du Colombier 103e12c5d1SDavid du Colombier typedef struct Pipe Pipe; 113e12c5d1SDavid du Colombier struct Pipe 123e12c5d1SDavid du Colombier { 133e12c5d1SDavid du Colombier Ref; 143e12c5d1SDavid du Colombier QLock; 153e12c5d1SDavid du Colombier Pipe *next; 163e12c5d1SDavid du Colombier ulong path; 173e12c5d1SDavid du Colombier }; 183e12c5d1SDavid du Colombier 193e12c5d1SDavid du Colombier struct 203e12c5d1SDavid du Colombier { 213e12c5d1SDavid du Colombier Lock; 223e12c5d1SDavid du Colombier Pipe *pipe; 233e12c5d1SDavid du Colombier ulong path; 243e12c5d1SDavid du Colombier } pipealloc; 253e12c5d1SDavid du Colombier 263e12c5d1SDavid du Colombier static Pipe *getpipe(ulong); 273e12c5d1SDavid du Colombier static void pipeiput(Queue*, Block*); 283e12c5d1SDavid du Colombier static void pipeoput(Queue*, Block*); 293e12c5d1SDavid du Colombier static void pipestclose(Queue *); 303e12c5d1SDavid du Colombier 313e12c5d1SDavid du Colombier Qinfo pipeinfo = 323e12c5d1SDavid du Colombier { 333e12c5d1SDavid du Colombier pipeiput, 343e12c5d1SDavid du Colombier pipeoput, 353e12c5d1SDavid du Colombier 0, 363e12c5d1SDavid du Colombier pipestclose, 373e12c5d1SDavid du Colombier "pipe" 383e12c5d1SDavid du Colombier }; 393e12c5d1SDavid du Colombier 403e12c5d1SDavid du Colombier Dirtab pipedir[] = 413e12c5d1SDavid du Colombier { 423e12c5d1SDavid du Colombier "data", {Sdataqid}, 0, 0600, 433e12c5d1SDavid du Colombier "ctl", {Sctlqid}, 0, 0600, 443e12c5d1SDavid du Colombier "data1", {Sdataqid}, 0, 0600, 453e12c5d1SDavid du Colombier "ctl1", {Sctlqid}, 0, 0600, 463e12c5d1SDavid du Colombier }; 473e12c5d1SDavid du Colombier #define NPIPEDIR 4 483e12c5d1SDavid du Colombier 493e12c5d1SDavid du Colombier void 503e12c5d1SDavid du Colombier pipeinit(void) 513e12c5d1SDavid du Colombier { 523e12c5d1SDavid du Colombier } 533e12c5d1SDavid du Colombier 543e12c5d1SDavid du Colombier void 553e12c5d1SDavid du Colombier pipereset(void) 563e12c5d1SDavid du Colombier { 573e12c5d1SDavid du Colombier } 583e12c5d1SDavid du Colombier 593e12c5d1SDavid du Colombier /* 603e12c5d1SDavid du Colombier * create a pipe, no streams are created until an open 613e12c5d1SDavid du Colombier */ 623e12c5d1SDavid du Colombier Chan* 633e12c5d1SDavid du Colombier pipeattach(char *spec) 643e12c5d1SDavid du Colombier { 653e12c5d1SDavid du Colombier Pipe *p; 663e12c5d1SDavid du Colombier Chan *c; 673e12c5d1SDavid du Colombier 683e12c5d1SDavid du Colombier c = devattach('|', spec); 693e12c5d1SDavid du Colombier p = smalloc(sizeof(Pipe)); 703e12c5d1SDavid du Colombier p->ref = 1; 713e12c5d1SDavid du Colombier 723e12c5d1SDavid du Colombier lock(&pipealloc); 733e12c5d1SDavid du Colombier p->path = ++pipealloc.path; 743e12c5d1SDavid du Colombier p->next = pipealloc.pipe; 753e12c5d1SDavid du Colombier pipealloc.pipe = p; 763e12c5d1SDavid du Colombier unlock(&pipealloc); 773e12c5d1SDavid du Colombier 783e12c5d1SDavid du Colombier c->qid = (Qid){CHDIR|STREAMQID(2*p->path, 0), 0}; 793e12c5d1SDavid du Colombier c->dev = 0; 803e12c5d1SDavid du Colombier return c; 813e12c5d1SDavid du Colombier } 823e12c5d1SDavid du Colombier 833e12c5d1SDavid du Colombier Chan* 843e12c5d1SDavid du Colombier pipeclone(Chan *c, Chan *nc) 853e12c5d1SDavid du Colombier { 863e12c5d1SDavid du Colombier Pipe *p; 873e12c5d1SDavid du Colombier 883e12c5d1SDavid du Colombier p = getpipe(STREAMID(c->qid.path)/2); 893e12c5d1SDavid du Colombier nc = devclone(c, nc); 903e12c5d1SDavid du Colombier if(incref(p) <= 1) 913e12c5d1SDavid du Colombier panic("pipeclone"); 923e12c5d1SDavid du Colombier return nc; 933e12c5d1SDavid du Colombier } 943e12c5d1SDavid du Colombier 953e12c5d1SDavid du Colombier int 963e12c5d1SDavid du Colombier pipegen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) 973e12c5d1SDavid du Colombier { 983e12c5d1SDavid du Colombier int id; 993e12c5d1SDavid du Colombier 1003e12c5d1SDavid du Colombier id = STREAMID(c->qid.path); 1013e12c5d1SDavid du Colombier if(i > 1) 1023e12c5d1SDavid du Colombier id++; 1033e12c5d1SDavid du Colombier if(tab==0 || i>=ntab) 1043e12c5d1SDavid du Colombier return -1; 1053e12c5d1SDavid du Colombier tab += i; 1063e12c5d1SDavid du Colombier devdir(c, (Qid){STREAMQID(id, tab->qid.path),0}, tab->name, tab->length, eve, tab->perm, dp); 1073e12c5d1SDavid du Colombier return 1; 1083e12c5d1SDavid du Colombier } 1093e12c5d1SDavid du Colombier 1103e12c5d1SDavid du Colombier 1113e12c5d1SDavid du Colombier int 1123e12c5d1SDavid du Colombier pipewalk(Chan *c, char *name) 1133e12c5d1SDavid du Colombier { 1143e12c5d1SDavid du Colombier return devwalk(c, name, pipedir, NPIPEDIR, pipegen); 1153e12c5d1SDavid du Colombier } 1163e12c5d1SDavid du Colombier 1173e12c5d1SDavid du Colombier void 1183e12c5d1SDavid du Colombier pipestat(Chan *c, char *db) 1193e12c5d1SDavid du Colombier { 1203e12c5d1SDavid du Colombier streamstat(c, db, "pipe", 0666); 1213e12c5d1SDavid du Colombier } 1223e12c5d1SDavid du Colombier 1233e12c5d1SDavid du Colombier /* 1243e12c5d1SDavid du Colombier * if the stream doesn't exist, create it 1253e12c5d1SDavid du Colombier */ 1263e12c5d1SDavid du Colombier Chan * 1273e12c5d1SDavid du Colombier pipeopen(Chan *c, int omode) 1283e12c5d1SDavid du Colombier { 1293e12c5d1SDavid du Colombier Pipe *p; 1303e12c5d1SDavid du Colombier int other; 1313e12c5d1SDavid du Colombier Stream *local, *remote; 1323e12c5d1SDavid du Colombier 1333e12c5d1SDavid du Colombier if(c->qid.path & CHDIR){ 1343e12c5d1SDavid du Colombier if(omode != OREAD) 1353e12c5d1SDavid du Colombier error(Ebadarg); 1363e12c5d1SDavid du Colombier c->mode = omode; 1373e12c5d1SDavid du Colombier c->flag |= COPEN; 1383e12c5d1SDavid du Colombier c->offset = 0; 1393e12c5d1SDavid du Colombier return c; 1403e12c5d1SDavid du Colombier } 1413e12c5d1SDavid du Colombier 1423e12c5d1SDavid du Colombier p = getpipe(STREAMID(c->qid.path)/2); 1433e12c5d1SDavid du Colombier if(waserror()){ 1443e12c5d1SDavid du Colombier qunlock(p); 1453e12c5d1SDavid du Colombier nexterror(); 1463e12c5d1SDavid du Colombier } 1473e12c5d1SDavid du Colombier qlock(p); 1483e12c5d1SDavid du Colombier streamopen(c, &pipeinfo); 1493e12c5d1SDavid du Colombier local = c->stream; 1503e12c5d1SDavid du Colombier if(local->devq->ptr == 0){ 1513e12c5d1SDavid du Colombier /* 1523e12c5d1SDavid du Colombier * first open, create the other end also 1533e12c5d1SDavid du Colombier */ 1543e12c5d1SDavid du Colombier other = STREAMID(c->qid.path)^1; 1553e12c5d1SDavid du Colombier remote = streamnew(c->type, c->dev, other, &pipeinfo,1); 1563e12c5d1SDavid du Colombier 1573e12c5d1SDavid du Colombier /* 1583e12c5d1SDavid du Colombier * connect the device ends of both streams 1593e12c5d1SDavid du Colombier */ 1603e12c5d1SDavid du Colombier local->devq->ptr = remote; 1613e12c5d1SDavid du Colombier remote->devq->ptr = local; 1623e12c5d1SDavid du Colombier local->devq->other->next = remote->devq; 1633e12c5d1SDavid du Colombier remote->devq->other->next = local->devq; 1643e12c5d1SDavid du Colombier } else if(local->opens == 1){ 1653e12c5d1SDavid du Colombier /* 1663e12c5d1SDavid du Colombier * keep other side around till last close of this side 1673e12c5d1SDavid du Colombier */ 1683e12c5d1SDavid du Colombier streamenter(local->devq->ptr); 1693e12c5d1SDavid du Colombier } 1703e12c5d1SDavid du Colombier qunlock(p); 1713e12c5d1SDavid du Colombier poperror(); 1723e12c5d1SDavid du Colombier 173*219b2ee8SDavid du Colombier c->mode = openmode(omode); 1743e12c5d1SDavid du Colombier c->flag |= COPEN; 1753e12c5d1SDavid du Colombier c->offset = 0; 1763e12c5d1SDavid du Colombier return c; 1773e12c5d1SDavid du Colombier } 1783e12c5d1SDavid du Colombier 1793e12c5d1SDavid du Colombier void 1803e12c5d1SDavid du Colombier pipecreate(Chan *c, char *name, int omode, ulong perm) 1813e12c5d1SDavid du Colombier { 1823e12c5d1SDavid du Colombier USED(c, name, omode, perm); 1833e12c5d1SDavid du Colombier error(Egreg); 1843e12c5d1SDavid du Colombier } 1853e12c5d1SDavid du Colombier 1863e12c5d1SDavid du Colombier void 1873e12c5d1SDavid du Colombier piperemove(Chan *c) 1883e12c5d1SDavid du Colombier { 1893e12c5d1SDavid du Colombier USED(c); 1903e12c5d1SDavid du Colombier error(Egreg); 1913e12c5d1SDavid du Colombier } 1923e12c5d1SDavid du Colombier 1933e12c5d1SDavid du Colombier void 1943e12c5d1SDavid du Colombier pipewstat(Chan *c, char *db) 1953e12c5d1SDavid du Colombier { 1963e12c5d1SDavid du Colombier USED(c, db); 1973e12c5d1SDavid du Colombier error(Eperm); 1983e12c5d1SDavid du Colombier } 1993e12c5d1SDavid du Colombier 2003e12c5d1SDavid du Colombier void 2013e12c5d1SDavid du Colombier pipeclose(Chan *c) 2023e12c5d1SDavid du Colombier { 2033e12c5d1SDavid du Colombier Pipe *p, *f, **l; 2043e12c5d1SDavid du Colombier Stream *remote; 2053e12c5d1SDavid du Colombier 2063e12c5d1SDavid du Colombier p = getpipe(STREAMID(c->qid.path)/2); 2073e12c5d1SDavid du Colombier 2083e12c5d1SDavid du Colombier /* 2093e12c5d1SDavid du Colombier * take care of local and remote streams 2103e12c5d1SDavid du Colombier */ 2113e12c5d1SDavid du Colombier if(c->stream){ 2123e12c5d1SDavid du Colombier qlock(p); 2133e12c5d1SDavid du Colombier remote = c->stream->devq->ptr; 2143e12c5d1SDavid du Colombier if(streamclose(c) == 0){ 2153e12c5d1SDavid du Colombier if(remote) 2163e12c5d1SDavid du Colombier streamexit(remote); 2173e12c5d1SDavid du Colombier } 2183e12c5d1SDavid du Colombier qunlock(p); 2193e12c5d1SDavid du Colombier } 2203e12c5d1SDavid du Colombier 2213e12c5d1SDavid du Colombier /* 2223e12c5d1SDavid du Colombier * free the structure 2233e12c5d1SDavid du Colombier */ 2243e12c5d1SDavid du Colombier if(decref(p) == 0){ 2253e12c5d1SDavid du Colombier lock(&pipealloc); 2263e12c5d1SDavid du Colombier l = &pipealloc.pipe; 2273e12c5d1SDavid du Colombier for(f = *l; f; f = f->next) { 2283e12c5d1SDavid du Colombier if(f == p) { 2293e12c5d1SDavid du Colombier *l = p->next; 2303e12c5d1SDavid du Colombier break; 2313e12c5d1SDavid du Colombier } 2323e12c5d1SDavid du Colombier l = &f->next; 2333e12c5d1SDavid du Colombier } 2343e12c5d1SDavid du Colombier unlock(&pipealloc); 2353e12c5d1SDavid du Colombier free(p); 2363e12c5d1SDavid du Colombier } 2373e12c5d1SDavid du Colombier } 2383e12c5d1SDavid du Colombier 2393e12c5d1SDavid du Colombier long 2403e12c5d1SDavid du Colombier piperead(Chan *c, void *va, long n, ulong offset) 2413e12c5d1SDavid du Colombier { 2423e12c5d1SDavid du Colombier USED(offset); 2433e12c5d1SDavid du Colombier if(c->qid.path & CHDIR) 2443e12c5d1SDavid du Colombier return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen); 2453e12c5d1SDavid du Colombier 2463e12c5d1SDavid du Colombier return streamread(c, va, n); 2473e12c5d1SDavid du Colombier } 2483e12c5d1SDavid du Colombier 2493e12c5d1SDavid du Colombier /* 2503e12c5d1SDavid du Colombier * a write to a closed pipe causes a note to be sent to 2513e12c5d1SDavid du Colombier * the process. 2523e12c5d1SDavid du Colombier */ 2533e12c5d1SDavid du Colombier long 2543e12c5d1SDavid du Colombier pipewrite(Chan *c, void *va, long n, ulong offset) 2553e12c5d1SDavid du Colombier { 2563e12c5d1SDavid du Colombier USED(offset); 2573e12c5d1SDavid du Colombier 2583e12c5d1SDavid du Colombier /* avoid notes when pipe is a mounted stream */ 2593e12c5d1SDavid du Colombier if(c->flag & CMSG) 2603e12c5d1SDavid du Colombier return streamwrite(c, va, n, 0); 2613e12c5d1SDavid du Colombier 2623e12c5d1SDavid du Colombier if(waserror()) { 2633e12c5d1SDavid du Colombier postnote(u->p, 1, "sys: write on closed pipe", NUser); 264*219b2ee8SDavid du Colombier error(Ehungup); 2653e12c5d1SDavid du Colombier } 2663e12c5d1SDavid du Colombier n = streamwrite(c, va, n, 0); 2673e12c5d1SDavid du Colombier poperror(); 2683e12c5d1SDavid du Colombier return n; 2693e12c5d1SDavid du Colombier } 2703e12c5d1SDavid du Colombier 2713e12c5d1SDavid du Colombier /* 2723e12c5d1SDavid du Colombier * send a block upstream to the process. 2733e12c5d1SDavid du Colombier * sleep until there's room upstream. 2743e12c5d1SDavid du Colombier */ 2753e12c5d1SDavid du Colombier static void 2763e12c5d1SDavid du Colombier pipeiput(Queue *q, Block *bp) 2773e12c5d1SDavid du Colombier { 2783e12c5d1SDavid du Colombier FLOWCTL(q, bp); 2793e12c5d1SDavid du Colombier } 2803e12c5d1SDavid du Colombier 2813e12c5d1SDavid du Colombier /* 2823e12c5d1SDavid du Colombier * send the block to the other side 2833e12c5d1SDavid du Colombier */ 2843e12c5d1SDavid du Colombier static void 2853e12c5d1SDavid du Colombier pipeoput(Queue *q, Block *bp) 2863e12c5d1SDavid du Colombier { 2873e12c5d1SDavid du Colombier PUTNEXT(q, bp); 2883e12c5d1SDavid du Colombier } 2893e12c5d1SDavid du Colombier 2903e12c5d1SDavid du Colombier /* 2913e12c5d1SDavid du Colombier * send a hangup and disconnect the streams 2923e12c5d1SDavid du Colombier */ 2933e12c5d1SDavid du Colombier static void 2943e12c5d1SDavid du Colombier pipestclose(Queue *q) 2953e12c5d1SDavid du Colombier { 2963e12c5d1SDavid du Colombier Block *bp; 2973e12c5d1SDavid du Colombier 2983e12c5d1SDavid du Colombier /* 2993e12c5d1SDavid du Colombier * point to the bit-bucket and let any in-progress 3003e12c5d1SDavid du Colombier * write's finish. 3013e12c5d1SDavid du Colombier */ 3023e12c5d1SDavid du Colombier q->put = nullput; 3033e12c5d1SDavid du Colombier wakeup(&q->r); 3043e12c5d1SDavid du Colombier 3053e12c5d1SDavid du Colombier /* 3063e12c5d1SDavid du Colombier * send a hangup 3073e12c5d1SDavid du Colombier */ 3083e12c5d1SDavid du Colombier q = q->other; 3093e12c5d1SDavid du Colombier if(q->next == 0) 3103e12c5d1SDavid du Colombier return; 3113e12c5d1SDavid du Colombier bp = allocb(0); 3123e12c5d1SDavid du Colombier bp->type = M_HANGUP; 3133e12c5d1SDavid du Colombier PUTNEXT(q, bp); 3143e12c5d1SDavid du Colombier } 3153e12c5d1SDavid du Colombier 3163e12c5d1SDavid du Colombier Pipe* 3173e12c5d1SDavid du Colombier getpipe(ulong path) 3183e12c5d1SDavid du Colombier { 3193e12c5d1SDavid du Colombier Pipe *p; 3203e12c5d1SDavid du Colombier 3213e12c5d1SDavid du Colombier lock(&pipealloc); 3223e12c5d1SDavid du Colombier for(p = pipealloc.pipe; p; p = p->next) { 3233e12c5d1SDavid du Colombier if(path == p->path) { 3243e12c5d1SDavid du Colombier unlock(&pipealloc); 3253e12c5d1SDavid du Colombier return p; 3263e12c5d1SDavid du Colombier } 3273e12c5d1SDavid du Colombier } 3283e12c5d1SDavid du Colombier unlock(&pipealloc); 3293e12c5d1SDavid du Colombier panic("getpipe"); 3303e12c5d1SDavid du Colombier return 0; /* not reached */ 3313e12c5d1SDavid du Colombier } 332