dslinux/user/perl/mpeix mpeix.c mpeix_setjmp.c mpeixish.h nm relink

cayenne dslinux_cayenne at user.in-berlin.de
Mon Dec 4 18:01:20 CET 2006


Update of /cvsroot/dslinux/dslinux/user/perl/mpeix
In directory antilope:/tmp/cvs-serv17422/mpeix

Added Files:
	mpeix.c mpeix_setjmp.c mpeixish.h nm relink 
Log Message:
Adding fresh perl source to HEAD to branch from

--- NEW FILE: relink ---
#!/bin/sh

# The MPE POSIX libc archive library contains rand(), but this function has
# been omitted from the libc shared library on the mistaken assumption that
# the rand() function in the kernel library /SYS/PUB/XL could be used instead.
# However, rand() in /SYS/PUB/XL is a Fortran function with different semantics
# from the C version that we expect.

# So in order to get the correct rand() function and to make it available to
# the dynamically loaded perl extensions, we will build our own mini rand()
# shared library and add this to the perl NMPRG's XL list.

RAND=/$HPACCOUNT/$HPGROUP/libcrand

echo "Creating $RAND.sl...\n"

TEMP=perlmpe.$$

rm -f $TEMP $RAND.a $RAND.sl

/bin/cat - >$TEMP <<EOF
buildrl $RAND.a
copyrl from=/lib/libc.a;to=$RAND.a;module=rand
revealrl rl=$RAND.a;all
buildxl $RAND.sl;limit=1
addxl from=$RAND.a;to=$RAND.sl;share
listxl xl=$RAND.sl
EOF

callci "xeq LINKEDIT.PUB.SYS <$TEMP"

rm -f $TEMP $RAND.a

# MPE/iX as of 5.5 does not yet properly support linking against dynamic
# libraries via gcc or ld.  For now, re-run gcc without the external library
# list, and then run the native linker with the list of dynamic libraries.

echo "Creating the perl executable NMPRG..."

gcc -o perl perlmain.o \
  lib/auto/DynaLoader/DynaLoader.a \
  libperl.a \
  `cat ext.libs` \
  -L/BINDFW/CURRENT/lib -lbind \
  -L/SYSLOG/PUB -lsyslog

echo "Modifying the perl executable NMPRG XL list...\n"

callci "xeq LINKEDIT.PUB.SYS 'altprog ./perl;xl=/usr/lib/libcurses.sl,/lib/libsvipc.sl,/usr/lib/libsocket.sl,/usr/lib/libstr.sl,/lib/libm.sl,$RAND.sl,/lib/libc.sl'"

--- NEW FILE: mpeix.c ---

/*
 * gcc long pointer support code for HPPA.
 * Copyright 1998, DIS International, Ltd.
 * This code is free software; you may redistribute it and/or modify
 * it under the same terms as Perl itself.  (Relicensed for Perl in
 * in April 2002 by Mark Klein.)
 */
typedef struct {
  int           spaceid;
  unsigned int  offset;
  } LONGPOINTER, longpointer;

/*
 * gcc long pointer support code for HPPA.
 * Copyright 1998, DIS International, Ltd.
 * This code is free software; you may redistribute it and/or modify
 * it under the same terms as Perl itself.  (Relicensed for Perl in
 * in April 2002 by Mark Klein.)
 */

int __perl_mpe_getspaceid(void *source)
  {
  int val;
  /*
   * Given the short pointer, determine it's space ID.
   */

  /*
   * The colons separate output from input parameters. In this case,
   * the output of the instruction (output indicated by the "=" in the
   * constraint) is to a memory location (indicated by the "m"). The
   * input constraint indicates that the source to the instruction
   * is a register reference (indicated by the "r").
   * The general format is:
   *   asm("<instruction template>" : <output> : <input> : <clobbers>);
   *     where <output> and <input> are:
   *       "<constraint>" (<token>)
   *     <instruction template> is the PA-RISC instruction in template fmt.
   *     <clobbers> indicates those registers clobbered by the instruction
   *     and provides hints to the optimizer.
   *
   * Refer to the gcc documentation or http://www.dis.com/gnu/gcc_toc.html
   */
  __asm__ __volatile__ (
      "   comiclr,= 0,%1,%%r28\n"
      "\t  ldsid (%%r0,%1),%%r28\n"
      "\t stw %%r28, %0"
                        : "=m" (val)    // Output to val
                        : "r" (source)  // Source must be gen reg
                        : "%r28");      // Clobbers %r28
  return (val);
  };

LONGPOINTER __perl_mpe_longaddr(void *source)
  {
  LONGPOINTER lptr;
  /*
   * Return the long pointer for the address in sr5 space.
   */

  __asm__ __volatile__ (
      "  comiclr,= 0,%2,%%r28\n"
      "\t    ldsid (%%r0,%2),%%r28\n"
      "\t  stw %%r28, %0\n"
      "\t  stw %2, %1"
                        : "=m" (lptr.spaceid),
                          "=m" (lptr.offset)    // Store to lptr
                        : "r" (source)          // Source must be gen reg
                        : "%r28");      // Clobbers %r28
  return (lptr);
  };

LONGPOINTER __perl_mpe_addtopointer(LONGPOINTER source,    // %r26 == source offset
                                                // %r25 == source space
                        int             len)    // %r24 == length in bytes
  {
  /*
   * Increment a longpointer.
   */

  __asm__ __volatile__ (
      "  copy %0,%%r28\n"                       // copy space to r28
      "\t  add %1,%2,%%r29"                     // Increment the pointer
                        :                       // No output
                        : "r" (source.spaceid), // Source address
                          "r" (source.offset),
                          "r" (len)             // Length
                        : "%r28",               // Clobbers
                          "%r29");
  };

