babyos2(27) pipe

为babyos2实现pipe进程间通信方式。

一个pipe表现为两个文件描述符fd[2],对应两个打开的文件,一个只读,一个只写。当通过fork创建子进程的时候,会拷贝父进程打开的文件,所以也持有这两个打开的文件。
使用的时候,一个关闭读端,一个关闭写端。即父子进程各自只剩下一个打开的文件,例如父进程关闭写端,子进程关闭读端:
parent:
fd[0] <-> file {
TYPE_PIPE;
pipe;
readable;
};

child:
fd[1] <-> file {
TYPE_PIPE;
pipe;
writable;
}

父子进程剩下的文件中都有一个pipe的指针,这两个指针指向内核中同一个pipe结构。
对TYPE_PIPE类型的文件,读写时会调用pipe->read()或pipe->write()。
pipe中有一个缓冲区,及读写指针,锁等。write会往缓冲区写数据,read从里面读数据,由于父子进程的pipe指针对应同一个pipe结构,这样就实现了父子进程一个读一个写的操作。
对应缓冲区的操作是一个类似于生产者/消费者的问题。

userlib pipe:

int userlib_t::pipe(int fd[2])
{
    uint32 ret = 0;
    __asm__ volatile("int $0x80" : "=a" (ret) : "a" (SYS_PIPE), "b" (fd));
    return ret;
}

sys_pipe:

int32 syscall_t::sys_pipe(trap_frame_t* frame)
{
    int* fd = (int *) frame->ebx;
    return os()->get_fs()->do_pipe(fd);
}

fs do_pipe:

int file_system_t::alloc_pipe(file_t*& file_read, file_t*& file_write)
{
    pipe_t* pipe = NULL;

    file_read = alloc_file();
    if (file_read == NULL) {
        goto failed;
    }
    file_write = alloc_file();
    if (file_write == NULL) {
        goto failed;
    }

    pipe = (pipe_t *) os()->get_obj_pool(PIPE_POOL)->alloc_from_pool();
    if (pipe == NULL) {
        goto failed;
    }

    pipe->init();
    file_read->init(file_t::TYPE_PIPE, NULL, pipe, 0, 1, 0);
    file_write->init(file_t::TYPE_PIPE, NULL, pipe, 0, 0, 1);

    return 0;

failed:
    if (file_read != NULL) {
        close_file(file_read);
    }
    if (file_write != NULL) {
        close_file(file_write);
    }
    if (pipe != NULL) {
        os()->get_obj_pool(PIPE_POOL)->free_object((void *) pipe);
    }
    return -1;
}

int file_system_t::do_pipe(int fd[2])
{
    file_t* file_read = NULL;
    file_t* file_write = NULL;
    int fd_read = -1, fd_write = -1;
    if (alloc_pipe(file_read, file_write) < 0) {
        return -1;
    }

    fd_read = current->alloc_fd(file_read);
    if (fd_read < 0) {
        goto failed;
    }
    fd_write = current->alloc_fd(file_write);
    if (fd_write < 0) {
        current->free_fd(fd_read);
        goto failed;
    }

    fd[0] = fd_read;
    fd[1] = fd_write;
    return 0;

failed:
    close_file(file_read);
    close_file(file_write);
    return -1;
}

read/write

int file_system_t::do_read(int fd, void* buffer, uint32 count)
{
    file_t* file = current->get_file(fd);
    if (file == NULL || file->m_readable == 0) {
        return -1;
    }

    if (file->m_type == file_t::TYPE_PIPE) {
        return file->m_pipe->read(buffer, count);
    }
    if (file->m_type == file_t::TYPE_INODE) {
        int nbyte = 0;
        if ((nbyte = read_inode(file->m_inode, (char *) buffer, file->m_offset, count)) > 0) {
            file->m_offset += nbyte;
        }
        return nbyte;
    }

    return -1;
}

int file_system_t::do_write(int fd, void* buffer, uint32 count)
{
    file_t* file = current->get_file(fd);
    if (file == NULL || file->m_writeable == 0) {
        return -1;
    }

    if (file->m_type == file_t::TYPE_PIPE) {
        return file->m_pipe->write(buffer, count);
    }
    if (file->m_type == file_t::TYPE_INODE) {
        int nbyte = 0;
        if ((nbyte = write_inode(file->m_inode, (char *) buffer, file->m_offset, count)) > 0) {
            file->m_offset += nbyte;
        }
        return nbyte;
    }

    return -1;
}

pipe:

/*
 * guzhoudiaoke@126.com
 * 2018-01-20
 */

