Re-examination of inter-process communication (i)

Source: Internet
Author: User
Tags goto message queue readable semaphore

Recently working in the Linux pipeline and message queue with a face. At the beginning of their own learning to learn that the content is very simple, the result left a big pit, borrowed UNIX network programming to complement, re-examine the two parts, and WARNING!!!

First look at the pipeline

#include <unistd.h>int pipe (int fd[2]);
Return: Success is 0, error 1, two file descriptor fd[0] used to read, fd[1] to write

Soul Mapping


Single-Process pipeline


Just after fork


The parent process closes the pipe read-out end, the child process closes the pipe write end, and provides a one-way data flow between the parent and child processes

Pipelines can only be used for parent-child processes or sibling interprocess communication, meaning that pipelines can only be used for inter-process communication with affinity

The buffer size of the pipeline is restricted. The pipeline transmits an unformatted stream of bytes. This requires that the pipeline input and output parties agree on the data format beforehand.

Well-known pipelines can be used for inter-process communication without affinity (name pipe or FIFO)

#include <sys/types.h> #include <sys/stat.h>int mkinfo (const char *pathname, mode_t mode);//<span style= "Font-family: Song body, Arial; line-height:26px; " ><span style= "FONT-SIZE:12PX;" >pathname to create the full pathname of the named pipe, mode is the pattern for creating a named pipe </span></span>
Return: If successful then 0, unsuccessful then-1


Implementation analysis

