Re: Today's compiling adventure
Ken Hirsch [Thu, 12 Jan 2006 13:26:16 +0000 (08:26 -0500)]
Message-ID: <43C69F48.7090600@ftml.net>

p4raw-id: //depot/perl@26807

README.mpeix
hints/mpeix.sh
mpeix/mpeix.c
mpeix/mpeix_setjmp.c [new file with mode: 0644]
mpeix/mpeixish.h

index 0f7c0ac..f6727b1 100644 (file)
@@ -11,7 +11,8 @@ README.mpeix - Perl/iX for HP e3000 MPE
    http://www.bixby.org/mark/perlix.html
    http://jazz.external.hp.com/src/hp_freeware/perl/
    Perl language for MPE
-   Last updated July 29, 2003 @ 2100 UTC
+   Last updated January 12, 2006 @ 2100 UTC
+
 
 =head1 NOTE
 
@@ -31,6 +32,58 @@ Use which ever one is more recent.
 
 =head1 What's New in Perl for MPE/iX
 
+January 12, 2006
+
+=over 4
+
+=item *
+
+Updated for perl-5.8.8 and perl-5.9.3 by Ken Hirsch.
+
+Simplified the build process by using the MPEAUTOCONF
+functionality in Mark Klein's ld.
+
+If you build this from scratch, make sure you have a version
+of ld which supports it.  In the shell, type
+
+  ld --help
+    and look for AUTOCONF or MPEAUTOCONF near the bottom
+
+  or do this:
+  ld --help 2>&1 | grep AUTOCONF
+
+If you see don't see AUTOCONF or MPEAUTOCONF, make sure you get a new
+version.
+
+You also do not have to use mpeix/relink after building, so the
+recommend sequence is:
+
+  ./Configure -de
+
+      # or ./Configure -de -Dusedevel 
+      # if you're building a development version
+
+  make
+  make test
+     # if you run this in a job, do "make test_notty"
+
+  make install
+
+Be prepared for a wait. These take much longer on MPE/iX than on a Unix
+system, because of a slow forking, mostly.  On a lightly-loaded HP3000
+Series 979 running MPE/iX 7.5:
+
+    Configure: 1 hour
+    make:      1 hour 15 minutes
+    make test  1 hour 45 minutes
+
+Various socket problems were fixed in mpeix.c.
+
+Mark Klein provided a fixed sigsetjmp (that works with dynamic
+libraries) in mpeix_setjmp.c
+
+=item *
+
 June 1, 2000
 
 =over 4
index a5152af..afa6cf8 100644 (file)
@@ -1,30 +1,23 @@
-# The MPE/iX linker doesn't complain about unresolved symbols, and so the only
-# way to test for unresolved symbols in a program is by attempting to run it.
-# But this is slow, and fraught with problems, so the better solution is to use
-# nm.
-#
-# MPE/iX lacks a fully functional native nm, so we need to use our fake nm
-# script which will extract the symbol info from the native link editor and
-# reformat into something nm-like.
-#
 # Created for 5.003 by Mark Klein, mklein@dis.com.
 # Substantially revised for 5.004_01 by Mark Bixby, markb@cccd.edu.
 # Revised again for 5.004_69 by Mark Bixby, markb@cccd.edu.
 # Revised for 5.6.0 by Mark Bixby, mbixby@power.net.
 # Revised for 5.7.3 by Mark Bixby, mark@bixby.org.
 # Revised for 5.8.0 by Mark Bixby, mark@bixby.org.
+# Revised for 5.8.8/5.9.3 by Ken Hirsch, kenhirsch@ftml.net
 #
 osname='mpeix'
 osvers=`uname -r | sed -e 's/.[A-Z]\.\([0-9]\)\([0-9]\)\.[0-9][0-9]/\1.\2/'`
+
 #
-# Force Configure to use our wrapper mpeix/nm script
-#
-PATH="$PWD/mpeix:$PATH"
-nm="$PWD/mpeix/nm"
-_nm=$nm
-nm_opt='-configperl'
-usenm='true'
-#
+# Don't use nm.  Instead, we'll use the MPEAUTOCONF environment variable
+# to force error for unresolved externals.
+# This is slower than nm (about 70 minutes instead of 35 minutes),
+# but much more reliable.
+
+usenm='false'
+export AUTOCONF=1 MPEAUTOCONF=1
+
 # Work around the broken inline cat bug that corrupts here docs
 #
 alias -x cat=/bin/cat
@@ -43,23 +36,31 @@ perlpath="$prefix/PERL"
 scriptdir="$prefix"
 startperl="#!$prefix/perl"
 startsh='#!/bin/sh'
+
 #
 # Compiling.
 #
 test -z "$cc" && cc='gcc'
 cccdlflags='none'
