3 * gcc long pointer support code for HPPA.
4 * Copyright 1998, DIS International, Ltd.
5 * This code is free software; you may redistribute it and/or modify
6 * it under the same terms as Perl itself. (Relicensed for Perl in
7 * in April 2002 by Mark Klein.)
12 } LONGPOINTER, longpointer;
15 * gcc long pointer support code for HPPA.
16 * Copyright 1998, DIS International, Ltd.
17 * This code is free software; you may redistribute it and/or modify
18 * it under the same terms as Perl itself. (Relicensed for Perl in
19 * in April 2002 by Mark Klein.)
22 int __perl_mpe_getspaceid(void *source)
26 * Given the short pointer, determine it's space ID.
30 * The colons separate output from input parameters. In this case,
31 * the output of the instruction (output indicated by the "=" in the
32 * constraint) is to a memory location (indicated by the "m"). The
33 * input constraint indicates that the source to the instruction
34 * is a register reference (indicated by the "r").
35 * The general format is:
36 * asm("<instruction template>" : <output> : <input> : <clobbers>);
37 * where <output> and <input> are:
38 * "<constraint>" (<token>)
39 * <instruction template> is the PA-RISC instruction in template fmt.
40 * <clobbers> indicates those registers clobbered by the instruction
41 * and provides hints to the optimizer.
43 * Refer to the gcc documentation or http://www.dis.com/gnu/gcc_toc.html
45 __asm__ __volatile__ (
46 " comiclr,= 0,%1,%%r28\n"
47 "\t ldsid (%%r0,%1),%%r28\n"
49 : "=m" (val) // Output to val
50 : "r" (source) // Source must be gen reg
51 : "%r28"); // Clobbers %r28
55 LONGPOINTER __perl_mpe_longaddr(void *source)
59 * Return the long pointer for the address in sr5 space.
62 __asm__ __volatile__ (
63 " comiclr,= 0,%2,%%r28\n"
64 "\t ldsid (%%r0,%2),%%r28\n"
67 : "=m" (lptr.spaceid),
68 "=m" (lptr.offset) // Store to lptr
69 : "r" (source) // Source must be gen reg
70 : "%r28"); // Clobbers %r28
74 LONGPOINTER __perl_mpe_addtopointer(LONGPOINTER source, // %r26 == source offset
75 // %r25 == source space
76 int len) // %r24 == length in bytes
79 * Increment a longpointer.
82 __asm__ __volatile__ (
83 " copy %0,%%r28\n" // copy space to r28
84 "\t add %1,%2,%%r29" // Increment the pointer
86 : "r" (source.spaceid), // Source address
93 void __perl_mpe_longmove(int len, // %r26 == byte length
94 LONGPOINTER source, // %r23 == source space, %r24 == off
95 LONGPOINTER target) // sp-#56 == target space, sp-#52== off
98 * Move data between two buffers in long pointer space.
101 __asm__ __volatile__ (
102 " .import $$lr_unk_unk_long,MILLICODE\n"
103 "\t mtsp %0,%%sr1\n" // copy source space to sr1
104 "\t copy %1,%%r26\n" // load source offset to r26
105 "\t copy %4,%%r24\n" // load length to r24
106 "\t copy %3,%%r25\n" // load target offset to r25
107 "\t bl $$lr_unk_unk_long,%%r31\n" // start branch to millicode
108 "\t mtsp %2,%%sr2" // copy target space to sr2
110 : "r" (source.spaceid), // Source address
112 "r" (target.spaceid), // Target address
114 "r" (len) // Byte length
122 int __perl_mpe_longpeek(LONGPOINTER source)
125 * Fetch the int in long pointer space.
129 __asm__ __volatile__ (
131 "\t copy %2, %%r28\n"
132 "\t ldw 0(%%sr1, %%r28), %%r28\n"
134 : "=m" (val) // Output val
135 : "r" (source.spaceid), // Source space ID
136 "r" (source.offset) // Source offset
137 : "%r28"); // Clobbers %r28
142 void __perl_mpe_longpoke(LONGPOINTER target, // %r25 == spaceid, %r26 == offset
143 unsigned int val) // %r24 == value
146 * Store the val into long pointer space.
148 __asm__ __volatile__ (
150 "\t copy %1, %%r28\n"
151 "\t stw %2, 0(%%sr1, %%r28)"
153 : "r" (target.spaceid), // Target space ID
154 "r" (target.offset), // Target offset
155 "r" (val) // Value to store
156 : "%r28" // Clobbers %r28
157 ); // Copy space to %sr1
160 void __perl_mpe_move_fast(int len, // %r26 == byte length
161 void *source, // %r25 == source addr
162 void *target) // %r24 == target addr
165 * Move using short pointers.
167 __asm__ __volatile__ (
168 " .import $$lr_unk_unk,MILLICODE\n"
169 "\t copy %1, %%r26\n" // Move source addr into pos
170 "\t copy %2, %%r25\n" // Move target addr into pos
171 "\t bl $$lr_unk_unk,%%r31\n" // Start branch to millicode
172 "\t copy %0, %%r24" // Move length into position
174 : "r" (len), // Byte length
175 "r" (source), // Source address
176 "r" (target) // Target address
177 : "%r24", // Clobbers
184 * ftruncate - set file size, BSD Style
186 * shortens or enlarges the file as neeeded
187 * uses some undocumented locking call. It is known to work on SCO unix,
188 * other vendors should try.
189 * The #error directive prevents unsupported OSes
191 * ftruncate/truncate code by Mark Bixby.
192 * This code is free software; you may redistribute it and/or modify
193 * it under the same terms as Perl itself.
197 #ifndef _POSIX_SOURCE
198 # define _POSIX_SOURCE
200 #ifndef _SOCKET_SOURCE
201 # define _SOCKET_SOURCE
208 #include <sys/socket.h>
212 extern void FCONTROL(short, short, longpointer);
213 extern void PRINTFILEINFO(int);
215 int ftruncate(int fd, long wantsize);
218 ftruncate(int fd, long wantsize)
220 int ccode_return,dummy=0;
222 if (lseek(fd, wantsize, SEEK_SET) < 0)
227 FCONTROL(_mpe_fileno(fd),6,__perl_mpe_longaddr(&dummy)); /* Write new EOF */
228 if ((ccode_return=ccode()) != CCE)
231 "MPE ftruncate failed, ccode=%d, wantsize=%ld\n",
232 ccode_return, wantsize);
233 PRINTFILEINFO(_mpe_fileno(fd));
242 wrapper for truncate():
244 truncate() is UNIX, not POSIX.
246 This function requires ftruncate().
256 int truncate(const char *pathname, off_t length);
258 Returns: 0 if OK, -1 on error
260 from: Stevens' Advanced Programming in the UNIX Environment, p. 92
267 EDQUOT (not POSIX) <- not implemented here
271 ELOOP (not POSIX) <- not implemented here
275 ETXTBSY (not POSIX) <- not implemented here
282 PRINT_ERROR - make this function print an error message to stderr
286 #include <sys/types.h> /* off_t, required by open() */
287 #include <sys/stat.h> /* required by open() */
288 #include <fcntl.h> /* open() */
289 #include <unistd.h> /* close() */
290 #include <stdio.h> /* perror(), sprintf() */
295 truncate(const char *pathname, off_t length)
299 char error_msg[80+1];
304 if ( (fd = open(pathname, O_WRONLY | O_TRUNC)) < 0)
306 /* errno already set */
309 "truncate(): open(%s, O_WRONLY | OTRUNC)\0",
318 if ( (fd = open(pathname, O_WRONLY)) < 0)
320 /* errno already set */
323 "truncate(): open(%s, O_WRONLY)\0",
330 if (ftruncate(fd, length) < 0)
332 /* errno already set */
334 perror("truncate(): ftruncate()");
342 /* errno already set */
344 perror("truncate(): close()");
353 wrapper for gettimeofday():
354 gettimeofday() is UNIX, not POSIX.
355 gettimeofday() is a BSD function.
361 #include <sys/time.h>
363 int gettimeofday(struct timeval *tp, struct timezone *tzp);
366 This function returns seconds and microseconds since midnight
367 January 1, 1970. The microseconds is actually only accurate to
370 Note: To pick up the definitions of structs timeval and timezone
371 from the <time.h> include file, the directive
372 _SOCKET_SOURCE must be used.
375 A 0 return value indicates that the call succeeded. A -1 return
376 value indicates an error occurred; errno is set to indicate the
380 EFAULT not implemented
387 /* need _SOCKET_SOURCE to pick up structs timeval and timezone in time.h */
388 #ifndef _SOCKET_SOURCE
389 # define _SOCKET_SOURCE
392 #include <time.h> /* structs timeval & timezone,
393 difftime(), localtime(), mktime(), time() */
398 * gettimeofday code by Mark Bixby.
399 * This code is free software; you may redistribute it and/or modify
400 * it under the same terms as Perl itself.
404 int gettimeofday( struct timeval *tp, struct timezone *tpz )
406 int gettimeofday( tp, tpz )
408 struct timezone *tpz;
411 static unsigned long basetime = 0;
412 static int dsttime = 0;
413 static int minuteswest = 0;
414 static int oldtime = 0;
415 register int newtime;
418 /*-------------------------------------------------------------------*/
419 /* Setup a base from which all future time will be computed. */
420 /*-------------------------------------------------------------------*/
425 struct tm *loc_time_tm;
427 gmt_time = time( NULL );
428 loc_time_tm = localtime( &gmt_time ) ;
429 loc_time = mktime( loc_time_tm );
432 basetime = (unsigned long) ( loc_time - (oldtime/1000) );
434 /*----------------------------------------------------------------*/
435 /* The calling process must be restarted if timezone or dst */
437 /*----------------------------------------------------------------*/
438 minuteswest = (int) (difftime( loc_time, gmt_time ) / 60);
439 dsttime = loc_time_tm->tm_isdst;
442 /*-------------------------------------------------------------------*/
443 /* Get the new time value. The timer value rolls over every 24 days, */
444 /* so if the delta is negative, the basetime value is adjusted. */
445 /*-------------------------------------------------------------------*/
447 if ( newtime < oldtime ) basetime += 2073600;
450 /*-------------------------------------------------------------------*/
451 /* Return the timestamp info. */
452 /*-------------------------------------------------------------------*/
453 tp->tv_sec = basetime + newtime/1000;
454 tp->tv_usec = (newtime%1000) * 1000; /* only accurate to milli */
457 tpz->tz_minuteswest = minuteswest;
458 tpz->tz_dsttime = dsttime;
463 } /* gettimeofday() */
466 ** MPE_FCNTL -- shadow function for fcntl()
468 ** MPE requires sfcntl() for sockets, and fcntl() for everything
469 ** else. This shadow routine determines the descriptor type and
470 ** makes the appropriate call.
480 #include <sys/socket.h>
483 mpe_fcntl(int fildes, int cmd, ...)
492 arg = va_arg(ap, void *);
496 if (getsockname(fildes, &sa, &len) == -1)
498 if (errno == EAFNOSUPPORT)
500 return sfcntl(fildes, cmd, arg);
502 if (errno == ENOTSOCK)
504 return fcntl(fildes, cmd, arg);
506 /* unknown getsockname() failure */
512 if ((result = sfcntl(fildes, cmd, arg)) != -1 && cmd == F_GETFL)
513 result |= O_RDWR; /* fill in some missing flags */
521 * Stuff from here on down is written by Ken Hirsch
522 * and you may use it for any purpose.
523 * No warranty, express or implied.
527 #include <sys/ioctl.h>
528 #include <netinet/in.h>
531 typedef unsigned int socklen_t;
535 static int max_io_size(int filedes);
538 mpe_read(int filedes, void *buffer, size_t len)
541 if (len > 4096 && (len > (maxio = max_io_size(filedes))))
544 return read(filedes, buffer, len);
548 mpe_write(int filedes, const void *buffer, size_t len)
552 int maxio = (len>4096)?max_io_size(filedes):INT_MAX;
553 const char *buf = (const char *)buffer;
556 written = write(filedes, buf, len>maxio?maxio:len);
563 if (written < 0 && len == orig_len)
566 return orig_len - len;
571 mpe_send(int socket, const void *buffer, size_t len, int flags)
575 int maxio = (len>4096)?max_io_size(socket):INT_MAX;
576 const char *buf = (const char *)buffer;
579 written = send(socket, buf, len>maxio?maxio:len, flags);
586 if (written < 0 && len == orig_len)
589 return orig_len - len;
593 mpe_sendto(int socket, const void *buffer, size_t len,
594 int flags, const struct sockaddr *dest_addr,
599 int maxio = (len>4096)?max_io_size(socket):INT_MAX;
600 const char *buf = (const char *)buffer;
604 sendto(socket, buf, len>maxio?maxio:len, flags, dest_addr, dest_len);
611 if (written < 0 && len == orig_len)
614 return orig_len - len;
619 mpe_recv(int socket, void *buffer, size_t len, int flags)
622 if (len > 4096 && (len > (maxio = max_io_size(socket))))
624 return recv(socket, buffer, len, flags);
628 mpe_recvfrom(int socket, void *buffer, size_t len,
629 int flags, struct sockaddr *address,
630 socklen_t *address_len)
633 if (len > 4096 && (len > (maxio = max_io_size(socket))))
635 return recvfrom(socket, buffer, len, flags, address, address_len);
639 I didn't do thse two:
640 ssize_t mpe_recvmsg(int, struct msghdr *, int);
641 ssize_t mpe_sendmsg(int, const struct msghdr *, int);
645 * On MPE/iX (at least version 6.0), a getsockname()
646 * performed on a socket that is listening
647 * will return INADDR_ANY, even if you used
648 * bind to bind it to a particular IP address.
650 * (In fact, it appears that the socket always acts as
651 * if you used INADDR_ANY.)
653 * Here I save the IP address used in bind
654 * So I can get it in getsockname()
658 /* I just save 40. Usually one or two should be enough
662 mpe_connect(int socket,
663 const struct sockaddr *address,
664 socklen_t address_len)
666 int ret = connect(socket, address, address_len);
667 if (ret < 0 && errno == EINPROGRESS)
669 /* Need to call getsockopt to clear socket error */
671 socklen_t err_size = sizeof(socket_error);
672 (void)getsockopt(socket, SOL_SOCKET, SO_ERROR,
673 &socket_error, &err_size);
681 struct in_addr holdaddr;
683 #define HOLDBINDLAST ((sizeof(holdbind))/(sizeof(holdbind[0])))
687 * Fix peculiarities of bind() on MPE
688 * 1. call GETPRIVMODE to bind to ports < 1024
689 * 2. save IP address for future calls to getsockname
690 * 3. set IP address to 0 (INADDR_ANY)
694 mpe_bind(int socket, const struct sockaddr *address, socklen_t address_len)
699 extern void GETPRIVMODE(void);
700 extern void GETUSERMODE(void);
702 for (i = 0; i<HOLDBINDLAST; i++) {
703 if (holdbind[i].fd == socket)
706 /* If we didn't find previously used slot, use next */
707 if (i == HOLDBINDLAST)
710 holdbind[i].fd = socket;
712 memset(&holdbind[i].holdaddr, '\0', sizeof(holdbind[i].holdaddr));
713 if (address->sa_family == AF_INET
714 && address_len >= offsetof(struct sockaddr_in, sin_addr)
715 +sizeof(struct in_addr)) {
716 holdbind[i].holdaddr = ((struct sockaddr_in *)address)->sin_addr;
720 if (++nextbind >= HOLDBINDLAST)
724 if (address->sa_family == AF_INET)
726 /* The address *MUST* stupidly be zero. */
727 ((struct sockaddr_in *)address)->sin_addr.s_addr = INADDR_ANY;
728 /* PRIV mode is required to bind() to ports < 1024. */
729 if (((struct sockaddr_in *)address)->sin_port < 1024 &&
730 ((struct sockaddr_in *)address)->sin_port > 0) {
731 GETPRIVMODE(); /* If this fails, we are aborted by MPE/iX. */
735 result = bind(socket, address, address_len);
745 mpe_getsockname(int socket, struct sockaddr *address, socklen_t *address_len)
748 ret = getsockname(socket, address, address_len);
750 && address->sa_family == AF_INET
751 && *address_len >= offsetof(struct sockaddr_in, sin_addr)
752 +sizeof(struct in_addr)
753 && ((struct sockaddr_in *)address)->sin_addr.s_addr == INADDR_ANY) {
755 for (i=0; i<HOLDBINDLAST; i++) {
756 if (holdbind[i].fd == socket)
758 ((struct sockaddr_in *)address)->sin_addr.s_addr
759 = holdbind[i].holdaddr.s_addr;
768 mpe_getpeername(int socket, struct sockaddr *address, socklen_t *address_len)
771 ret = getpeername(socket, address, address_len);
774 /* Try a zero-length write to see if socket really connected */
775 int written = write(socket, "", 0);
784 max_io_size(int filedes)
789 int result = INT_MAX; /* all other files */
793 if (getsockname(filedes, &sa, &len) == -1)
795 if (errno == EAFNOSUPPORT) /* AF_UNIX socket */
799 result = 30000; /* AF_INET sock max */