2 * Misc. functions for systems that don't have them
4 * Copyright 1996 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
25 #include <be/kernel/fs_info.h>
26 #include <be/kernel/OS.h>
38 #include <sys/types.h>
39 #ifdef HAVE_SYS_INTTYPES_H
40 # include <sys/inttypes.h>
42 #ifdef HAVE_SYS_TIME_h
43 # include <sys/time.h>
46 #ifdef HAVE_SYS_IOCTL_H
47 #include <sys/ioctl.h>
54 #ifdef HAVE_SYS_MMAN_H
67 /***********************************************************************
71 int usleep (unsigned int useconds
)
76 #elif defined(__BEOS__)
77 return snooze(useconds
);
78 #elif defined(HAVE_SELECT)
81 delay
.tv_sec
= useconds
/ 1000000;
82 delay
.tv_usec
= useconds
% 1000000;
84 select( 0, 0, 0, 0, &delay
);
86 #else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
89 #endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
91 #endif /* HAVE_USLEEP */
93 /***********************************************************************
97 void *memmove( void *dest
, const void *src
, size_t len
)
99 register char *dst
= dest
;
101 /* Use memcpy if not overlapping */
102 if ((dst
+ len
<= (char *)src
) || ((char *)src
+ len
<= dst
))
104 memcpy( dst
, src
, len
);
106 /* Otherwise do it the hard way (FIXME: could do better than this) */
107 else if (dst
< (char *)src
)
109 while (len
--) *dst
++ = *((char *)src
)++;
114 src
= (char *)src
+ len
- 1;
115 while (len
--) *dst
-- = *((char *)src
)--;
119 #endif /* HAVE_MEMMOVE */
121 /***********************************************************************
124 #ifndef HAVE_STRERROR
125 const char *strerror( int err
)
127 /* Let's hope we have sys_errlist then */
128 return sys_errlist
[err
];
130 #endif /* HAVE_STRERROR */
133 /***********************************************************************
136 #ifndef HAVE_GETPAGESIZE
137 size_t getpagesize(void)
140 return sysconf(_SC_PAGESIZE
);
141 # elif defined(__i386__)
144 # error Cannot get the page size on this platform
147 #endif /* HAVE_GETPAGESIZE */
150 /***********************************************************************
153 #if !defined(HAVE_CLONE) && defined(__linux__)
154 int clone( int (*fn
)(void *), void *stack
, int flags
, void *arg
)
158 void **stack_ptr
= (void **)stack
;
159 *--stack_ptr
= arg
; /* Push argument on stack */
160 *--stack_ptr
= fn
; /* Push function pointer (popped into ebx) */
161 __asm__
__volatile__( "pushl %%ebx\n\t"
164 "popl %%ebx\n\t" /* Contains fn in the child */
165 "testl %%eax,%%eax\n\t"
167 "xorl %ebp,%ebp\n\t" /* Terminate the stack frames */
168 "call *%%ebx\n\t" /* Should never return */
169 "xorl %%eax,%%eax\n\t" /* Just in case it does*/
172 : "0" (SYS_clone
), "r" (flags
), "c" (stack_ptr
) );
173 assert( ret
); /* If ret is 0, we returned from the child function */
174 if (ret
> 0) return ret
;
180 #endif /* __i386__ */
182 #endif /* !HAVE_CLONE && __linux__ */
184 /***********************************************************************
187 #ifndef HAVE_STRCASECMP
188 int strcasecmp( const char *str1
, const char *str2
)
190 const unsigned char *ustr1
= (const unsigned char *)str1
;
191 const unsigned char *ustr2
= (const unsigned char *)str2
;
193 while (*ustr1
&& toupper(*ustr1
) == toupper(*ustr2
)) {
197 return toupper(*ustr1
) - toupper(*ustr2
);
199 #endif /* HAVE_STRCASECMP */
201 /***********************************************************************
204 #ifndef HAVE_STRNCASECMP
205 int strncasecmp( const char *str1
, const char *str2
, size_t n
)
207 const unsigned char *ustr1
= (const unsigned char *)str1
;
208 const unsigned char *ustr2
= (const unsigned char *)str2
;
212 while ((--n
> 0) && *ustr1
) {
213 if ((res
= toupper(*ustr1
) - toupper(*ustr2
))) return res
;
217 return toupper(*ustr1
) - toupper(*ustr2
);
219 #endif /* HAVE_STRNCASECMP */
221 /***********************************************************************
224 #ifndef HAVE_GETSOCKOPT
225 int getsockopt(int socket
, int level
, int option_name
,
226 void *option_value
, size_t *option_len
)
231 #endif /* !defined(HAVE_GETSOCKOPT) */
233 /***********************************************************************
236 #ifndef HAVE_INET_NETWORK
237 unsigned long inet_network(const char *cp
)
242 #endif /* defined(HAVE_INET_NETWORK) */
244 /***********************************************************************
248 int statfs(const char *name
, struct statfs
*info
)
259 if ((mydev
= dev_for_path(name
)) < 0) {
264 if (fs_stat_dev(mydev
,&fsinfo
) < 0) {
269 info
->f_bsize
= fsinfo
.block_size
;
270 info
->f_blocks
= fsinfo
.total_blocks
;
271 info
->f_bfree
= fsinfo
.free_blocks
;
273 #else /* defined(__BEOS__) */
276 #endif /* defined(__BEOS__) */
278 #endif /* !defined(HAVE_STATFS) */
281 /***********************************************************************
285 int lstat(const char *file_name
, struct stat
*buf
)
287 return stat( file_name
, buf
);
289 #endif /* HAVE_LSTAT */
291 /***********************************************************************
295 int mkstemp(char *tmpfn
)
300 xstart
= tmpfn
+strlen(tmpfn
)-1;
301 while ((xstart
> tmpfn
) && (*xstart
== 'X'))
305 char *newfn
= mktemp(tmpfn
);
307 if (!newfn
) /* something else broke horribly */
309 fd
= open(newfn
,O_CREAT
|O_RDWR
|O_EXCL
,0600);
313 /* fill up with X and try again ... */
314 while (*newfn
) *newfn
++ = 'X';
318 #endif /* HAVE_MKSTEMP */
321 /***********************************************************************
324 * FIXME: this is not thread-safe
327 ssize_t
pread( int fd
, void *buf
, size_t count
, off_t offset
)
332 if ((old_pos
= lseek( fd
, 0, SEEK_CUR
)) == -1) return -1;
333 if (lseek( fd
, offset
, SEEK_SET
) == -1) return -1;
334 if ((ret
= read( fd
, buf
, count
)) == -1)
336 int err
= errno
; /* save errno */
337 lseek( fd
, old_pos
, SEEK_SET
);
341 if (lseek( fd
, old_pos
, SEEK_SET
) == -1) return -1;
344 #endif /* HAVE_PREAD */
347 /***********************************************************************
350 * FIXME: this is not thread-safe
353 ssize_t
pwrite( int fd
, const void *buf
, size_t count
, off_t offset
)
358 if ((old_pos
= lseek( fd
, 0, SEEK_CUR
)) == -1) return -1;
359 if (lseek( fd
, offset
, SEEK_SET
) == -1) return -1;
360 if ((ret
= write( fd
, buf
, count
)) == -1)
362 int err
= errno
; /* save errno */
363 lseek( fd
, old_pos
, SEEK_SET
);
367 if (lseek( fd
, old_pos
, SEEK_SET
) == -1) return -1;
370 #endif /* HAVE_PWRITE */
373 #if defined(__svr4__) || defined(__NetBSD__)
374 /***********************************************************************
377 * The purpose of this routine is to emulate the behaviour of
378 * the Linux mmap() routine if a non-NULL address is passed,
379 * but the MAP_FIXED flag is not set. Linux in this case tries
380 * to place the mapping at the specified address, *unless* the
381 * range is already in use. Solaris, however, completely ignores
382 * the address argument in this case.
384 * As Wine code occasionally relies on the Linux behaviour, e.g. to
385 * be able to map non-relocateable PE executables to their proper
386 * start addresses, or to map the DOS memory to 0, this routine
387 * emulates the Linux behaviour by checking whether the desired
388 * address range is still available, and placing the mapping there
389 * using MAP_FIXED if so.
391 static int try_mmap_fixed (void *addr
, size_t len
, int prot
, int flags
,
392 int fildes
, off_t off
)
394 char * volatile result
= NULL
;
395 int pagesize
= getpagesize();
398 /* We only try to map to a fixed address if
399 addr is non-NULL and properly aligned,
400 and MAP_FIXED isn't already specified. */
404 if ( (uintptr_t)addr
& (pagesize
-1) )
406 if ( flags
& MAP_FIXED
)
409 /* We use vfork() to freeze all threads of the
410 current process. This allows us to check without
411 race condition whether the desired memory range is
412 already in use. Note that because vfork() shares
413 the address spaces between parent and child, we
414 can actually perform the mapping in the child. */
416 if ( (pid
= vfork()) == -1 )
418 perror("try_mmap_fixed: vfork");
426 /* We call mincore() for every page in the desired range.
427 If any of these calls succeeds, the page is already
428 mapped and we must fail. */
429 for ( i
= 0; i
< len
; i
+= pagesize
)
430 if ( mincore( (caddr_t
)addr
+ i
, pagesize
, &vec
) != -1 )
433 /* Perform the mapping with MAP_FIXED set. This is safe
434 now, as none of the pages is currently in use. */
435 result
= mmap( addr
, len
, prot
, flags
| MAP_FIXED
, fildes
, off
);
436 if ( result
== addr
)
439 if ( result
!= (void *) -1 ) /* This should never happen ... */
440 munmap( result
, len
);
445 /* vfork() lets the parent continue only after the child
446 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
447 so we don't need to wait for the child. */
449 return result
== addr
;
453 /***********************************************************************
456 * Portable wrapper for anonymous mmaps
458 void *wine_anon_mmap( void *start
, size_t size
, int prot
, int flags
)
461 static int fdzero
= -1;
468 if ((fdzero
= open( "/dev/zero", O_RDONLY
)) == -1)
470 perror( "/dev/zero: open" );
474 #endif /* MAP_ANON */
477 flags
&= ~MAP_SHARED
;
480 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
482 flags
|= MAP_PRIVATE
;
485 #if defined(__svr4__) || defined(__NetBSD__)
486 if ( try_mmap_fixed( start
, size
, prot
, flags
, fdzero
, 0 ) )
490 return mmap( start
, size
, prot
, flags
, fdzero
, 0 );
498 * These functions provide wrappers around dlopen() and associated
499 * functions. They work around a bug in glibc 2.1.x where calling
500 * a dl*() function after a previous dl*() function has failed
501 * without a dlerror() call between the two will cause a crash.
502 * They all take a pointer to a buffer that
503 * will receive the error description (from dlerror()). This
504 * parameter may be NULL if the error description is not required.
507 /***********************************************************************
510 void *wine_dlopen( const char *filename
, int flag
, char *error
, int errorsize
)
515 dlerror(); dlerror();
516 ret
= dlopen( filename
, flag
);
520 strncpy( error
, s
? s
: "", errorsize
);
521 error
[errorsize
- 1] = '\0';
528 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
529 error
[errorsize
- 1] = '\0';
535 /***********************************************************************
538 void *wine_dlsym( void *handle
, const char *symbol
, char *error
, int errorsize
)
543 dlerror(); dlerror();
544 ret
= dlsym( handle
, symbol
);
548 strncpy( error
, s
? s
: "", errorsize
);
549 error
[errorsize
- 1] = '\0';
556 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
557 error
[errorsize
- 1] = '\0';
563 /***********************************************************************
566 int wine_dlclose( void *handle
, char *error
, int errorsize
)
571 dlerror(); dlerror();
572 ret
= dlclose( handle
);
576 strncpy( error
, s
? s
: "", errorsize
);
577 error
[errorsize
- 1] = '\0';
584 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
585 error
[errorsize
- 1] = '\0';
591 /***********************************************************************
592 * wine_rewrite_s4tos2
594 * Convert 4 byte Unicode strings to 2 byte Unicode strings in-place.
595 * This is only practical if literal strings are writable.
597 unsigned short* wine_rewrite_s4tos2(const wchar_t* str4
)
599 unsigned short *str2
,*s2
;
604 if ((*str4
& 0xffff0000) != 0) {
605 /* This string has already been converted. Return it as is */
606 return (unsigned short*)str4
;
609 /* Note that we can also end up here if the string has a single
610 * character. In such a case we will convert the string over and
611 * over again. But this is harmless.
613 str2
=s2
=(unsigned short*)str4
;
615 *s2
=(unsigned short)*str4
;
617 } while (*str4
++ != L
'\0');
623 /***********************************************************************
626 char *ecvt (double number
, int ndigits
, int *decpt
, int *sign
)
628 static char buf
[40]; /* ought to be enough */
630 sprintf(buf
, "%.*e", ndigits
/* FIXME wrong */, number
);
631 *sign
= (number
< 0);
632 dec
= strchr(buf
, '.');
633 *decpt
= (dec
) ? (int)dec
- (int)buf
: -1;
636 #endif /* HAVE_ECVT */
639 /***********************************************************************
642 char *fcvt (double number
, int ndigits
, int *decpt
, int *sign
)
644 static char buf
[40]; /* ought to be enough */
646 sprintf(buf
, "%.*e", ndigits
, number
);
647 *sign
= (number
< 0);
648 dec
= strchr(buf
, '.');
649 *decpt
= (dec
) ? (int)dec
- (int)buf
: -1;
652 #endif /* HAVE_FCVT */
655 /***********************************************************************
658 * FIXME: uses both E and F.
660 char *gcvt (double number
, size_t ndigit
, char *buff
)
662 sprintf(buff
, "%.*E", (int)ndigit
, number
);
665 #endif /* HAVE_GCVT */
668 #ifndef wine_memcpy_unaligned
669 /***********************************************************************
670 * wine_memcpy_unaligned
672 * This is necessary to defeat optimizations of memcpy by gcc.
674 void *wine_memcpy_unaligned( void *dst
, const void *src
, size_t size
)
676 return memcpy( dst
, src
, size
);
681 /***********************************************************************
685 #ifndef HAVE_PTHREAD_GETSPECIFIC
686 void pthread_getspecific() { assert(0); }
689 #ifndef HAVE_PTHREAD_KEY_CREATE
690 void pthread_key_create() { assert(0); }
693 #ifndef HAVE_PTHREAD_MUTEX_LOCK
694 void pthread_mutex_lock() { assert(0); }
697 #ifndef HAVE_PTHREAD_MUTEX_UNLOCK
698 void pthread_mutex_unlock() { assert(0); }
701 #ifndef HAVE_PTHREAD_SETSPECIFIC
702 void pthread_setspecific() { assert(0); }
705 /***********************************************************************
706 * interlocked functions
712 __ASM_GLOBAL_FUNC(interlocked_cmpxchg
,
713 "movl 12(%esp),%eax\n\t"
714 "movl 8(%esp),%ecx\n\t"
715 "movl 4(%esp),%edx\n\t"
716 "lock; cmpxchgl %ecx,(%edx)\n\t"
718 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr
,
719 "movl 12(%esp),%eax\n\t"
720 "movl 8(%esp),%ecx\n\t"
721 "movl 4(%esp),%edx\n\t"
722 "lock; cmpxchgl %ecx,(%edx)\n\t"
724 __ASM_GLOBAL_FUNC(interlocked_xchg
,
725 "movl 8(%esp),%eax\n\t"
726 "movl 4(%esp),%edx\n\t"
727 "lock; xchgl %eax,(%edx)\n\t"
729 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr
,
730 "movl 8(%esp),%eax\n\t"
731 "movl 4(%esp),%edx\n\t"
732 "lock; xchgl %eax,(%edx)\n\t"
734 __ASM_GLOBAL_FUNC(interlocked_xchg_add
,
735 "movl 8(%esp),%eax\n\t"
736 "movl 4(%esp),%edx\n\t"
737 "lock; xaddl %eax,(%edx)\n\t"
740 #elif defined(_MSC_VER)
742 __declspec(naked
) long interlocked_cmpxchg( long *dest
, long xchg
, long compare
)
744 __asm mov eax
, 12[esp
];
745 __asm mov ecx
, 8[esp
];
746 __asm mov edx
, 4[esp
];
747 __asm lock cmpxchg
[edx
], ecx
;
751 __declspec(naked
) void *interlocked_cmpxchg_ptr( void **dest
, void *xchg
, void *compare
)
753 __asm mov eax
, 12[esp
];
754 __asm mov ecx
, 8[esp
];
755 __asm mov edx
, 4[esp
];
756 __asm lock cmpxchg
[edx
], ecx
;
760 __declspec(naked
) long interlocked_xchg( long *dest
, long val
)
762 __asm mov eax
, 8[esp
];
763 __asm mov edx
, 4[esp
];
764 __asm lock xchg
[edx
], eax
;
768 __declspec(naked
) void *interlocked_xchg_ptr( void **dest
, void *val
)
770 __asm mov eax
, 8[esp
];
771 __asm mov edx
, 4[esp
];
772 __asm lock xchg
[edx
], eax
;
776 __declspec(naked
) long interlocked_xchg_add( long *dest
, long incr
)
778 __asm mov eax
, 8[esp
];
779 __asm mov edx
, 4[esp
];
780 __asm lock xadd
[edx
], eax
;
785 # error You must implement the interlocked* functions for your compiler
788 #elif defined(__powerpc__)
789 void* interlocked_cmpxchg_ptr( void **dest
, void* xchg
, void* compare
)
793 __asm__
__volatile__(
800 : "=&r"(ret
), "=&r"(scratch
)
801 : "r"(dest
), "r"(xchg
), "r"(compare
)
806 long interlocked_cmpxchg( long *dest
, long xchg
, long compare
)
810 __asm__
__volatile__(
817 : "=&r"(ret
), "=&r"(scratch
)
818 : "r"(dest
), "r"(xchg
), "r"(compare
)
823 long interlocked_xchg_add( long *dest
, long incr
)
827 __asm__
__volatile__(
828 "0: lwarx %0, %3, %1;"
830 " stwcx. %0, %3, %1;"
833 : "r"(dest
), "r"(incr
), "r"(zero
)
839 long interlocked_xchg( long* dest
, long val
)
842 __asm__
__volatile__(
847 : "r"(dest
), "r"(val
)
852 void* interlocked_xchg_ptr( void** dest
, void* val
)
855 __asm__
__volatile__(
860 : "r"(dest
), "r"(val
)
865 #elif defined(__sparc__) && defined(__sun__)
868 * As the earlier Sparc processors lack necessary atomic instructions,
869 * I'm simply falling back to the library-provided _lwp_mutex routines
870 * to ensure mutual exclusion in a way appropriate for the current
873 * FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
874 * we could use this to speed up the Interlocked operations ...
877 static lwp_mutex_t interlocked_mutex
= DEFAULTMUTEX
;
879 long interlocked_cmpxchg( long *dest
, long xchg
, long compare
)
881 _lwp_mutex_lock( &interlocked_mutex
);
882 if (*dest
== compare
) *dest
= xchg
;
883 else compare
= *dest
;
884 _lwp_mutex_unlock( &interlocked_mutex
);
888 void *interlocked_cmpxchg_ptr( void **dest
, void *xchg
, void *compare
)
890 _lwp_mutex_lock( &interlocked_mutex
);
891 if (*dest
== compare
) *dest
= xchg
;
892 else compare
= *dest
;
893 _lwp_mutex_unlock( &interlocked_mutex
);
897 long interlocked_xchg( long *dest
, long val
)
900 _lwp_mutex_lock( &interlocked_mutex
);
903 _lwp_mutex_unlock( &interlocked_mutex
);
907 void *interlocked_xchg_ptr( void **dest
, void *val
)
910 _lwp_mutex_lock( &interlocked_mutex
);
913 _lwp_mutex_unlock( &interlocked_mutex
);
917 long interlocked_xchg_add( long *dest
, long incr
)
920 _lwp_mutex_lock( &interlocked_mutex
);
923 _lwp_mutex_unlock( &interlocked_mutex
);
927 # error You must implement the interlocked* functions for your CPU