-ccflags="$ccflags -DMPE -D_POSIX_SOURCE -D_SOCKET_SOURCE -D_POSIX_JOB_CONTROL -DIS_SOCKET_CLIB_ITSELF"
-locincpth="$locincpth /usr/local/include /usr/contrib/include /BINDFW/CURRENT/include /SYSLOG/PUB"
+ccdlflags='-Xlinker -WL,xl=/usr/lib/libcurses.sl,/lib/libsvipc.sl,/usr/lib/libsocket.sl,/usr/lib/libstr.sl,/lib/libm.sl,/lib/libc.sl'
+ccflags="$ccflags -DMPE -D_POSIX_SOURCE -D_SOCKET_SOURCE -D_POSIX_JOB_CONTROL"
+locincpth="$locincpth /usr/local/include /usr/contrib/include /BIND/CURRENT/include /SYSLOG/PUB"
 test -z "$optimize" && optimize="-O2"
 ranlib='/bin/true'
 # Special compiling options for certain source files.
 # But what if you want -g?
 regcomp_cflags='optimize=-O'
 toke_cflags='ccflags="$ccflags -DARG_ZERO_IS_SCRIPT"'
+
 #
 # Linking.
 #
-lddlflags='-b'
+# Build a fixed sigsetjmp that can be used in dynamic libraries
+# This needs to be compiled with -O2, so I do it here, rather
+# than with make
+gcc -c -O2 mpeix/mpeix_setjmp.c
+lddlflags="-b $PWD/mpeix_setjmp.o"
+
 # Delete bsd and BSD from the library list.  Remove other randomly ordered
 # libraries and then re-add them in their proper order (the MPE linker is
 # order-sensitive).  Add additional MPE-specific libraries.
@@ -68,7 +69,7 @@ for mpe_remove in bind bsd BSD c curses m socket str svipc syslog; do
   libswanted="$*"
 done
 libswanted="$libswanted bind syslog curses svipc socket str m c"
-loclibpth="$loclibpth /usr/local/lib /usr/contrib/lib /BINDFW/CURRENT/lib /SYSLOG/PUB"
+loclibpth="$loclibpth /usr/local/lib /usr/contrib/lib /BIND/CURRENT/lib /SYSLOG/PUB"
 #
 # External functions and data items.
 #
@@ -78,68 +79,41 @@ loclibpth="$loclibpth /usr/local/lib /usr/contrib/lib /BINDFW/CURRENT/lib /SYSLO
 # but are merely dummy routines that return ENOTIMPL or ESYSERR.  Since they're
 # useless, let's just tell Perl to avoid them.  Also, a few data items are
 # 'undef' because while they may exist in structures, they are uninitialized.
-#
-# The 'define' cases are a bit weirder.  MPE has a libc.a, libc.sl, and two
-# special kernel shared libraries, /SYS/PUB/XL and /SYS/PUB/NL.  Much of what
-# is in libc.a is duplicated within XL and NL, so when we created libc.sl, we
-# omitted the duplicated functions.  Since Configure end ups scanning libc.sl,
-# we need to 'define' the functions that had been removed.
-#
-# We don't want to scan XL or NL because we would find way too many POSIX or
-# Unix named functions that are really vanilla MPE functions that do something
-# completely different than on POSIX or Unix.
-d_crypt='define'
-d_dbmclose='undef'
-d_difftime='define'
-d_dlerror='undef'
-d_dlopen='undef'
+
 d_Gconvert='gcvt((x),(n),(b))'
-d_getnbyaddr='define'
-d_getnbyname='define'
-d_getpbyname='define'
-d_getpbynumber='define'
-d_getsbyname='define'
-d_getsbyport='define'
-d_gettimeod='undef'
+
 d_inetaton='undef'
-d_lchown='undef'
-d_link='undef'
-d_mblen='define'
-d_mbstowcs='define'
-d_mbtowc='define'
-d_memchr='define'
-d_memcmp='define'
-d_memcpy='define'
-d_memmove='define'
-d_memset='define'
+
+# these fields exist, but are uninitialized
 d_pwage='undef'
 d_pwcomment='undef'
 d_pwgecos='undef'
 d_pwpasswd='undef'
+d_statblks='undef'
+
+# These functions exist, 
+#  but either return ENOSYS/ESYSERR/ENOSYS or work so differently
+# that it is not helpful to include them
+
+d_lchown='undef'
+d_link='undef'
 d_setegid='undef'
 d_seteuid='undef'
 d_setitimer='undef'
 d_setpgid='undef'
 d_setsid='undef'
