delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1997/03/18/06:32:28

Date: Tue, 18 Mar 1997 14:15:04 +0300 (IDT)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
To: Delong <dandelong AT osha DOT igs DOT net>
cc: djgpp AT delorie DOT com
Subject: Re: A way to find how many files are currently 'open'?
In-Reply-To: <332C8C47.59EF@osha.igs.net>
Message-ID: <Pine.SUN.3.91.970318141417.17465H-100000@is>
MIME-Version: 1.0

On Sun, 16 Mar 1997, Delong wrote:

> Suppose I read from this 'function', then opened a file (with 'open()'),
> then read from this function again. I would expect it to return 1 more
> opened file than the first time.
> 
> Any way to do this? It would really help me find a problem I'm currently
> having so let me know if you've seen one, 

There's no such function in the library, you will have to roll your
own.

One way to do that is to use the DJGPP Filesystem Extensions mechanism
to install a handler for the `open' and `creat' functions and maintain
a table of open files.  See the library reference for more details
about Filesystem Extensions (type "info libc alpha __FSEXT_add" from
the DOS prompt).

Another way to do that is to walk the JFT (Job File Table) which is
the table of open files maintained by DOS inside the PSP of every
program.  The JFT is just an array of unsigned char numbers which are
255 for a file that isn't open or a number other than 255 for a file
that is currently open.  A real-mode-style seg:off pointer to the JFT
is at offset 34h in the PSP, and the number of entries in the JFT is
at offset 32h in the PSP.  I recommend this method, because it is
simpler in your case, and will work with all methods available to open
files (the FSEXT method doesn't work if a program calls DOS directly
via INT 21h or similar low-level calls).

I attach below an excerpt from the DJGPP debug interface that uses
both the above methods (see the comments for the reasons), written by
Robert Hoehne, which is a working example of using the above
techniques.  If you have any further questions, please post them to
the news group.

--------------------------- cut here --------------------------------

/*
   Now the FSEXT function for watching files being opened. This is needed,
   because the debuggee can open files which are not closed and if you
   do this multiple times, the limit of max opened files is reached.

   The watching is done by the FSEXT function by hooking the _open(),
   _creat() and _close() calls from the libc functions. The only things
   which are added is recording files which are opened (and closed) by
   the debugger. When cleanup_client() is called, this list is compared
   with actual open files and every file, which was not seen by dbg_fsext()
   is closed.

   This technique does not work correctly when the debugger uses the lowest
   routines for opening/creating/closing files which are
   _dos_open(), _dos_creat(), _dos_creatnew() and _dos_close().
*/

static unsigned char handles[256];
static int in_dbg_fsext = 0;

static void close_handles(void)
{
  __dpmi_regs r;
  int psp_la;
  int jft_ofs;
  int jft_count;
  int handle;

  /* Get our PSP address.  */
  r.x.ax = 0x6200;
  __dpmi_int (0x21, &r);
  psp_la = ( (int)r.x.bx ) << 4;

  /* Get the offset of the JFT table by (seg << 4) + offset */
  jft_ofs = (_farpeekw(_dos_ds, psp_la + 0x36) << 4) +
            _farpeekw(_dos_ds, psp_la + 0x34);

  /* Number of used entries in the JFT table */
  jft_count = _farpeekw(_dos_ds, psp_la + 0x32);

  /* Disable the fsext function */
  in_dbg_fsext++;

  for (handle=0;handle<jft_count;handle++)
  {
    if (_farpeekb(_dos_ds,jft_ofs++) != 0xff /* it is an opened handle */
        && handles[handle] == 0xff /* but not recorded by the fsext function */
       )
    { /* it was opened by the debuggee */
#ifdef DEBUG_DBGCOM
      fprintf(stderr,"closing %d\n",handle);
#endif
      _close(handle);
    }
  }

  /* Enable the fsext function */
  in_dbg_fsext--;
}


static int dbg_fsext(__FSEXT_Fnumber _function_number,
                      int *_rv, va_list _args)
{
  int attrib,oflag,retval = 0,handle;
  const char *filename;
  /* We are called from this function */
  if (in_dbg_fsext) return 0;
  switch (_function_number)
  {
    default:
      return 0;
    case __FSEXT_creat:
      filename = va_arg(_args,const char *);
      attrib = va_arg(_args,int);
      in_dbg_fsext++;
      retval = _creat(filename,attrib);
#ifdef DEBUG_DBGCOM
      fprintf(stderr,"_creat() => %d\n",retval);
#endif
      in_dbg_fsext--;
      if (retval != -1)
      {
        handles[retval] = retval;
        __FSEXT_set_function(retval,dbg_fsext);
      }
      break;
    case __FSEXT_open:
      filename = va_arg(_args,const char *);
      oflag = va_arg(_args,int);
      in_dbg_fsext++;
      retval = _open(filename,oflag);
#ifdef DEBUG_DBGCOM
      fprintf(stderr,"_open(%s) => %d\n",filename,retval);
#endif
      in_dbg_fsext--;
      if (retval != -1)
      {
        handles[retval] = retval;
        __FSEXT_set_function(retval,dbg_fsext);
      }
      break;
    case __FSEXT_close:
      handle = va_arg(_args,int);
      in_dbg_fsext++;
#ifdef DEBUG_DBGCOM
      fprintf(stderr,"_close(%d)\n",handle);
#endif
      retval = _close(handle);
      in_dbg_fsext--;
      if (retval == 0)
      {
        handles[handle] = 0xff;
        __FSEXT_set_function(handle,NULL);
      }
      break;
  }
  *_rv = retval;
  return 1;
}

/* With attribute constructor to be called automaticaly before main */

static void __attribute__((__constructor__))
_init_dbg_fsext(void)
{
  __dpmi_regs r;
  int psp_la;
  int jft_ofs;
  int jft_count;

  /* Get our PSP address.  */
  r.x.ax = 0x6200;
  __dpmi_int (0x21, &r);
  psp_la = ( (int)r.x.bx ) << 4;

  /* Get the offset of the JFT table by (seg << 4) + offset */
  jft_ofs = (_farpeekw(_dos_ds, psp_la + 0x36) << 4) +
            _farpeekw(_dos_ds, psp_la + 0x34);

  /* Number of used entries in the JFT table */
  jft_count = _farpeekw(_dos_ds, psp_la + 0x32);

  /* Add the handler for opening/creating files */
  __FSEXT_add_open_handler(dbg_fsext);

  /* Initialize all the handles to 0xff */
  memset(handles,0xff,sizeof(handles));

  /* Get a copy of all already opened handles */
  movedata(_dos_ds,jft_ofs,_my_ds(),(int)handles,jft_count);

  /* enable the fsext function */
  in_dbg_fsext = 0;
}

- Raw text -


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