void __perl_mpe_longmove(int len,                  // %r26 == byte length
              LONGPOINTER source,       // %r23 == source space, %r24 == off
              LONGPOINTER target)       // sp-#56 == target space, sp-#52== off
  {
  /*
   * Move data between two buffers in long pointer space.
   */

  __asm__ __volatile__ (
      "  .import $$lr_unk_unk_long,MILLICODE\n"
      "\t  mtsp %0,%%sr1\n"                     // copy source space to sr1
      "\t  copy %1,%%r26\n"                     // load source offset to r26
      "\t  copy %4,%%r24\n"                     // load length to r24
      "\t  copy %3,%%r25\n"                     // load target offset to r25
      "\t  bl $$lr_unk_unk_long,%%r31\n"        // start branch to millicode
      "\t  mtsp %2,%%sr2"                       // copy target space to sr2
                        :                       // No output
                        : "r" (source.spaceid), // Source address
                          "r" (source.offset),
                          "r" (target.spaceid), // Target address
                          "r" (target.offset),
                          "r" (len)             // Byte length
                        : "%r1",                // Clobbers
                          "%r24",
                          "%r25",
                          "%r26",
                          "%r31");
  };

int __perl_mpe_longpeek(LONGPOINTER source)
  {
  /*
   * Fetch the int in long pointer space.
   */
  unsigned int val;

  __asm__ __volatile__ (
      "  mtsp %1, %%sr1\n"
      "\t  copy %2, %%r28\n"
      "\t  ldw 0(%%sr1, %%r28), %%r28\n"
      "\t  stw %%r28, %0"
                        : "=m" (val)            // Output val
                        : "r" (source.spaceid), // Source space ID
                          "r" (source.offset)   // Source offset
                        : "%r28");              // Clobbers %r28

  return (val);
  };

void __perl_mpe_longpoke(LONGPOINTER target,       // %r25 == spaceid, %r26 == offset
          unsigned int val)             // %r24 == value
  {
  /*
   * Store the val into long pointer space.
   */
  __asm__ __volatile__ (
      "  mtsp %0,%%sr1\n"
      "\t  copy %1, %%r28\n"
      "\t  stw %2, 0(%%sr1, %%r28)"
                        :                       // No output
                        : "r" (target.spaceid), // Target space ID
                          "r" (target.offset),  // Target offset
                          "r" (val)             // Value to store
                        : "%r28"                // Clobbers %r28
                        );                      // Copy space to %sr1
  };

void __perl_mpe_move_fast(int len,                 // %r26 == byte length
               void *source,            // %r25 == source addr
               void *target)            // %r24 == target addr
  {
  /*
   * Move using short pointers.
   */
  __asm__ __volatile__ (
      "  .import $$lr_unk_unk,MILLICODE\n"
      "\t  copy %1, %%r26\n"                    // Move source addr into pos
      "\t  copy %2, %%r25\n"                    // Move target addr into pos
      "\t  bl $$lr_unk_unk,%%r31\n"             // Start branch to millicode
      "\t  copy %0, %%r24"                      // Move length into position
                        :                       // No output
                        : "r" (len),            // Byte length
                          "r" (source),         // Source address
                          "r" (target)          // Target address
                        : "%r24",               // Clobbers
                          "%r25",
                          "%r26",
                          "%r31");
  };

/*
 * ftruncate - set file size, BSD Style
 *
 * shortens or enlarges the file as neeeded
 * uses some undocumented locking call. It is known to work on SCO unix,
 * other vendors should try.
 * The #error directive prevents unsupported OSes
 *
 * ftruncate/truncate code by Mark Bixby.
 * This code is free software; you may redistribute it and/or modify
 * it under the same terms as Perl itself.
 *
 */

#ifndef _POSIX_SOURCE
#  define _POSIX_SOURCE
#endif
#ifndef _SOCKET_SOURCE
#  define _SOCKET_SOURCE
#endif
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <limits.h>
#include <mpe.h>

extern void FCONTROL(short, short, longpointer);
extern void PRINTFILEINFO(int);

int ftruncate(int fd, long wantsize);

int
ftruncate(int fd, long wantsize)
{
  int ccode_return,dummy=0;

  if (lseek(fd, wantsize, SEEK_SET) < 0)
  {
      return (-1);
  }

  FCONTROL(_mpe_fileno(fd),6,__perl_mpe_longaddr(&dummy)); /* Write new EOF */
  if ((ccode_return=ccode()) != CCE)
  {
          fprintf(stderr,
              "MPE ftruncate failed, ccode=%d, wantsize=%ld\n",
              ccode_return, wantsize);
          PRINTFILEINFO(_mpe_fileno(fd));
          errno = ESYSERR;
          return (-1);
  }

  return (0);
}

/*
   wrapper for truncate():

   truncate() is UNIX, not POSIX.

   This function requires ftruncate().



   NAME
      truncate -

   SYNOPSIS
      #include <unistd.h>

      int truncate(const char *pathname, off_t length);

                                             Returns: 0 if OK, -1 on error

            from: Stevens' Advanced Programming in the UNIX Environment, p. 92



   ERRORS
      EACCES
      EBADF
      EDQUOT (not POSIX)    <- not implemented here
      EFAULT
      EINVAL
      EISDIR
      ELOOP (not POSIX)     <- not implemented here
      ENAMETOOLONG
      ENOTDIR
      EROFS
      ETXTBSY (not POSIX)   <- not implemented here

                                          from: HP-UX man page



   Compile directives:
      PRINT_ERROR - make this function print an error message to stderr
*/


#include <sys/types.h>  /* off_t, required by open() */
#include <sys/stat.h>   /* required by open() */
#include <fcntl.h>      /* open() */
#include <unistd.h>     /* close() */
#include <stdio.h>      /* perror(), sprintf() */



