[ID 20020407.002] Bug (?) and patch for DProf
[perl.git] / mpeix / mpeix.c
1
2 /*
3  * gcc long pointer support code for HPPA.
4  * Copyright 1998, DIS International, Ltd.
5  * Permission is granted to use this code under the GNU LIBRARY GENERAL
6  * PUBLIC LICENSE, Version 2, June 1991.
7  */
8 typedef struct {
9   int           spaceid;
10   unsigned int  offset;
11   } LONGPOINTER, longpointer;
12
13 /*
14  * gcc long pointer support code for HPPA.
15  * Copyright 1998, DIS International, Ltd.
16  * Permission is granted to use this code under the GNU LIBRARY GENERAL
17  * PUBLIC LICENSE, Version 2, June 1991.
18  */
19
20 int __perl_mpe_getspaceid(void *source)
21   {
22   int val;
23   /*
24    * Given the short pointer, determine it's space ID.
25    */
26
27   /*
28    * The colons separate output from input parameters. In this case,
29    * the output of the instruction (output indicated by the "=" in the
30    * constraint) is to a memory location (indicated by the "m"). The
31    * input constraint indicates that the source to the instruction
32    * is a register reference (indicated by the "r").
33    * The general format is:
34    *   asm("<instruction template>" : <output> : <input> : <clobbers>);
35    *     where <output> and <input> are:
36    *       "<constraint>" (<token>)
37    *     <instruction template> is the PA-RISC instruction in template fmt.
38    *     <clobbers> indicates those registers clobbered by the instruction
39    *     and provides hints to the optimizer.
40    *
41    * Refer to the gcc documentation or http://www.dis.com/gnu/gcc_toc.html
42    */
43   asm volatile (
44       "comiclr,= 0,%1,%%r28;
45          ldsid (%%r0,%1),%%r28;
46        stw %%r28, %0"
47                         : "=m" (val)    // Output to val
48                         : "r" (source)  // Source must be gen reg
49                         : "%r28");      // Clobbers %r28
50   return (val);
51   };
52
53 LONGPOINTER __perl_mpe_longaddr(void *source)
54   {
55   LONGPOINTER lptr;
56   /*
57    * Return the long pointer for the address in sr5 space.
58    */
59
60   asm volatile (
61       "comiclr,= 0,%2,%%r28;
62          ldsid (%%r0,%2),%%r28;
63        stw %%r28, %0;
64        stw %2, %1"
65                         : "=m" (lptr.spaceid),
66                           "=m" (lptr.offset)    // Store to lptr
67                         : "r" (source)          // Source must be gen reg
68                         : "%r28");      // Clobbers %r28
69   return (lptr);
70   };
71
72 LONGPOINTER __perl_mpe_addtopointer(LONGPOINTER source,    // %r26 == source offset
73                                                 // %r25 == source space
74                         int             len)    // %r24 == length in bytes
75   {
76   /*
77    * Increment a longpointer.
78    */
79
80   asm volatile (
81       "copy %0,%%r28;                           // copy space to r28
82        add %1,%2,%%r29"                         // Increment the pointer
83                         :                       // No output
84                         : "r" (source.spaceid), // Source address
85                           "r" (source.offset),
86                           "r" (len)             // Length
87                         : "%r28",               // Clobbers
88                           "%r29");
89   };
90
91 void __perl_mpe_longmove(int len,                  // %r26 == byte length
92               LONGPOINTER source,       // %r23 == source space, %r24 == off
93               LONGPOINTER target)       // sp-#56 == target space, sp-#52== off
94   {
95   /*
96    * Move data between two buffers in long pointer space.
97    */
98
99   asm volatile (
100       ".import $$lr_unk_unk_long,MILLICODE;
101        mtsp %0,%%sr1;                           // copy source space to sr1
102        copy %1,%%r26;                           // load source offset to r26
103        copy %4,%%r24;                           // load length to r24
104        copy %3,%%r25;                           // load target offset to r25
105        bl $$lr_unk_unk_long,%%r31;              // start branch to millicode
106        mtsp %2,%%sr2"                           // copy target space to sr2
107                         :                       // No output
108                         : "r" (source.spaceid), // Source address
109                           "r" (source.offset),
110                           "r" (target.spaceid), // Target address
111                           "r" (target.offset),
112                           "r" (len)             // Byte length
113                         : "%r1",                // Clobbers
114                           "%r24",
115                           "%r25",
116                           "%r26",
117                           "%r31");
118   };
119
120 int __perl_mpe_longpeek(LONGPOINTER source)
121   {
122   /*
123    * Fetch the int in long pointer space.
124    */
125   unsigned int val;
126
127   asm volatile (
128       "mtsp %1, %%sr1;
129        copy %2, %%r28;
130        ldw 0(%%sr1, %%r28), %%r28;
131        stw %%r28, %0"
132                         : "=m" (val)            // Output val
133                         : "r" (source.spaceid), // Source space ID
134                           "r" (source.offset)   // Source offset
135                         : "%r28");              // Clobbers %r28
136
137   return (val);
138   };
139
140 void __perl_mpe_longpoke(LONGPOINTER target,       // %r25 == spaceid, %r26 == offset
141           unsigned int val)             // %r24 == value
142   {
143   /*
144    * Store the val into long pointer space.
145    */
146   asm volatile (
147       "mtsp %0,%%sr1;
148        copy %1, %%r28;
149        stw %2, 0(%%sr1, %%r28)"
150                         :                       // No output
151                         : "r" (target.spaceid), // Target space ID
152                           "r" (target.offset),  // Target offset
153                           "r" (val)             // Value to store
154                         : "%r28"                // Clobbers %r28
155                         );                      // Copy space to %sr1
156   };
157
158 void __perl_mpe_move_fast(int len,                 // %r26 == byte length
159                void *source,            // %r25 == source addr
160                void *target)            // %r24 == target addr
161   {
162   /*
163    * Move using short pointers.
164    */
165   asm volatile (
166       ".import $$lr_unk_unk,MILLICODE;
167        copy %1, %%r26;                          // Move source addr into pos
168        copy %2, %%r25;                          // Move target addr into pos
169        bl $$lr_unk_unk,%%r31;                   // Start branch to millicode
170        copy %0, %%r24"                          // Move length into position
171                         :                       // No output
172                         : "r" (len),            // Byte length
173                           "r" (source),         // Source address
174                           "r" (target)          // Target address
175                         : "%r24",               // Clobbers
176                           "%r25",
177                           "%r26",
178                           "%r31");
179   };
180
181 /*
182  * ftruncate - set file size, BSD Style
183  *
184  * shortens or enlarges the file as neeeded
185  * uses some undocumented locking call. It is known to work on SCO unix,
186  * other vendors should try.
187  * The #error directive prevents unsupported OSes
188  */
189
190 #include <unistd.h>
191 #include <errno.h>
192 #include <fcntl.h>
193 #include <stdio.h>
194 #include <mpe.h>
195
196 extern void FCONTROL(short, short, longpointer);
197 extern void PRINTFILEINFO(int);
198
199 int ftruncate(int fd, long wantsize);
200
201 int ftruncate(int fd, long wantsize) {
202
203 int ccode_return,dummy=0;
204
205 if (lseek(fd, wantsize, SEEK_SET) < 0) {
206         return (-1);
207 }
208
209 FCONTROL(_mpe_fileno(fd),6,__perl_mpe_longaddr(&dummy)); /* Write new EOF */
210 if ((ccode_return=ccode()) != CCE) {
211         fprintf(stderr,"MPE ftruncate failed, ccode=%d, wantsize=%ld\n",ccode_return,wantsize);
212         PRINTFILEINFO(_mpe_fileno(fd));
213         errno = ESYSERR;
214         return (-1);
215 }
216
217 return (0);
218 }
219
220 /*
221    wrapper for truncate():
222
223    truncate() is UNIX, not POSIX.
224
225    This function requires ftruncate().
226
227
228
229    NAME
230       truncate -
231
232    SYNOPSIS
233       #include <unistd.h>
234
235       int truncate(const char *pathname, off_t length);
236
237                                              Returns: 0 if OK, -1 on error
238
239             from: Stevens' Advanced Programming in the UNIX Environment, p. 92
240
241
242
243    ERRORS
244       EACCES
245       EBADF
246       EDQUOT (not POSIX)    <- not implemented here
247       EFAULT
248       EINVAL
249       EISDIR
250       ELOOP (not POSIX)     <- not implemented here
251       ENAMETOOLONG
252       ENOTDIR
253       EROFS
254       ETXTBSY (not POSIX)   <- not implemented here
255
256                                           from: HP-UX man page
257
258
259
260    Compile directives:
261       PRINT_ERROR - make this function print an error message to stderr
262 */
263
264 #ifndef _POSIX_SOURCE
265 # define _POSIX_SOURCE
266 #endif
267
268 #include <sys/types.h>  /* off_t, required by open() */
269 #include <sys/stat.h>   /* required by open() */
270 #include <fcntl.h>      /* open() */
271 #include <unistd.h>     /* close() */
272 #include <stdio.h>      /* perror(), sprintf() */
273
274
275
276 int
277 truncate(const char *pathname, off_t length)
278 {
279         int fd;
280 #ifdef PRINT_ERROR
281         char error_msg[80+1];
282 #endif
283
284         if (length == 0)
285         {
286                 if ( (fd = open(pathname, O_WRONLY | O_TRUNC)) < 0)
287                 {
288                         /* errno already set */
289 #ifdef PRINT_ERROR
290                         sprintf(error_msg,
291                                 "truncate(): open(%s, O_WRONLY | OTRUNC)\0",
292                                 pathname);
293                         perror(error_msg);
294 #endif
295                         return -1;
296                 }
297         }
298         else
299         {
300                 if ( (fd = open(pathname, O_WRONLY)) < 0)
301                 {
302                         /* errno already set */
303 #ifdef PRINT_ERROR
304                         sprintf(error_msg,
305                                 "truncate(): open(%s, O_WRONLY)\0",
306                                 pathname);
307                         perror(error_msg);
308 #endif
309                         return -1;
310                 }
311
312                 if (ftruncate(fd, length) < 0)
313                 {
314                         /* errno already set */
315 #ifdef PRINT_ERROR
316                         perror("truncate(): ftruncate()");
317 #endif
318                         return -1;
319                 }
320         }
321
322         if (close(fd) < 0)
323         {
324                 /* errno already set */
325 #ifdef PRINT_ERROR
326                 perror("truncate(): close()");
327 #endif
328                 return -1;
329         }
330
331         return 0;
332 } /* truncate() */
333
334 /* 
335    wrapper for gettimeofday():
336       gettimeofday() is UNIX, not POSIX.
337       gettimeofday() is a BSD function.
338
339
340
341    NAME
342       gettimeofday -
343
344    SYNOPSIS
345       #include <sys/time.h>
346
347       int gettimeofday(struct timeval *tp, struct timezone *tzp);
348
349    DESCRIPTION
350       This function returns seconds and microseconds since midnight
351       January 1, 1970. The microseconds is actually only accurate to
352       the millisecond.
353
354       Note: To pick up the definitions of structs timeval and timezone
355             from the <time.h> include file, the directive
356             _SOCKET_SOURCE must be used.
357
358    RETURN VALUE
359       A 0 return value indicates that the call succeeded.  A -1 return
360       value indicates an error occurred; errno is set to indicate the
361       error.
362
363    ERRORS
364       EFAULT     not implemented
365
366    Changes:
367       2-91    DR.  Created.
368 */
369
370
371 /* need _SOCKET_SOURCE to pick up structs timeval and timezone in time.h */
372 #ifndef _SOCKET_SOURCE
373 # define _SOCKET_SOURCE
374 #endif
375
376 #include <time.h>       /* structs timeval & timezone,
377                                 difftime(), localtime(), mktime(), time() */
378 #include <sys/time.h>   /* gettimeofday() */
379
380 extern int TIMER();
381
382
383
384 #ifdef __STDC__
385 int gettimeofday( struct timeval *tp, struct timezone *tpz )
386 #else
387 int gettimeofday(  tp, tpz )
388 struct timeval  *tp;
389 struct timezone *tpz;
390 #endif
391 {
392    static unsigned long    basetime        = 0;
393    static int              dsttime         = 0;
394    static int              minuteswest     = 0;
395    static int              oldtime         = 0;
396    register int            newtime;
397
398
399    /*-------------------------------------------------------------------*/
400    /* Setup a base from which all future time will be computed.         */
401    /*-------------------------------------------------------------------*/
402    if ( basetime == 0 )
403    {
404       time_t    gmt_time;
405       time_t    loc_time;
406       struct tm *loc_time_tm;
407
408       gmt_time    = time( NULL );
409       loc_time_tm = localtime( &gmt_time ) ;
410       loc_time    = mktime( loc_time_tm );
411
412       oldtime     = TIMER();
413       basetime    = (unsigned long) ( loc_time - (oldtime/1000) );
414
415       /*----------------------------------------------------------------*/
416       /* The calling process must be restarted if timezone or dst       */
417       /* changes.                                                       */
418       /*----------------------------------------------------------------*/
419       minuteswest = (int) (difftime( loc_time, gmt_time ) / 60);
420       dsttime     = loc_time_tm->tm_isdst;
421    }
422
423    /*-------------------------------------------------------------------*/
424    /* Get the new time value. The timer value rolls over every 24 days, */
425    /* so if the delta is negative, the basetime value is adjusted.      */
426    /*-------------------------------------------------------------------*/
427    newtime = TIMER();
428    if ( newtime < oldtime )  basetime += 2073600;
429    oldtime = newtime;
430
431    /*-------------------------------------------------------------------*/
432    /* Return the timestamp info.                                        */
433    /*-------------------------------------------------------------------*/
434    tp->tv_sec          = basetime + newtime/1000;
435    tp->tv_usec         = (newtime%1000) * 1000;   /* only accurate to milli */
436    if (tpz)
437    {
438       tpz->tz_minuteswest = minuteswest;
439       tpz->tz_dsttime     = dsttime;
440    }
441
442    return 0;
443
444 } /* gettimeofday() */