~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Minix Cross Reference
Minix/fs/pipe.c


  1 /* This file deals with the suspension and revival of processes.  A process can
  2  * be suspended because it wants to read or write from a pipe and can't, or
  3  * because it wants to read or write from a special file and can't.  When a
  4  * process can't continue it is suspended, and revived later when it is able
  5  * to continue.
  6  *
  7  * The entry points into this file are
  8  *   do_pipe:     perform the PIPE system call
  9  *   pipe_check:  check to see that a read or write on a pipe is feasible now
 10  *   suspend:     suspend a process that cannot do a requested read or write
 11  *   release:     check to see if a suspended process can be released and do it
 12  *   revive:      mark a suspended process as able to run again
 13  *   do_unpause:  a signal has been sent to a process; see if it suspended
 14  */
 15 
 16 #include "fs.h"
 17 #include <fcntl.h>
 18 #include <signal.h>
 19 #include <minix/boot.h>
 20 #include <minix/callnr.h>
 21 #include <minix/com.h>
 22 #include "dev.h"
 23 #include "file.h"
 24 #include "fproc.h"
 25 #include "inode.h"
 26 #include "param.h"
 27 
 28 PRIVATE message mess;
 29 
 30 /*===========================================================================*
 31  *                              do_pipe                                      *
 32  *===========================================================================*/
 33 PUBLIC int do_pipe()
 34 {
 35 /* Perform the pipe(fil_des) system call. */
 36 
 37   register struct fproc *rfp;
 38   register struct inode *rip;
 39   int r;
 40   struct filp *fil_ptr0, *fil_ptr1;
 41   int fil_des[2];               /* reply goes here */
 42 
 43   /* Acquire two file descriptors. */
 44   rfp = fp;
 45   if ( (r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r);
 46   rfp->fp_filp[fil_des[0]] = fil_ptr0;
 47   fil_ptr0->filp_count = 1;
 48   if ( (r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) {
 49         rfp->fp_filp[fil_des[0]] = NIL_FILP;
 50         fil_ptr0->filp_count = 0;
 51         return(r);
 52   }
 53   rfp->fp_filp[fil_des[1]] = fil_ptr1;
 54   fil_ptr1->filp_count = 1;
 55 
 56   /* Make the inode on the pipe device. */
 57   if ( (rip = alloc_inode(PIPE_DEV, I_REGULAR) ) == NIL_INODE) {
 58         rfp->fp_filp[fil_des[0]] = NIL_FILP;
 59         fil_ptr0->filp_count = 0;
 60         rfp->fp_filp[fil_des[1]] = NIL_FILP;
 61         fil_ptr1->filp_count = 0;
 62         return(err_code);
 63   }
 64 
 65   if (read_only(rip) != OK) panic("pipe device is read only", NO_NUM);
 66  
 67   rip->i_pipe = I_PIPE;
 68   rip->i_mode &= ~I_REGULAR;
 69   rip->i_mode |= I_NAMED_PIPE;  /* pipes and FIFOs have this bit set */
 70   fil_ptr0->filp_ino = rip;
 71   fil_ptr0->filp_flags = O_RDONLY;
 72   dup_inode(rip);               /* for double usage */
 73   fil_ptr1->filp_ino = rip;
 74   fil_ptr1->filp_flags = O_WRONLY;
 75   rw_inode(rip, WRITING);       /* mark inode as allocated */
 76   reply_i1 = fil_des[0];
 77   reply_i2 = fil_des[1];
 78   rip->i_update = ATIME | CTIME | MTIME;
 79   return(OK);
 80 }
 81 
 82 
 83 /*===========================================================================*
 84  *                              pipe_check                                   *
 85  *===========================================================================*/
 86 PUBLIC int pipe_check(rip, rw_flag, oflags, bytes, position, canwrite)
 87 register struct inode *rip;     /* the inode of the pipe */
 88 int rw_flag;                    /* READING or WRITING */
 89 int oflags;                     /* flags set by open or fcntl */
 90 register int bytes;             /* bytes to be read or written (all chunks) */
 91 register off_t position;        /* current file position */
 92 int *canwrite;                  /* return: number of bytes we can write */
 93 {
 94 /* Pipes are a little different.  If a process reads from an empty pipe for
 95  * which a writer still exists, suspend the reader.  If the pipe is empty
 96  * and there is no writer, return 0 bytes.  If a process is writing to a
 97  * pipe and no one is reading from it, give a broken pipe error.
 98  */
 99 
100   int r = 0;
101 
102   /* If reading, check for empty pipe. */
103   if (rw_flag == READING) {
104         if (position >= rip->i_size) {
105                 /* Process is reading from an empty pipe. */
106                 if (find_filp(rip, W_BIT) != NIL_FILP) {
107                         /* Writer exists */
108                         if (oflags & O_NONBLOCK) 
109                                 r = EAGAIN;
110                         else 
111                                 suspend(XPIPE); /* block reader */
112 
113                         /* If need be, activate sleeping writers. */
114                         if (susp_count > 0) release(rip, WRITE, susp_count);
115                 }
116                 return(r);
117         }
118   } else {
119         /* Process is writing to a pipe. */
120 /*      if (bytes > PIPE_SIZE) return(EFBIG); */
121         if (find_filp(rip, R_BIT) == NIL_FILP) {
122                 /* Tell kernel to generate a SIGPIPE signal. */
123                 sys_kill((int)(fp - fproc), SIGPIPE);
124                 return(EPIPE);
125         }
126 
127         if (position + bytes > PIPE_SIZE) {
128                 if ((oflags & O_NONBLOCK) && bytes < PIPE_SIZE) 
129                         return(EAGAIN);
130                 else if ((oflags & O_NONBLOCK) && bytes > PIPE_SIZE) {
131                         if ( (*canwrite = (PIPE_SIZE - position)) > 0)  {
132                                 /* Do a partial write. Need to wakeup reader */
133                                 release(rip, READ, susp_count);
134                                 return(1);
135                         } else {
136                                 return(EAGAIN);
137                         }
138                      }
139                 if (bytes > PIPE_SIZE) {
140                         if ((*canwrite = PIPE_SIZE - position) > 0) {
141                                 /* Do a partial write. Need to wakeup reader
142                                  * since we'll suspend ourself in read_write()
143                                  */
144                                 release(rip, READ, susp_count);
145                                 return(1);
146                         }
147                 }
148                 suspend(XPIPE); /* stop writer -- pipe full */
149                 return(0);
150         }
151 
152         /* Writing to an empty pipe.  Search for suspended reader. */
153         if (position == 0) release(rip, READ, susp_count);
154   }
155 
156   *canwrite = 0;
157   return(1);
158 }
159 
160 
161 /*===========================================================================*
162  *                              suspend                                      *
163  *===========================================================================*/
164 PUBLIC void suspend(task)
165 int task;                       /* who is proc waiting for? (PIPE = pipe) */
166 {
167 /* Take measures to suspend the processing of the present system call.
168  * Store the parameters to be used upon resuming in the process table.
169  * (Actually they are not used when a process is waiting for an I/O device,
170  * but they are needed for pipes, and it is not worth making the distinction.)
171  */
172 
173   if (task == XPIPE || task == XPOPEN) susp_count++;/* #procs susp'ed on pipe*/
174   fp->fp_suspended = SUSPENDED;
175   fp->fp_fd = fd << 8 | fs_call;
176   fp->fp_task = -task;
177   if (task == XLOCK) {
178         fp->fp_buffer = (char *) name1; /*  third arg to fcntl() */
179         fp->fp_nbytes =request;         /* second arg to fcntl() */
180   } else {
181         fp->fp_buffer = buffer;         /* for reads and writes */
182         fp->fp_nbytes = nbytes;
183   }
184   dont_reply = TRUE;            /* do not send caller a reply message now */
185 }
186 
187 
188 /*===========================================================================*
189  *                              release                                      *
190  *===========================================================================*/
191 PUBLIC void release(ip, call_nr, count)
192 register struct inode *ip;      /* inode of pipe */
193 int call_nr;                    /* READ, WRITE, OPEN or CREAT */
194 int count;                      /* max number of processes to release */
195 {
196 /* Check to see if any process is hanging on the pipe whose inode is in 'ip'.
197  * If one is, and it was trying to perform the call indicated by 'call_nr',
198  * release it.
199  */
200 
201   register struct fproc *rp;
202 
203   /* Search the proc table. */
204   for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) {
205         if (rp->fp_suspended == SUSPENDED &&
206                         rp->fp_revived == NOT_REVIVING &&
207                         (rp->fp_fd & BYTE) == call_nr &&
208                         rp->fp_filp[rp->fp_fd>>8]->filp_ino == ip) {
209                 revive((int)(rp - fproc), 0);
210                 susp_count--;   /* keep track of who is suspended */
211                 if (--count == 0) return;
212         }
213   }
214 }
215 
216 
217 /*===========================================================================*
218  *                              revive                                       *
219  *===========================================================================*/
220 PUBLIC void revive(proc_nr, bytes)
221 int proc_nr;                    /* process to revive */
222 int bytes;                      /* if hanging on task, how many bytes read */
223 {
224 /* Revive a previously blocked process. When a process hangs on tty, this
225  * is the way it is eventually released.
226  */
227 
228   register struct fproc *rfp;
229   register int task;
230 
231   if (proc_nr < 0 || proc_nr >= NR_PROCS) panic("revive err", proc_nr);
232   rfp = &fproc[proc_nr];
233   if (rfp->fp_suspended == NOT_SUSPENDED || rfp->fp_revived == REVIVING)return;
234 
235   /* The 'reviving' flag only applies to pipes.  Processes waiting for TTY get
236    * a message right away.  The revival process is different for TTY and pipes.
237    * For TTY revival, the work is already done, for pipes it is not: the proc
238    * must be restarted so it can try again.
239    */
240   task = -rfp->fp_task;
241   if (task == XPIPE || task == XLOCK) {
242         /* Revive a process suspended on a pipe or lock. */
243         rfp->fp_revived = REVIVING;
244         reviving++;             /* process was waiting on pipe or lock */
245   } else {
246         rfp->fp_suspended = NOT_SUSPENDED;
247         if (task == XPOPEN) /* process blocked in open or create */
248                 reply(proc_nr, rfp->fp_fd>>8);
249         else {
250                 /* Revive a process suspended on TTY or other device. */
251                 rfp->fp_nbytes = bytes; /*pretend it wants only what there is*/
252                 reply(proc_nr, bytes);  /* unblock the process */
253         }
254   }
255 }
256 
257 
258 /*===========================================================================*
259  *                              do_unpause                                   *
260  *===========================================================================*/
261 PUBLIC int do_unpause()
262 {
263 /* A signal has been sent to a user who is paused on the file system.
264  * Abort the system call with the EINTR error message.
265  */
266 
267   register struct fproc *rfp;
268   int proc_nr, task, fild;
269   struct filp *f;
270   dev_t dev;
271 
272   if (who > MM_PROC_NR) return(EPERM);
273   proc_nr = pro;
274   if (proc_nr < 0 || proc_nr >= NR_PROCS) panic("unpause err 1", proc_nr);
275   rfp = &fproc[proc_nr];
276   if (rfp->fp_suspended == NOT_SUSPENDED) return(OK);
277   task = -rfp->fp_task;
278 
279   switch(task) {
280         case XPIPE:             /* process trying to read or write a pipe */
281                 break;
282 
283         case XOPEN:             /* process trying to open a special file */
284                 panic ("fs/do_unpause called with XOPEN\n", NO_NUM);
285 
286         case XLOCK:             /* process trying to set a lock with FCNTL */
287                 break;
288 
289         case XPOPEN:            /* process trying to open a fifo */
290                 break;
291 
292         default:                /* process trying to do device I/O (e.g. tty)*/
293                 fild = (rfp->fp_fd >> 8) & BYTE;/* extract file descriptor */
294                 if (fild < 0 || fild >= OPEN_MAX)panic("unpause err 2",NO_NUM);
295                 f = rfp->fp_filp[fild];
296                 dev = (dev_t) f->filp_ino->i_zone[0];   /* device hung on */
297                 mess.TTY_LINE = (dev >> MINOR) & BYTE;
298                 mess.PROC_NR = proc_nr;
299 
300                 /* Tell kernel R or W. Mode is from current call, not open. */
301                 mess.COUNT = (rfp->fp_fd & BYTE) == READ ? R_BIT : W_BIT;
302                 mess.m_type = CANCEL;
303                 fp = rfp;       /* hack - call_ctty uses fp */
304                 (*dmap[(dev >> MAJOR) & BYTE].dmap_rw)(task, &mess);
305   }
306 
307   rfp->fp_suspended = NOT_SUSPENDED;
308   reply(proc_nr, EINTR);        /* signal interrupted call */
309   return(OK);
310 }
311 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.