553 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			553 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* f4write.c (c)Copyright Sequiter Software Inc., 1988-1996.  All rights reserved. */
 | |
| 
 | |
| #include "d4all.h"
 | |
| #ifdef __TURBOC__
 | |
|    #pragma hdrstop
 | |
| #endif
 | |
| 
 | |
| #ifdef S4TEMP
 | |
|    #include "t4test.h"
 | |
| #endif
 | |
| 
 | |
| #ifdef S4WINTEL
 | |
|    #ifndef S4IBMOS2
 | |
|       #ifndef __TURBOC__
 | |
|          #include <sys\locking.h>
 | |
|          #define S4LOCKING
 | |
|       #endif
 | |
|       #ifdef _MSC_VER
 | |
|          #include <sys\types.h>
 | |
|          #include <sys\locking.h>
 | |
|       #endif
 | |
|    #endif
 | |
|    #ifndef S4OFF_OPTIMIZE
 | |
|       #ifdef E4ANALYZE_ALL
 | |
|          #include <sys\stat.h>
 | |
|          #include <share.h>
 | |
|          #include <fcntl.h>
 | |
|       #endif
 | |
|    #endif
 | |
| 
 | |
| /*   #include <sys\stat.h>*/
 | |
| /*   #include <share.h>*/
 | |
| #endif
 | |
| 
 | |
| /*#include <fcntl.h>*/
 | |
| 
 | |
| /* returns the length written */
 | |
| static unsigned file4writeLowDo( FILE4 *f4, const long pos, const void *ptr, const unsigned len )
 | |
| {
 | |
|    unsigned int urc ;
 | |
| /* */
 | |
| /* */
 | |
| /* */
 | |
| 
 | |
|    #ifdef S4MULTI_THREAD
 | |
|       EnterCriticalSection( &f4->critical4file ) ;
 | |
|    #endif
 | |
| 
 | |
|    #ifdef S4WIN32
 | |
|       if ( SetFilePointer( (HANDLE)f4->hand, pos, NULL, FILE_BEGIN ) == (DWORD)-1 )
 | |
|    #else
 | |
| /* */
 | |
| /* */
 | |
| /* */
 | |
|          #ifdef S4WINDOWS
 | |
|             if ( _llseek( f4->hand, pos, 0 ) != pos )
 | |
|          #else
 | |
|             #ifdef S4LSEEK
 | |
|                if ( f4lseek( f4->hand, pos, 0, 1 ) != pos )
 | |
|             #else
 | |
|                if ( lseek( f4->hand, pos, 0 ) != pos )
 | |
|             #endif
 | |
|          #endif
 | |
| /* */
 | |
|    #endif
 | |
|    {
 | |
|       #ifdef S4MULTI_THREAD
 | |
|          LeaveCriticalSection( &f4->critical4file ) ;
 | |
|       #endif
 | |
|       return error4describe( f4->codeBase, e4write, E90615, f4->name, 0, 0 ) ;
 | |
|    }
 | |
| 
 | |
|    #ifdef S4WIN32
 | |
|       WriteFile( (HANDLE)f4->hand, ptr, len, (unsigned long *)&urc, NULL ) ;
 | |
|    #else
 | |
| /* */
 | |
| /* */
 | |
| /* */
 | |
| /* */
 | |
| /* */
 | |
| /* */
 | |
|          #ifdef S4WINDOWS
 | |
|             urc = (unsigned)_lwrite( f4->hand, (char *) ptr, len ) ;
 | |
|          #else
 | |
|             urc = (unsigned)write( f4->hand, ptr, len ) ;
 | |
|          #endif
 | |
| /* */
 | |
|    #endif
 | |
| 
 | |
|    #ifdef S4MULTI_THREAD
 | |
|       LeaveCriticalSection( &f4->critical4file ) ;
 | |
|    #endif
 | |
| 
 | |
|    return urc ;
 | |
| }
 | |
| 
 | |
| #ifdef P4ARGS_USED
 | |
|    #pragma argsused
 | |
| #endif
 | |
