home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / biblioteki / c_library / asyncio / source / openasyncfh.c < prev    next >
C/C++ Source or Header  |  1977-12-31  |  6KB  |  216 lines

  1. #include "async.h"
  2.  
  3. #ifdef ASIO_NOEXTERNALS
  4. AsyncFile*
  5. AS_OpenAsyncFH(
  6.     BPTR handle,
  7.     OpenModes mode,
  8.     LONG bufferSize,
  9.     BOOL closeIt,
  10.     struct ExecBase *SysBase,
  11.     struct DosLibrary *DOSBase )
  12. #else
  13. AsyncFile *
  14. AS_OpenAsyncFH( BPTR handle, OpenModes mode, LONG bufferSize, BOOL closeIt )
  15. #endif
  16. {
  17.     struct FileHandle    *fh;
  18.     AsyncFile        *file = NULL;
  19.     BPTR    lock = NULL;
  20.     LONG    blockSize, blockSize2;
  21.     D_S( struct InfoData, infoData );
  22.  
  23.     if( mode == MODE_READ )
  24.     {
  25.         if( handle )
  26.         {
  27.             lock = DupLockFromFH( handle );
  28.         }
  29.     }
  30.     else
  31.     {
  32.         if( mode == MODE_APPEND )
  33.         {
  34.             /* in append mode, we open for writing, and then seek to the
  35.              * end of the file. That way, the initial write will happen at
  36.              * the end of the file, thus extending it
  37.              */
  38.  
  39.             if( handle )
  40.             {
  41.                 if( Seek( handle, 0, OFFSET_END ) < 0 )
  42.                 {
  43.                     if( closeIt )
  44.                     {
  45.                         Close( handle );
  46.                     }
  47.  
  48.                     handle = NULL;
  49.                 }
  50.             }
  51.         }
  52.  
  53.         /* we want a lock on the same device as where the file is. We can't
  54.          * use DupLockFromFH() for a write-mode file though. So we get sneaky
  55.          * and get a lock on the parent of the file
  56.          */
  57.         if( handle )
  58.         {
  59.             lock = ParentOfFH( handle );
  60.         }
  61.     }
  62.  
  63.     if( handle )
  64.     {
  65.         /* if it was possible to obtain a lock on the same device as the
  66.          * file we're working on, get the block size of that device and
  67.          * round up our buffer size to be a multiple of the block size.
  68.          * This maximizes DMA efficiency.
  69.          */
  70.  
  71.         blockSize = 512;
  72.         blockSize2 = 1024;
  73.  
  74.         if( lock )
  75.         {
  76.             if( Info( lock, infoData ) )
  77.             {
  78.                 blockSize = infoData->id_BytesPerBlock;
  79.                 blockSize2 = blockSize * 2;
  80.                 bufferSize = ( ( bufferSize + blockSize2 - 1 ) / blockSize2 ) * blockSize2;
  81.             }
  82.  
  83.             UnLock(lock);
  84.         }
  85.  
  86.         /* now allocate the ASyncFile structure, as well as the read buffers.
  87.          * Add 15 bytes to the total size in order to allow for later
  88.          * quad-longword alignement of the buffers
  89.          */
  90.  
  91.         for( ;; )
  92.         {
  93.             if( file = AllocVec( sizeof( AsyncFile ) + bufferSize + 15, MEMF_PUBLIC | MEMF_ANY ) )
  94.             {
  95.                 break;
  96.             }
  97.             else
  98.             {
  99.                 if( bufferSize > blockSize2 )
  100.                 {
  101.                     bufferSize -= blockSize2;
  102.                 }
  103.                 else
  104.                 {
  105.                     break;
  106.                 }
  107.             }
  108.         }
  109.  
  110.         if( file )
  111.         {
  112.             file->af_File        = handle;
  113.             file->af_ReadMode    = ( mode == MODE_READ );
  114.             file->af_BlockSize    = blockSize;
  115.             file->af_CloseFH    = closeIt;
  116.  
  117.             /* initialize the ASyncFile structure. We do as much as we can here,
  118.              * in order to avoid doing it in more critical sections
  119.              *
  120.              * Note how the two buffers used are quad-longword aligned. This
  121.              * helps performance on 68040 systems with copyback cache. Aligning
  122.              * the data avoids a nasty side-effect of the 040 caches on DMA.
  123.              * Not aligning the data causes the device driver to have to do
  124.              * some magic to avoid the cache problem. This magic will generally
  125.              * involve flushing the CPU caches. This is very costly on an 040.
  126.              * Aligning things avoids the need for magic, at the cost of at
  127.              * most 15 bytes of ram.
  128.              */
  129.  
  130.             fh            = BADDR( file->af_File );
  131.             file->af_Handler    = fh->fh_Type;
  132.             file->af_BufferSize    = ( ULONG ) bufferSize / 2;
  133.             file->af_Buffers[ 0 ]    = ( APTR ) ( ( ( ULONG ) file + sizeof( AsyncFile ) + 15 ) & 0xfffffff0 );
  134.             file->af_Buffers[ 1 ]    = file->af_Buffers[ 0 ] + file->af_BufferSize;
  135.             file->af_CurrentBuf    = 0;
  136.             file->af_SeekOffset    = 0;
  137.             file->af_PacketPending    = FALSE;
  138. #ifdef ASIO_NOEXTERNALS
  139.             file->af_SysBase    = SysBase;
  140.             file->af_DOSBase    = DOSBase;
  141. #endif
  142.  
  143.             /* this is the port used to get the packets we send out back.
  144.              * It is initialized to PA_IGNORE, which means that no signal is
  145.              * generated when a message comes in to the port. The signal bit
  146.              * number is initialized to SIGB_SINGLE, which is the special bit
  147.              * that can be used for one-shot signalling. The signal will never
  148.              * be set, since the port is of type PA_IGNORE. We'll change the
  149.              * type of the port later on to PA_SIGNAL whenever we need to wait
  150.              * for a message to come in.
  151.              *
  152.              * The trick used here avoids the need to allocate an extra signal
  153.              * bit for the port. It is quite efficient.
  154.              */
  155.  
  156.             file->af_PacketPort.mp_MsgList.lh_Head        = ( struct Node * ) &file->af_PacketPort.mp_MsgList.lh_Tail;
  157.             file->af_PacketPort.mp_MsgList.lh_Tail        = NULL;
  158.             file->af_PacketPort.mp_MsgList.lh_TailPred    = ( struct Node * ) &file->af_PacketPort.mp_MsgList.lh_Head;
  159.             file->af_PacketPort.mp_Node.ln_Type        = NT_MSGPORT;
  160.             /* Avoid problems with SnoopDos */
  161.             file->af_PacketPort.mp_Node.ln_Name        = NULL;
  162.             file->af_PacketPort.mp_Flags            = PA_IGNORE;
  163.             file->af_PacketPort.mp_SigBit            = SIGB_SINGLE;
  164.             file->af_PacketPort.mp_SigTask            = FindTask( NULL );
  165.  
  166.             file->af_Packet.sp_Pkt.dp_Link            = &file->af_Packet.sp_Msg;
  167.             file->af_Packet.sp_Pkt.dp_Arg1            = fh->fh_Arg1;
  168.             file->af_Packet.sp_Pkt.dp_Arg3            = file->af_BufferSize;
  169.             file->af_Packet.sp_Pkt.dp_Res1            = 0;
  170.             file->af_Packet.sp_Pkt.dp_Res2            = 0;
  171.             file->af_Packet.sp_Msg.mn_Node.ln_Name        = ( STRPTR ) &file->af_Packet.sp_Pkt;
  172.             file->af_Packet.sp_Msg.mn_Node.ln_Type        = NT_MESSAGE;
  173.             file->af_Packet.sp_Msg.mn_Length        = sizeof( struct StandardPacket );
  174.  
  175.             if( mode == MODE_READ )
  176.             {
  177.                 /* if we are in read mode, send out the first read packet to
  178.                  * the file system. While the application is getting ready to
  179.                  * read data, the file system will happily fill in this buffer
  180.                  * with DMA transfers, so that by the time the application
  181.                  * needs the data, it will be in the buffer waiting
  182.                  */
  183.  
  184.                 file->af_Packet.sp_Pkt.dp_Type    = ACTION_READ;
  185.                 file->af_BytesLeft        = 0;
  186.  
  187.                 /* MH: We set the offset to the buffer not being filled, in
  188.                  * order to avoid special case code in SeekAsync. ReadAsync
  189.                  * isn't affected by this, since af_BytesLeft == 0.
  190.                  */
  191.                 file->af_Offset = file->af_Buffers[ 1 ];
  192.  
  193.                 if( file->af_Handler )
  194.                 {
  195.                     AS_SendPacket( file, file->af_Buffers[ 0 ] );
  196.                 }
  197.             }
  198.             else
  199.             {
  200.                 file->af_Packet.sp_Pkt.dp_Type    = ACTION_WRITE;
  201.                 file->af_BytesLeft        = file->af_BufferSize;
  202.                 file->af_Offset            = file->af_Buffers[ 0 ];
  203.             }
  204.         }
  205.         else
  206.         {
  207.             if( closeIt )
  208.             {
  209.                 Close( handle );
  210.             }
  211.         }
  212.     }
  213.  
  214.     return( file );
  215. }
  216.