From: Ken Hirsch Date: Thu, 12 Jan 2006 13:26:16 +0000 (-0500) Subject: Re: Today's compiling adventure X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=f382e41b709944009ae4d545ba1b94e4ddc6a66e;p=p5sagit%2Fp5-mst-13.2.git Re: Today's compiling adventure Message-ID: <43C69F48.7090600@ftml.net> p4raw-id: //depot/perl@26807 --- diff --git a/README.mpeix b/README.mpeix index 0f7c0ac..f6727b1 100644 --- a/README.mpeix +++ b/README.mpeix @@ -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 diff --git a/hints/mpeix.sh b/hints/mpeix.sh index a5152af..afa6cf8 100644 --- a/hints/mpeix.sh +++ b/hints/mpeix.sh @@ -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' diff --git a/mpeix/mpeix.c b/mpeix/mpeix.c index 4898fd7..a758c23 100644 --- a/mpeix/mpeix.c +++ b/mpeix/mpeix.c @@ -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 #include #include #include +#include +#include +#include #include 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 /* off_t, required by open() */ -#include /* required by open() */ -#include /* open() */ -#include /* close() */ -#include /* perror(), sprintf() */ +#include /* off_t, required by open() */ +#include /* required by open() */ +#include /* open() */ +#include /* close() */ +#include /* 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 /* structs timeval & timezone, - difftime(), localtime(), mktime(), time() */ -#include /* gettimeofday() */ +#include /* 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 @@ -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 +#include +#include + +#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; isa_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; isin_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 index 0000000..955fe03 --- /dev/null +++ b/mpeix/mpeix_setjmp.c @@ -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 diff --git a/mpeix/mpeixish.h b/mpeix/mpeixish.h index 49ef435..165aae7 100644 --- a/mpeix/mpeixish.h +++ b/mpeix/mpeixish.h @@ -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 -#include +#include +#include +#include + 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