int
truncate(const char *pathname, off_t length)
{
        int fd;
#ifdef PRINT_ERROR
        char error_msg[80+1];
#endif

        if (length == 0)
        {
                if ( (fd = open(pathname, O_WRONLY | O_TRUNC)) < 0)
                {
                        /* errno already set */
#ifdef PRINT_ERROR
                        sprintf(error_msg,
                                "truncate(): open(%s, O_WRONLY | OTRUNC)\0",
                                pathname);
                        perror(error_msg);
#endif
                        return -1;
                }
        }
        else
        {
                if ( (fd = open(pathname, O_WRONLY)) < 0)
                {
                        /* errno already set */
#ifdef PRINT_ERROR
                        sprintf(error_msg,
                                "truncate(): open(%s, O_WRONLY)\0",
                                pathname);
                        perror(error_msg);
#endif
                        return -1;
                }

                if (ftruncate(fd, length) < 0)
                {
                        /* errno already set */
#ifdef PRINT_ERROR
                        perror("truncate(): ftruncate()");
#endif
                        return -1;
                }
        }

        if (close(fd) < 0)
        {
                /* errno already set */
#ifdef PRINT_ERROR
                perror("truncate(): close()");
#endif
                return -1;
        }

        return 0;
} /* truncate() */

/* 
   wrapper for gettimeofday():
      gettimeofday() is UNIX, not POSIX.
      gettimeofday() is a BSD function.

   NAME
      gettimeofday -

   SYNOPSIS
      #include <sys/time.h>

      int gettimeofday(struct timeval *tp, struct timezone *tzp);

   DESCRIPTION
      This function returns seconds and microseconds since midnight
      January 1, 1970. The microseconds is actually only accurate to
      the millisecond.

      Note: To pick up the definitions of structs timeval and timezone
            from the <time.h> include file, the directive
            _SOCKET_SOURCE must be used.

   RETURN VALUE
      A 0 return value indicates that the call succeeded.  A -1 return
      value indicates an error occurred; errno is set to indicate the
      error.

   ERRORS
      EFAULT     not implemented

   Changes:
      2-91    DR.  Created.
*/


/* need _SOCKET_SOURCE to pick up structs timeval and timezone in time.h */
#ifndef _SOCKET_SOURCE
# define _SOCKET_SOURCE
#endif

#include <time.h>       /* structs timeval & timezone,
                                difftime(), localtime(), mktime(), time() */

extern int TIMER();

/*
 * gettimeofday code by Mark Bixby.
 * This code is free software; you may redistribute it and/or modify
 * it under the same terms as Perl itself.
 */

#ifdef __STDC__
int gettimeofday( struct timeval *tp, struct timezone *tpz )
#else
int gettimeofday(  tp, tpz )
struct timeval  *tp;
struct timezone *tpz;
#endif
{
   static unsigned long    basetime        = 0;
   static int              dsttime         = 0;
   static int              minuteswest     = 0;
   static int              oldtime         = 0;
   register int            newtime;


   /*-------------------------------------------------------------------*/
   /* Setup a base from which all future time will be computed.         */
   /*-------------------------------------------------------------------*/
   if ( basetime == 0 )
   {
      time_t    gmt_time;
      time_t    loc_time;
      struct tm *loc_time_tm;

      gmt_time    = time( NULL );
      loc_time_tm = localtime( &gmt_time ) ;
      loc_time    = mktime( loc_time_tm );

      oldtime     = TIMER();
      basetime    = (unsigned long) ( loc_time - (oldtime/1000) );

      /*----------------------------------------------------------------*/
      /* The calling process must be restarted if timezone or dst       */
      /* changes.                                                       */
      /*----------------------------------------------------------------*/
      minuteswest = (int) (difftime( loc_time, gmt_time ) / 60);
      dsttime     = loc_time_tm->tm_isdst;
   }

   /*-------------------------------------------------------------------*/
   /* Get the new time value. The timer value rolls over every 24 days, */
   /* so if the delta is negative, the basetime value is adjusted.      */
   /*-------------------------------------------------------------------*/
   newtime = TIMER();
   if ( newtime < oldtime )  basetime += 2073600;
   oldtime = newtime;

   /*-------------------------------------------------------------------*/
   /* Return the timestamp info.                                        */
   /*-------------------------------------------------------------------*/
   tp->tv_sec          = basetime + newtime/1000;
   tp->tv_usec         = (newtime%1000) * 1000;   /* only accurate to milli */
   if (tpz)
   {
      tpz->tz_minuteswest = minuteswest;
      tpz->tz_dsttime     = dsttime;
   }

   return 0;

} /* gettimeofday() */

/*
**  MPE_FCNTL -- shadow function for fcntl()
**
**      MPE requires sfcntl() for sockets, and fcntl() for everything 
**      else.  This shadow routine determines the descriptor type and
**      makes the appropriate call.
**
**      Parameters:
**              same as fcntl().
**
**      Returns:
**              same as fcntl().
*/

#include <stdarg.h>
#include <sys/socket.h>

int
mpe_fcntl(int fildes, int cmd, ...)
{
        int len, result;
        struct sockaddr sa;
        
        void *arg;
        va_list ap;
        
        va_start(ap, cmd);
        arg = va_arg(ap, void *);
        va_end(ap);
        
        len = sizeof sa;
        if (getsockname(fildes, &sa, &len) == -1)
        {
                if (errno == EAFNOSUPPORT)
                        /* AF_UNIX socket */
                        return sfcntl(fildes, cmd, arg);

                if (errno == ENOTSOCK) 
                        /* file or pipe */
                        return fcntl(fildes, cmd, arg);

                /* unknown getsockname() failure */
                return (-1); 
        }
        else
        {
                /* AF_INET socket */
                if ((result = sfcntl(fildes, cmd, arg)) != -1 && cmd == F_GETFL)
                        result |= O_RDWR;  /* fill in some missing flags */
                return result;
        }
}



/* 
 * Stuff from here on down is written by Ken Hirsch
 * and you may use it for any purpose.
 * No warranty, express or implied.
 */

#include <stddef.h>
#include <sys/ioctl.h>
#include <netinet/in.h>

#ifndef _SOCKLEN_T
typedef unsigned int socklen_t;
#define _SOCKLEN_T
#endif

static int max_io_size(int filedes);

