Known Bugs and Workarounds

or "Lessons Learned the Hard Way"


Last Updated: 8/29/96

Contents


The XMODEM LDD: P_FCANCEL vs F_FDISCONNECT

The XMODEM/YMODEM attached device driver attaches to an existing serial device and (after converting the channel to 8-bits with only hardware handshaking - XMODEM is an 8-bit protocol) allows serial reads and writes to be converted into XMODEM/YMODEM packets.

The P_FCANCEL service which you would normally use during asynchronous operations (for instance when a timeout event is detected you will call P_FCANCEL on any outstanding serial event) will cause a panic when called on an outstanding P_READ/P_WRITE when XMD: has already been attached to a TTY: channel. The proper service to call is P_FDISCONNECT.

These two preprocessor macros are defined differently, and if you are using a standardized read-with-timeout or write-with-timeout style utility routine, it needs to have a state variable or flag to indicate whether it should call the P_FCANCEL or the P_FDISCONNECT service. (In the case of active objects, this is extremely important - since active objects will use the P_FCANCEL service of their own volition - you may have to replace several methods.)

Back to Contents

Window Server Graphics Panics

If you're dealing with multiple permanent graphics contexts, when destroying a window which has an associated permanent graphics context or freeing an existing permanent graphics context, it is important to call gSetGC0(gc) where gc is the graphics context id of the permanent graphics context which you expect to be drawing to.

When a permanent graphics context is destroyed while it is the current graphics context, the Window Server is left in un-defined state with regards to the current graphics context. Any subsequent drawing not preceded by a gSetGC0(gc) could result in a panic. With client-side buffering, it may not be immediately obvious, either!

While Psion currently claims that there is no way to find out the current graphics context id, there is one way to avoid this problem - minimize the live time of graphics contexts. If you are sufficiently adept at minimizing and localizing all drawing, you can also get away with using temporary graphics contexts - which do restore the previous permanent graphics context upon the call to gFreeTempGC(). One caveat: You can only have one temporary gc at any given time - and you cannot use any permanent graphics contexts during the live time of the temporary graphics context.

Back to Contents

wStartup() changes bx - TopSpeed thinks it can optimize local data into bx

#include <plib.h>
#include <wlib.h>

GLDEF_C INT foo(TEXT **pp, INT i) {
    if ( i != 1 ) {
        if ( (i > 10) || (i < 1) ) {
            i = 10 ;
        }
        for (  ; i > 0 ; i-- ) {
            p_sound(5, 320) ;
        }
    }

    return(0) ;
}

#ifdef SHOW_BUG
    // Bug here
    // C Code                   TopSpeed Disassembled code
    GLDEF_C VOID main(VOID) {   // public _main:
                                //   push  bx
                                //   push  ax
        INT         i = 1 ;     //   mov   bx,1

        wStartup() ;            //   call  near _wStartup
         //   wStartup() changes bx, though!

                                //   xor   ax,ax
        foo(NULL, i) ;          //   call  near _foo
                                //   xor   bx,bx

        p_exit(0) ;             //   call  near _p_exit
                                //   pop   ax
                                //   pop   bx
                                //   ret 0
    }
#else
    // No bug here
    // C Code                   TopSpeed Disassembled code
    GLDEF_C VOID main(VOID) {   // public _main:
                                //   push  bx
                                //   push  ax
        INT         i ;

        wStartup() ;            //   call  near _wStartup
         //   wStartup() changes bx, but it gets re-initialized

        i = 1 ;                 //   mov   bx,1

                                //   xor   ax,ax
        foo(NULL, i) ;          //   call  near _foo
                                //   xor   bx,bx
        p_exit(0) ;             //   call  near _p_exit
                                //   pop   ax
                                //   pop   bx
                                //   ret 0
    }
#endif
Back to Contents

The O_IS_INEXT service can sometimes falsely return E_FILE_EOF.

This one is documented in V2.10 of the ISAM Reference. A workaround is given there. It's equivalent to:
GLDEF_C INT NEXT_RECORD(PR_ISAMAN *pIsam, INT id) {
    INT     ret ;
    ret = p_send3(pIsam, O_IS_INEXT, id) ;
    if ( ret == E_FILE_EOF ) {
        p_send3(pIsam, O_IS_IBACK, id) ;
        p_send3(pIsam, O_IS_INEXT, id) ;
        ret = p_send3(pIsam, O_IS_INEXT, id) ;
    }
    return(ret) ;
}
Back to Contents

The ISAM DYL can sometimes call p_leave(E_FILE_EOF)

(Bug researched and workaround provided by Chris Hennings: 100010.511@compuserve.com)

Under some circumstances a operation involving index navigation will produce a p_leave(E_FILE_EOF) being called - this is quite distinct from an operation *returning* a false result of E_FILE_EOF. In fact the file read that generates this is not even to do with the .DBF but rather the C_BLOCKER is reading past the end of the .IDX The problem arises in the following circumstance:

What's happened is this, Index A has remained open so the Blocker is not destroyed. When index B is closed and index C is created, the "actualblocks" property that holds the number of blocks that hold index data is not zeroised. Thus the index file may not be extended during a subsequent O_BL_ALLOC as it believes the file to be big enough already. This leads to blocks not being written in the correct position and eventually to a potential read from a non-existent file location.

The work round uses the fact that the property *is* correctly zeroised when an *existing* index is opened as opposed to when a new one is created thus to create an index safely, the sequence should be used:

iId=p_send4(p_isam,O_IS_IOPEN,idxname,P_FREPLACE|P_FUPDATE);
p_send3(p_isam,O_IS_ICLOSE,iId);
iId=p_send4(p_isam,O_IS_IOPEN,idxname,P_FOPEN|P_FUPDATE);
Back to Contents


Back to My home page
© 1996 J. C. Roux