X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=mpeix%2Fmpeix.c;h=a758c23be9ed9978d887fc3c6334a55247c2d90e;hb=15414d2b8179f5759172a843e63bd4f4857b021d;hp=7ad8eb2e8380fbfc0708c3ae7e9974877c31f219;hpb=feb334998467cf1c2ce6355cb4372da98b963090;p=p5sagit%2Fp5-mst-13.2.git diff --git a/mpeix/mpeix.c b/mpeix/mpeix.c index 7ad8eb2..a758c23 100644 --- a/mpeix/mpeix.c +++ b/mpeix/mpeix.c @@ -2,8 +2,9 @@ /* * gcc long pointer support code for HPPA. * Copyright 1998, DIS International, Ltd. - * Permission is granted to use this code under the GNU LIBRARY GENERAL - * PUBLIC LICENSE, Version 2, June 1991. + * 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; @@ -13,8 +14,9 @@ typedef struct { /* * gcc long pointer support code for HPPA. * Copyright 1998, DIS International, Ltd. - * Permission is granted to use this code under the GNU LIBRARY GENERAL - * PUBLIC LICENSE, Version 2, June 1991. + * 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) @@ -40,10 +42,10 @@ int __perl_mpe_getspaceid(void *source) * * Refer to the gcc documentation or http://www.dis.com/gnu/gcc_toc.html */ - asm volatile ( - "comiclr,= 0,%1,%%r28; - ldsid (%%r0,%1),%%r28; - stw %%r28, %0" + __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 @@ -57,11 +59,11 @@ LONGPOINTER __perl_mpe_longaddr(void *source) * Return the long pointer for the address in sr5 space. */ - asm volatile ( - "comiclr,= 0,%2,%%r28; - ldsid (%%r0,%2),%%r28; - stw %%r28, %0; - stw %2, %1" + __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 @@ -77,9 +79,9 @@ LONGPOINTER __perl_mpe_addtopointer(LONGPOINTER source, // %r26 == source off * Increment a longpointer. */ - asm volatile ( - "copy %0,%%r28; // copy space to r28 - add %1,%2,%%r29" // Increment the pointer + __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), @@ -96,14 +98,14 @@ void __perl_mpe_longmove(int len, // %r26 == byte length * Move data between two buffers in long pointer space. */ - asm volatile ( - ".import $$lr_unk_unk_long,MILLICODE; - mtsp %0,%%sr1; // copy source space to sr1 - copy %1,%%r26; // load source offset to r26 - copy %4,%%r24; // load length to r24 - copy %3,%%r25; // load target offset to r25 - bl $$lr_unk_unk_long,%%r31; // start branch to millicode - mtsp %2,%%sr2" // copy target space to sr2 + __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), @@ -124,11 +126,11 @@ int __perl_mpe_longpeek(LONGPOINTER source) */ unsigned int val; - asm volatile ( - "mtsp %1, %%sr1; - copy %2, %%r28; - ldw 0(%%sr1, %%r28), %%r28; - stw %%r28, %0" + __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 @@ -143,10 +145,10 @@ void __perl_mpe_longpoke(LONGPOINTER target, // %r25 == spaceid, %r26 == o /* * Store the val into long pointer space. */ - asm volatile ( - "mtsp %0,%%sr1; - copy %1, %%r28; - stw %2, 0(%%sr1, %%r28)" + __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 @@ -162,12 +164,12 @@ void __perl_mpe_move_fast(int len, // %r26 == byte length /* * Move using short pointers. */ - asm volatile ( - ".import $$lr_unk_unk,MILLICODE; - copy %1, %%r26; // Move source addr into pos - copy %2, %%r25; // Move target addr into pos - bl $$lr_unk_unk,%%r31; // Start branch to millicode - copy %0, %%r24" // Move length into position + __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 @@ -185,12 +187,26 @@ void __perl_mpe_move_fast(int len, // %r26 == byte length * 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 #include #include #include +#include +#include +#include #include extern void FCONTROL(short, short, longpointer); @@ -198,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); } /* @@ -261,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() */ /* @@ -336,8 +354,6 @@ truncate(const char *pathname, off_t length) gettimeofday() is UNIX, not POSIX. gettimeofday() is a BSD function. - - NAME gettimeofday - @@ -373,13 +389,16 @@ 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(); - +/* + * 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 ) @@ -442,3 +461,342 @@ struct timezone *tpz; 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 +#include + +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 +#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; +}