plan9fox/sys/src/9/port/devpipe.c
cinap_lenrek 56ffc907ac kernel: stop the practice of passing DMDIR to devir() perm argument
devdir internally replicates the qid in ther perm stat field
already and the practice of explicitely passing just causing
confusion when done inconsistently.
2018-06-03 23:33:35 +02:00

428 lines
6.3 KiB
C

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "netif.h"
typedef struct Pipe Pipe;
struct Pipe
{
QLock;
Pipe *next;
int ref;
ulong path;
long perm;
Queue *q[2];
int qref[2];
};
struct
{
Lock;
ulong path;
} pipealloc;
enum
{
Qdir,
Qdata0,
Qdata1,
};
Dirtab pipedir[] =
{
".", {Qdir,0,QTDIR}, 0, DMDIR|0500,
"data", {Qdata0}, 0, 0600,
"data1", {Qdata1}, 0, 0600,
};
#define NPIPEDIR 3
static void
pipeinit(void)
{
if(conf.pipeqsize == 0){
if(conf.nmach > 1)
conf.pipeqsize = 256*1024;
else
conf.pipeqsize = 32*1024;
}
}
/*
* create a pipe, no streams are created until an open
*/
static Chan*
pipeattach(char *spec)
{
Pipe *p;
Chan *c;
c = devattach('|', spec);
if(waserror()){
chanfree(c);
nexterror();
}
p = malloc(sizeof(Pipe));
if(p == 0)
exhausted("memory");
p->ref = 1;
p->q[0] = qopen(conf.pipeqsize, 0, 0, 0);
if(p->q[0] == 0){
free(p);
exhausted("memory");
}
p->q[1] = qopen(conf.pipeqsize, 0, 0, 0);
if(p->q[1] == 0){
qfree(p->q[0]);
free(p);
exhausted("memory");
}
poperror();
lock(&pipealloc);
p->path = ++pipealloc.path;
unlock(&pipealloc);
p->perm = pipedir[Qdata0].perm;
mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
c->aux = p;
c->dev = 0;
return c;
}
static int
pipegen(Chan *c, char*, Dirtab *tab, int ntab, int i, Dir *dp)
{
Qid q;
int len;
Pipe *p;
if(i == DEVDOTDOT){
devdir(c, c->qid, "#|", 0, eve, 0555, dp);
return 1;
}
i++; /* skip . */
if(tab==0 || i>=ntab)
return -1;
tab += i;
p = c->aux;
switch((ulong)tab->qid.path){
case Qdata0:
len = qlen(p->q[0]);
break;
case Qdata1:
len = qlen(p->q[1]);
break;
default:
len = tab->length;
break;
}
mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE);
devdir(c, q, tab->name, len, eve, p->perm, dp);
return 1;
}
static Walkqid*
pipewalk(Chan *c, Chan *nc, char **name, int nname)
{
Walkqid *wq;
Pipe *p;
wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen);
if(wq != nil && wq->clone != nil && wq->clone != c){
p = c->aux;
qlock(p);
p->ref++;
if(c->flag & COPEN){
print("channel open in pipewalk\n");
switch(NETTYPE(c->qid.path)){
case Qdata0:
p->qref[0]++;
break;
case Qdata1:
p->qref[1]++;
break;
}
}
qunlock(p);
}
return wq;
}
static int
pipestat(Chan *c, uchar *db, int n)
{
Pipe *p;
Dir dir;
p = c->aux;
switch(NETTYPE(c->qid.path)){
case Qdir:
devdir(c, c->qid, ".", 0, eve, 0555, &dir);
break;
case Qdata0:
devdir(c, c->qid, "data", qlen(p->q[0]), eve, p->perm, &dir);
break;
case Qdata1:
devdir(c, c->qid, "data1", qlen(p->q[1]), eve, p->perm, &dir);
break;
default:
panic("pipestat");
}
n = convD2M(&dir, db, n);
if(n < BIT16SZ)
error(Eshortstat);
return n;
}
static int
pipewstat(Chan* c, uchar* db, int n)
{
int m;
Dir *dir;
Pipe *p;
p = c->aux;
if(strcmp(up->user, eve) != 0)
error(Eperm);
if(NETTYPE(c->qid.path) == Qdir)
error(Eisdir);
dir = smalloc(sizeof(Dir)+n);
if(waserror()){
free(dir);
nexterror();
}
m = convM2D(db, n, &dir[0], (char*)&dir[1]);
if(m == 0)
error(Eshortstat);
if(!emptystr(dir[0].uid))
error("can't change owner");
if(dir[0].mode != ~0UL)
p->perm = dir[0].mode;
poperror();
free(dir);
return m;
}
/*
* if the stream doesn't exist, create it
*/
static Chan*
pipeopen(Chan *c, int omode)
{
Pipe *p;
if(c->qid.type & QTDIR){
if(omode != OREAD)
error(Ebadarg);
c->mode = omode;
c->flag |= COPEN;
c->offset = 0;
return c;
}
p = c->aux;
qlock(p);
switch(NETTYPE(c->qid.path)){
case Qdata0:
p->qref[0]++;
break;
case Qdata1:
p->qref[1]++;
break;
}
qunlock(p);
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
c->iounit = qiomaxatomic;
return c;
}
static void
pipeclose(Chan *c)
{
Pipe *p;
p = c->aux;
qlock(p);
if(c->flag & COPEN){
/*
* closing either side hangs up the stream
*/
switch(NETTYPE(c->qid.path)){
case Qdata0:
p->qref[0]--;
if(p->qref[0] == 0){
qhangup(p->q[1], 0);
qclose(p->q[0]);
}
break;
case Qdata1:
p->qref[1]--;
if(p->qref[1] == 0){
qhangup(p->q[0], 0);
qclose(p->q[1]);
}
break;
}
}
/*
* if both sides are closed, they are reusable
*/
if(p->qref[0] == 0 && p->qref[1] == 0){
qreopen(p->q[0]);
qreopen(p->q[1]);
}
/*
* free the structure on last close
*/
p->ref--;
if(p->ref == 0){
qunlock(p);
free(p->q[0]);
free(p->q[1]);
free(p);
} else
qunlock(p);
}
static long
piperead(Chan *c, void *va, long n, vlong)
{
Pipe *p;
p = c->aux;
switch(NETTYPE(c->qid.path)){
case Qdir:
return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen);
case Qdata0:
return qread(p->q[0], va, n);
case Qdata1:
return qread(p->q[1], va, n);
default:
panic("piperead");
}
return -1; /* not reached */
}
static Block*
pipebread(Chan *c, long n, ulong offset)
{
Pipe *p;
p = c->aux;
switch(NETTYPE(c->qid.path)){
case Qdata0:
return qbread(p->q[0], n);
case Qdata1:
return qbread(p->q[1], n);
}
return devbread(c, n, offset);
}
/*
* a write to a closed pipe causes a note to be sent to
* the process.
*/
static long
pipewrite(Chan *c, void *va, long n, vlong)
{
Pipe *p;
if(!islo())
print("pipewrite hi %#p\n", getcallerpc(&c));
if(waserror()) {
/* avoid notes when pipe is a mounted queue */
if((c->flag & CMSG) == 0)
postnote(up, 1, "sys: write on closed pipe", NUser);
nexterror();
}
p = c->aux;
switch(NETTYPE(c->qid.path)){
case Qdata0:
n = qwrite(p->q[1], va, n);
break;
case Qdata1:
n = qwrite(p->q[0], va, n);
break;
default:
panic("pipewrite");
}
poperror();
return n;
}
static long
pipebwrite(Chan *c, Block *bp, ulong)
{
long n;
Pipe *p;
if(waserror()) {
/* avoid notes when pipe is a mounted queue */
if((c->flag & CMSG) == 0)
postnote(up, 1, "sys: write on closed pipe", NUser);
nexterror();
}
p = c->aux;
switch(NETTYPE(c->qid.path)){
case Qdata0:
n = qbwrite(p->q[1], bp);
break;
case Qdata1:
n = qbwrite(p->q[0], bp);
break;
default:
n = 0;
panic("pipebwrite");
}
poperror();
return n;
}
Dev pipedevtab = {
'|',
"pipe",
devreset,
pipeinit,
devshutdown,
pipeattach,
pipewalk,
pipestat,
pipeopen,
devcreate,
pipeclose,
piperead,
pipebread,
pipewrite,
pipebwrite,
devremove,
pipewstat,
};