| int file4writeLow( FILE4 *f4, const long pos, const void *ptr, const unsigned len, const int checkDelayList, const int checkAdvanceList )
 | |
| {
 | |
|    unsigned urc ;
 | |
|    CODE4 *c4 ;
 | |
|    #ifdef S4WRITE_DELAY
 | |
|       FILE4WRITE_DELAY *writeDelay ;
 | |
|       LINK4 *delayLink ;
 | |
|    #endif
 | |
| 
 | |
|    c4 = f4->codeBase ;
 | |
| 
 | |
|    if ( f4->isReadOnly )
 | |
|       return error4( c4, e4write, E80606 ) ;
 | |
| 
 | |
|    #ifdef S4ADVANCE_READ
 | |
|       /* take care of over-writing advance-read buffers where appropriate */
 | |
|       if ( c4->advanceReadsEnabled )
 | |
|          file4advanceReadWriteOver( f4, pos, len, ptr, 1 ) ;
 | |
|    #endif
 | |
| 
 | |
|    #ifdef S4MULTI_THREAD
 | |
|       EnterCriticalSection( &f4->critical4file ) ;
 | |
|    #endif
 | |
| 
 | |
|    #ifdef S4WRITE_DELAY
 | |
|       if ( checkDelayList )  /* check to see if write request covers delayed areas */
 | |
|          if ( l4numNodes( &f4->delayWriteFileList ) != 0 )
 | |
|          {
 | |
|             for ( delayLink = (LINK4 *)l4first( &f4->delayWriteFileList ) ;; )
 | |
|             {
 | |
|                if ( delayLink == 0 )
 | |
|                   break ;
 | |
|                writeDelay = (FILE4WRITE_DELAY *)(delayLink - 1 ) ;
 | |
|                delayLink = (LINK4 *)l4next( &f4->delayWriteFileList, delayLink ) ;
 | |
| 
 | |
|                if ( pos >= ( writeDelay->pos + (long)writeDelay->len ) )  /* outside of block */
 | |
|                   continue ;
 | |
|                if ( ( pos + (long)len ) <= writeDelay->pos )  /* outside of block */
 | |
|                   continue ;
 | |
| 
 | |
|                /* now, if the delay piece belongs in the buffer, then read all
 | |
|                   the info before the delay piece, copy the delay piece over,
 | |
|                   and read all the info after the delay piece */
 | |
|                while ( writeDelay->usageFlag == r4inUse )  /* is being written to disk, just wait until it is done... */
 | |
|                   Sleep( 0 ) ;
 | |
| 
 | |
|                if ( writeDelay->usageFlag == r4finished ) /* is written to disk, so can just ignore */
 | |
|                   continue ;
 | |
| 
 | |
|                /* if the entire block is within the range, then can just delete
 | |
|                   it, otherwise must write it now (note that, due to constant
 | |
|                   contents of the delay-write buffer, cannot copy into it
 | |
|                   directly */
 | |
| 
 | |
|                if ( ( writeDelay->pos >= pos ) && ( pos + len >= writeDelay->pos + writeDelay->len ) ) /* remove */
 | |
|                   writeDelay->status = 0 ;
 | |
|                else /* otherwise must write the block now, and then continue */
 | |
|                   writeDelay->status = file4writeLow( writeDelay->file, writeDelay->pos, writeDelay->data, writeDelay->len, 0, 1 ) ;
 | |
| 
 | |
|                writeDelay->usageFlag = r4finished ;  /* outside of critical section, to allow a wait for completion while keeping the critical section */
 | |
|                l4remove( &c4->delayWriteList, writeDelay ) ;
 | |
|                l4remove( &f4->delayWriteFileList, &writeDelay->fileLink ) ;
 | |
|                writeDelay->completionRoutine( writeDelay ) ;
 | |
|                mem4free( c4->delayWriteMemory, writeDelay ) ;
 | |
|             }
 | |
|          }
 | |
|    #endif
 | |
| 
 | |
|    urc = file4writeLowDo( f4, pos, ptr, len ) ;
 | |
| 
 | |
|    #ifdef S4MULTI_THREAD
 | |
|       LeaveCriticalSection( &f4->critical4file ) ;
 | |
|    #endif
 | |
| 
 | |
|    if ( urc != len )
 | |
|       return error4describe( c4, e4write, E90615, f4->name, 0, 0 ) ;
 | |
| 
 | |
|    #ifndef S4OFF_MULTI
 | |
|       if ( f4->codeBase->fileFlush != 0 )
 | |
|          file4flush( f4 ) ;
 | |
|    #endif
 | |
| 
 | |
|    return 0 ;
 | |
| }
 | |
