Build only the catalogs which don't cause errors.
[AROS.git] / workbench / fs / pipe / pipesched.c
blobb8e559820cbade9ec4d9eff01dbf01eb6824d8a2
1 /****************************************************************************
2 ** File: pipesched.c
3 ** Program: pipe-handler - an AmigaDOS handler for named pipes
4 ** Version: 1.1
5 ** Author: Ed Puckett qix@mit-oz
6 **
7 ** Copyright 1987 by EpAc Software. All Rights Reserved.
8 **
9 ** History: 05-Jan-87 Original Version (1.0)
10 ** 07-Feb-87 Added "lockct" check in CheckWaiting().
13 #include <libraries/dos.h>
14 #include <libraries/dosextens.h>
15 #include <libraries/filehandler.h>
16 #include <exec/exec.h>
18 #include "pipelists.h"
19 #include "pipename.h"
20 #include "pipebuf.h"
21 #include "pipecreate.h"
22 #include "pipesched.h"
23 #include "pipe-handler.h"
25 #if PIPEDIR
26 # include "pipedir.h"
27 #endif /* PIPEDIR */
29 #ifdef DEBUG
30 # include "pipedebug.h"
31 #endif /* DEBUG */
35 /*---------------------------------------------------------------------------
36 ** pipesched.c
37 ** -----------
38 ** This module handles pipe I/O scheduling.
40 ** Visible Functions
41 ** -----------------
42 ** void StartPipeIO (pkt, iotype)
43 ** void CheckWaiting (pipe)
44 ** struct DosPacket *AllocPacket (ReplyPort)
45 ** void FreePacket (pkt)
46 ** void StartTapIO (pkt, Type, Arg1, Arg2, Arg3, Handler)
47 ** void HandleTapReply (pkt)
49 ** Macros (in pipesched.h)
50 ** -----------------------
51 ** - none -
53 ** Local Functions
54 ** ---------------
55 ** void EndPipeIO (pipe, wd)
58 static void EndPipeIO (PIPEDATA *pipe, WAITINGDATA *wd);
62 /*---------------------------------------------------------------------------
63 ** A pipe I/O request is begun. A WAITINGDATA structure is allocated and
64 ** the request is stored in it. It is then stored in the appropriate list
65 ** (readerlist or writerlist) of the pipe. Finally, CheckWaiting is called
66 ** to service requests for that pipe.
67 ** Notice that CheckWaiting() is only called when a new I/O request
68 ** comes in, or when the pipe is closed. At no other time will the state of
69 ** the pipe change in such a way that more requests for it can be honored.
72 void StartPipeIO (pkt, iotype)
74 struct DosPacket *pkt;
75 IOTYPE iotype; /* assumed only PIPEREAD or PIPEWRITE */
77 { PIPEKEY *pipekey;
78 PIPEDATA *pipe;
79 WAITINGDATA *wd;
82 if ((iotype != PIPEREAD) && (iotype != PIPEWRITE))
83 { pkt->dp_Res2= ERROR_ACTION_NOT_KNOWN;
84 SPIOEXIT:
85 pkt->dp_Res1= -1;
86 QuickReplyPkt (pkt);
87 return;
91 pipekey= (PIPEKEY *) pkt->dp_Arg1;
92 pipe= pipekey->pipe;
94 if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL)
95 { pkt->dp_Res2= ERROR_NO_FREE_STORE;
96 goto SPIOEXIT;
100 pkt->dp_Res2= ERROR_INVALID_LOCK; /* in case not open for iotype */
102 if (iotype == PIPEREAD)
103 { if ((pipekey->iotype != PIPEREAD) && (pipekey->iotype != PIPERW))
104 goto SPIOEXIT;
106 InsertTail (&pipe->readerlist, wd);
108 else /* PIPEWRITE */
109 { if ((pipekey->iotype != PIPEWRITE) && (pipekey->iotype != PIPERW))
110 goto SPIOEXIT;
112 InsertTail (&pipe->writerlist, wd);
116 wd->pkt= pkt;
117 wd->pktinfo.pipewait.reqtype= iotype;
118 wd->pktinfo.pipewait.buf= (BYTE *) pkt->dp_Arg2; /* buffer */
119 wd->pktinfo.pipewait.len= (ULONG) pkt->dp_Arg3; /* length */
121 CheckWaiting (pipe);
126 /*---------------------------------------------------------------------------
127 ** Read requests for the pipe are satisfied until the pipe is empty or no
128 ** more requests are left. Then, write requests are satisifed until the pipe
129 ** is full or no more requests are left. This alternating process is
130 ** repeated until no further changes are possible.
131 ** Finished requests are sent to EndPipeIO() so that replies may be sent
132 ** to their owners. Aftereward, if the pipe is empty and is not open for
133 ** either read or write, then it is discarded. If it is open for read, but
134 ** is empty and has no write requests and is not open for write, then all
135 ** remaining read requests are returned in their current state. (This
136 ** implements EOF.) A pipe with a positive "lockct" will not be discarded.
137 ** UnLock() is expected to call here so that a previously locked, empty pipe
138 ** will be discarded.
141 void CheckWaiting (pipe)
143 PIPEDATA *pipe;
145 { BYTE change;
146 WAITINGDATA *wd;
147 ULONG amt;
148 void EndPipeIO();
151 #if PIPEDIR
152 SetPipeDate (pipe);
153 #endif /* PIPEDIR */
155 for (change= TRUE; change; )
156 { change= FALSE;
158 while ( (! (PipebufEmpty (pipe->buf))) &&
159 ((wd= (WAITINGDATA *) FirstItem (&pipe->readerlist)) != NULL) )
160 { amt= MoveFromPipebuf (pipe->buf, wd->pktinfo.pipewait.buf, wd->pktinfo.pipewait.len);
162 if (amt)
163 { wd->pktinfo.pipewait.buf += amt;
164 wd->pktinfo.pipewait.len -= amt;
165 change= TRUE;
168 if (wd->pktinfo.pipewait.len == 0L) /* then finished with request */
169 EndPipeIO (pipe, wd);
170 } /* end of readerlist loop */
173 while ( (! (PipebufFull (pipe->buf))) &&
174 ((wd= (WAITINGDATA *) FirstItem (&pipe->writerlist)) != NULL) )
175 { amt= MoveToPipebuf (pipe->buf, wd->pktinfo.pipewait.buf, wd->pktinfo.pipewait.len);
177 if (amt)
178 { wd->pktinfo.pipewait.buf += amt;
179 wd->pktinfo.pipewait.len -= amt;
180 change= TRUE;
183 if (wd->pktinfo.pipewait.len == 0L) /* then finished with request */
184 EndPipeIO (pipe, wd);
185 } /* end of writerlist loop */
189 if ( PipebufEmpty (pipe->buf) &&
190 (! (pipe->flags & OPEN_FOR_WRITE)) &&
191 (FirstItem (&pipe->writerlist) == NULL) ) /* then EOF */
192 { while ((wd= (WAITINGDATA *) FirstItem (&pipe->readerlist)) != NULL)
193 EndPipeIO (pipe, wd);
195 if (! (pipe->flags & OPEN_FOR_READ)) /* readerlist is now empty */
196 #if PIPEDIR
197 if (pipe->lockct == 0)
198 #endif /* PIPEDIR */
199 DiscardPipe (pipe);
205 /*---------------------------------------------------------------------------
206 ** This routine returns a finished pipe I/O request. If it is a write
207 ** request to a pipe with a tap, then the same write request is sent to the
208 ** tap, and the reply is deferred until HandleTapReply() gets the tap request
209 ** reply. (This lets the user stop a pipe by typing a character into a
210 ** tap window.)
213 static void EndPipeIO (pipe, wd)
215 PIPEDATA *pipe;
216 WAITINGDATA *wd;
218 { struct DosPacket *pkt, *tappkt;
219 struct FileHandle *taphandle;
222 pkt= wd->pkt;
224 pkt->dp_Res1= pkt->dp_Arg3 - wd->pktinfo.pipewait.len;
225 pkt->dp_Res2= 0;
227 if (wd->pktinfo.pipewait.reqtype == PIPEREAD)
228 { Delete (&pipe->readerlist, wd);
230 QuickReplyPkt (pkt);
231 FreeMem (wd, sizeof (WAITINGDATA));
233 else /* must be PIPEWRITE -- reqtype is new PIPERW */
234 { Delete (&pipe->writerlist, wd);
236 if (pipe->tapfh != 0) /* then write to the pipe tap */
237 { if ((tappkt= AllocPacket (TapReplyPort)) == NULL)
238 { QuickReplyPkt (pkt);
239 FreeMem (wd, sizeof (WAITINGDATA));
240 #ifdef DEBUG
241 OS ("!!! ERROR - Could not allocate packet for tap write\n");
242 #endif /* DEBUG */
244 else
245 { wd->pkt= tappkt; /* reuse wd for tap write request */
246 wd->pktinfo.tapwait.clientpkt= pkt;
247 /* don't need ...tapwait.handle */
249 taphandle= (struct FileHandle *) BPTRtoCptr (pipe->tapfh);
251 StartTapIO ( tappkt, ACTION_WRITE,
252 taphandle->fh_Arg1, pkt->dp_Arg2, pkt->dp_Arg3,
253 taphandle->fh_Type );
255 InsertHead (&tapwaitlist, wd); /* for HandleTapReply() */
258 else /* otherwise, return finished packet */
259 { QuickReplyPkt (pkt);
260 FreeMem (wd, sizeof (WAITINGDATA));
267 /*---------------------------------------------------------------------------
268 ** An exec Message and a DosPacket are allocated, and they are initialized.
269 ** A pointer to the packet is returned, or NULL if it could not be allocated.
272 struct DosPacket *AllocPacket (ReplyPort)
274 struct MsgPort *ReplyPort;
276 { struct Message *msg;
277 struct DosPacket *pkt;
280 if ((msg = (struct Message *) AllocMem (sizeof (struct Message), (ALLOCMEM_FLAGS | MEMF_CLEAR))) == NULL)
281 return NULL;
283 if ((pkt = (struct DosPacket *) AllocMem (sizeof (struct DosPacket), (ALLOCMEM_FLAGS | MEMF_CLEAR))) == NULL)
284 { FreeMem (msg, sizeof (struct Message));
285 return NULL;
288 msg->mn_Node.ln_Type= NT_MESSAGE;
289 msg->mn_Node.ln_Name= (char *) pkt;
291 msg->mn_ReplyPort= ReplyPort;
293 pkt->dp_Link= msg;
294 pkt->dp_Port= ReplyPort;
296 return pkt;
301 /*---------------------------------------------------------------------------
302 ** A DosPacket/exec Message pair is freed.
305 void FreePacket (pkt)
307 struct DosPacket *pkt;
309 { if (pkt != NULL)
310 { if (pkt->dp_Link != NULL)
311 FreeMem (pkt->dp_Link, sizeof (struct Message));
313 FreeMem (pkt, sizeof (struct DosPacket));
319 /*---------------------------------------------------------------------------
320 ** The indicated fields are filled into the packet and it is sent.
323 void StartTapIO (pkt, Type, Arg1, Arg2, Arg3, Handler)
325 struct DosPacket *pkt;
326 LONG Type;
327 LONG Arg1;
328 LONG Arg2;
329 LONG Arg3;
330 struct MsgPort *Handler;
332 { pkt->dp_Type= Type;
333 pkt->dp_Arg1= Arg1;
334 pkt->dp_Arg2= Arg2;
335 pkt->dp_Arg3= Arg3;
337 PutMsg (Handler, pkt->dp_Link);
342 /*---------------------------------------------------------------------------
343 ** Handle replies from tap I/O requests. These were initiated by OpenTap(),
344 ** CloseTap() and EndPipeIO().
347 void HandleTapReply (pkt)
349 struct DosPacket *pkt;
351 { WAITINGDATA *wd;
354 for (wd= (WAITINGDATA *) FirstItem (&tapwaitlist); wd != NULL; wd= (WAITINGDATA *) NextItem (wd))
355 if (wd->pkt == pkt)
356 { Delete (&tapwaitlist, wd);
357 break;
360 if (wd == NULL)
362 #ifdef DEBUG
363 OS ("!!! ERROR - WAITINGDATA not found in HandleTapReply()\n");
364 #endif /* DEBUG */
365 FreePacket (pkt);
366 return; /* not found - this should never happen */
369 switch (pkt->dp_Type)
370 { case MODE_READWRITE:
371 case MODE_READONLY:
372 case MODE_NEWFILE: /* for a tap open request */
373 if (pkt->dp_Res1) /* then successful */
374 OpenPipe (wd->pktinfo.tapwait.clientpkt, pkt->dp_Arg1);
375 else /* couldn't open tap */
376 { FreeMem (wd->pktinfo.tapwait.handle, sizeof (struct FileHandle));
377 pkt->dp_Res1= 0;
378 pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
379 QuickReplyPkt (wd->pktinfo.tapwait.clientpkt);
382 FreeMem (BPTRtoCptr (pkt->dp_Arg3), OPENTAP_STRSIZE);
383 break;
385 case ACTION_END: /* for a tap close request */
386 FreeMem (wd->pktinfo.tapwait.handle, sizeof (struct FileHandle));
387 break;
389 case ACTION_WRITE: /* for a tap write request */
390 QuickReplyPkt (wd->pktinfo.tapwait.clientpkt); /* return to client */
391 break;
393 #ifdef DEBUG
394 default: /* should never happen */
395 OS ("!!! ERROR - bad packet type in HandleTapReply(), type ="); OL (pkt->dp_Type); NL;
396 #endif /* DEBUG */
399 FreePacket (pkt);
400 FreeMem (wd, sizeof (WAITINGDATA));