Number of pipe buffers # # Pipe_buffers (16)//Pipe buffer object structure struct Pipe_buffer {    struct page *page;//Pipeline Buffers Page Box descriptor address    unsigned int offset, Len; The current position of valid data in the page box, and the length of the valid data    struct pipe_buf_operations *ops;//address of the pipeline buffer method table};
Pipe information structure struct Pipe_inode_info {    wait_queue_head_t wait;//pipeline wait queue    unsigned int nrbufs, curbuf;// The number of buffers containing the data to be read and the index of the first buffer containing the data to be read    struct pipe_buffer bufs[pipe_buffers];//pipe buffer descriptor Array    struct page *tmp_page; Cache area Page box pointer    unsigned int start;  Current pipeline buffer read position    unsigned int readers;//read process flag, or number    unsigned int writers;//write process flag, or number    unsigned int waiting_ Writers; The number of write processes in the wait queue    unsigned int r_counter;//similar to readers, but when the process waiting to write FIFO is using    unsigned int w_counter; Similar to writers, but uses struct fasync_struct *fasync_readers when waiting for a process to write to the FIFO,    //To notify the struct fasync_ of asynchronous I/O through the signal    struct *fasync_writers; For asynchronous I/O notifications via signals};

Pipe read operation function static ssize_tpipe_readv (struct file *filp, const struct IOVEC *_iov, unsigned long nr_segs, loff_t *ppos) {St Ruct inode *inode = filp->f_dentry->d_inode; Get inode node pointer struct pipe_inode_info *info; int do_wakeup; ssize_t ret; struct Iovec *iov = (struct Iovec *) _iov; Gets the structure of the read buffer size_t Total_len; Total_len = Iov_length (Iov, Nr_segs); /* Null read succeeds. */if (unlikely (Total_len = = 0)) return 0; Do_wakeup = 0; ret = 0; Down (Pipe_sem (*inode)); Get the I_sem semaphore in the inode info = inode->i_pipe; Gets the PIPE_INODE_INFO structure pointer for the inode structure for (;;) {int bufs = info->nrbufs;//Check there are several pipeline buffers that have read data if (BUFS) {//description has a buffer containing read data int curbuf = info->curbuf;//Get current reading The index of the pipeline buffer is the struct pipe_buffer *buf = info->bufs + curbuf; A total of 16 buffers, CURBUF is the current struct pipe_buf_operations *ops = buf->ops;   Gets the list of operation functions void *addr;    size_t chars = buf->len;   int error;   If the buffer length is greater than the length of data required to read, chars is set to the required length if (Chars > Total_len) chars = Total_len; Execute Map Method addr = ops->mAP (FILP, info, buf);   Copy data from cache error = Pipe_iov_copy_to_user (Iov, addr + buf->offset, chars);   Execute Umap Method Ops->unmap (info, buf);   if (unlikely (error)) {if (!ret) ret =-efault;//first read failure break;   }//Update the offset and Len fields of the pipeline ret + = chars;   Buf->offset + = chars;      Buf->len-= chars;    If the current buffer has a data length of 0 if (!buf->len) {buf->ops = NULL;    Ops->release (info, buf);    Curbuf = (curbuf + 1) & (PIPE_BUFFERS-1);    Info->curbuf = Curbuf;    Info->nrbufs =--bufs;   Do_wakeup = 1;  } Total_len-= chars; The total length of the update read if (!total_len)//Read completion of the read break; /* Common Path:read succeeded */} if (BUFS)/* More to do?  */Continue; If Bufs is 0, all pipelines are null, at which point the operation if (!  Pipe_writers (*inode))//whether there is a write operation is being break; if (! Pipe_waiting_writers (*inode)) {//Whether you need to wait/* Syscall merging:usually We must not sleep * If O_nonblock is set, or if    We got some data. * But if a writer is sleeps in kernel space and then * we can wait for the data withOut violating POSIX.   */if (ret) break;    if (Filp->f_flags & O_nonblock) {//To wait but set the Nonblock tag again, the contradiction is ret =-eagain;   Break   }} if (Signal_pending (current)) {//Set process blocking flag if (!ret) ret =-erestartsys;  Break    } if (Do_wakeup) {Wake_up_interruptible_sync (pipe_wait (*inode));  Kill_fasync (Pipe_fasync_writers (*inode), SIGIO, poll_out);  } pipe_wait (Inode); } Up (Pipe_sem (*inode));  /* Signal writers asynchronously that there are more.  */if (do_wakeup) {wake_up_interruptible (pipe_wait (*inode)); Kill_fasync (Pipe_fasync_writers (*inode), SIGIO, poll_out);  } if (Ret > 0) file_accessed (FILP); Update the file structure of the Atime object return ret;}  Static ssize_tpipe_read (struct file *filp, char __user *buf, size_t count, loff_t *ppos) {struct Iovec Iov = {. Iov_base = BUF,. Iov_len = count}; Return Pipe_readv (Filp, &iov, 1, PPOs);} /* Drop The inode semaphore and wait for a pipe event, atomically */void pipe_wait (struct inode * inode) {define_wait (w AIT); Add current to the tubePrepare_to_wait (Pipe_wait (*inode), &wait, task_interruptible) in the waiting queue of the Tao;    Release I_sem Up (Pipe_sem (*inode)); Schedule (); Be woken up, remove it from the waiting queue finish_wait (pipe_wait (*inode), &wait); Get I_SEM index node semaphore down again (Pipe_sem (*inode));}
Static Ssize_tpipe_writev (struct file *filp, const struct IOVEC *_iov, unsigned long nr_segs, loff_t *ppos) {struct    Inode *inode = filp->f_dentry->d_inode;    struct Pipe_inode_info *info;    ssize_t ret;    int do_wakeup;    struct Iovec *iov = (struct Iovec *) _iov;    size_t Total_len;    Total_len = Iov_length (Iov, Nr_segs); /* Null write succeeds.    */if (unlikely (Total_len = = 0)) return 0;    Do_wakeup = 0;    ret = 0;    Down (Pipe_sem (*inode));    info = inode->i_pipe; Whether there is a reader process exists, if there is no write pipeline operation does not have any meaning//at this time produce sigpipe signal if (!)        Pipe_readers (*inode)) {Send_sig (sigpipe, current, 0);        ret =-epipe;    Goto out; }/* We try to merge small writes *///If the buffer for the data is to be read, and the length of the written data is less than page_size if (Info->nrbufs && Total_len & Lt Page_size) {//first read buffer + number of readable buffers-1 Gets the address of the first writable buffer int lastbuf = (info->curbuf + info->nrbufs-1) & (P        IPE_BUFFERS-1);        struct Pipe_buffer *buf = info->bufs + lastbuf; StRuct pipe_buf_operations *ops = buf->ops;        int offset = Buf->offset + buf->len;             If the remaining space of the writable buffer is greater than the total amount of data written Total_len if (ops->can_merge && offset + total_len <= page_size) {            void *addr = Ops->map (Filp, info, buf);            Copy data to pipeline buffer int error = Pipe_iov_copy_from_user (offset + addr, Iov, Total_len);            Ops->unmap (info, buf);            ret = error;            Do_wakeup = 1;            if (error) goto out;            Update valid data length field Buf->len + = Total_len;            ret = Total_len;        Goto out; }}//If all writable (number of readable buffers is 0),//or write data length greater than the length of the pipe buffer (page_size) for (;;)        {int bufs; Whether there is a reader process exists if (!            Pipe_readers (*inode)) {Send_sig (sigpipe, current, 0);            if (!ret) ret =-epipe;        Break        }//Get read buffer number Bufs = info->nrbufs; if (Bufs < pipe_buffers) {ssize_t CharS            Get the address int newbuf = (info->curbuf + bufs) & (pipe_buffers-1) of the writable (empty) buffer with the first readable buffer + the number of readable buffers;            struct Pipe_buffer *buf = info->bufs + newbuf;            struct page *page = info->tmp_page;            int error;                If the value of the page is empty, get a page if (!page) {page = Alloc_page (Gfp_highuser) from the partner system;                    if (unlikely (!page)) {ret = ret?:-enomem;                Break            } info->tmp_page = page; }/* Always wakeup, even if the copy fails.             Otherwise * We lock Up (o_nonblock-) readers this sleep due to * syscall merging. * fixme!             Is this really true?            */do_wakeup = 1;            chars = page_size;            if (Chars > Total_len) chars = Total_len;            Write chars bytes into the buffer in error = Pipe_iov_copy_from_user (Kmap (page), Iov, chars);    Kunmap (page);        if (unlikely (error)) {if (!ret) ret =-efault;            Break            } ret + = chars;            /* Insert it into the buffer array *//Update nrbufs, and Len fields.            buf->page = page;            Buf->ops = &anon_pipe_buf_ops;            Buf->offset = 0;            Buf->len = chars;            Info->nrbufs = ++bufs;            Info->tmp_page = NULL;            If you have not finished writing, continue writing the remaining data total_len-= chars;        if (!total_len) break;        }//There is also a writable buffer to continue writing if (Bufs < pipe_buffers) continue;        If the setting is non-blocking,//If no data ret=0 is written, then an error is returned//if the data has been written, the write operation is completed.            if (Filp->f_flags & O_nonblock) {if (!ret) ret =-eagain;        Break            } if (signal_pending (current)) {if (!ret) ret =-erestartsys;        Break       } if (Do_wakeup) {Wake_up_interruptible_sync (pipe_wait (*inode));     Kill_fasync (Pipe_fasync_readers (*inode), SIGIO, poll_in);        Do_wakeup = 0;        } pipe_waiting_writers (*inode) + +;        Pipe_wait (Inode);    Pipe_waiting_writers (*inode)--;    }out:up (Pipe_sem (*inode));        if (do_wakeup) {wake_up_interruptible (pipe_wait (*inode));    Kill_fasync (Pipe_fasync_readers (*inode), SIGIO, poll_in);    } if (Ret > 0) inode_update_time (inode, 1); /* Mtime and CTime */return RET;}


Ps:pipelines are implemented as a set of VFS objects, so there is no corresponding disk image. So the pipeline installation and implementation are similar to VFS, not discussed here

Re-examination of inter-process communication (i)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.