Fork me on GitHub

root/fs/pipefs/pipe.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pipefs_close
  2. pipefs_read
  3. pipefs_write
  4. pipefs_ioctl
  5. pipefs_lseek
  6. pipefs_select

   1 /*
   2  * fiwix/fs/pipefs/pipe.c
   3  *
   4  * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/types.h>
   9 #include <fiwix/errno.h>
  10 #include <fiwix/fs.h>
  11 #include <fiwix/filesystems.h>
  12 #include <fiwix/fs_pipe.h>
  13 #include <fiwix/stat.h>
  14 #include <fiwix/fcntl.h>
  15 #include <fiwix/ioctl.h>
  16 #include <fiwix/sleep.h>
  17 #include <fiwix/sched.h>
  18 #include <fiwix/stdio.h>
  19 #include <fiwix/string.h>
  20 
  21 static struct resource pipe_resource = { NULL, NULL };
  22 
  23 int pipefs_close(struct inode *i, struct fd *fd_table)
  24 {
  25         if((fd_table->flags & O_ACCMODE) == O_RDONLY) {
  26                 if(!--i->u.pipefs.i_readers) {
  27                         wakeup(&do_select);
  28                         wakeup(&pipefs_write);
  29                 }
  30         }
  31         if((fd_table->flags & O_ACCMODE) == O_WRONLY) {
  32                 if(!--i->u.pipefs.i_writers) {
  33                         wakeup(&do_select);
  34                         wakeup(&pipefs_read);
  35                 }
  36         }
  37         if((fd_table->flags & O_ACCMODE) == O_RDWR) {
  38                 if(!--i->u.pipefs.i_readers) {
  39                         wakeup(&do_select);
  40                         wakeup(&pipefs_write);
  41                 }
  42                 if(!--i->u.pipefs.i_writers) {
  43                         wakeup(&do_select);
  44                         wakeup(&pipefs_read);
  45                 }
  46         }
  47         return 0;
  48 }
  49 
  50 int pipefs_read(struct inode *i, struct fd *fd_table, char *buffer, __size_t count)
  51 {
  52         __off_t bytes_read;
  53         __size_t n, limit;
  54         char *data;
  55 
  56         bytes_read = 0;
  57         data = i->u.pipefs.i_data;
  58 
  59         while(count) {
  60                 if(i->u.pipefs.i_writeoff) {
  61                         if(i->u.pipefs.i_readoff >= i->u.pipefs.i_writeoff) {
  62                                 limit = PIPE_BUF - i->u.pipefs.i_readoff;
  63                         } else {
  64                                 limit = i->u.pipefs.i_writeoff - i->u.pipefs.i_readoff;
  65                         }
  66                 } else {
  67                         limit = PIPE_BUF - i->u.pipefs.i_readoff;
  68                 }
  69                 n = MIN(limit, count);
  70                 if(i->i_size && n) {
  71                         lock_resource(&pipe_resource);
  72                         memcpy_b(buffer + bytes_read, data + i->u.pipefs.i_readoff, n);
  73                         bytes_read += n;
  74                         i->u.pipefs.i_readoff += n;
  75                         i->i_size -= n;
  76                         if(i->u.pipefs.i_writeoff >= PIPE_BUF) {
  77                                 i->u.pipefs.i_writeoff = 0;
  78                         }
  79                         unlock_resource(&pipe_resource);
  80                         wakeup(&do_select);
  81                         wakeup(&pipefs_write);
  82                         break;
  83                 } else {
  84                         if(i->u.pipefs.i_writers) {
  85                                 if(fd_table->flags & O_NONBLOCK) {
  86                                         return -EAGAIN;
  87                                 }
  88                                 if(sleep(&pipefs_read, PROC_INTERRUPTIBLE)) {
  89                                         return -EINTR;
  90                                 }
  91                         } else {
  92                                 if(i->i_size) {
  93                                         if(i->u.pipefs.i_readoff >= PIPE_BUF) {
  94                                                 i->u.pipefs.i_readoff = 0;
  95                                                 continue;
  96                                         }
  97                                 }
  98                                 break;
  99                         }
 100                 }
 101         }
 102         if(!i->i_size) {
 103                 i->u.pipefs.i_readoff = 0;
 104                 i->u.pipefs.i_writeoff = 0;
 105         }
 106         return bytes_read;
 107 }
 108 
 109 int pipefs_write(struct inode *i, struct fd *fd_table, const char *buffer, __size_t count)
 110 {
 111         __off_t bytes_written;
 112         __size_t n;
 113         char *data;
 114         int limit;
 115 
 116         bytes_written = 0;
 117         data = i->u.pipefs.i_data;
 118 
 119         while(bytes_written < count) {
 120                 /* if the read end closes then send signal and return */
 121                 if(!i->u.pipefs.i_readers) {
 122                         send_sig(current, SIGPIPE);
 123                         return -EPIPE;
 124                 }
 125 
 126                 if(i->u.pipefs.i_readoff) {
 127                         if(i->u.pipefs.i_writeoff <= i->u.pipefs.i_readoff) {
 128                                 limit = i->u.pipefs.i_readoff;
 129                         } else {
 130                                 limit = PIPE_BUF;
 131                         }
 132                 } else {
 133                         limit = PIPE_BUF;
 134                 }
 135 
 136                 n = MIN((count - bytes_written), (limit - i->u.pipefs.i_writeoff));
 137 
 138                 /*
 139                  * POSIX requires that any write operation involving fewer than
 140                  * PIPE_BUF bytes must be automatically executed and finished
 141                  * without being interleaved with write operations of other
 142                  * processes to the same pipe.
 143                 */
 144                 if(n && n <= PIPE_BUF) {
 145                         lock_resource(&pipe_resource);
 146                         memcpy_b(data + i->u.pipefs.i_writeoff, buffer + bytes_written, n);
 147                         bytes_written += n;
 148                         i->u.pipefs.i_writeoff += n;
 149                         i->i_size += n;
 150                         if(i->u.pipefs.i_readoff >= PIPE_BUF) {
 151                                 i->u.pipefs.i_readoff = 0;
 152                         }
 153                         unlock_resource(&pipe_resource);
 154                         wakeup(&do_select);
 155                         wakeup(&pipefs_read);
 156                         continue;
 157                 }
 158 
 159                 wakeup(&do_select);
 160                 wakeup(&pipefs_read);
 161                 if(!(fd_table->flags & O_NONBLOCK)) {
 162                         if(sleep(&pipefs_write, PROC_INTERRUPTIBLE)) {
 163                                 return -EINTR;
 164                         }
 165                 } else {
 166                         return -EAGAIN;
 167                 }
 168         }
 169         return bytes_written;
 170 }
 171 
 172 int pipefs_ioctl(struct inode *i, int cmd, unsigned long int arg)
 173 {
 174         int errno;
 175 
 176         switch(cmd) {
 177                 case FIONREAD:
 178                         if((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {
 179                                 return errno;
 180                         }
 181                         memcpy_b((void *)arg, &i->i_size, sizeof(unsigned int));
 182                         break;
 183                 default:
 184                         return -EINVAL;
 185         }
 186         return 0;
 187 }
 188 
 189 int pipefs_lseek(struct inode *i, __off_t offset)
 190 {
 191         return -ESPIPE;
 192 }
 193 
 194 int pipefs_select(struct inode *i, int flag)
 195 {
 196         switch(flag) {
 197                 case SEL_R:
 198                         /*
 199                          * if !i->i_size && !i->u.pipefs.i_writers
 200                          * should also return 1?
 201                          */
 202                         if(i->i_size || !i->u.pipefs.i_writers) {
 203                                 return 1;
 204                         }
 205                         break;
 206                 case SEL_W:
 207                         /*
 208                          * if i->i_size == PIPE_BUF && !i->u.pipefs.i_readers
 209                          * should also return 1?
 210                          */
 211                         if(i->i_size < PIPE_BUF || !i->u.pipefs.i_readers) {
 212                                 return 1;
 213                         }
 214                         break;
 215         }
 216         return 0;
 217 }

/* [previous][next][first][last][top][bottom][index][help] */