ssize_t
mpe_read(int filedes, void *buffer, size_t len)
{
  int maxio;
  if (len > 4096 && (len > (maxio = max_io_size(filedes))))
    len = maxio;

  return read(filedes, buffer, len);
}

ssize_t
mpe_write(int filedes, const void *buffer, size_t len)
{
  int written = 0;
  int orig_len = len;
  int maxio = (len>4096)?max_io_size(filedes):INT_MAX;
  const char *buf = (const char *)buffer;

  do {
    written = write(filedes, buf, len>maxio?maxio:len);
    if (written < 0)
      break;
    len -= written;
    buf += written;
  } while (len > 0);

  if (written < 0 && len == orig_len)
    return -1;
  else
    return orig_len - len;
}


ssize_t
mpe_send(int socket, const void *buffer, size_t len, int flags)
{
  int written = 0;
  int orig_len = len;
  int maxio = (len>4096)?max_io_size(socket):INT_MAX;
  const char *buf = (const char *)buffer;

  do {
    written = send(socket, buf, len>maxio?maxio:len, flags);
    if (written < 0)
      break;
    len -= written;
    buf += written;
  } while (len > 0);

  if (written < 0 && len == orig_len)
    return -1;
  else
    return orig_len - len;
}

ssize_t
mpe_sendto(int socket, const void *buffer, size_t len,
       int flags, const struct sockaddr *dest_addr,
       socklen_t dest_len)
{
  int written = 0;
  int orig_len = len;
  int maxio = (len>4096)?max_io_size(socket):INT_MAX;
  const char *buf = (const char *)buffer;

  do {
    written = 
       sendto(socket, buf, len>maxio?maxio:len, flags, dest_addr, dest_len);
    if (written < 0)
      break;
    len -= written;
    buf += written;
  } while (len > 0);

  if (written < 0 && len == orig_len)
    return -1;
  else
    return orig_len - len;
}


ssize_t
mpe_recv(int socket, void *buffer, size_t len, int flags)
{
  int maxio;
  if (len > 4096 && (len > (maxio = max_io_size(socket))))
    len = maxio;
  return recv(socket, buffer, len, flags);
}

ssize_t
mpe_recvfrom(int socket, void *buffer, size_t len,
           int flags, struct sockaddr *address,
           socklen_t *address_len) 
{
  int maxio;
  if (len > 4096 && (len > (maxio = max_io_size(socket))))
    len = maxio;
  return recvfrom(socket, buffer, len, flags, address, address_len);
}

/*
   I didn't do thse two:
ssize_t mpe_recvmsg(int, struct msghdr *, int);
ssize_t mpe_sendmsg(int, const struct msghdr *, int);
*/

/* 
 * On MPE/iX (at least version 6.0), a getsockname()
 * performed on a socket that is listening
 * will return INADDR_ANY, even if you used
 * bind to bind it to a particular IP address.
 *
 * (In fact, it appears that the socket always acts as
 *  if you used INADDR_ANY.)
 *
 * Here I save the IP address used in bind
 * So I can get it in getsockname()
 *
 */

/* I just save 40.  Usually one or two should be enough
 */

int
mpe_connect(int socket, 
    const struct sockaddr *address,
    socklen_t address_len)
{
  int ret = connect(socket, address, address_len);
  if (ret < 0 && errno == EINPROGRESS)
  {
    /* Need to call getsockopt to clear socket error */
    int socket_error;
    socklen_t err_size = sizeof(socket_error);
    (void)getsockopt(socket, SOL_SOCKET, SO_ERROR,
                          &socket_error, &err_size);
    errno = EINPROGRESS;
  }
  return ret;
}

static struct {
  int fd;
  struct in_addr holdaddr;
} holdbind[40];
#define HOLDBINDLAST ((sizeof(holdbind))/(sizeof(holdbind[0])))
static int nextbind;

/*
 * Fix peculiarities of bind() on MPE
 * 1. call GETPRIVMODE to bind to ports < 1024
 * 2. save IP address for future calls to getsockname
 * 3. set IP address to 0 (INADDR_ANY)
 */

int
mpe_bind(int socket, const struct sockaddr *address, socklen_t address_len)
{
   int i;
   int result;
   int mpeprivmode=0;
   extern void GETPRIVMODE(void);
   extern void GETUSERMODE(void);

   for (i = 0; i<HOLDBINDLAST; i++) {
     if (holdbind[i].fd == socket)
       break;
   }
   /* If we didn't find previously used slot, use next */
   if (i == HOLDBINDLAST)
     i = nextbind;

   holdbind[i].fd = socket;

   memset(&holdbind[i].holdaddr, '\0', sizeof(holdbind[i].holdaddr));
   if (address->sa_family == AF_INET
      && address_len >= offsetof(struct sockaddr_in, sin_addr)
                        +sizeof(struct in_addr)) {
      holdbind[i].holdaddr = ((struct sockaddr_in *)address)->sin_addr;
   }
   if (i == nextbind)
   {
     if (++nextbind >= HOLDBINDLAST)
       nextbind = 0;
   }

   if (address->sa_family == AF_INET)
   {
        /* The address *MUST* stupidly be zero. */
        ((struct sockaddr_in *)address)->sin_addr.s_addr = INADDR_ANY;
        /* PRIV mode is required to bind() to ports < 1024. */
        if (((struct sockaddr_in *)address)->sin_port < 1024 &&
            ((struct sockaddr_in *)address)->sin_port > 0) {
            GETPRIVMODE(); /* If this fails, we are aborted by MPE/iX. */
            mpeprivmode = 1;
        }
    }
    result = bind(socket, address, address_len);
    if (mpeprivmode)
    {
      GETUSERMODE();
    }
    return result;

}

