← Back to team overview

sslug-teknik team mailing list archive

Re: Bedre browser

 

Mads Bondo Dydensborg wrote:
> 
> On Sat, 8 May 1999, Anders S. Johansen wrote:
> 
> > root wrote:
> > > Men måske er det på maskiner med lavere CPU kraft at den hænger, min er en
> > > PII-300, 128 mb RH6.0
> > > jeg har oplevet at NS hænger meget på en P75
> >
> > Hmmm. PPro, 200MhZ, 128Mb ram, ISDN, RH 6.0 og RH5.1.
> >
> > Ikke maskinens muskler det handler om :)
> 
> Well. Hvis der er deadlocks, som følge af tidsting, kunne maskinens styrke
> egentlig godt have noget at sige, mht. frekvensen af fejl man oplever. Men
> ellers har du ret.

Ifølge et indlæg på l-k, så er det dels et tidsrelateret spørgsmål. Kig
i arkivet efter uge 4, jan 1999, der er en tråd med subject "Kernel OK,
netscape buggy" med en del diskussion. Jeg har vedlagt et patch som en
person i denne tråd havde lavet. Patchet oversættes til at shared
library, og vha. LD_PRELOAD overskriver man så read/write og pipe
kaldene. Det er et temmelig skummelt hack, og skulle vist resultere i at
man ikke kunne klikke på links efter et stykke tid. Derudover skulle det
af uransagelige årsager betyde 2-3 gange hurtigere sidevisning,
ihvertfald på en hurtig forbindelse. Problemet ligger i at netscape
bruger en blokerende pipe til noget synkronisering/kommunikation imellem
de 2+ processer, hvor det så går galt på en eller anden måde.

Mvh Morten
#include <dlfcn.h>
#include <unistd.h>
#include <limits.h>

/* This is a netscape bug workaround. Search for a pipe,
   where only 1 byte strings \0372 are written to the write
   end and only 1 byte strings are requested back. Count
   the difference and fake any writes that would cause
   an overflow of the pipe and corresponding reads.

   This is a really dirty hack with almost no error checking
   and relying on the netscape's behaviour.

   Compile with
     gcc -c nspipepatch.c
     ld -shared -o libnspipepatch.so -ldl nspipepatch.o

   and add
     LD_PRELOAD=<path>/libnspipepatch.so

   to your netscape starting script.

   (C) 1999 Stanislav Meduna <stano@xxxxxxxxxxxxxxxxx>
   There is absolutely NO WARRANTY. The use and distribution
   is completely free
*/

/* The magic netscape char flowing through the pipe */
#define MAGIC ((unsigned char) '\372')

/* libc handle for dlsym */
static void *dlhdl=0;

/* pointers to overloaded functions */
static int (*pipe_fp)(int [2])=0;
static ssize_t (*write_fp)(int, const void *, size_t)=0;
static ssize_t (*read_fp)(int, void *, size_t)=0;
static int (*close_fp)(int)=0;

/* we keep the info about our descriptors here */
static struct nshack_pipe_t
{
  /* If this is a pipe that could be our one,
     mark both ends here. If we shouldn't touch
     the descriptor, enter -1 here
  */
  int read_end, write_end;

  /* The difference between writes and reads,
     maintained on the write end
  */
  int diff;

  /* Number of faked writes, maintained on the write end */
  int faked;
} fdflags[256];


/* Mark the descriptors as unused or not of our interest */
static void clearfd(int fd)
{
  fdflags[fd].read_end = fdflags[fd].write_end = -1;
  fdflags[fd].diff = fdflags[fd].faked = 0;
}

/* Clear both ends */
static void clearboth(int fd)
{
  int rd = fdflags[fd].read_end;
  int wr = fdflags[fd].write_end;

  if (rd >= 0)
    clearfd(rd);
  if (wr >= 0)
    clearfd(wr);
}

/* Init the pointers to overloaded functions */
static void initptrs()
{
  int i;

  dlhdl = dlopen("/lib/libc.so.6", RTLD_NOW);

  if (! dlhdl)
    exit(99);

  pipe_fp  = dlsym(dlhdl, "pipe");
  write_fp = dlsym(dlhdl, "write");
  read_fp  = dlsym(dlhdl, "read");
  close_fp = dlsym(dlhdl, "close");

  if (! pipe_fp || ! write_fp || ! read_fp || ! close_fp)
    exit(99);

  for (i=0; i < sizeof(fdflags)/sizeof(fdflags[0]); i++)
    clearfd(i);
}

/* Unload the library */
void _fini()
{
  if (dlhdl)
    dlclose(dlhdl);
}

/* Overloaded pipe - mark the fresh pipes */
int pipe(int fd[2])
{
  int res;

  if (! pipe_fp)
    initptrs();

  res = (*pipe_fp)(fd);

  if (! res)
  {
    /* This could be our pipe - watch it during read/write */
    fdflags[fd[0]].read_end  = fdflags[fd[1]].read_end = fd[0];
    fdflags[fd[0]].write_end = fdflags[fd[1]].write_end= fd[1];
    fdflags[fd[0]].diff      = fdflags[fd[1]].faked = 0;
  }

  return res;
}

/* Overloaded write */
ssize_t write(int fd, const void *buf, size_t cnt)
{
  int res=0;

  if (! write_fp)
    initptrs();
  if (cnt != 1 || *(unsigned char *)buf != MAGIC)
    clearboth(fd); /* This is not our pipe - magic not seen */

  if (fd == fdflags[fd].write_end)
  {
    /* This is the write end of a watched pipe */
    fdflags[fd].diff++;

    /* Play safe - reduce the allowed difference
       to guard against off-by-one errors and
       similar :-)
    */
    if (fdflags[fd].diff >= PIPE_BUF-64)
    {
        /* We fake the write */
        fdflags[fd].faked++;
        res = 1;
    }
    else
      res = (*write_fp)(fd, buf, cnt);
  }
  else
    res = (*write_fp)(fd, buf, cnt);

  return res;
}

/* Overloaded read */
ssize_t read(int fd, void *buf, size_t cnt)
{
  int res;
  int watch=0;

  if (! read_fp)
    initptrs();

  if (fd == fdflags[fd].read_end)
  {
    if (cnt == 1)
      watch = 1;
    else
      clearboth(fd); /* The true one always wants one char only */

    /* This is the read end of a watched pipe */
    if (watch && fdflags[fdflags[fd].write_end].faked)
    {
      /* Faked writes exist - compensate with faked reads */
      fdflags[fdflags[fd].write_end].faked--;
      fdflags[fdflags[fd].write_end].diff--;
      *((unsigned char *) buf) = MAGIC;
      return 1;
    }
  }

  /* Do the real read */
  res = (*read_fp)(fd, buf, cnt);

  if (watch && res == 1)
  {
    /* If we watch the pipe and the read was successfull,
       use the read value to make sure this is THE pipe.
    */
    if (*((unsigned char *) buf) == MAGIC)
      fdflags[fd].diff--;
    else
      clearboth(fd);
  }

  return res;
}

/* Overloaded close (we want to be at least a bit correct) */
int close(int fd)
{
  if (! close_fp)
    initptrs();

  if (fd == fdflags[fd].read_end || fd == fdflags[fd].write_end)
    clearboth(fd);

  return (*close_fp)(fd);
}

References