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 )GetProcAd dress(hins tWNASPI32, "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_ExecSCSICm d *cmd) {
pfnSendASPI32Command(cmd);
if (cmd->SRB_Status == SS_PENDING) {
WaitForSingleObject(eventH andle, 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_ExecSC SICmd))) == 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 -----------------
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
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
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_ExecSCSICm
pfnSendASPI32Command(cmd);
if (cmd->SRB_Status == SS_PENDING) {
WaitForSingleObject(eventH
}
}
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_ExecSC
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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.
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 ;-)
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.)
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.)