int 
mpe_getsockname(int socket, struct sockaddr *address, socklen_t *address_len)
{
  int ret;
  ret = getsockname(socket, address, address_len);
  if (ret == 0 
      && address->sa_family == AF_INET
      && *address_len >= offsetof(struct sockaddr_in, sin_addr)
                        +sizeof(struct in_addr)
      && ((struct sockaddr_in *)address)->sin_addr.s_addr == INADDR_ANY) {
    int i;
    for (i=0; i<HOLDBINDLAST; i++) {
      if (holdbind[i].fd == socket)
      {
        ((struct sockaddr_in *)address)->sin_addr.s_addr 
            = holdbind[i].holdaddr.s_addr;
        break;
      }
    }
  }
  return ret;
}

int 
mpe_getpeername(int socket, struct sockaddr *address, socklen_t *address_len)
{
  int ret;
  ret = getpeername(socket, address, address_len);
  if (ret == 0)
  {
    /* Try a zero-length write to see if socket really connected */
    int written = write(socket, "", 0);
    if (written < 0)
      ret = -1;
  }
  return ret;
}


static int
max_io_size(int filedes)
{
  int save_errno;
  struct sockaddr sa;
  int len;
  int result = INT_MAX; /* all other files */

  save_errno = errno;
  len = sizeof sa;
  if (getsockname(filedes, &sa, &len) == -1)
  {
     if (errno == EAFNOSUPPORT) /* AF_UNIX socket */
       result = 4096;
     errno = save_errno;
  } else {
    result = 30000; /* AF_INET sock max */
  }
  return result;
}

--- NEW FILE: mpeix_setjmp.c ---
/* Workaround for CR JAGab60546 setjmp/longjmp and
   JAGad55982 sigsetjmp/siglongjmp from shared libraries. */

/*
  * tabstop=4
  *
  * _setjmp/setjmp/sigsetjmp and
  *_longjmp/longjmp/siglongjmp.
  *
  * Written by Mark Klein, 10 October, 2000
  * Updated for gcc 3.x 6 October, 2005
  *
  * These routines are GCC specific and MUST BE COMPILED
  * WITH -O2
  *
  * The existing setjmp/longjmp code in both libc.a and XL.PUB.SYS
  * are not SR4 aware and cause problems when working with shared
  * libraries (XLs), especially when executing a longjmp between
  * XLs. This code preserves SR4 and will successfully handle
  * a cross space longjmp. However, the setjmp code must be
  * bound into each XL from which it will be called as well as
  * being bound into the main program.
  */

/*
  * The following macro takes the contents of the jmpbuf and
  * restores the registers from them. There is other code
  * elsewhere that ensures that __jmpbuf is %r26 at this
  * point in time. If it becomes some other register, that
  * register must be the last restored. At the end will
  * be a branch external that will cause a cross space
  * return if needed.
  */
#define RESTORE_REGS_AND_RETURN(__jmpbuf, __retval)                  \
({                                                                   \
         __asm__ __volatile__ (                                      \
             "   ldw    0(%%sr0, %0), %%rp\n"                        \
             "\t   ldw    4(%%sr0, %0), %%sp\n"                      \
             "\t   ldw   16(%%sr0, %0), %%r3\n"                      \
             "\t   ldw   20(%%sr0, %0), %%r4\n"                      \
             "\t   ldw   24(%%sr0, %0), %%r5\n"                      \
             "\t   ldw   28(%%sr0, %0), %%r6\n"                      \
             "\t   ldw   32(%%sr0, %0), %%r7\n"                      \
             "\t   ldw   36(%%sr0, %0), %%r8\n"                      \
             "\t   ldw   40(%%sr0, %0), %%r9\n"                      \
             "\t   ldw   44(%%sr0, %0), %%r10\n"                     \
             "\t   ldw   48(%%sr0, %0), %%r11\n"                     \
             "\t   ldw   52(%%sr0, %0), %%r12\n"                     \
             "\t   ldw   56(%%sr0, %0), %%r13\n"                     \
             "\t   ldw   60(%%sr0, %0), %%r14\n"                     \
             "\t   ldw   64(%%sr0, %0), %%r15\n"                     \
             "\t   ldw   68(%%sr0, %0), %%r16\n"                     \
             "\t   ldw   72(%%sr0, %0), %%r17\n"                     \
             "\t   ldw   76(%%sr0, %0), %%r18\n"                     \
             "\t   ldw   80(%%sr0, %0), %%r19\n"                     \
             "\t   ldw   84(%%sr0, %0), %%r20\n"                     \
             "\t   ldw   88(%%sr0, %0), %%r21\n"                     \
             "\t   ldw   92(%%sr0, %0), %%r22\n"                     \
             "\t   ldw   96(%%sr0, %0), %%r23\n"                     \
             "\t   ldw  100(%%sr0, %0), %%r24\n"                     \
             "\t   ldw  104(%%sr0, %0), %%r25\n"                     \
             "\t   ldw  112(%%sr0, %0), %%r27\n"                     \
             "\t   ldw  116(%%sr0, %0), %%r1\n"                      \
             "\t   mtsp %%r1, %%sr3\n"                               \
             "\t   ldw  120(%%sr0, %0), %%r1\n"                      \
             "\t   mtsp %%r1, %%sr1\n"                               \
             "\t   or,<>   %%r0, %1, %%r0\n"                         \
             "\t     ldi 1, %%r28\n"                                 \
             "\t   ldw  108(%%sr0, %0), %%r26\n"                     \
             "\t   be       0(%%sr1, %%rp)\n"                        \
             "\t   mtsp %%r1, %%sr4\n"                               \
                 : \
                 : "r" (__jmpbuf),                                   \
                   "r" (__retval));                                  \
})

/*
  * The following macro extracts the signal mask
  * from  __jmpbuf from the 3rd and 4th words and
  * if non-zero, calls sigprocmask with that value
  * to set the signal mask. This macro is usually
  * invoked before the registers are restored in
  * the longjmp routines and it can clobber things
  * without needing to spill them as a result.
  * A quick frame is built before making the
  * call and cut back just afterwards.
  * The ldi 2, %r26 is actually SIG_SETMASK from
  * /usr/include/signal.h.
  */
