Link to home
Start Free TrialLog in
Avatar of styx
styx

asked on

WaitForSingleObject with timout on CD-ROM

I have written an application which uses ASPI (from the WNASPI32.DLL) to read data from a CD-ROM drive. All is well except that some drives take an excessive time to return if there is an error on the disc. I tried to put a time-out of 1 second on the 'WaitForSingleObject' rather than the original 'INFINITE'. When I did this my application starts to crash in ring 0.

On debugging the program it seems to behave OK up-to the first time that the WaitForSingleObject returns with a time-out. Sometime after this the program crashes. Unfortunately if I step through the code it all works, this seems to indicate a timing problem that I am finding very difficult to trace, hence the high points for the answer!

Program crashes in same way on both W95 and W98.

The full code is:-
---------------- cut here -------------
#include <windows.h>
#include <stdio.h>

typedef void *LPSRB;

#define SS_PENDING                  0x00        // SRB being processed
#define SS_COMP                     0x01        // SRB completed without error

#define SENSE_LEN                   14          // Default sense buffer length
#define SRB_EVENT_NOTIFY            0x40        // Enable ASPI event notification
#define SRB_DIR_IN                  0x08        // Transfer from SCSI target to host
#define SC_EXEC_SCSI_CMD            0x02        // Execute SCSI command

typedef struct
{
    BYTE    SRB_Cmd;                // ASPI command code = SC_EXEC_SCSI_CMD
    BYTE    SRB_Status;             // ASPI command status byte
    BYTE    SRB_HaId;               // ASPI host adapter number
    BYTE    SRB_Flags;              // ASPI request flags
    DWORD   SRB_Hdr_Rsvd;           // Reserved
    BYTE    SRB_Target;             // Target's SCSI ID
    BYTE    SRB_Lun;                // Target's LUN number
    WORD    SRB_Rsvd1;              // Reserved for Alignment
    DWORD   SRB_BufLen;             // Data Allocation Length
    LPBYTE  SRB_BufPointer;         // Data Buffer Pointer
    BYTE    SRB_SenseLen;           // Sense Allocation Length  
    BYTE    SRB_CDBLen;             // CDB Length
    BYTE    SRB_HaStat;             // Host Adapter Status
    BYTE    SRB_TargStat;           // Target Status
    LPVOID  SRB_PostProc;           // Post routine
    BYTE    SRB_Rsvd2[20];          // Reserved for alignment
    BYTE    CDBByte[16];            // SCSI CDB
    BYTE    SenseArea[SENSE_LEN+2]; // Request Sense buffer
}
SRB_ExecSCSICmd, *PSRB_ExecSCSICmd;


#define      PAGE_SIZE                  4096
typedef DWORD (_cdecl *SEND_ASPI_32_COMMAND_PROC)(LPSRB);

void      ReadSector(int *retVal, long sector, int device, int unit, BYTE *bufPtr, int sectorSize);

BYTE      buffer[PAGE_SIZE];                              // General purpose buffer. sector data and pe file data
HANDLE      eventHandle;
SEND_ASPI_32_COMMAND_PROC            pfnSendASPI32Command;
HINSTANCE                                    hinstWNASPI32;

void main(void) {
      long                  sector;
      int                        rv;
      int                        device;
      int                        unit;

      device = 0;
      unit = 0;

      eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
      hinstWNASPI32 = LoadLibrary("WNASPI32");
      if (!hinstWNASPI32) {
            printf("Cannot load wnaspi32.dll\n");
            exit(0);
      }
      pfnSendASPI32Command = (SEND_ASPI_32_COMMAND_PROC)GetProcAddress(hinstWNASPI32, "SendASPI32Command");

      if (!pfnSendASPI32Command) {
            printf("Cannot get address of SendASPI32Command\n");
            exit(0);
      }

      //
      // Test disc using aspi calls
      //
      for (sector = 16; sector < 500; sector++) {
            ReadSector(&rv, sector, device, unit, buffer, 2048);
            if (rv == SS_COMP) {
                  printf(".");
            } else {
                  printf("*");
            }
      }
}

void SendASPICmd(SRB_ExecSCSICmd *cmd) {
       pfnSendASPI32Command(cmd);
      if (cmd->SRB_Status == SS_PENDING) {
            WaitForSingleObject(eventHandle, INFINITE);
      }
}

void      ReadSector(int *retVal, long sector, int device, int unit, BYTE *bufPtr, int sectorSize) {
      SRB_ExecSCSICmd      *srbCmd = NULL;
      BYTE      *buffer = NULL;

      *retVal = 0;
      if ((srbCmd = (SRB_ExecSCSICmd *)malloc(sizeof(SRB_ExecSCSICmd))) == NULL) {
            goto TIDY_EXIT;
      }
      if ((buffer = (BYTE *)malloc(sectorSize)) == NULL) {
            goto TIDY_EXIT;
      }

      memset(srbCmd, 0, sizeof(SRB_ExecSCSICmd));
      memset(buffer, 0, sectorSize);

      srbCmd->SRB_Cmd                  = SC_EXEC_SCSI_CMD;
      srbCmd->SRB_HaId            = device;
      srbCmd->SRB_Flags            = SRB_EVENT_NOTIFY | SRB_DIR_IN;
      srbCmd->SRB_Target            = unit;
      srbCmd->SRB_BufLen            = sectorSize;
      srbCmd->SRB_BufPointer      = buffer;
      srbCmd->SRB_SenseLen      = 14;
      srbCmd->SRB_CDBLen            = 10;
      srbCmd->SRB_PostProc      = eventHandle;
      srbCmd->CDBByte[0]            = 40;
      srbCmd->CDBByte[2]            = HIBYTE(HIWORD(sector));
      srbCmd->CDBByte[3]            = LOBYTE(HIWORD(sector));
      srbCmd->CDBByte[4]            = HIBYTE(LOWORD(sector));
      srbCmd->CDBByte[5]            = LOBYTE(LOWORD(sector));
      srbCmd->CDBByte[8]            = 1;

      SendASPICmd(srbCmd);

      *retVal= srbCmd->SRB_Status;
      memcpy(bufPtr, buffer, sectorSize);
TIDY_EXIT:
      if (srbCmd) free(srbCmd);
      if (buffer) free(buffer);
}
--------------- cut here -----------------
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of nietod
nietod

Wow, 2000 pts, I thought it was 200.  That hardly seems like a 2000 point answer.  But I'm not sure what else to say, unless you don't understand what I wrote.
Avatar of styx

ASKER

2000 points may seem a lot for such a simple answer. However as far as I am concerned it was well worth it since I had not be able to 'see the wood for the trees' for several days.
I knew your answer was correct as soon as I saw it, as indeed it turned out to be.

Having gotten past that problem however I then found that I was left with unfinished SRBs on the SCSI bus by timing out the event. I first thought I could send an ABORT SRB but the documentation told me that they rarely work! I concluded that I must set target timeouts rather than timeout the event.

The bottom line now that this problem has been solved is that I am throwing this approach away and using an alternative method!

This must be the most 'expensive' throw-away question on EE :-)

Thanks again for your timely help.

ps. This question should now put you into second place ;-)

>> This must be the most 'expensive' throw-away question on EE :-)
It may have been the most expensive period.  I've seen a few 500 point questions, I don't think I've ever seen anything more than that.  EE doesn't even show 4 digit point questions correctly.  One the question screen it was listed as 200 points not as 2000.  (Which is why I was surprised to see it was for 2000 after I answered.)