-d_setvbuf='define'
-d_statblks='undef'
-d_strchr='define'
-d_strcoll='define'
-d_strerrm='strerror(e)'
-d_strerror='define'
-d_strtod='define'
-d_strtol='define'
-d_strtoul='define'
-d_strxfrm='define'
-d_syserrlst='define'
-d_time='define'
-d_wcstombs='define'
-d_wctomb='define'
-#
+
+
+# These are defined in mpeix/mpeix.c
+d_gettimeod='define'
+d_truncate='define'
+
 # Include files.
 #
-i_gdbm='undef' # the port is currently incomplete
+#??i_gdbm='undef' # the port is currently incomplete
+
 i_termios='undef' # we have termios, but not the full set (just tcget/setattr)
+
 i_time='define'
 i_systime='undef'
 i_systimek='undef'
@@ -148,17 +122,15 @@ timeincl='/usr/include/time.h'
 # Data types.
 #
 timetype='time_t'
-#
+
 # Functionality.
 #
 uselargefiles="$undef"
-#
+
 # Expected functionality provided in mpeix.c.
 #
-archobjs='mpeix.o'
 
 # Help gmake find mpeix.c
 test -h mpeix.c || ln -s mpeix/mpeix.c mpeix.c
 
-d_gettimeod='define'
-d_truncate='define'
+archobjs='mpeix.o mpeix_setjmp.o'
index 4898fd7..a758c23 100644 (file)
@@ -194,10 +194,19 @@ void __perl_mpe_move_fast(int len,                 // %r26 == byte length
  *
  */
 
+#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);
@@ -205,23 +214,28 @@ 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);
-}
+int
+ftruncate(int fd, long wantsize)
+{
+  int ccode_return,dummy=0;
 
-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);
-}
+  if (lseek(fd, wantsize, SEEK_SET) < 0)
+  {
+      return (-1);
+  }
 
-return (0);
+  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);
 }
 
 /*
@@ -268,74 +282,71 @@ return (0);
       PRINT_ERROR - make this function print an error message to stderr
 */
 
-#ifndef _POSIX_SOURCE
-# define _POSIX_SOURCE
-#endif
 
-#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() */
+#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;
+        int fd;
 #ifdef PRINT_ERROR
-       char error_msg[80+1];
+        char error_msg[80+1];
 #endif
 
-       if (length == 0)
-       {
-               if ( (fd = open(pathname, O_WRONLY | O_TRUNC)) < 0)
-               {
-                       /* errno already set */
+        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);
+                        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 */
+                        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);
+                        sprintf(error_msg,
+                                "truncate(): open(%s, O_WRONLY)\0",
+                                pathname);
+                        perror(error_msg);
 #endif
-                       return -1;
-               }
+                        return -1;
+                }
 
-               if (ftruncate(fd, length) < 0)
-               {
-                       /* errno already set */
+                if (ftruncate(fd, length) < 0)
+                {
+                        /* errno already set */
 #ifdef PRINT_ERROR
-                       perror("truncate(): ftruncate()");
+                        perror("truncate(): ftruncate()");
 #endif
-                       return -1;
-               }
-       }
+                        return -1;
+                }
+        }
 
-       if (close(fd) < 0)
-       {
-               /* errno already set */
+        if (close(fd) < 0)
+        {
+                /* errno already set */
 #ifdef PRINT_ERROR
-               perror("truncate(): close()");
+                perror("truncate(): close()");
 #endif
-               return -1;
-       }
+                return -1;
+        }
 
-       return 0;
+        return 0;
 } /* truncate() */
 
 /* 
@@ -378,9 +389,8 @@ truncate(const char *pathname, off_t length)
 # define _SOCKET_SOURCE
 #endif
 
-#include <time.h>      /* structs timeval & timezone,
-                               difftime(), localtime(), mktime(), time() */
-#include <sys/time.h>  /* gettimeofday() */
+#include <time.h>       /* structs timeval & timezone,
+                                difftime(), localtime(), mktime(), time() */
 
 extern int TIMER();
 
@@ -455,15 +465,15 @@ struct timezone *tpz;
 /*
 **  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.
+**      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().
+**      Parameters:
+**              same as fcntl().
 **
-**     Returns:
-**             same as fcntl().
+**      Returns:
+**              same as fcntl().
 */
 
 #include <stdarg.h>
@@ -472,35 +482,321 @@ struct timezone *tpz;
 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;
-       }
+        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;
 }
diff --git a/mpeix/mpeix_setjmp.c b/mpeix/mpeix_setjmp.c
new file mode 100644 (file)
index 0000000..955fe03
--- /dev/null
@@ -0,0 +1,355 @@
+/* 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
index 49ef435..165aae7 100644 (file)
@@ -138,6 +138,14 @@ 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 */
 
@@ -146,10 +154,40 @@ extern void srand48(long int seedval);
 /* declarations for wrappers in mpeix.c */
 
 #include <time.h>
-#include <sys/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