From: rri!potter AT vtserf DOT cc DOT vt DOT edu (Mark Allen Potter) Subject: Re: Catching disk errors To: djgpp AT sun DOT soe DOT clarkson DOT edu (DJ G++ Mailing List ) Date: Mon, 27 Jun 1994 11:27:30 -0400 (EDT) Reply-To: rri!potter AT vtserf DOT cc DOT vt DOT edu Sorry if this is a duplicate message. This is the third time I've tried to send it. It just keeps coming back (don't know if it actually got out any of the other times). Any ways, here I go again. ... > I want my programs to be able to successfully catch I/O errors with a > floppy disk. This is not a problem if the disk is full, for instance, but if > there is actually no disk in the drive then I get the DOS "Abort, Retry, Fail" > message repeatedly on my screen. What's the easiest way to beat DOS to it and > have MY program be able to handle a no-disk situation? Well one question, how does one normally do it in real mode program? Typically one uses the harderr() functions to establish a catch function, however the harderr() functions aren't in the DJGPP library. Right after v1.11 came out I wrote the follow code. It still has a couple problems, but it is still usable. I ment to finish it up befor generally releasing it but its been a while and I just haven't had the time (or need) to finish it. Therefore I figured I might as well release it now, and maybe someone else can finish it up. The code has the following known problems: 1. I never wrote the hardretn() or _hardretn() functions. This was because the program I needed the harderr() functions for didn't need them. Also I didn't think they would be anywhere near trivial. I thoughts are one will have to play with the real mode stack to get this to work. This might not even be possible. 2. I wrote this assuming non-DPMI operation (see MK_FP macro). Again the program I needed this for could be restricted to VCPI only system. I also seem to think I didn't even need to examine that pointer anyways, so it's a moot point. 3. This code can suffer from the virtual memory system. (Example: A program sets the hard-error catch function. Then much later on the program experiences a hard-error. However, in the mean time, the VM system swapped out the harderr() code, thus the interrupt vector was pointing to who knows what.) This did bite me in my program. Between when I set the hard-error catch and when the hard-error occured I did a system() call which swapped out everything. My work around was to re-set the catch function right after a system() call. Better probably would have been right befor where the hard-error was expected. Basically all I needed to do was touch something in the harderr()'s code-page so that it would be swapped it. The actuall solution should be, use a DPMI call to lock the harderr()'s code so that it won't be swapped out. Currently however GO32 doesn't support this call. So such a fix would only work under DPMI until GO32 is updated. Weither or not it should be harderr()'s or the calls responsibility to lock the catch-function is to be desided. I'd probably say that harderr() should lock to page that the catch function starts in plus a bit (thus one or two pages), this would help in blind porting. But it really should be the programmers responsibility to verify that this is correct, locking any additional pages needed. Potter ------------------------------------------------------------------------------- FILE: harderr.h ------------------------------------------------------------------------------- #if !defined( harderr_h ) #define harderr_h #if defined( __cplusplus ) void _harderr ( void (*fn)( unsigned device_error_code, unsigned errval, unsigned *devhdr ) ); void harderr ( int (*fn)( int error_value, int device_error_code, int device_header_segment, int device_header_offset ) ); #else void _harderr ( void (*fn)() ); void harderr ( int (*fn)() ); #endif void _hardresume ( int ret ); void _hardretn ( int ret ); void hardresume ( int ret ); void hardretn ( int ret ); /* constants for _hardresume(), hardresume(), or harderr() */ #define _HARDERR_IGNORE 0x0 /* Ignore the error */ #define _HARDERR_RETRY 0x1 /* Retry the operation */ #define _HARDERR_ABORT 0x2 /* Terminate the program */ #define _HARDERR_FAIL 0x3 /* Terminate the function */ #endif ------------------------------------------------------------------------------- FILE: harderr.c ------------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #define __cplusplus /* to get full prototypes */ # include "harderr.h" #undef __cplusplus #define INTERRUPT 0x24 #define MK_FP( seg, off ) ((void*)( ((seg)<<4) + (off) + 0xE0000000 )) typedef int (*generic_fn_ptr)( void ); typedef void (*microsoft_fn)( unsigned device_error_code, unsigned errval, unsigned *devhdr ); typedef int (*borland_fn)( int error_value, int device_error_code, int device_header_segment, int device_header_offset ); typedef enum he_style_e { STYLE_MICROSOFT, STYLE_BORLAND } he_style_t; typedef enum he_handler_ret_method_e { HRM_UNKNOWN, HRM_RESUME, /* HRM_RETN * Not implemented */ } he_handler_ret_method_t; static _go32_dpmi_seginfo dpmi_info; /*extern*/ _go32_dpmi_registers dpmi_regs; static he_style_t he_style; static generic_fn_ptr he_func = NULL; static jmp_buf he_jmp_buf; static int he_resume_val; static /*interrupt*/ void harderr_handler( _go32_dpmi_registers *r ) { switch( (he_handler_ret_method_t)setjmp( he_jmp_buf ) ) { case HRM_UNKNOWN: if ( he_style == STYLE_MICROSOFT ) { ((microsoft_fn)(he_func))( r->x.ax, r->x.di, MK_FP( r->x.bp, r->x.si ) ); r->h.al = _HARDERR_ABORT; } else { r->h.al = ((borland_fn)(he_func))( r->x.di & 0xff, r->x.ax, r->x.bp, r->x.si ); } return; case HRM_RESUME: r->h.al = he_resume_val; return; } } static void __harderr( generic_fn_ptr fn ) { if ( he_func != NULL ) { _go32_dpmi_free_real_mode_callback( &dpmi_info ); } he_func = fn; dpmi_info.pm_offset = (int)harderr_handler; _go32_dpmi_allocate_real_mode_callback_iret( &dpmi_info, &dpmi_regs ); _go32_dpmi_set_real_mode_interrupt_vector( INTERRUPT, &dpmi_info ); } extern void _harderr( void (*fn)( unsigned device_error_code, unsigned errval, unsigned *devhdr ) ) { he_style = STYLE_MICROSOFT; __harderr( (generic_fn_ptr)fn ); } void harderr( int (*fn)( int error_value, int device_error_code, int device_header_segment, int device_header_offset ) ) { he_style = STYLE_BORLAND; __harderr( (generic_fn_ptr)fn ); } void _hardresume( int ret ) { he_resume_val = ret; longjmp( he_jmp_buf, HRM_RESUME ); } void hardresume( int ret ) { _hardresume( ret ); } void _hardretn( int ret ) { /* to be implemented */ } void hardretn( int ret ) { _hardretn( ret ); }