| 
 | |
| #ifndef S4OFF_OPTIMIZE
 | |
| #ifdef P4ARGS_USED
 | |
|    #pragma argsused
 | |
| #endif
 | |
| #ifdef S4WRITE_DELAY
 | |
| int file4writeOpt( FILE4 *f4, const long pos, const void *ptr, const unsigned len, int doDelay, S4DELAY_FUNCTION *completionRoutine, void *completionData )
 | |
| #else
 | |
| int file4writeOpt( FILE4 *f4, const long pos, const void *ptr, const unsigned len, int doDelay, void *completionRoutine, void *completionData )
 | |
| #endif
 | |
| {
 | |
|    int rc ;
 | |
|    CODE4 *c4 ;
 | |
|    #ifndef S4OFF_OPTIMIZE
 | |
|       unsigned urc ;
 | |
|       #ifdef E4ANALYZE_ALL
 | |
|          char buf[512] ;
 | |
|          long bufWritePos, bufWriteLen ;
 | |
|       #endif
 | |
|       #ifdef S4OPTIMIZE_STATS
 | |
|          DATA4 *stat ;
 | |
|       #endif
 | |
|    #endif
 | |
| 
 | |
|    c4 = f4->codeBase ;
 | |
|    rc = 0 ;
 | |
| 
 | |
|    if ( f4->doBuffer )
 | |
|    {
 | |
|       #ifdef S4OPTIMIZE_STATS
 | |
|          stat = c4->statusDbf ;
 | |
|          if ( stat != 0 )  /* track stats */
 | |
|          {
 | |
|             if ( f4 != &stat->dataFile->file )  /* don't do for the stat file! */
 | |
|             {
 | |
|                if ( d4appendStart( stat, 0 ) == 0 )
 | |
|                {
 | |
|                   f4assignChar( c4->typeFld, 'W' ) ;  /* high-level */
 | |
|                   f4assign( c4->fileNameFld, f4->name ) ;
 | |
|                   f4assignLong( c4->offsetFld, pos ) ;
 | |
|                   f4assignLong( c4->lengthFld, len ) ;
 | |
|                   d4append( stat ) ;
 | |
|                }
 | |
|             }
 | |
|          }
 | |
|       #endif
 | |
| 
 | |
|       urc = (unsigned int)opt4fileWrite( f4, pos, len, ptr, f4->bufferWrites ) ;
 | |
|       if ( urc != len )
 | |
|          return error4describe( c4, e4write, E90619, f4->name, 0, 0 ) ;
 | |
|    }
 | |
| 
 | |
|    if ( f4->doBuffer == 0 || f4->writeBuffer == 0 || f4->bufferWrites == 0 )
 | |
|    {
 | |
|       if ( f4->fileCreated == 0 )
 | |
|       {
 | |
|          c4->opt.forceCurrent = 1 ;
 | |
|          #ifdef S4CB51
 | |
|             file4temp( f4, c4, (char *)f4->name, 1 );
 | |
|          #else
 | |
|             file4tempLow( f4, c4, 1 ) ;
 | |
|          #endif
 | |
|          c4->opt.forceCurrent = 0 ;
 | |
|       }
 | |
| 
 | |
|       #ifdef E4ANALYZE_ALL
 | |
|          if ( f4->hasDup == 1 )
 | |
|          {
 | |
|             if ( file4len( f4 ) < pos )
 | |
|             {
 | |
|                /* need to null out any extra file contents in order for file verification for optimization
 | |
|                   to work properly */
 | |
|                memset( buf, 0, sizeof( buf ) ) ;
 | |
|                while ( file4len( f4 ) < pos )
 | |
|                {
 | |
|                   bufWritePos = file4len( f4 ) ;
 | |
|                   bufWriteLen = (pos - bufWritePos) ;
 | |
|                   if ( bufWriteLen > (long)sizeof( buf ) )
 | |
|                      bufWriteLen = (long)sizeof( buf ) ;
 | |
|                   if ( file4write( f4, bufWritePos, buf, (int)bufWriteLen ) != 0 )
 | |
|                      break ;
 | |
|                }
 | |
|             }
 | |
|          }
 | |
|       #endif  /* E4ANALYZE_ALL */
 | |
| 
 | |
|       #ifdef S4OPTIMIZE_STATS
 | |
|          stat = c4->statusDbf ;
 | |
|          if ( stat != 0 )  /* track stats */
 | |
|          {
 | |
|             if ( f4 != &stat->dataFile->file )  /* don't do for the stat file! */
 | |
|             {
 | |
|                if ( d4appendStart( stat, 0 ) == 0 )
 | |
|                {
 | |
|                   f4assignChar( c4->typeFld, 'X' ) ;  /* low-level */
 | |
|                   f4assign( c4->fileNameFld, f4->name ) ;
 | |
|                   f4assignLong( c4->offsetFld, pos ) ;
 | |
|                   f4assignLong( c4->lengthFld, len ) ;
 | |
|                   d4append( stat ) ;
 | |
|                }
 | |
|             }
 | |
|          }
 | |
|       #endif
 | |
|       #ifdef S4WRITE_DELAY
 | |
|          if ( doDelay == 1 )
 | |
|             rc = file4writeDelay( f4, pos, ptr, len, completionRoutine, completionData ) ;
 | |
|          else
 | |
|       #endif
 | |
|          rc = file4writeLow( f4, pos, ptr, len, 1, 1 ) ;
 | |
|    }
 | |
| 
 | |
|    #ifdef E4ANALYZE_ALL
 | |
|       if ( f4->hasDup == 1 )
 | |
|          if ( f4->doBuffer == 1 || f4->link.n == 0 )
 | |
|             if ( file4writePart( ptr, f4, pos, urc ) != 0 )
 | |
|                return error4( c4, e4opt, E80602 ) ;
 | |
|    #endif
 | |
| 
 | |
|    return rc ;
 | |
| }
 | |
