?
Solved

WaitForSingleObject with timout on CD-ROM

Posted on 1999-01-07
4
Medium Priority
?
339 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
4 Comments
 
LVL 22

Accepted Solution

by:
nietod earned 8000 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

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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…
Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
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…
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…

764 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