/*
* linux/fs/pipe.c
*
* (C) 1991 Linus Torvalds
*/

#include <signal.h>		// źͷļźŷųźŽṹԼźŲԭ͡

#include <linux/sched.h>	// ȳͷļṹtask_structʼ0 ݣ
// һЩйúͻȡǶʽຯ䡣
#include <linux/mm.h> /* for get_free_page */	/* ʹеget_free_page */
// ڴͷļҳСһЩҳͷźԭ͡
#include <asm/segment.h>	// βͷļйضμĴǶʽຯ

//// ܵ
// inode ǹܵӦi ڵ㣬buf ݻָ룬count Ƕȡֽ
int
read_pipe (struct m_inode *inode, char *buf, int count)
{
  int chars, size, read = 0;

// ȡֽڼֵcount 0ѭִ²
  while (count > 0)
    {
// ǰܵû(size=0)ѵȴýڵḶ̌ûдܵߣ򷵻Ѷ
// ֽ˳ڸi ڵ˯ߣȴϢ
      while (!(size = PIPE_SIZE (*inode)))
	{
	  wake_up (&inode->i_wait);
	  ܵ(PAGE_SIZE)  ܵݳ(PIPE_SIZE)  ָtail (i_zone[1])  ָhead (i_zone[0])  ָ(i_size) if (inode->i_count != 2)	/* are there any writers? */
	    return read;
	  sleep_on (&inode->i_wait);
	}
// ȡܵβĩ˵ֽcharsڻҪȡֽcountcount
// chars ڵǰܵкݵĳsizesize
      chars = PAGE_SIZE - PIPE_TAIL (*inode);
      if (chars > count)
	chars = count;
      if (chars > size)
	chars = size;
// ֽڼȥ˴οɶֽcharsۼѶֽ
      count -= chars;
      read += chars;
// size ָܵβǰܵβָ루ǰchars ֽڣ
      size = PIPE_TAIL (*inode);
      PIPE_TAIL (*inode) += chars;
      PIPE_TAIL (*inode) &= (PAGE_SIZE - 1);
// ܵеݸƵûСڹܵi ڵ㣬i_size ֶǹָܵ롣
      while (chars-- > 0)
	put_fs_byte (((char *) inode->i_size)[size++], buf++);
    }
// ѵȴùܵi ڵḶ̌ضȡֽ
  wake_up (&inode->i_wait);
  return read;
}

//// ܵд
// inode ǹܵӦi ڵ㣬buf ݻָ룬count ǽдֽܵ
int
write_pipe (struct m_inode *inode, char *buf, int count)
{
  int chars, size, written = 0;

// дֽڼֵcount 0ѭִ²
  while (count > 0)
    {
// ǰܵûѾ(size=0)ѵȴýڵḶ̌ûжܵߣ
// SIGPIPE źţдֽ˳д0 ֽڣ򷵻-1ڸi ڵ
// ˯ߣȴܵڳռ䡣
      while (!(size = (PAGE_SIZE - 1) - PIPE_SIZE (*inode)))
	{
	  wake_up (&inode->i_wait);
	  if (inode->i_count != 2)
	    {			/* no readers */
	      current->signal |= (1 << (SIGPIPE - 1));
	      return written ? written : -1;
	    }
	  sleep_on (&inode->i_wait);
	}
// ȡܵͷĩ˿ռֽcharsڻҪдֽcount
// countchars ڵǰܵппռ䳤sizesize
      chars = PAGE_SIZE - PIPE_HEAD (*inode);
      if (chars > count)
	chars = count;
      if (chars > size)
	chars = size;
// дֽڼȥ˴οдֽcharsۼдֽwritten
      count -= chars;
      written += chars;
// size ָܵͷǰܵͷָ루ǰchars ֽڣ
      size = PIPE_HEAD (*inode);
      PIPE_HEAD (*inode) += chars;
      PIPE_HEAD (*inode) &= (PAGE_SIZE - 1);
// ûchars ֽڵܵСڹܵi ڵ㣬i_size ֶǹָܵ롣
      while (chars-- > 0)
	((char *) inode->i_size)[size++] = get_fs_byte (buf++);
    }
// ѵȴi ڵḶ̌дֽ˳
  wake_up (&inode->i_wait);
  return written;
}

//// ܵϵͳú
// fildes ָдһļ()ļָһܵi ڵ㡣fildes[0]
// ڶܵݣfildes[1]ܵдݡ
// ɹʱ0ʱ-1
int
sys_pipe (unsigned long *fildes)
{
  struct m_inode *inode;
  struct file *f[2];
  int fd[2];
  int i, j;

// ϵͳļȡüֶΪ0 ֱüΪ1
  j = 0;
  for (i = 0; j < 2 && i < NR_FILE; i++)
    if (!file_table[i].f_count)
      (f[j++] = i + file_table)->f_count++;
// ֻһͷŸ(üλ)
  if (j == 1)
    f[0]->f_count = 0;
// ûҵ򷵻-1
  if (j < 2)
    return -1;
// ȡõļṹֱһļʹ̵ļṹֱָָ
// ļṹ
  j = 0;
  for (i = 0; j < 2 && i < NR_OPEN; i++)
    if (!current->filp[i])
      {
	current->filp[fd[j] = i] = f[j];
	j++;
      }
// ֻһļͷŸþ
  if (j == 1)
    current->filp[fd[0]] = NULL;
// ûҵоͷȡļṹλüֵ-1
  if (j < 2)
    {
      f[0]->f_count = f[1]->f_count = 0;
      return -1;
    }
// ܵi ڵ㣬Ϊܵ仺1 ҳڴ棩ɹӦͷļ
// ṹ-1
  if (!(inode = get_pipe_inode ()))
    {
      current->filp[fd[0]] = current->filp[fd[1]] = NULL;
      f[0]->f_count = f[1]->f_count = 0;
      return -1;
    }
// ʼļṹָͬһi ڵ㣬дָ붼㡣1 ļṹļģʽΪ
// 2 ļṹļģʽΪд
  f[0]->f_inode = f[1]->f_inode = inode;
  f[0]->f_pos = f[1]->f_pos = 0;
  f[0]->f_mode = 1;		/* read */
  f[1]->f_mode = 2;		/* write */
// ļ鸴ƵӦûУ0˳
  put_fs_long (fd[0], 0 + fildes);
  put_fs_long (fd[1], 1 + fildes);
  return 0;
}