| #endif /* S4OFF_OPTIMIZE */
 | |
| 
 | |
| int S4FUNCTION file4write( FILE4 *f4, const long pos, const void *ptr, const unsigned len )
 | |
| {
 | |
|    CODE4 *c4 ;
 | |
| 
 | |
|    #ifdef E4PARM_HIGH
 | |
|       if ( f4 == 0 )
 | |
|          return error4( 0, e4parm_null, E90619 ) ;
 | |
|       if ( pos < 0 || ( ptr == 0 && len ) )
 | |
|          return error4( f4->codeBase, e4parm, E90619 ) ;
 | |
|       if ( f4->hand < 0 )
 | |
|          return error4( f4->codeBase, e4parm, E90619 ) ;
 | |
|    #endif
 | |
| 
 | |
|    c4 = f4->codeBase ;
 | |
| 
 | |
|    if ( error4code( c4 ) < 0 )
 | |
|       return e4codeBase ;
 | |
| 
 | |
|    if ( f4->isReadOnly )
 | |
|       return error4( c4, e4write, E80606 ) ;
 | |
| 
 | |
|    #ifndef S4OFF_OPTIMIZE
 | |
|       #ifdef S4ADVANCE_READ
 | |
|          /* take care of over-writing advance-read buffers where appropriate */
 | |
|          if ( c4->advanceReadsEnabled )
 | |
|             file4advanceReadWriteOver( f4, pos, len, ptr, 1 ) ;
 | |
|       #endif
 | |
|       return file4writeOpt( f4, pos, ptr, len, 0, 0, 0 ) ;
 | |
|    #else
 | |
|       /* file4writeLow() itself takes care of the advance-read condition... */
 | |
|       return file4writeLow( f4, pos, ptr, len, 1, 0 ) ;
 | |
|    #endif
 | |
| }
 | |
