view src/pipe.cbc @ 81:d41e0a5f7e2f

merge
author tobaru
date Wed, 09 Oct 2019 20:43:04 +0900
parents 214d21c891c7
children
line wrap: on
line source

#include "types.h"
#include "defs.h"
#include "param.h"
#include "mmu.h"
#include "proc.h"
#include "fs.h"
#include "file.h"
#include "spinlock.h"

#define PIPESIZE 512

#define __ncode __code
#
struct pipe {
    struct spinlock lock;
    char data[PIPESIZE];
    uint nread;     // number of bytes read
    uint nwrite;    // number of bytes written
    int readopen;   // read fd is still open
    int writeopen;  // write fd is still open
};

int pipealloc(struct file **f0, struct file **f1)
{
    struct pipe *p;

    p = 0;
    *f0 = *f1 = 0;

    if((*f0 = filealloc()) == 0 || (*f1 = filealloc()) == 0) {
        goto bad;
    }

    if((p = kmalloc (get_order(sizeof(*p)))) == 0) {
        goto bad;
    }

    p->readopen = 1;
    p->writeopen = 1;
    p->nwrite = 0;
    p->nread = 0;

    initlock(&p->lock, "pipe");

    (*f0)->type = FD_PIPE;
    (*f0)->readable = 1;
    (*f0)->writable = 0;
    (*f0)->pipe = p;
    (*f1)->type = FD_PIPE;
    (*f1)->readable = 0;
    (*f1)->writable = 1;
    (*f1)->pipe = p;

    return 0;

    //PAGEBREAK: 20
    bad:
    if(p) {
        kfree (p, get_order(sizeof*p));
    }

    if(*f0) {
        fileclose(*f0);
    }

    if(*f1) {
        fileclose(*f1);
    }

    return -1;
}

void pipeclose(struct pipe *p, int writable)
{
    acquire(&p->lock);

    if(writable){
        p->writeopen = 0;
        wakeup(&p->nread);

    } else {
        p->readopen = 0;
        wakeup(&p->nwrite);
    }

    if(p->readopen == 0 && p->writeopen == 0){
        release(&p->lock);
        kfree (p, get_order(sizeof(*p)));

    } else {
        release(&p->lock);
    }
}

//PAGEBREAK: 40
int pipewrite(struct pipe *p, char *addr, int n)
{
    int i;

    acquire(&p->lock);

    for(i = 0; i < n; i++){
        while(p->nwrite == p->nread + PIPESIZE){  //DOC: pipewrite-full
            if(p->readopen == 0 /*|| proc->killed*/){
                release(&p->lock);
                return -1;
            }

            wakeup(&p->nread);
            sleep(&p->nwrite, &p->lock);  //DOC: pipewrite-sleep
        }

        p->data[p->nwrite++ % PIPESIZE] = addr[i];
    }

    wakeup(&p->nread);  //DOC: pipewrite-wakeup1
    release(&p->lock);
    return n;
}

__ncode cbc_piperead3(){
    struct pipe *p = proc->cbc_arg.cbc_console_arg.p;
    int i = proc->cbc_arg.cbc_console_arg.i;
    __code(*next)(int ret) = proc->cbc_arg.cbc_console_arg.next;
    release(&p->lock);

    goto next(i);
}

__ncode cbc_piperead2(){
    int i = proc->cbc_arg.cbc_console_arg.i;
    int n = proc->cbc_arg.cbc_console_arg.n;
    struct pipe *p = proc->cbc_arg.cbc_console_arg.p;
    char *addr = proc->cbc_arg.cbc_console_arg.addr;
    if (i < n && !(p->nread == p->nwrite)) {
        addr[i] = p->data[p->nread++ % PIPESIZE];
        i ++;
        proc->cbc_arg.cbc_console_arg.i = i;
        proc->cbc_arg.cbc_console_arg.p = p;
        proc->cbc_arg.cbc_console_arg.addr = addr;
        goto cbc_piperead2();
    }
    proc->cbc_arg.cbc_console_arg.p = p;
    goto cbc_wakeup(&p->nwrite, cbc_piperead3);  //DOC: piperead-wakeup
}

__ncode cbc_piperead1(){
    struct pipe *p = proc->cbc_arg.cbc_console_arg.p;
    __code(*next)(int ret) = proc->cbc_arg.cbc_console_arg.next;
    if (p->nread == p->nwrite && p->writeopen){
        if(proc->killed){
            release(&p->lock);
            goto next(-1);
        }
        proc->cbc_arg.cbc_console_arg.p = p;
        goto cbc_sleep(&p->nread, &p->lock, cbc_piperead1);        
    }
    int i = 0;
    proc->cbc_arg.cbc_console_arg.i = i;
    proc->cbc_arg.cbc_console_arg.p = p;
    goto cbc_piperead2();
}

__ncode cbc_piperead(struct pipe *p, char *addr, int n, __code (*next)(int ret))
{
    acquire(&p->lock);
    proc->cbc_arg.cbc_console_arg.n = n;
    proc->cbc_arg.cbc_console_arg.p = p;
    proc->cbc_arg.cbc_console_arg.addr = addr;
    proc->cbc_arg.cbc_console_arg.next = next;
    goto cbc_piperead1();
}

int piperead(struct pipe *p, char *addr, int n)
{
    int i;

    acquire(&p->lock);

    while(p->nread == p->nwrite && p->writeopen){  //DOC: pipe-empty
        if(proc->killed){
            release(&p->lock);
            return -1;
        }

        sleep(&p->nread, &p->lock); //DOC: piperead-sleep*/
    }

    for(i = 0; i < n; i++){  //DOC: piperead-copy
        if(p->nread == p->nwrite) {
            break;
        }

        addr[i] = p->data[p->nread++ % PIPESIZE];
    }

    wakeup(&p->nwrite);  //DOC: piperead-wakeup
    release(&p->lock);

    return i;
}