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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.