cynix

x86 UNIX-like OS
git clone git://git.2f30.org/cynix
Log | Files | Refs | README | LICENSE

pipe.c (2777B)


      1 /*
      2  *  core/pipe.c
      3  *
      4  *  Copyright (C) 2010 stateless
      5  */
      6 
      7 #include <pipe.h>
      8 #include <ext2.h>
      9 #include <common.h>
     10 #include <errno.h>
     11 #include <string.h>
     12 #include <heap.h>
     13 #include <x86.h>
     14 #include <tss.h>
     15 
     16 extern spinlock_t flist_lock;
     17 extern struct list_head flist;
     18 
     19 static int
     20 pipealloc(void)
     21 {
     22 	struct file_t *f;
     23 	int i;
     24 
     25 	acquire(&flist_lock);
     26 	for (i = 3; i < NR_MAX_OPEN_FILES; ++i) {
     27 		if (curr_proc->fdtable[i]
     28 				&& curr_proc->fdtable[i]->f_state != FILE_NONE)
     29 			continue;
     30 		if (!curr_proc->fdtable[i]) {
     31 			f = kmalloc(sizeof(struct file_t));
     32 			if (IS_ERR(f)) {
     33 				release(&flist_lock);
     34 				return PTR_ERR(f);
     35 			}
     36 			f->f_state = FILE_NONE;
     37 			list_add_tail(&f->f_listopen, &flist);
     38 			curr_proc->fdtable[i] = f;
     39 		}
     40 		f = curr_proc->fdtable[i];
     41 		assert(f->f_state == FILE_NONE);
     42 		f->f_refcount = 1;
     43 		f->f_off = 0;
     44 		f->f_state = FILE_ALLOC;
     45 		f->f_type = FILE_PIPE;
     46 		f->f_inode = NULL;
     47 		f->f_inode_nr = 0;
     48 		curr_proc->pipebufs[i] = NULL;
     49 		release(&flist_lock);
     50 		return i;
     51 	}
     52 	release(&flist_lock);
     53 	return -EMFILE;
     54 }
     55 
     56 int
     57 pipe(int pipefd[2])
     58 {
     59 	int ret;
     60 	char *buf;
     61 
     62 	pipefd[0] = pipealloc();
     63 	if (pipefd[0] < 0)
     64 		return pipefd[0];
     65 	pipefd[1] = pipealloc();
     66 	if (pipefd[1] < 0) {
     67 		ret = pipefd[1];
     68 		goto err;
     69 	}
     70 	buf = kmalloc(PIPE_SIZ);
     71 	if (IS_ERR(buf)) {
     72 		ret = PTR_ERR(buf);
     73 		goto err1;
     74 	}
     75 	curr_proc->pipebufs[pipefd[0]] = buf;
     76 	curr_proc->pipebufs[pipefd[1]] = buf;
     77 	return 0;
     78 err1:
     79 	fileclose(pipefd[1]);
     80 err:
     81 	fileclose(pipefd[0]);
     82 	return ret;
     83 }
     84 
     85 /* must be called with flist_lock acquired */
     86 ssize_t
     87 piperead(int fd, void *buf, size_t count)
     88 {
     89 	size_t i;
     90 	struct file_t *f = NULL;
     91 	char *pbuf;
     92 
     93 	pbuf = curr_proc->pipebufs[fd];
     94 	for (i = 0; i < NR_MAX_OPEN_FILES; ++i)
     95 		if (curr_proc->pipebufs[i] == pbuf && i != (size_t)fd) {
     96 			f = curr_proc->fdtable[i];
     97 			break;
     98 		}
     99 	if (!f) f = curr_proc->fdtable[i];
    100 	for (i = 0; i < count && i < (size_t)f->f_off; ++i) {
    101 		((char *)buf)[i] = *pbuf;
    102 		memcpy(pbuf, pbuf + 1, PIPE_SIZ - 1);
    103 	}
    104 	f->f_off -= i;
    105 	return i;
    106 }
    107 
    108 /* must be called with flist_lock acquired */
    109 ssize_t
    110 pipewrite(int fd, const void *buf, size_t count)
    111 {
    112 	size_t i;
    113 	char *pbuf;
    114 	ssize_t r;
    115 
    116 	pbuf = curr_proc->pipebufs[fd];
    117 	for (i = 0; i < NR_MAX_OPEN_FILES; ++i)
    118 		if (curr_proc->pipebufs[i] == pbuf && i != (size_t)fd)
    119 			break;
    120 	/* read end has been closed */
    121 	if (i != NR_MAX_OPEN_FILES
    122 			&& curr_proc->fdtable[i]->f_state == FILE_NONE)
    123 		return -EPIPE;
    124 	for (i = 0; i < count && curr_proc->fdtable[fd]->f_off + i < PIPE_SIZ; ++i)
    125 		pbuf[curr_proc->fdtable[fd]->f_off + i] = ((char *)buf)[i];
    126 	curr_proc->fdtable[fd]->f_off += i;
    127 	r = i;
    128 	for (i = 0; i < NR_MAX_OPEN_FILES; ++i)
    129 		if (curr_proc->pipebufs[i] == pbuf && i != (size_t)fd)
    130 			curr_proc->fdtable[i]->f_off = curr_proc->fdtable[fd]->f_off;
    131 	return r;
    132 }
    133