delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1994/06/27/14:15:49

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 <dmalloc.h>
#include <dos.h>
#include <sys/types.h>
#include <dpmi.h>
#include <go32.h>
#include <pc.h>
#include <setjmp.h>
#include <stdio.h>

#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 );
}



- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019