| 
 | |
| #ifdef S4WRITE_DELAY
 | |
| 
 | |
| /* f4writed.c (c)Copyright Sequiter Software Inc., 1988-1996.  All rights reserved. */
 | |
| 
 | |
| #define MEM4DELAY_START 10
 | |
| #define MEM4DELAY_EXPAND 10
 | |
| 
 | |
| int file4writeDelay( FILE4 *f4, const long pos, const void *data, const unsigned int len, S4DELAY_FUNCTION *completionRoutine, void *completionData )
 | |
| {
 | |
|    FILE4WRITE_DELAY *writeDelay ;
 | |
|    LINK4 *delayLink ;
 | |
|    CODE4 *c4 ;
 | |
|    int rc ;
 | |
| 
 | |
|    c4 = f4->codeBase ;
 | |
| 
 | |
|    /* first check to see if the current delay-write over-rides an existing one */
 | |
|    if ( l4numNodes( &f4->delayWriteFileList ) != 0 )
 | |
|    {
 | |
|       EnterCriticalSection( &c4->critical4delayWriteList ) ;
 | |
| 
 | |
|       for ( delayLink = (LINK4 *)l4first( &f4->delayWriteFileList ) ;; )
 | |
|       {
 | |
|          if ( delayLink == 0 )
 | |
|             break ;
 | |
|          writeDelay = (FILE4WRITE_DELAY *)(delayLink - 1 ) ;
 | |
|          delayLink = (LINK4 *)l4next( &f4->delayWriteFileList, delayLink ) ;
 | |
| 
 | |
|          if ( pos >= ( writeDelay->pos + (long)writeDelay->len ) )  /* outside of block */
 | |
|             continue ;
 | |
|          if ( ( pos + (long)len ) <= writeDelay->pos )  /* outside of block */
 | |
|             continue ;
 | |
| 
 | |
|          while ( writeDelay->usageFlag == r4inUse )  /* is being written to disk, just wait until it is done... */
 | |
|             Sleep( 0 ) ;
 | |
| 
 | |
|          if ( writeDelay->usageFlag == r4finished ) /* is written to disk, so can just ignore */
 | |
|             continue ;
 | |
| 
 | |
|          /* we have a delay-write which overlaps the current request */
 | |
| 
 | |
|          /* if the entire block is within the range, then can just delete
 | |
|             it, otherwise must write it now (note that, due to constant
 | |
|             contents of the delay-write buffer, cannot copy into it
 | |
|             directly */
 | |
| 
 | |
|          if ( ( writeDelay->pos >= pos ) && ( pos + len >= writeDelay->pos + writeDelay->len ) ) /* remove */
 | |
|             writeDelay->status = 0 ;
 | |
|          else /* otherwise must write the block now, and then continue */
 | |
|             writeDelay->status = file4writeLow( writeDelay->file, writeDelay->pos, writeDelay->data, writeDelay->len, 0, 1 ) ;
 | |
| 
 | |
|          writeDelay->usageFlag = r4finished ;  /* outside of critical section, to allow a wait for completion while keeping the critical section */
 | |
|          l4remove( &f4->codeBase->delayWriteList, writeDelay ) ;
 | |
|          l4remove( &f4->delayWriteFileList, &writeDelay->fileLink ) ;
 | |
|          writeDelay->completionRoutine( writeDelay ) ;
 | |
|          mem4free( c4->delayWriteMemory, writeDelay ) ;
 | |
|       }
 | |
|       LeaveCriticalSection( &c4->critical4delayWriteList ) ;
 | |
|    }
 | |
| 
 | |
|    if ( c4->delayWriteMemory == 0 )
 | |
|       writeDelay = (FILE4WRITE_DELAY *)mem4createAlloc( c4, &c4->delayWriteMemory, MEM4DELAY_START, sizeof( FILE4WRITE_DELAY ), MEM4DELAY_EXPAND, 0 ) ;
 | |
|    else
 | |
|       writeDelay = (FILE4WRITE_DELAY *)mem4alloc( c4->delayWriteMemory ) ;
 | |
| 
 | |
|    if ( writeDelay == 0 )
 | |
|       return error4( c4, e4memory, E90624 ) ;
 | |
| 
 | |
|    writeDelay->file = f4 ;
 | |
|    writeDelay->data = (const char *)data ;
 | |
|    writeDelay->len = len ;
 | |
|    writeDelay->pos = pos ;
 | |
|    writeDelay->usageFlag = r4queued ;
 | |
|    writeDelay->completionRoutine = completionRoutine ;
 | |
|    writeDelay->completionData = completionData ;
 | |
| 
 | |
|    if ( c4->delayWritesEnabled == 0 )   /* delay-writes not enabled, so just write */
 | |
|    {
 | |
|       rc = file4writeLow( f4, pos, data, len, 1, 1 ) ;
 | |
|       completionRoutine( writeDelay ) ;
 | |
|       return rc ;
 | |
|    }
 | |
| 
 | |
|    EnterCriticalSection( &c4->critical4delayWriteList ) ;
 | |
| 
 | |
|    l4add( &c4->delayWriteList, writeDelay ) ;
 | |
|    l4add( &f4->delayWriteFileList, &writeDelay->fileLink ) ;
 | |
| 
 | |
|    LeaveCriticalSection( &c4->critical4delayWriteList ) ;
 | |
| 
 | |
|    SetEvent( c4->pendingWriteEvent ) ;  /* notify the write thread */
 | |
|    Sleep( 0 ) ;
 | |
| 
 | |
|    return 0 ;
 | |
| }
 | |
