;/* CompareIO.c - Execute me to compile me with SAS/C 6.56 sc DATA=FAR NMINC STRMERGE STREQ NOSTKCHK SAVEDS IGNORE=73 CompareIO.c slink FROM LIB:c.o,CompareIO.o TO CompareIO LIBRARY LIB:sc.lib,LIB:amiga.lib,lib:debug.lib quit ;*/ /* (c) Copyright 1992-1999 Amiga, Inc. All rights reserved. */ /* The information contained herein is subject to change without notice, */ /* and is provided "as is" without warranty of any kind, either expressed */ /* or implied. The entire risk as to the use of this information is */ /* assumed by the user. */ /* CompareIO.c uses packet level I/O to copy the standard input channel to the */ /* standard output channel (as set up by the standard startup code, c.o). */ /* CompareIO uses both synchronous and asynchronous I/O to perform the copy */ /* and reports the time it takes to do each. */ #include <exec/types.h> #include <dos/dosextens.h> #include <devices/timer.h> #include <clib/dos_protos.h> #include <clib/timer_protos.h> #include <clib/exec_protos.h> #include <clib/alib_protos.h> #include <clib/alib_stdio_protos.h> #ifdef LATTICE int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */ void chkabort(void) { return; } #endif #define BUFSIZE 8192 UBYTE *vers = "\0$VER: CompareIO 37.14 Nov-12-92"; ULONG AsyncLoop(void); ULONG SyncLoop(void); extern struct Library *DOSBase; struct Library *TimerBase; struct MsgPort *myport; struct FileHandle *in, *out; BPTR results, in_start, out_start; struct DosPacket *sp_read, *sp_write; UBYTE buffer[BUFSIZE*2]; struct timeval time_start, time_finish; struct timerequest timer_io; ULONG vfprintfargs[2]; /* An array of pointers */ void main(void) { if (DOSBase->lib_Version >= 37) { if (results = Open("*", MODE_NEWFILE)) /* This is for printing the results. */ { /* Since the example is already using the */ /* standard I/O channels for its own */ /* purposes, there needs to be a separate */ /* channel to output the results. */ if (!OpenDevice(TIMERNAME, UNIT_MICROHZ, &timer_io, 0L)) { TimerBase = (struct Library *)timer_io.tr_node.io_Device; if (myport = CreateMsgPort()) { in_start = Input(); /* Need to hold on to input and output so no one can */ out_start = Output(); /* change them while this example is using them. */ if (in = (struct FileHandle *)BADDR(in_start)) { if (out = (struct FileHandle *)BADDR(out_start)) { if (sp_read = AllocDosObject(DOS_STDPKT, NULL)) { if (sp_write = AllocDosObject(DOS_STDPKT, NULL)) { /* When AllocDosObject() allocates a StandardPacket, it takes */ /* care of linking together the Message and DosPacket. */ /* AllocDosObject() points the DosPacket's dp_Link field at */ /* the StandardPacket's Message structure. It also points */ /* the Message's mn_Node.ln_Name field at the DosPacket: */ /* sp_read->dp_Link = sp_Msg; */ /* sp_Msg->mn_Node.ln_Name = (STRPTR)sp_read; */ sp_read->dp_Type = ACTION_READ; /* Fill out ACTION_READ packet. */ sp_read->dp_Arg1 = in->fh_Arg1; sp_write->dp_Type = ACTION_WRITE; /* Fill out ACTION_WRITE packet. */ sp_write->dp_Arg1 = out->fh_Arg1; VFPrintf(results, "\n Method Seconds Micros\n", NULL); VFPrintf(results, " ------------ ------- ------\n", NULL); GetSysTime(&time_start); if (AsyncLoop()) { GetSysTime(&time_finish); SubTime(&time_finish, &time_start); vfprintfargs[0] = time_finish.tv_secs; vfprintfargs[1] = time_finish.tv_micro; VFPrintf(results, " Asynchronous: %3ld %7ld\n", &vfprintfargs[0]); GetSysTime(&time_start); if (SyncLoop()) { GetSysTime(&time_finish); SubTime(&time_finish, &time_start); vfprintfargs[0] = time_finish.tv_secs; vfprintfargs[1] = time_finish.tv_micro; VFPrintf(results, " Synchronous: %3ld %7ld\n", &vfprintfargs[0]); } else VFPrintf(results, " ******* Stop ******\n", NULL); } else VFPrintf(results, " ******* Stop ******\n", NULL); FreeDosObject(DOS_STDPKT, sp_write); } FreeDosObject(DOS_STDPKT, sp_read); } } } DeleteMsgPort(myport); } CloseLibrary(TimerBase); } Close(results); } } } ULONG AsyncLoop() { struct StandardPacket *mysp; UBYTE *buf; LONG amount_read; BOOL sp_read_busy = TRUE, /* Is the ACTION_READ packet busy? */ sp_write_busy = FALSE, /* Is the ACTION_WRITE packet busy? */ done = FALSE; /* Is the program finished? */ ULONG ok = TRUE; if (!((out->fh_Arg1) && (in->fh_Arg1))) /* Don't bother if in or out uses NIL: */ return(FALSE); sp_read->dp_Arg2 = (LONG)buffer; /* The buffer to fill in. */ sp_read->dp_Arg3 = BUFSIZE; /* The size of the Arg2 buffer. */ SendPkt(sp_read, in->fh_Type, myport); /* Send initial read request. */ sp_write->dp_Type = ACTION_WRITE; /* Fill out the ACTION_WRITE packet. */ sp_write->dp_Arg1 = out->fh_Arg1; sp_write->dp_Arg2 = (LONG)&buffer[BUFSIZE]; /* Arg2 points to the buffer to write */ sp_write->dp_Arg3 = 0L; /* out. At first glance, it might */ sp_write->dp_Res1 = 0L; /* seem odd to bother setting Arg2 */ /* when the program hasn't read anything yet. */ /* This is to set up for the main loop. The */ /* main loop swaps the ACTION_READ buffer with */ /* the ACTION_WRITE buffer when it receives */ /* a completed read. Likewise, dp_Arg3 and */ /* dp_Res1 are set to make the ACTION_READ */ /* look like it has a valid return value so */ /* main loop won't fail the first time through */ /* the loop. */ /* main() has already taken care of sending the initial read to the */ /* handler. Because we need the data from that read before we can */ while (!done) /* do anything, the first thing to do is wait for its return. */ { do /* Wait for the ACTION_READ to return. */ { WaitPort(myport); while (mysp = (struct StandardPacket *)GetMsg(myport)) /* ...empty the port. */ { /* If this message is the ACTION_READ packet, mark it as */ /* no longer busy so we can use it to start another read. */ if (mysp->sp_Pkt.dp_Type == ACTION_READ) sp_read_busy = FALSE; /* If this message is instead the ACTION_WRITE packet, */ /* mark it as not busy. We need to check for this because */ /* the WRITE_PACKET from the previous interation through */ /* the loop might have come back before the ACTION_WRITE */ /* from the previous interation. */ else if (mysp->sp_Pkt.dp_Type == ACTION_WRITE) sp_write_busy = FALSE; } } while (sp_read_busy); /* End of "wait for ACTION_READ" loop. */ /* Get ready to send the next ACTION_READ. */ buf = (UBYTE *)(sp_read->dp_Arg2); /* Hold on to the important stuff from the */ amount_read = sp_read->dp_Res1; /* ACTION_READ we just got back so we can */ /* reuse the packet to start a new read */ /* while processing the last read's data. */ while (sp_write_busy) /* Because this example only uses two buffers and */ { /* the ACTION_WRITE might be using one of them, */ /* this example has to wait for an outstanding */ /* ACTION_WRITE to return before reusing the */ /* ACTION_WRITE packet's buffer. */ WaitPort(myport); while (mysp = (struct StandardPacket *)GetMsg(myport)) if (mysp->sp_Pkt.dp_Type == ACTION_WRITE) sp_write_busy = FALSE; } if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { done = TRUE; ok = FALSE; } else { /* This tests the return values from the ACTION_READ and ACTION_WRITE */ /* packets. The ACTION_READ packet returns the number of bytes it */ /* read in dp_Res1, which was copied earlier into amount_read. If it */ /* is 0, the read packet found the EOF. If it is negative, there was */ /* an error. In the case of ACTION_WRITE, an error occurs if the */ /* number of bytes that ACTION_WRITE was supposed to write (Arg3) */ /* does not match the actual number it wrote, which ACTION_WRITE re- */ /* turns in Res1. This test is the reason dp_Res1 and dp_Arg3 were */ /* set to zero when the ACTION_WRITE packet was set up in main(). */ if ((amount_read > 0) && (sp_write->dp_Res1 == sp_write->dp_Arg3)) { sp_read->dp_Arg2 = sp_write->dp_Arg2; /* ACTION_WRITE is finished with its */ /* buffer, use it in the next read. */ SendPkt(sp_read, in->fh_Type, myport); /* Send the next ACTION_READ and mark */ sp_read_busy = TRUE; /* the ACTION_READ as busy. */ /* Process Buffer. This example doesn't do anything with the data from the */ /* last ACTION_READ, it just passes it on to the STDOUT handler. */ sp_write->dp_Arg2 = (LONG)buf; /* Set up the ACTION_WRITE packet. */ sp_write->dp_Arg3 = amount_read; SendPkt(sp_write, out->fh_Type, myport); /* Send the next ACTION_WRITE and */ sp_write_busy = TRUE; /* mark the ACTION_WRITE as busy. */ } else /* A packet returned with a failure, so quit. */ { done = TRUE; if ((amount_read < 0) || (sp_write->dp_Res1 != sp_write->dp_Arg3)) ok = FALSE; } } } return(ok); } ULONG SyncLoop() { BOOL done = FALSE; ULONG ok = TRUE; BPTR lock; if (!((out->fh_Arg1) && (in->fh_Arg1))) /* Don't bother if in or out uses NIL: */ return(FALSE); sp_read->dp_Arg2 = (LONG)buffer; sp_read->dp_Arg3 = BUFSIZE*2; sp_write->dp_Arg2 = (LONG)buffer; if (lock = DupLockFromFH(in_start)) { UnLock(lock); /* Make sure this is a filesystem and not */ Seek(in_start, 0, OFFSET_BEGINNING); /* a console. If this is a filesystem, */ } /* go to the beginning of the file. */ while (!done) { if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) { done = TRUE; ok = FALSE; } else { SendPkt(sp_read, in->fh_Type, myport); WaitPort(myport); while (GetMsg(myport)); if (sp_read->dp_Res1 > 0) { sp_write->dp_Arg3 = sp_read->dp_Res1; SendPkt(sp_write, out->fh_Type, myport); WaitPort(myport); while (GetMsg(myport)); if (sp_write->dp_Res1 != sp_write->dp_Arg3) { done = TRUE; ok = FALSE; } } else { done = TRUE; if (sp_read->dp_Res1 < 0) ok = FALSE; } } } return(ok); }