|
|
1.1 root 1: /* $Header: /src386/kernel/coh.386/RCS/pipe.c,v 1.9 93/04/16 06:49:10 bin Exp Locker: bin $ */
2: /* (lgl-
3: * The information contained herein is a trade secret of Mark Williams
4: * Company, and is confidential information. It is provided under a
5: * license agreement, and may be copied or disclosed only under the
6: * terms of that agreement. Any reproduction or disclosure of this
7: * material without the express written authorization of Mark Williams
8: * Company or persuant to the license agreement is unlawful.
9: *
10: * COHERENT Version 2.3.37
11: * Copyright (c) 1982, 1983, 1984.
12: * An unpublished work by Mark Williams Company, Chicago.
13: * All rights reserved.
14: -lgl) */
15: /*
16: * Coherent.
17: * Pipes.
18: *
19: * $Log: pipe.c,v $
20: * Revision 1.9 93/04/16 06:49:10 bin
21: * Hal: kernel 76 update
22: *
23: * Revision 1.7 93/04/14 10:06:40 root
24: * r75
25: *
26: * Revision 1.2 92/01/06 11:59:52 hal
27: * Compile with cc.mwc.
28: *
29: * Revision 1.1 88/03/24 16:14:07 src
30: * Initial revision
31: *
32: * 86/11/19 Allan Cornish /usr/src/sys/coh/pipe.c
33: * Added check for non-blocking read and write if (io_flag & IPNDLY) set.
34: * Eliminated use of i_a inode field since now included in inode macros.
35: */
36: #include <sys/coherent.h>
37: #include <errno.h>
38: #include <sys/filsys.h>
39: #include <sys/ino.h>
40: #include <sys/inode.h>
41: #include <sys/io.h>
42: #include <sys/proc.h>
43: #include <sys/sched.h>
44: #include <signal.h>
45:
46: /*
47: * These are nothing more than random different values at this point!
48: * Historically, these were bit's or'ed into ip->i_flag, no more!
49: */
50:
51: #define IFWFR 1 /* Sleeping Waiting for a Reader */
52: #define IFWFW 2 /* Sleeping Waiting for a Writer */
53:
54:
55: /*
56: * pmake(mode) -- called from the upipe() system call in sys3.c
57: *
58: * Creates and returns a locked pipe inode with the given mode on
59: * the pipedev.
60: */
61:
62: INODE *
63: pmake(mode)
64: {
65: register INODE *ip;
66:
67: if ((ip=ialloc(pipedev, IFPIPE|mode)) != NULL)
68: pclear(ip);
69: pdump("M", ip, mode);
70: return(ip);
71: }
72:
73: pclear(ip)
74: register INODE *ip;
75: {
76: ip->i_pnc =
77: ip->i_prx =
78: ip->i_pwx =
79: ip->i_par =
80: ip->i_paw =
81: ip->i_psr =
82: ip->i_psw = 0;
83: ip->i_iev.e_pnext =
84: ip->i_iev.e_dnext =
85: ip->i_iev.e_dlast =
86: ip->i_iev.e_procp =
87: ip->i_oev.e_pnext =
88: ip->i_oev.e_dnext =
89: ip->i_oev.e_dlast =
90: ip->i_oev.e_procp = NULL;
91: }
92:
93: /*
94: * popen(ip, mode) -- Opens a pipe inode, with the given mode.
95: * Note: The inode is locked upon entry.
96: *
97: * This routine follows the requirements concerning opening pipes.
98: * Specifically, if opening readonly without O_NDELAY, then block
99: * until we have a writer. If opening readonly with O_NDELAY, then
100: * return opened, no blocking. If opening writeonly without O_NDELAY,
101: * then block until we have a reader. If opening writeonly with
102: * O_NDELAY, then return an error, and set u.u_errno to ENXIO.
103: * Beware of subtle race conditions! Also notice, I followed hal's
104: * style of no internal returns in a function.
105: *
106: * Note: these pipe routines maintain the pipe counter variables:
107: * ip->i_par: Number of Awake readers
108: * ip->i_paw: Number of Awake writers
109: * ip->i_psr: Number of Sleeping readers
110: * ip->i_psw: Number of Sleeping writers
111: */
112:
113: popen(ip, mode)
114: register INODE *ip;
115: {
116: pdump("OA", ip, mode);
117: switch ( mode&(IPR|IPW) ) {
118: case IPR:
119: ++ip->i_par;
120: while ( !ip->i_paw && !ip->i_psw ) {
121: if ( mode & IPNDLY )
122: break;
123: else {
124: if ( psleep(ip, IFWFW) < 0 ) {
125: --ip->i_par;
126: goto popen_done;
127: }
128: if ( ip->i_pnc != 0 )
129: break;
130: }
131: }
132: pwake(ip, IFWFR);
133: break;
134: case IPW:
135: ++ip->i_paw;
136: if ( !ip->i_par && !ip->i_psr ) {
137: if ( mode & IPNDLY ) {
138: u.u_error = ENXIO;
139: --ip->i_paw;
140: goto popen_done;
141: } else {
142: if ( psleep(ip, IFWFR) < 0 ) {
143: --ip->i_paw;
144: goto popen_done;
145: }
146: }
147: }
148: pwake(ip, IFWFW);
149: break;
150: case IPR|IPW:
151: ++ip->i_par;
152: ++ip->i_paw;
153: pwake(ip, IFWFW);
154: pwake(ip, IFWFR);
155: break;
156: }
157:
158: popen_done:
159: pdump("OZ", ip, mode);
160: return;
161: }
162:
163:
164: /*
165: * pclose(ip, mode) -- Opens a pipe inode, with the given mode.
166: * Note: The inode is locked upon entry.
167: *
168: * This routine closes the given INODE with the given mode. We
169: * must have the mode correct to maintain counters properly.
170: * Good thing that mode cannot be changed by fcntl()!
171: */
172:
173: pclose(ip, mode)
174: register INODE *ip;
175: {
176: pdump("CA", ip, mode);
177: pwake(ip, IFWFR);
178: pwake(ip, IFWFW);
179: if ( mode & IPR )
180: if ( --ip->i_par < 0 )
181: panic("Out of sync IPR in pclose");
182: if ( mode & IPW )
183: if ( --ip->i_paw < 0 )
184: panic("Out of sync IPW in pclose");
185:
186: if ( !ip->i_paw && !ip->i_psw && !ip->i_par && !ip->i_psr )
187: pclear(ip);
188: pdump("CZ", ip, mode);
189: }
190:
191:
192: /*
193: * pread(ip, iop) -- Reads from a pipe inode, accoring to the IO info.
194: * Note: The inode is locked upon entry.
195: *
196: * This routine follows the requirements concerning reading from pipes.
197: * Specifically, if there is no data in the pipe, then the read will
198: * block waiting for data, unless you have IONDLY set in which case
199: * it will simply return zero. Notice, the traditional value returned
200: * from uread() is the number of characters actually read. This is
201: * nothing more that iop->io_ioc on entry minus iop->io_ioc on exit.
202: * This routine also works with the ring buffer in the inode maintained
203: * by the variables ip->i_pnc: Number of Characters in pipe.
204: * ip->i_prx: Offset in pipe to begin reading.
205: * ip->i_pwx: Offset in pipe to begin writing.
206: * Notice: we do not unlock the inode when we call fread(), this is to
207: * guarantee that we read all that is available even if we go to sleep.
208: * Subtle race condition? I don't think so, since if we go to sleep
209: * in fread(), it's wrt a resource unrelated to this particular INODE.
210: */
211:
212: pread(ip, iop)
213: register INODE *ip;
214: register IO *iop;
215: {
216: register unsigned n;
217: register unsigned ioc;
218:
219: pdump("R", ip, 0);
220: while (ip->i_pnc == 0) {
221: if ( iop->io_flag & IONDLY )
222: goto pread_done;
223: if ( !ip->i_paw && !ip->i_psw )
224: goto pread_done;
225: if ( psleep(ip, IFWFW) < 0 )
226: goto pread_done;
227: }
228:
229: ioc = iop->io_ioc;
230: while ( !u.u_error && (ioc > 0) && (ip->i_pnc > 0) ) {
231: if ( (n = (PIPSIZE-ip->i_prx)) > ioc )
232: n = ioc;
233: if ( n > ip->i_pnc )
234: n = ip->i_pnc;
235: iop->io_ioc = n;
236: iop->io_seek = ip->i_prx;
237: fread(ip, iop);
238: n -= iop->io_ioc;
239: if ( (ip->i_prx+=n) == PIPSIZE )
240: ip->i_prx = 0;
241: if ( (ip->i_pnc-=n) == 0 ) {
242: ip->i_prx =
243: ip->i_pwx = 0;
244: }
245: ioc -= n;
246: }
247: iop->io_ioc = ioc;
248:
249: if ( ip->i_pnc < PIPSIZE )
250: pwake(ip, IFWFR);
251:
252: pread_done:
253: return;
254: }
255:
256:
257: /*
258: * pwrite(ip, iop) -- Writes to a pipe inode, accoring to the IO info.
259: * Note: The inode is locked upon entry.
260: *
261: * This routine follows the requirements concerning writing to pipes.
262: * Specifically, if the pipe is full, then the write will block waiting
263: * for data to be consumed, unless you have IONDLY set in which case
264: * it will simply return zero. Notice, the traditional value returned
265: * from uwrite() is the number of characters actually written. This is
266: * nothing more that iop->io_ioc on entry minus iop->io_ioc on exit.
267: * In other words, iop->io_ioc had better be zero on exit. The possibility
268: * does exist if the number of characters to be written is larger than
269: * PIPSIZE, and thus we do not guarantee atomic writes, that while the
270: * process is sleeping waiting for a reader to consume data, that the
271: * process will be woken from sleeping by a SIGNAL, thus causing a partial
272: * write. The return value will be the actual number of character written.
273: * This routine also works with the ring buffer in the inode maintained
274: * by the variables ip->i_pnc: Number of Characters in pipe.
275: * ip->i_prx: Offset in pipe to begin reading.
276: * ip->i_pwx: Offset in pipe to begin writing.
277: * Notice: we do not unlock the inode when we call fwrite(), this is to
278: * guarantee that we have an atomic write for all writes of size less
279: * than PIPSIZE, even if we go to sleep in the fwrite(). Subtle race
280: * condition? I don't think so, since if we go to sleep in fwrite(),
281: * it's wrt a resource unrelated to this particular INODE.
282: */
283:
284: pwrite(ip, iop)
285: register INODE *ip;
286: register IO *iop;
287: {
288: register unsigned n;
289: register unsigned ioc;
290:
291: pdump("W", ip, 0);
292: ioc = iop->io_ioc;
293: while ( !u.u_error && (ioc > 0) ) {
294: if ( !ip->i_par && !ip->i_psr ) {
295: u.u_error = EPIPE;
296: sendsig(SIGPIPE, SELF);
297: goto pwrite_done;
298: }
299: if ( (n = (PIPSIZE-ip->i_pwx)) > ioc )
300: n = ioc;
301: if ( n > (PIPSIZE-ip->i_pnc) )
302: n = PIPSIZE - ip->i_pnc;
303: if ( (n == 0) || ((ioc <= PIPSIZE) && (n != ioc)) ) {
304: if ( iop->io_flag & IONDLY )
305: goto pwrite_done;
306: if ( psleep(ip, IFWFR) < 0 )
307: goto pwrite_done;
308: continue;
309: }
310: iop->io_ioc = n;
311: iop->io_seek = ip->i_pwx;
312: fwrite(ip, iop);
313: n -= iop->io_ioc;
314: if ( (ip->i_pwx+=n) == PIPSIZE )
315: ip->i_pwx = 0;
316: ip->i_pnc += n;
317: ioc -= n;
318:
319: if ( ip->i_pnc > 0 )
320: pwake(ip, IFWFW);
321: }
322: pwrite_done:
323: iop->io_ioc = ioc;
324: }
325:
326:
327: /*
328: * psleep(ip, who) -- go to sleep either waiting for a reader if (who==IFWFR)
329: * or waiting for a writer if (who==IFWFW).
330: * Returns: 0 if woke up ok
331: * -1 if woke up by signal (e.g. SIGALRM, SIGKILL, etc.)
332: */
333:
334: psleep(ip, who)
335: register INODE *ip;
336: {
337: pdump("SA", ip, 0);
338: iunlock(ip);
339: switch ( who ) {
340: case IFWFW:
341: --ip->i_par; ++ip->i_psr;
342: x_sleep((char *)&ip->i_psw, primed, slpriSigCatch, "pipe wx");
343: ++ip->i_par; --ip->i_psr;
344: break;
345: case IFWFR:
346: --ip->i_paw; ++ip->i_psw;
347: x_sleep((char *)&ip->i_psr, primed, slpriSigCatch, "pipe rx");
348: ++ip->i_paw; --ip->i_psw;
349: break;
350: default:
351: panic("psleep() internal error");
352: }
353: ilock(ip);
354: pdump("SZ", ip, 0);
355: if ( SELF->p_ssig && nondsig() ) {
356: u.u_error = EINTR;
357: return -1;
358: }
359: return(0);
360: }
361:
362:
363: /*
364: * pwake(ip, who) -- wake up processes which are waiting for a reader if
365: * (who==IFWFR) or waiting for a writer if (who==IFWFW).
366: */
367:
368: pwake(ip, who)
369: register INODE *ip;
370: {
371: pdump("KA", ip, 0);
372: switch ( who ) {
373: case IFWFW:
374: if ( ip->i_psr )
375: wakeup((char *)&ip->i_psw);
376: if ( ip->i_pnc > 0 )
377: pollwake(&ip->i_iev);
378: break;
379: case IFWFR:
380: if ( ip->i_psw )
381: wakeup((char *)&ip->i_psr);
382: if ( (ip->i_pnc<PIPSIZE) && (ip->i_par || ip->i_psr) )
383: pollwake(&ip->i_oev);
384: break;
385: default:
386: panic("pwake() internal error");
387: }
388: pdump("KZ", ip, 0);
389: }
390:
391:
392: /*
393: * ppoll(ip, ev) -- Poll the given pipe inode.
394: * INODE *ip -- The inode in question.
395: * int ev -- The event bit field.
396: * int msec -- Number of msecs to wait.
397: * Returns or'ed bits according to the following rules:
398: * POLLIN: indicates input is available for reading, notice it is possible
399: * to read even if there are no more writers anywhere!
400: * POLLOUT: indicates room in pipe for new output, notice it is not possible
401: * to write unless there is a reader attached!
402: *
403: * No priority polls are supported.
404: */
405:
406: ppoll(ip, ev, msec)
407: register INODE *ip;
408: int ev, msec;
409: {
410: register int rval = 0;
411:
412: if ( ev & POLLIN ) {
413: if ( ip->i_pnc > 0 )
414: rval |= POLLIN;
415: else if ( msec != 0 )
416: pollopen(&ip->i_iev);
417: }
418: if ( ev & POLLOUT ) {
419: if ( (ip->i_pnc<PIPSIZE) && (ip->i_par || ip->i_psr) )
420: rval |= POLLOUT;
421: else if ( msec != 0 )
422: pollopen(&ip->i_oev);
423: }
424: return( rval );
425: }
426:
427: /*
428: * pdump(loc, ip, mode) -- A kernel debugging output line.
429: * char *loc -- prefix of line (two characters indicating where we are)
430: * INODE *ip -- The inode information to dump
431: * int mode -- The mode of the IO call, i.e. IPW, IPR, IPNDLY, ...
432: */
433:
434: #if 1
435: pdump()
436: {}
437: #else
438: pdump(loc, ip, mode)
439: char *loc;
440: register INODE *ip;
441: int mode;
442: {
443: printf("%s ip=%x mde=%x nlk=%x rf=%x nc=%x rx=%x wx=%x",
444: loc, ip, mode, ip->i_nlink, ip->i_refc,
445: ip->i_pnc, ip->i_prx, ip->i_pwx);
446:
447: printf(" ar=%x aw=%x sr=%x sw=%x f=%x\n",
448: ip->i_par, ip->i_paw, ip->i_psr, ip->i_psw, ip->i_flag);
449: }
450: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.