Path Table eXtension Module --------------------------- Copyright (c) 1995 Nick Holgate, Southampton, UK nick@bvmltd.demon.co.uk The PTXM is courtesyware, it is entirly free in the hope that it will be of some use, but it would be a nice gesture to let me know if you like it enough to use it. If nobody tells me they are using it it's unlikely that I will continue to maintain it! What is it? ----------- PTXM is a kernel extension module that allows user state processes to open an unlimited number of I/O paths. Installation ------------ Installation is straight forward either: 1. Install Ptxm in your bootfile and add Ptxm to the list of system extensions in your 'init' module. or 2. Load the Ptxm module into memory then execute the 'ptxminst' utility. How it works ------------ PTXM intercepts all the I$???? calls that create or use user state path numbers extending the processes path table into system memory when the one in the process descriptor becomes full. When a user state I$Open or I$Create call is made PTXM performs the call system state equivalent, then records the system state path number in the process descriptor like IOMAN would, but if the process descriptors path table is full it records the path number internally in a path extension table allocated from system memory for the calling process. When other I/O system calls are made, with the exception of I$Dup, PTXM finds the system state path number that corresponds to the supplied user path number, from either the process descriptor or path extension table, then passes the call on to the system state dispatch address to be executed. The I$Dup call is handled entirely by PTXM and does not call on IOMAN at all. Process termination is handled with a user accounting subroutine, F$Uacct, that closes any open paths left by terminating and chained processes. Current Limitations ------------------- Only the first 32 open paths, (i.e. the ones held in the process descriptor), may be inherited by a child process. To be able to close user paths that are left open when the a process terminates it is necessary to install a user accounting routine. As OS-9 provides no way to install multiple user accounting routines any user accounting software installed after the PTXM will likely replace the PTXM's handler, however provided the PTXM is installed after any other user accounting software there should be no problem, as the PTXM calls the user accounting handler that it replaced before it returns to the kernel. Will not work with OS-9 V3 ATOMIC kernel, as there is no user accounting support. 'C' Stream I/O -------------- Microware's standard stream I/O has a fixed size array of 32 FILE buffers, which prevents more than 32 fopen(), fdopen() or freopen() calls being performed. By moving the initialised FILE buffer into malloc'ed memory after each path is opened and free'ing it after each path is closed, it is possible to defeat this limitation. /*--------------------------------------------------------------------------*/ #include #if defined(__STDC__) || defined(_ANSI_EXT) #include #else #define const /**/ extern void *malloc(); #endif FILE * ptxm_fopen ( const char *fname, const char *action ) { FILE *fp; FILE *fbuf; if ((fbuf = malloc(sizeof(FILE))) == NULL) { return NULL; } if ((fp = fopen(fname, action)) == NULL) { free(fbuf); return NULL; } /* save it in our FILE buffer */ *fbuf = *fp; /* make it look unused */ memset(fp, 0, sizeof(FILE)); return fbuf; } FILE * ptxm_fdopen ( int path, char *action ) { FILE *fp; FILE *fbuf; if ((fbuf = malloc(sizeof(FILE))) == NULL) { return NULL; } if ((fp = fdopen(path, action)) == NULL) { free(fbuf); return NULL; } /* save it in our FILE buffer */ *fbuf = *fp; /* make it look unused */ memset(fp, 0, sizeof(FILE)); return fbuf; } FILE * ptxm_freopen ( const char *fname, const char *action, FILE *oldfp ) { FILE *fp; FILE *fbuf; if ((fbuf = malloc(sizeof(FILE))) == NULL) { /* to be consistant, the original is closed if open fails */ fclose(oldfp); return NULL; } fp = freopen(fname, action, oldfp); /* use stdin to iron out differences in naming * between the K & R compiler (_iob[]) and Ultra 'C' (_niob[]) */ if (oldfp < stdin || oldfp >= &stdin[_NFILE]) { free(oldfp); } if (fp == NULL) { free(fbuf); return NULL; } /* save it in our FILE buffer */ *fbuf = *fp; /* make it look unused */ memset(fp, 0, sizeof(FILE)); return fbuf; } int ptxm_fclose ( FILE *fp ) { int status; status = fclose(fp); /* use stdin to iron out differences in naming * between the K & R compiler (_iob) and Ultra 'C' (_niob) */ if (fp < stdin || fp >= &stdin[_NFILE]) { free(fp); } return status; } #define fopen ptxm_fopen #define fdopen ptxm_fdopen #define freopen ptxm_freopen #define fclose ptxm_fclose /*--------------------------------------------------------------------------*/ Nick Holgate 13.3.95