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';
592 /***********************************************************************
595 char *ecvt (double number, int ndigits, int *decpt, int *sign)
597 static char buf[40]; /* ought to be enough */
599 sprintf(buf, "%.*e", ndigits /* FIXME wrong */, number);
600 *sign = (number < 0);
601 dec = strchr(buf, '.');
602 *decpt = (dec) ? (int)dec - (int)buf : -1;
605 #endif /* HAVE_ECVT */
608 /***********************************************************************
611 char *fcvt (double number, int ndigits, int *decpt, int *sign)
613 static char buf[40]; /* ought to be enough */
615 sprintf(buf, "%.*e", ndigits, number);
616 *sign = (number < 0);
617 dec = strchr(buf, '.');
618 *decpt = (dec) ? (int)dec - (int)buf : -1;
621 #endif /* HAVE_FCVT */
624 /***********************************************************************
627 * FIXME: uses both E and F.
629 char *gcvt (double number, size_t ndigit, char *buff)
631 sprintf(buff, "%.*E", (int)ndigit, number);
634 #endif /* HAVE_GCVT */
637 #ifndef wine_memcpy_unaligned
638 /***********************************************************************
639 * wine_memcpy_unaligned
641 * This is necessary to defeat optimizations of memcpy by gcc.
643 void *wine_memcpy_unaligned( void *dst, const void *src, size_t size )
645 return memcpy( dst, src, size );
650 /***********************************************************************
654 #ifndef HAVE_PTHREAD_GETSPECIFIC
655 void pthread_getspecific() { assert(0); }
658 #ifndef HAVE_PTHREAD_KEY_CREATE
659 void pthread_key_create() { assert(0); }
662 #ifndef HAVE_PTHREAD_MUTEX_LOCK
663 void pthread_mutex_lock() { assert(0); }
666 #ifndef HAVE_PTHREAD_MUTEX_UNLOCK
667 void pthread_mutex_unlock() { assert(0); }
670 #ifndef HAVE_PTHREAD_SETSPECIFIC
671 void pthread_setspecific() { assert(0); }
674 /***********************************************************************
675 * interlocked functions
681 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
682 "movl 12(%esp),%eax\n\t"
683 "movl 8(%esp),%ecx\n\t"
684 "movl 4(%esp),%edx\n\t"
685 "lock; cmpxchgl %ecx,(%edx)\n\t"
687 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
688 "movl 12(%esp),%eax\n\t"
689 "movl 8(%esp),%ecx\n\t"
690 "movl 4(%esp),%edx\n\t"
691 "lock; cmpxchgl %ecx,(%edx)\n\t"
693 __ASM_GLOBAL_FUNC(interlocked_xchg,
694 "movl 8(%esp),%eax\n\t"
695 "movl 4(%esp),%edx\n\t"
696 "lock; xchgl %eax,(%edx)\n\t"
698 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
699 "movl 8(%esp),%eax\n\t"
700 "movl 4(%esp),%edx\n\t"
701 "lock; xchgl %eax,(%edx)\n\t"
703 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
704 "movl 8(%esp),%eax\n\t"
705 "movl 4(%esp),%edx\n\t"
706 "lock; xaddl %eax,(%edx)\n\t"
709 #elif defined(_MSC_VER)
711 __declspec(naked) long interlocked_cmpxchg( long *dest, long xchg, long compare )
713 __asm mov eax, 12[esp];
714 __asm mov ecx, 8[esp];
715 __asm mov edx, 4[esp];
716 __asm lock cmpxchg [edx], ecx;
720 __declspec(naked) void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
722 __asm mov eax, 12[esp];
723 __asm mov ecx, 8[esp];
724 __asm mov edx, 4[esp];
725 __asm lock cmpxchg [edx], ecx;
729 __declspec(naked) long interlocked_xchg( long *dest, long val )
731 __asm mov eax, 8[esp];
732 __asm mov edx, 4[esp];
733 __asm lock xchg [edx], eax;
737 __declspec(naked) void *interlocked_xchg_ptr( void **dest, void *val )
739 __asm mov eax, 8[esp];
740 __asm mov edx, 4[esp];
741 __asm lock xchg [edx], eax;
745 __declspec(naked) long interlocked_xchg_add( long *dest, long incr )
747 __asm mov eax, 8[esp];
748 __asm mov edx, 4[esp];
749 __asm lock xadd [edx], eax;
754 # error You must implement the interlocked* functions for your compiler
757 #elif defined(__powerpc__)
758 void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare)
762 __asm__ __volatile__(
769 : "=&r"(ret), "=&r"(scratch)
770 : "r"(dest), "r"(xchg), "r"(compare)
775 long interlocked_cmpxchg( long *dest, long xchg, long compare)
779 __asm__ __volatile__(
786 : "=&r"(ret), "=&r"(scratch)
787 : "r"(dest), "r"(xchg), "r"(compare)
792 long interlocked_xchg_add( long *dest, long incr )
796 __asm__ __volatile__(
797 "0: lwarx %0, %3, %1;"
799 " stwcx. %0, %3, %1;"
802 : "r"(dest), "r"(incr), "r"(zero)
808 long interlocked_xchg( long* dest, long val )
811 __asm__ __volatile__(
816 : "r"(dest), "r"(val)
821 void* interlocked_xchg_ptr( void** dest, void* val )
824 __asm__ __volatile__(
829 : "r"(dest), "r"(val)
834 #elif defined(__sparc__) && defined(__sun__)
837 * As the earlier Sparc processors lack necessary atomic instructions,
838 * I'm simply falling back to the library-provided _lwp_mutex routines
839 * to ensure mutual exclusion in a way appropriate for the current
842 * FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
843 * we could use this to speed up the Interlocked operations ...
846 static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
848 long interlocked_cmpxchg( long *dest, long xchg, long compare )
850 _lwp_mutex_lock( &interlocked_mutex );
851 if (*dest == compare) *dest = xchg;
852 else compare = *dest;
853 _lwp_mutex_unlock( &interlocked_mutex );
857 void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
859 _lwp_mutex_lock( &interlocked_mutex );
860 if (*dest == compare) *dest = xchg;
861 else compare = *dest;
862 _lwp_mutex_unlock( &interlocked_mutex );
866 long interlocked_xchg( long *dest, long val )
869 _lwp_mutex_lock( &interlocked_mutex );
872 _lwp_mutex_unlock( &interlocked_mutex );
876 void *interlocked_xchg_ptr( void **dest, void *val )
879 _lwp_mutex_lock( &interlocked_mutex );
882 _lwp_mutex_unlock( &interlocked_mutex );
886 long interlocked_xchg_add( long *dest, long incr )
889 _lwp_mutex_lock( &interlocked_mutex );
892 _lwp_mutex_unlock( &interlocked_mutex );
896 # error You must implement the interlocked* functions for your CPU