home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD v1.2 / amidev_cd_12.iso / reference / amiga_mail_vol2 / ii-95 / compareio.c < prev    next >
C/C++ Source or Header  |  1996-01-30  |  13KB  |  315 lines

  1. ;/* CompareIO.c - Execute me to compile me with SAS/C 6.56
  2. sc DATA=FAR NMINC STRMERGE STREQ NOSTKCHK SAVEDS IGNORE=73 CompareIO.c
  3. slink FROM LIB:c.o,CompareIO.o TO CompareIO LIBRARY LIB:sc.lib,LIB:amiga.lib,lib:debug.lib
  4. quit ;*/
  5.  
  6. /* (c)  Copyright 1992 Commodore-Amiga, Inc.   All rights reserved.       */
  7. /* The information contained herein is subject to change without notice,  */
  8. /* and is provided "as is" without warranty of any kind, either expressed */
  9. /* or implied.  The entire risk as to the use of this information is      */
  10. /* assumed by the user.                                                   */
  11.  
  12. /* CompareIO.c uses packet level I/O to copy the standard input channel to the */
  13. /* standard output channel (as set up by the standard startup code, c.o).      */
  14. /* CompareIO uses both synchronous and asynchronous I/O to perform the copy    */
  15. /* and reports the time it takes to do each.                                   */
  16.  
  17.  
  18. #include <exec/types.h>
  19. #include <dos/dosextens.h>
  20. #include <devices/timer.h>
  21.  
  22. #include <clib/dos_protos.h>
  23. #include <clib/timer_protos.h>
  24. #include <clib/exec_protos.h>
  25. #include <clib/alib_protos.h>
  26. #include <clib/alib_stdio_protos.h>
  27.  
  28. #ifdef LATTICE
  29. int CXBRK(void) { return(0); }                    /* Disable Lattice CTRL/C handling */
  30. void chkabort(void) { return; }
  31. #endif
  32.  
  33.  
  34. #define BUFSIZE 8192
  35.  
  36. UBYTE *vers = "\0$VER: CompareIO 37.14 Nov-12-92";
  37.  
  38. ULONG AsyncLoop(void);
  39. ULONG SyncLoop(void);
  40.  
  41. extern struct Library *DOSBase;
  42. struct Library *TimerBase;
  43.  
  44. struct MsgPort *myport;
  45.  
  46. struct FileHandle *in, *out;
  47. BPTR results, in_start, out_start;
  48.  
  49. struct DosPacket *sp_read, *sp_write;
  50.  
  51. UBYTE buffer[BUFSIZE*2];
  52.  
  53. struct timeval time_start, time_finish;
  54. struct timerequest timer_io;
  55.  
  56. ULONG vfprintfargs[2]; /* An array of pointers */
  57.  
  58.  
  59. void main(void)
  60. {
  61.   if (DOSBase->lib_Version >= 37)
  62.   {
  63.     if (results = Open("*", MODE_NEWFILE)) /* This is for printing the results.      */
  64.     {                                      /* Since the example is already using the */
  65.                                            /* standard I/O channels for its own      */
  66.                                            /* purposes, there needs to be a separate */
  67.                                            /* channel to output the results.         */
  68.       if (!OpenDevice(TIMERNAME, UNIT_MICROHZ, &timer_io, 0L))
  69.       {
  70.         TimerBase = (struct Library *)timer_io.tr_node.io_Device;
  71.  
  72.         if (myport = CreateMsgPort())
  73.         {
  74.           in_start  = Input();  /* Need to hold on to input and output so no one can */
  75.           out_start = Output(); /* change them while this example is using them.     */
  76.           if (in = (struct FileHandle *)BADDR(in_start))
  77.           {
  78.             if (out = (struct FileHandle *)BADDR(out_start))
  79.             {
  80.               if (sp_read = AllocDosObject(DOS_STDPKT, NULL))
  81.               {
  82.                 if (sp_write = AllocDosObject(DOS_STDPKT, NULL))
  83.                 {
  84.                        /* When AllocDosObject() allocates a StandardPacket, it takes */
  85.                        /* care of linking together the Message and DosPacket.        */
  86.                        /* AllocDosObject() points the DosPacket's dp_Link field at   */
  87.                        /* the StandardPacket's Message structure.  It also points    */
  88.                        /* the Message's mn_Node.ln_Name field at the DosPacket:      */
  89.                        /*                 sp_read->dp_Link = sp_Msg;                 */
  90.                        /*                 sp_Msg->mn_Node.ln_Name = (STRPTR)sp_read; */
  91.  
  92.                   sp_read->dp_Type = ACTION_READ;   /* Fill out ACTION_READ packet.  */
  93.                   sp_read->dp_Arg1 = in->fh_Arg1;
  94.  
  95.                   sp_write->dp_Type = ACTION_WRITE; /* Fill out ACTION_WRITE packet. */
  96.                   sp_write->dp_Arg1 = out->fh_Arg1;
  97.  
  98.                   VFPrintf(results, "\n      Method     Seconds   Micros\n", NULL);
  99.                   VFPrintf(results,   "   ------------  -------   ------\n", NULL);
  100.  
  101.                   GetSysTime(&time_start);
  102.                   if (AsyncLoop())
  103.                   {
  104.                     GetSysTime(&time_finish);
  105.                     SubTime(&time_finish, &time_start);
  106.                     vfprintfargs[0] = time_finish.tv_secs;
  107.                     vfprintfargs[1] = time_finish.tv_micro;
  108.                     VFPrintf(results,
  109.                              "   Asynchronous:  %3ld     %7ld\n", &vfprintfargs[0]);
  110.  
  111.                     GetSysTime(&time_start);
  112.                     if (SyncLoop())
  113.                     {
  114.                       GetSysTime(&time_finish);
  115.                       SubTime(&time_finish, &time_start);
  116.                       vfprintfargs[0] = time_finish.tv_secs;
  117.                       vfprintfargs[1] = time_finish.tv_micro;
  118.                       VFPrintf(results,
  119.                                "    Synchronous:  %3ld     %7ld\n", &vfprintfargs[0]);
  120.                     }
  121.                     else
  122.                       VFPrintf(results, "         *******  Stop  ******\n", NULL);
  123.                   }
  124.                   else
  125.                     VFPrintf(results, "         *******  Stop  ******\n", NULL);
  126.  
  127.  
  128.                   FreeDosObject(DOS_STDPKT, sp_write);
  129.                 }
  130.                 FreeDosObject(DOS_STDPKT, sp_read);
  131.               }
  132.             }
  133.           }
  134.           DeleteMsgPort(myport);
  135.         }
  136.         CloseLibrary(TimerBase);
  137.       }
  138.       Close(results);
  139.     }
  140.   }
  141. }
  142.  
  143. ULONG AsyncLoop()
  144. {
  145. struct StandardPacket *mysp;
  146. UBYTE *buf;
  147.  
  148. LONG amount_read;
  149.  
  150. BOOL sp_read_busy  = TRUE,                    /*    Is the ACTION_READ packet busy?  */
  151.      sp_write_busy = FALSE,                   /*    Is the ACTION_WRITE packet busy? */
  152.      done          = FALSE;                   /*    Is the program finished?         */
  153. ULONG ok           = TRUE;
  154.  
  155.  
  156.   if (!((out->fh_Arg1) && (in->fh_Arg1)))    /* Don't bother if in or out uses NIL:  */
  157.     return(FALSE);
  158.   sp_read->dp_Arg2 = (LONG)buffer;   /* The buffer to fill in.           */
  159.   sp_read->dp_Arg3 = BUFSIZE;        /* The size of the Arg2 buffer.     */
  160.  
  161.  
  162.   SendPkt(sp_read, in->fh_Type, myport);   /* Send initial read request. */
  163.  
  164.   sp_write->dp_Type = ACTION_WRITE; /* Fill out the ACTION_WRITE packet. */
  165.   sp_write->dp_Arg1 = out->fh_Arg1;
  166.   sp_write->dp_Arg2 = (LONG)&buffer[BUFSIZE];  /* Arg2 points to the buffer to write */
  167.   sp_write->dp_Arg3 = 0L;                      /* out.  At first glance, it might    */
  168.   sp_write->dp_Res1 = 0L;                      /* seem odd to bother setting Arg2    */
  169.                                       /* when the program hasn't read anything yet.  */
  170.                                       /* This is to set up for the main loop.  The   */
  171.                                       /* main loop swaps the ACTION_READ buffer with */
  172.                                       /* the ACTION_WRITE buffer when it receives    */
  173.                                       /* a completed read.  Likewise, dp_Arg3 and    */
  174.                                       /* dp_Res1 are set to make the ACTION_READ     */
  175.                                       /* look like it has a valid return value so    */
  176.                                       /* main loop won't fail the first time through */
  177.                                       /* the loop.                                   */
  178.  
  179.                 /* main() has already taken care of sending the initial read to the  */
  180.                 /* handler.  Because we need the data from that read before we can   */
  181.   while (!done) /* do anything, the first thing to do is wait for its return.        */
  182.   {
  183.     do                                   /*      Wait for the ACTION_READ to return. */
  184.     {
  185.       WaitPort(myport);
  186.       while (mysp = (struct StandardPacket *)GetMsg(myport))   /* ...empty the port. */
  187.       {
  188.                           /* If this message is the ACTION_READ packet, mark it as   */
  189.                           /* no longer busy so we can use it to start another read.  */
  190.         if (mysp->sp_Pkt.dp_Type == ACTION_READ)    sp_read_busy  = FALSE;
  191.  
  192.                           /* If this message is instead the ACTION_WRITE packet,     */
  193.                           /* mark it as not busy.  We need to check for this because */
  194.                           /* the WRITE_PACKET from the previous interation through   */
  195.                           /* the loop might have come back before the ACTION_WRITE   */
  196.                           /* from the previous interation.                           */
  197.         else
  198.           if (mysp->sp_Pkt.dp_Type == ACTION_WRITE) sp_write_busy = FALSE;
  199.       }
  200.     } while (sp_read_busy);                   /* End of "wait for ACTION_READ" loop. */
  201.  
  202.                                           /* Get ready to send the next ACTION_READ. */
  203.     buf = (UBYTE *)(sp_read->dp_Arg2);    /* Hold on to the important stuff from the */
  204.     amount_read = sp_read->dp_Res1;       /* ACTION_READ we just got back so we can  */
  205.                                           /* reuse the packet to start a new read    */
  206.                                           /* while processing the last read's data.  */
  207.  
  208.     while (sp_write_busy)          /* Because this example only uses two buffers and */
  209.     {                              /* the ACTION_WRITE might be using one of them,   */
  210.                                    /* this example has to wait for an outstanding    */
  211.                                    /* ACTION_WRITE to return before reusing the      */
  212.                                    /* ACTION_WRITE packet's buffer.                  */
  213.       WaitPort(myport);
  214.       while (mysp = (struct StandardPacket *)GetMsg(myport))
  215.         if (mysp->sp_Pkt.dp_Type == ACTION_WRITE) sp_write_busy = FALSE;
  216.     }
  217.  
  218.     if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
  219.     {
  220.       done = TRUE;
  221.       ok   = FALSE;
  222.     }
  223.     else
  224.     {
  225.                /* This tests the return values from the ACTION_READ and ACTION_WRITE */
  226.                /* packets.  The ACTION_READ packet returns the number of bytes it    */
  227.                /* read in dp_Res1, which was copied earlier into amount_read. If it  */
  228.                /* is 0, the read packet found the EOF.  If it is negative, there was */
  229.                /* an error.  In the case of ACTION_WRITE, an error occurs if the     */
  230.                /* number of bytes that ACTION_WRITE was supposed to write (Arg3)     */
  231.                /* does not match the actual number it wrote, which ACTION_WRITE re-  */
  232.                /* turns in Res1.  This test is the reason dp_Res1 and dp_Arg3 were   */
  233.                /* set to zero when the ACTION_WRITE packet was set up in main().     */
  234.       if ((amount_read > 0) && (sp_write->dp_Res1 == sp_write->dp_Arg3))
  235.       {
  236.         sp_read->dp_Arg2 = sp_write->dp_Arg2;  /* ACTION_WRITE is finished with its  */
  237.                                                /* buffer, use it in the next read.   */
  238.  
  239.         SendPkt(sp_read, in->fh_Type, myport); /* Send the next ACTION_READ and mark */
  240.         sp_read_busy = TRUE;                   /* the ACTION_READ as busy.           */
  241.  
  242.         /* Process Buffer.  This example doesn't do anything with the data from the  */
  243.         /* last ACTION_READ, it just passes it on to the STDOUT handler.             */
  244.  
  245.  
  246.         sp_write->dp_Arg2 = (LONG)buf;         /*    Set up the ACTION_WRITE packet. */
  247.         sp_write->dp_Arg3 = amount_read;
  248.         SendPkt(sp_write, out->fh_Type, myport);   /* Send the next ACTION_WRITE and */
  249.         sp_write_busy = TRUE;                      /* mark the ACTION_WRITE as busy. */
  250.       }
  251.       else                             /* A packet returned with a failure, so quit. */
  252.       {
  253.         done = TRUE;
  254.         if ((amount_read < 0) || (sp_write->dp_Res1 != sp_write->dp_Arg3)) ok = FALSE;
  255.       }
  256.     }
  257.   }
  258.   return(ok);
  259. }
  260.  
  261. ULONG SyncLoop()
  262. {
  263. BOOL  done = FALSE;
  264. ULONG ok   = TRUE;
  265. BPTR lock;
  266.  
  267.   if (!((out->fh_Arg1) && (in->fh_Arg1)))    /* Don't bother if in or out uses NIL:  */
  268.     return(FALSE);
  269.  
  270.   sp_read->dp_Arg2 = (LONG)buffer;
  271.   sp_read->dp_Arg3 = BUFSIZE*2;
  272.   sp_write->dp_Arg2 = (LONG)buffer;
  273.  
  274.   if (lock = DupLockFromFH(in_start))
  275.   {
  276.     UnLock(lock);                          /* Make sure this is a filesystem and not */
  277.     Seek(in_start, 0, OFFSET_BEGINNING);   /* a console.  If this is a filesystem,   */
  278.   }                                        /* go to the beginning of the file.       */
  279.  
  280.   while (!done)
  281.   {
  282.     if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
  283.     {
  284.       done = TRUE;
  285.       ok = FALSE;
  286.     }
  287.     else
  288.     {
  289.       SendPkt(sp_read, in->fh_Type, myport);
  290.       WaitPort(myport);
  291.       while (GetMsg(myport));
  292.  
  293.       if (sp_read->dp_Res1 > 0)
  294.       {
  295.         sp_write->dp_Arg3 = sp_read->dp_Res1;
  296.         SendPkt(sp_write, out->fh_Type, myport);
  297.         WaitPort(myport);
  298.         while (GetMsg(myport));
  299.         if (sp_write->dp_Res1 != sp_write->dp_Arg3)
  300.         {
  301.           done = TRUE;
  302.           ok   = FALSE;
  303.         }
  304.       }
  305.       else
  306.       {
  307.         done = TRUE;
  308.         if (sp_read->dp_Res1 < 0) ok = FALSE;
  309.       }
  310.     }
  311.   }
  312.   return(ok);
  313. }
  314.  
  315.