Solved

WaitForSingleObject with timout on CD-ROM

Posted on 1999-01-07
4
325 Views
Last Modified: 2013-12-03
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 -----------------
0
Comment
Question by:styx
  • 3
4 Comments
 
LVL 22

Accepted Solution

by:
nietod earned 2000 total points
ID: 1418280
You are crashing because when the SendASPICmd(srbCmd) function times out in the ReadSector() function, you then go and delete the buffer (to clean up).  however the SendASPI32Command(cmd) is still executing asynchronously and will continue to try to use that memory.  

Let me know if you have any questions.
0
 
LVL 22

Expert Comment

by:nietod
ID: 1418281
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.
0
 

Author Comment

by:styx
ID: 1418282
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 ;-)

0
 
LVL 22

Expert Comment

by:nietod
ID: 1418283
>> 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.)
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

In this article, I will show how to use the Ribbon IDs Tool Window to assign the built-in Office icons to a ribbon button.  This tool will help us to find the OfficeImageId that corresponds to our desired built-in Office icon. The tool is part of…
With most software applications trying to cater to multiple user needs nowadays, the focus is to make them as configurable as possible. For e.g., when creating Silverlight applications which will connect to WCF services, the service end point usuall…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now