| 
 | |
| /* flush out any delayed-writes for the file in question */
 | |
| /* if doWrite is false, then the blocks are just dumped (eg. temp. files) */
 | |
| int file4writeDelayFlush( FILE4 *file, const int doWrite )
 | |
| {
 | |
|    FILE4WRITE_DELAY *writeDelay ;
 | |
|    LINK4 *writeDelayLink, *saved ;
 | |
|    CODE4 *c4 ;
 | |
| 
 | |
|    c4 = file->codeBase ;
 | |
| 
 | |
|    /* by obtaining the critical4delayWriteList critical section, we can
 | |
|       guarantee that the other thread will be suspended.  Therefore
 | |
|       the flushes for this file will get high-priority treatment, which
 | |
|       is what is desired
 | |
|    */
 | |
| 
 | |
|    EnterCriticalSection( &c4->critical4delayWriteList ) ;
 | |
| 
 | |
|    /* go through the list and manually flush each one belonging to our file */
 | |
| 
 | |
|    for ( writeDelayLink = (LINK4 *)l4first( &file->delayWriteFileList ) ;; )
 | |
|    {
 | |
|       if ( writeDelayLink == 0 )
 | |
|          break ;
 | |
|       writeDelay = (FILE4WRITE_DELAY *)(writeDelayLink - 1) ;
 | |
|       saved = (LINK4 *)l4next( &file->delayWriteFileList, writeDelayLink ) ;
 | |
|       if ( writeDelay->usageFlag == r4queued )  /* do ourselves */
 | |
|       {
 | |
|          l4remove( &file->delayWriteFileList, writeDelayLink ) ;
 | |
|          l4remove( &c4->delayWriteList, writeDelay ) ;
 | |
|          if ( doWrite == 1 )
 | |
|             writeDelay->status = file4writeLow( writeDelay->file, writeDelay->pos, writeDelay->data, writeDelay->len, 0, 1 ) ;
 | |
|          else
 | |
|             writeDelay->status = 0 ;
 | |
|          writeDelay->usageFlag = r4finished ;
 | |
|          writeDelay->completionRoutine( writeDelay ) ;
 | |
|          mem4free( c4->delayWriteMemory, writeDelay ) ;
 | |
|       }
 | |
|       writeDelayLink = saved ;
 | |
|    }
 | |
| 
 | |
|    LeaveCriticalSection( &c4->critical4delayWriteList ) ;
 | |
| 
 | |
|    for ( ;; )
 | |
|    {
 | |
|       /* now verify that the checkInUse write gets completed */
 | |
|       if ( l4numNodes( &file->delayWriteFileList ) == 0 )
 | |
|          break ;
 | |
|       #ifdef E4ANALYZE
 | |
|          if ( l4numNodes( &file->delayWriteFileList ) > 1 )   /* in theory impossible, it means delay-write has 2 files writing at same time */
 | |
|             return error4( c4, e4struct, E90624 ) ;
 | |
|       #endif
 | |
|       SetEvent( c4->pendingWriteEvent ) ;  /* notify the write thread */
 | |
|       Sleep( 0 ) ;   /* give up our time slice to get the delay-write going */
 | |
|    }
 | |
| 
 | |
|    return 0 ;
 | |
| }
 | |