#ifndef _PIPE_H_
#define _PIPE_H_

#include "types.h"
#include "sem.h"
#include "spinlock.h"

#define PIPE_BUF_SIZE 512

class pipe_t {
public:
    void  init();
    int   get_char(char& ch);
    int   put_char(char ch);

    int32 read(void* buf, uint32 size);
    int32 write(void* buf, uint32 size);
    void  close(bool write_end);

private:
    char        m_buffer[PIPE_BUF_SIZE];
    uint32      m_read_index;
    uint32      m_write_index;
    spinlock_t  m_lock;
    semaphore_t m_space;    // how many space can use to put
    semaphore_t m_item;     // how many item can get

    bool        m_readable;
    bool        m_writable;
};

#endif


/*
 * guzhoudiaoke@126.com
 * 2018-01-20
 */

#include "pipe.h"
#include "babyos.h"

void pipe_t::init()
{
    m_read_index = 0;
    m_write_index = 0;
    m_lock.init();
    m_space.init(PIPE_BUF_SIZE);
    m_item.init(0);
    m_readable = true;
    m_writable = true;
}

int pipe_t::get_char(char& ch)
{
    int ret = -1;
    m_item.down();
    m_lock.lock();
    if (m_readable) {
        ch = m_buffer[m_read_index];
        m_read_index = (m_read_index + 1) % PIPE_BUF_SIZE;
        ret = 0;
    }
    m_lock.unlock();
    m_space.up();

    return ret;
}

int pipe_t::put_char(char ch)
{
    int ret = -1;
    m_space.down();
    m_lock.lock();
    if (m_writable) {
        m_buffer[m_write_index] = ch;
        m_write_index = (m_write_index + 1) % PIPE_BUF_SIZE;
        ret = 0;
    }
    m_lock.unlock();
    m_item.up();

    return ret;
}

int32 pipe_t::read(void* buf, uint32 size)
{
    char* p = (char *) buf;
    char ch;
    for (uint32 i = 0; i < size; i++) {
        if (get_char(ch) < 0) {
            return -1;
        }
        *p++ = ch;
    }

    return size;
}

int32 pipe_t::write(void* buf, uint32 size)
{
    char* p = (char *) buf;
    for (uint32 i = 0; i < size; i++) {
        if (put_char(*p++) < 0) {
            return -1;
        }
    }

    return size;
}

void pipe_t::close(bool write_end)
{
    m_lock.lock();

    if (write_end) {
        m_writable = false;
        m_item.up();
    }
    else {
        m_readable = false;
        m_space.up();
    }

    if (!m_readable && !m_writable) {
        m_lock.unlock();
        os()->get_obj_pool(PIPE_POOL)->free_object(this);
    }

    m_lock.unlock();
}

shell:

void test_pipe()
{
    int fd[2];
    if (userlib_t::pipe(fd) < 0) {
        userlib_t::printf("failed to create pipe\n");
        return;
    }

    userlib_t::printf("succ to create pipe: %d, %d\n", fd[0], fd[1]);

    int32 pid = userlib_t::fork();
    if (pid == 0) {
        userlib_t::close(fd[0]);

        char ch = 'a';
        for (int i = 0; i < 10; i++, ch++) {
            userlib_t::write(fd[1], &ch, 1);
            userlib_t::printf("child write %c to pipe\n", ch);
            userlib_t::sleep(1);
        }
        userlib_t::exit(0);
    }
    else {
        userlib_t::close(fd[1]);

        char ch = '\0';
        for (int i = 0; i < 10; i++) {
            userlib_t::read(fd[0], &ch, 1);
            userlib_t::printf("parent read %c from pipe\n", ch);
        }
        userlib_t::wait(pid);
    }
}

char cmd_line[MAX_CMD_LEN] = {0};
int main()
{
    userlib_t::printf("This is printed by shell.\n");

    while (true) {
        puts("liuruyi $ ");
        gets(cmd_line, MAX_CMD_LEN);
        if (userlib_t::strncmp(cmd_line, "cd ", 3) == 0) {
            if (userlib_t::chdir(cmd_line + 3) < 0) {
                userlib_t::printf("can't cd %s\n", cmd_line+3);
            }
            continue;
        }

        /* used for test */
        if (userlib_t::strncmp(cmd_line, "test ", 5) == 0) {
            test_fork_exec_wait_exit(cmd_line + 5);
            continue;
        }
        if (userlib_t::strncmp(cmd_line, "testpipe", 8) == 0) {
            test_pipe();
            continue;
        }

        do_cmd(cmd_line);
    }

    userlib_t::exit(0);
    return 1;
}

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值