#define RESTORE_SIGNAL_MASK(__jmpbuf)                                \
({                                                                   \
   __asm__ __volatile__ (                                            \
              "  ldw 8(%0), %%r26\n"                                 \
              "\t  comibt,=,n 0,%%r26,.+36\n"                        \
              "\t    ldo 64(%%sp), %%sp\n"                           \
              "\t    stw %0, -28(%%sp)\n"                            \
              "\t    ldi 0, %%r24\n"                                 \
              "\t    ldo 8(%0), %%r25\n"                             \
              "\t    .import sigprocmask,code\n"                     \
              "\t    bl sigprocmask,%%rp\n"                          \
              "\t    ldi 2, %%r26\n"                                 \
              "\t    ldw -28(%%sr0, %%sp), %0\n"                     \
              "\t    ldo -64(%%sp), %%sp\n"                          \
                     :                                               \
                     : "r" (__jmpbuf));                              \
})

/*
  * This macro saves the current contents of the
  * registers to __jmpbuf. Note that __jmpbuf is
  * guaranteed elsewhere to be in %r26. We do not
  * want it spilled, nor do we want a new frame
  * built.
  */
#define SAVE_REGS(__jmpbuf)                                          \
({                                                                   \
   __asm__ __volatile__ (                                            \
              "  stw %%rp,     0(%%sr0, %0)\n"                       \
              "\t  stw %%sp,     4(%%sr0, %0)\n"                     \
              "\t  stw %%r0,     8(%%sr0, %0)\n"                     \
              "\t  stw %%r3,    16(%%sr0, %0)\n"                     \
              "\t  stw %%r4,    20(%%sr0, %0)\n"                     \
              "\t  stw %%r5,    24(%%sr0, %0)\n"                     \
              "\t  stw %%r6,    28(%%sr0, %0)\n"                     \
              "\t  stw %%r7,    32(%%sr0, %0)\n"                     \
              "\t  stw %%r8,    36(%%sr0, %0)\n"                     \
              "\t  stw %%r9,    40(%%sr0, %0)\n"                     \
              "\t  stw %%r10,   44(%%sr0, %0)\n"                     \
              "\t  stw %%r11,   48(%%sr0, %0)\n"                     \
              "\t  stw %%r12,   52(%%sr0, %0)\n"                     \
              "\t  stw %%r13,   56(%%sr0, %0)\n"                     \
              "\t  stw %%r14,   60(%%sr0, %0)\n"                     \
              "\t  stw %%r15,   64(%%sr0, %0)\n"                     \
              "\t  stw %%r16,   68(%%sr0, %0)\n"                     \
              "\t  stw %%r17,   72(%%sr0, %0)\n"                     \
              "\t  stw %%r18,   76(%%sr0, %0)\n"                     \
              "\t  stw %%r19,   80(%%sr0, %0)\n"                     \
              "\t  stw %%r20,   84(%%sr0, %0)\n"                     \
              "\t  stw %%r21,   88(%%sr0, %0)\n"                     \
              "\t  stw %%r22,   92(%%sr0, %0)\n"                     \
              "\t  stw %%r23,   96(%%sr0, %0)\n"                     \
              "\t  stw %%r24,  100(%%sr0, %0)\n"                     \
              "\t  stw %%r25,  104(%%sr0, %0)\n"                     \
              "\t  stw %%r26,  108(%%sr0, %0)\n"                     \
              "\t  stw %%r27,  112(%%sr0, %0)\n"                     \
              "\t  mfsp %%sr3, %%r1\n"                               \
              "\t  stw %%r1,   116(%%sr0, %0)\n"                     \
              "\t  mfsp %%sr4, %%r1\n"                               \
              "\t  stw %%r1,   120(%%sr0, %0)\n"                     \
                   :                                                 \
                   : "r" (__jmpbuf));                                \
})

/*
  * This macro will save the signal mask to the
  * __jmpbuf if __savemask is non-zero. By this
  * point in time, the other resisters have been
  * saved into the __jmpbuf.
  * The ldi 0, %r26 is actually SIG_BLOCK from
  * /usr/include/signal.h. Since the block is
  * an OR of the bits, this does not change the
  * mask, but returns it into the double word at
  * the address in %r24.
  */
#define SAVE_SIGNAL_MASK(__jmpbuf,__savemask)                        \
({                                                                   \
   __asm__ __volatile__ (                                            \
              "  comibt,=,n 0,%1,.+36\n"                             \
              "\t    stw %%rp, -20(%%sr0, %%sp)\n"                   \
              "\t    ldo 64(%%sp), %%sp\n"                           \
              "\t    ldo 8(%0), %%r24\n"                             \
              "\t    ldi 0, %%r25\n"                                 \
              "\t    .import sigprocmask,code\n"                     \
              "\t    bl sigprocmask,%%rp\n"                          \
              "\t    ldi 0, %%r26\n"                                 \
              "\t    ldo -64(%%sp), %%sp\n"                          \
              "\t    ldw -20(%%sr0, %%sp), %%rp\n"                   \
                     :                                               \
                     : "r" (__jmpbuf),                               \
                       "r" (__savemask));                            \
})

/*
  * Construct a jump buffer and unconditionally save
  * the signal mask. Return a 0 unconditinoally.
  * Care is taken here and in the macros to assume
  * the __jumpbuf is in %r26 and that the return
  * value will be in %r28. It is done this way to
  * prevent a frame from being built and any registers
  * from being spilled.
  */
int setjmp(register void *jmpbuf)
{
   register int __jmpbuf asm ("%r26");

   SAVE_REGS(__jmpbuf);
   SAVE_SIGNAL_MASK(__jmpbuf, 1);
   return 0;
}

/*
  * Construct a jump buffer but do not save the
  * signal mask.
  */
int _setjmp(register void *jmpbuf)
{
   register int __jmpbuf asm ("%r26");

   SAVE_REGS(__jmpbuf);
   return 0;
}

/*
  * Construct a jump buffer and conditionally save
  * the signal mask. The mask is saved if the
  * savemask parameter is non-zero.
  */