| 
 | |
| /* main function for delay-write thread (i.e. paramater to CreateThread()) */
 | |
| #ifdef S4USE_INT_DELAY
 | |
|    int file4writeDelayMain( void *data )
 | |
| #else
 | |
|    void file4writeDelayMain( void *data )
 | |
| #endif
 | |
| {
 | |
|    CODE4 *c4 ;
 | |
|    FILE4WRITE_DELAY *writeDelay ;
 | |
| 
 | |
|    c4 = (CODE4 *)data ;
 | |
|    c4->delayWritesEnabled = 1 ;
 | |
| 
 | |
|    for ( ;; )
 | |
|    {
 | |
|       if ( l4numNodes( &c4->delayWriteList ) == 0 )
 | |
|       {
 | |
|          if ( c4->uninitializeDelayWrite == 1 )   /* shutdown */
 | |
|          {
 | |
|             SetEvent( c4->initUndoDelayWrite ) ;
 | |
|             #ifdef S4USE_INT_DELAY
 | |
|                return 0 ;
 | |
|             #else
 | |
|                return ;
 | |
|             #endif
 | |
|          }
 | |
|          else
 | |
|          {
 | |
|             WaitForSingleObject( c4->pendingWriteEvent, INFINITE ) ;
 | |
|             ResetEvent( c4->pendingWriteEvent ) ;
 | |
|          }
 | |
|       }
 | |
|       else  /* perform a write on the first available block */
 | |
|       {
 | |
|          EnterCriticalSection( &c4->critical4delayWriteList ) ;
 | |
|          writeDelay = (FILE4WRITE_DELAY *)l4first( &c4->delayWriteList ) ;
 | |
|          if ( writeDelay == 0 )   /* maybe got removed by main thread, so none to write... */
 | |
|          {
 | |
|             LeaveCriticalSection( &c4->critical4delayWriteList ) ;
 | |
|             Sleep( 0 ) ;
 | |
|             continue ;
 | |
|          }
 | |
|          writeDelay->usageFlag = r4inUse ;
 | |
|          LeaveCriticalSection( &c4->critical4delayWriteList ) ;
 | |
| 
 | |
|          writeDelay->status = file4writeLow( writeDelay->file, writeDelay->pos, writeDelay->data, writeDelay->len, 0, 1 ) ;
 | |
|          writeDelay->usageFlag = r4finished ;  /* outside of critical section, to allow a wait for completion while keeping the critical section */
 | |
|          EnterCriticalSection( &c4->critical4delayWriteList ) ;
 | |
|          l4remove( &c4->delayWriteList, writeDelay ) ;
 | |
|          l4remove( &writeDelay->file->delayWriteFileList, &writeDelay->fileLink ) ;
 | |
|          LeaveCriticalSection( &c4->critical4delayWriteList ) ;
 | |
|          writeDelay->completionRoutine( writeDelay ) ;
 | |
|          mem4free( c4->delayWriteMemory, writeDelay ) ;
 | |
|       }
 | |
|    }
 | |
| }
 | |
| 
 | |
| #endif /* S4WRITE_DELAY */
 |