int sigsetjmp(register void *jmpbuf, register int savemask)
{
   register int __jmpbuf   asm ("%r26");
   register int __savemask asm ("%r25");

   SAVE_REGS(__jmpbuf);
   SAVE_SIGNAL_MASK(__jmpbuf, __savemask);
   return 0;
}

/*
  * Return to the location established in the jmpbuf,
  * and place the value in i2 in %r28. Registers
  * %r4 and %r5 are co-opted to save the address and
  * value of jmpbuf and the return value. The signal
  * mask is re-established if needed, then the
  * address of jmpbuf and value of retval are placed
  * into %r26 and %r28 correspondingly. This routine
  * will never return to its caller and the stack
  * will be cut back to whatever exists in the jmpbuf.
  */
void longjmp(register void *jmpbuf, register int i2)
{
   register int __jmpbuf        asm ("%r26");
   register int __retval        asm ("%r28");

   __asm__ __volatile__ (
              "  copy %0, %%r4\n"
              "\t  copy %1, %%r5\n"
                     :
                     : "r" (jmpbuf),
                       "r" (i2));

   RESTORE_SIGNAL_MASK (__jmpbuf);

   __asm__ __volatile__ (
              "  copy %%r4, %0\n"
              "\t  copy %%r5, %1\n"
                     : "=r" (__jmpbuf),
                       "=r" (__retval));

   RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
}

/*
  * Return to the location established in the jmpbuf,
  * but do not restore the signal mask.
  */
void _longjmp(register void *jmpbuf, register int i2)
{
   register int __retval         asm ("%r28");
   register int __jmpbuf         asm ("%r26");

   __jmpbuf = (int)jmpbuf;
   __retval = i2;

   RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
}

/*
  * Return to the location establsihed in the jmpbuf,
  * and conditionally re-establish the signal mask.
  */
void siglongjmp(register void *jmpbuf, register int i2)
{
   register int __jmpbuf        asm ("%r26");
   register int __retval        asm ("%r28");

   __asm__ __volatile__ (
              "  copy %0, %%r4\n"
              "\t  copy %1, %%r5\n"
                     :
                     : "r" (jmpbuf),
                       "r" (i2));

   RESTORE_SIGNAL_MASK (__jmpbuf);

   __asm__ __volatile__ (
              "  copy %%r4, %0\n"
              "\t  copy %%r5, %1\n"
                     : "=r" (__jmpbuf),
                       "=r" (__retval));

   RESTORE_REGS_AND_RETURN (__jmpbuf, __retval);
}

#ifdef TEST
int buf1[50];
int buf2[50];

foo() {
   printf("In routine foo(). Doing Longjmp.\n");
   longjmp(buf1, 123);
   printf("This is in foo after the longjmp() call. Should not reach here.\n");
}

bar(int ret) {
   printf("In routine bar(%d). Doing siglongjmp.\n",ret);
   siglongjmp(buf2, ret);
   printf("This is in bar after the siglongjmp() call. Should not reach here.\n");
}

main() {
   int i;
   if ((i = setjmp(buf1)))
     {
           printf("This is the return from the longjmp. i: %d\n",i);
         }
   else
     {
           printf("Jump buffer established, i: %d. Calling foo()\n",i);
           foo();
           printf("This is in main after the foo() call. Should not reach here.\n ");
         }

   if ((i = sigsetjmp(buf2,0)))
     {
           printf("This is the return from the longjmp. i: %d\n",i);
         }
   else
     {
           printf("Jump buffer established, i: %d. Calling bar(456)\n",i);
           bar(456);
           printf("This is in main after the bar(456) call. Should not reach here.\n");
         }

   if ((i = sigsetjmp(buf2,1)))
     {
           printf("This is the return from the longjmp. i: %d\n",i);
         }
   else
     {
           printf("Jump buffer established, i: %d. Calling bar(789)\n",i);
           bar(789);
           printf("This is in main after the bar(789) call. Should not reach here.\n");
         }
}
#endif

--- NEW FILE: nm ---
#!/bin/sh

# MPE doesn't have a native nm, and the gcc nm isn't quite fully functional.
#
# If Perl Configure is calling us, then use the native linker to extract the
# symbol table and reformat it into something nm-like.
#
# Else it must be gcc calling us during the final link phase, so call gcc nm.

if [ "$1" != "-configperl" ]; then
  # Oops, the caller must be expecting gcc nm.  Give it to them.
  /usr/local/bin/nm $@
  exit $?
fi

case $2 in
  *.a) LIST="LISTRL RL=$2;DATA;ENTRYSYM" ;;
  *.sl) LIST="LISTXL XL=$2;DATA;ENTRYSYM" ;;
  *) exit 0 ;;
esac

# I wanted to pipe this into awk, but it fell victim to a known pipe/streams
# bug on my multiprocessor machine.

callci xeq linkedit.pub.sys \"$LIST\" >nm.$$

/bin/awk '\
    / data  univ / { printf "%-20s|%10s|%-6s|%-7s|%s\n",$1,$5,"extern","data","?"} \
    / entry univ / { printf "%-20s|%10s|%-6s|%-7s|%s\n",$1,$7,"extern","entry","?"}' nm.$$

rm -f nm.$$

exit 0

--- NEW FILE: mpeixish.h ---
/*
 * The following symbols are defined if your operating system supports
 * functions by that name.  All Unixes I know of support them, thus they
 * are not checked by the configuration script, but are directly defined
 * here.
 */

/* HAS_IOCTL:
 *	This symbol, if defined, indicates that the ioctl() routine is
 *	available to set I/O characteristics
 */
#define	HAS_IOCTL		/**/
 
/* HAS_UTIME:
 *	This symbol, if defined, indicates that the routine utime() is
 *	available to update the access and modification times of files.
 */
#define HAS_UTIME		/**/

/* HAS_GROUP
 *	This symbol, if defined, indicates that the getgrnam() and
 *	getgrgid() routines are available to get group entries.
 */
#define HAS_GROUP		/**/

/* HAS_PASSWD
 *	This symbol, if defined, indicates that the getpwnam() and
 *	getpwuid() routines are available to get password entries.
 */
#define HAS_PASSWD		/**/

#define HAS_KILL
#define HAS_WAIT
  
/* USEMYBINMODE
 *	This symbol, if defined, indicates that the program should
 *	use the routine my_binmode(FILE *fp, char iotype, int mode) to insure
 *	that a file is in "binary" mode -- that is, that no translation
 *	of bytes occurs on read or write operations.
 */
#undef USEMYBINMODE

/* Stat_t:
 *	This symbol holds the type used to declare buffers for information
 *	returned by stat().  It's usually just struct stat.  It may be necessary
 *	to include <sys/stat.h> and <sys/types.h> to get any typedef'ed
 *	information.
 */
#define Stat_t struct stat

/* USE_STAT_RDEV:
 *	This symbol is defined if this system has a stat structure declaring
 *	st_rdev
 */
#define USE_STAT_RDEV 	/**/

/* ACME_MESS:
 *	This symbol, if defined, indicates that error messages should be 
 *	should be generated in a format that allows the use of the Acme
 *	GUI/editor's autofind feature.
 */
#undef ACME_MESS	/**/

/* UNLINK_ALL_VERSIONS:
 *	This symbol, if defined, indicates that the program should arrange
 *	to remove all versions of a file if unlink() is called.  This is
 *	probably only relevant for VMS.
 */
/* #define UNLINK_ALL_VERSIONS		/ **/

/* VMS:
 *	This symbol, if defined, indicates that the program is running under
 *	VMS.  It is currently automatically set by cpps running under VMS,
 *	and is included here for completeness only.
 */
/* #define VMS		/ **/

/* ALTERNATE_SHEBANG:
 *	This symbol, if defined, contains a "magic" string which may be used
 *	as the first line of a Perl program designed to be executed directly
 *	by name, instead of the standard Unix #!.  If ALTERNATE_SHEBANG
 *	begins with a character other then #, then Perl will only treat
 *	it as a command line if if finds the string "perl" in the first
 *	word; otherwise it's treated as the first line of code in the script.
 *	(IOW, Perl won't hand off to another interpreter via an alternate
 *	shebang sequence that might be legal Perl code.)
 */
/* #define ALTERNATE_SHEBANG "#!" / **/

#include <signal.h>

#ifndef SIGABRT
#    define SIGABRT SIGILL
#endif
#ifndef SIGILL
#    define SIGILL 6         /* blech */
#endif
#define ABORT() kill(PerlProc_getpid(),SIGABRT);

/*
 * fwrite1() should be a routine with the same calling sequence as fwrite(),
 * but which outputs all of the bytes requested as a single stream (unlike
 * fwrite() itself, which on some systems outputs several distinct records
 * if the number_of_items parameter is >1).
 */
#define fwrite1 fwrite

#define Stat(fname,bufptr) stat((fname),(bufptr))
#define Fstat(fd,bufptr)   fstat((fd),(bufptr))
#define Fflush(fp)         fflush(fp)
#define Mkdir(path,mode)   mkdir((path),(mode))

#ifndef PERL_SYS_INIT
#  define PERL_SYS_INIT(c,v)	PERL_FPU_INIT MALLOC_INIT
#endif

#ifndef PERL_SYS_TERM
#define PERL_SYS_TERM()		MALLOC_TERM
#endif

#define BIT_BUCKET "/dev/null"

#define dXSUB_SYS

/* pw_passwd, pw_gecos, pw_age, pw_comment exist in the struct passwd
 * but they contain uninitialized (as in "accessing them will crash perl")
 * pointers.  Stay away from them. */

#undef PWGECOS
#undef PRPASSWD
#undef PWAGE
#undef PWCOMMENT

/* various missing external function declarations */

#include <sys/ipc.h>
extern key_t ftok (char *pathname, char id);
extern char *gcvt (double value, int ndigit, char *buf);
extern int isnan (double value);
extern void srand48(long int seedval);
extern double drand48(void);
extern double erand48(unsigned short xsubi[3]);
extern long jrand48(unsigned short xsubi[3]);
extern void lcong48(unsigned short param[7]);
extern long lrand48(void);
extern long mrand48(void);
extern long nrand48(unsigned short xsubi[3]);
extern unsigned short *seed48(unsigned short seed16v[3]);

/* various missing constants -- define 'em */

#define PF_UNSPEC 0

/* declarations for wrappers in mpeix.c */

#include <time.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>


extern int ftruncate(int fd, long wantsize);
extern int gettimeofday( struct timeval *tp, struct timezone *tpz );
extern int truncate(const char *pathname, off_t length);

extern int mpe_read(int filedes, void *buffer, size_t len);
extern int mpe_write(int filedes, const void *buffer, size_t len);
extern int mpe_send(int socket, const void *buffer, size_t len, int flags);
extern int mpe_sendto(int socket, const void *buffer, size_t len,
       int flags, const struct sockaddr *dest_addr,
       size_t dest_len);
extern int mpe_recv(int socket, void *buffer, size_t length, int flags);
extern int mpe_recvfrom(int socket, void *buffer, size_t length,
           int flags, struct sockaddr *address,
           size_t *address_len) ;
extern int mpe_bind(int socket, const struct sockaddr *address,
   size_t address_len);
extern int mpe_getsockname(int socket, struct sockaddr *address,
  size_t *address_len);
extern int mpe_getpeername(int socket, struct sockaddr *address, 
  size_t *address_len);

/* Replacements to fix various socket problems -- see mpeix.c */
#define fcntl mpe_fcntl
#define read mpe_read
#define write mpe_write
#define send mpe_send
#define sendto mpe_sendto
#define recv mpe_recv
#define recvfrom mpe_recvfrom
#define bind mpe_bind
#define getsockname mpe_getsockname
#define getpeername mpe_getpeername




More information about the dslinux-commit mailing list