Implement ParseFieldW function based on its ANSI sibling.
[wine/wine-gecko.git] / library / port.c
blobddb4283223b2d1cb9b05d3e061ba812697ebe276
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #ifdef __BEOS__
25 #include <be/kernel/fs_info.h>
26 #include <be/kernel/OS.h>
27 #endif
29 #include <assert.h>
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #include <sys/types.h>
39 #ifdef HAVE_SYS_INTTYPES_H
40 # include <sys/inttypes.h>
41 #endif
42 #ifdef HAVE_SYS_TIME_h
43 # include <sys/time.h>
44 #endif
45 #include <sys/stat.h>
46 #ifdef HAVE_SYS_IOCTL_H
47 #include <sys/ioctl.h>
48 #endif
49 #include <errno.h>
50 #include <fcntl.h>
51 #ifdef HAVE_TERMIOS_H
52 #include <termios.h>
53 #endif
54 #ifdef HAVE_SYS_MMAN_H
55 #include <sys/mman.h>
56 #endif
57 #ifdef HAVE_LIBIO_H
58 # include <libio.h>
59 #endif
60 #ifdef HAVE_SYSCALL_H
61 # include <syscall.h>
62 #endif
63 #ifdef HAVE_STDINT_H
64 # include <stdint.h>
65 #endif
67 /***********************************************************************
68 * usleep
70 #ifndef HAVE_USLEEP
71 int usleep (unsigned int useconds)
73 #if defined(__EMX__)
74 DosSleep(useconds);
75 return 0;
76 #elif defined(__BEOS__)
77 return snooze(useconds);
78 #elif defined(HAVE_SELECT)
79 struct timeval delay;
81 delay.tv_sec = useconds / 1000000;
82 delay.tv_usec = useconds % 1000000;
84 select( 0, 0, 0, 0, &delay );
85 return 0;
86 #else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
87 errno = ENOSYS;
88 return -1;
89 #endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
91 #endif /* HAVE_USLEEP */
93 /***********************************************************************
94 * memmove
96 #ifndef HAVE_MEMMOVE
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)++;
111 else
113 dst += len - 1;
114 src = (char *)src + len - 1;
115 while (len--) *dst-- = *((char *)src)--;
117 return dest;
119 #endif /* HAVE_MEMMOVE */
121 /***********************************************************************
122 * strerror
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 /***********************************************************************
134 * getpagesize
136 #ifndef HAVE_GETPAGESIZE
137 size_t getpagesize(void)
139 # ifdef __svr4__
140 return sysconf(_SC_PAGESIZE);
141 # elif defined(__i386__)
142 return 4096;
143 # else
144 # error Cannot get the page size on this platform
145 # endif
147 #endif /* HAVE_GETPAGESIZE */
150 /***********************************************************************
151 * clone
153 #if !defined(HAVE_CLONE) && defined(__linux__)
154 int clone( int (*fn)(void *), void *stack, int flags, void *arg )
156 #ifdef __i386__
157 int ret;
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"
162 "movl %2,%%ebx\n\t"
163 "int $0x80\n\t"
164 "popl %%ebx\n\t" /* Contains fn in the child */
165 "testl %%eax,%%eax\n\t"
166 "jnz 0f\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*/
170 "0:"
171 : "=a" (ret)
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;
175 errno = -ret;
176 return -1;
177 #else
178 errno = EINVAL;
179 return -1;
180 #endif /* __i386__ */
182 #endif /* !HAVE_CLONE && __linux__ */
184 /***********************************************************************
185 * strcasecmp
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)) {
194 ustr1++;
195 ustr2++;
197 return toupper(*ustr1) - toupper(*ustr2);
199 #endif /* HAVE_STRCASECMP */
201 /***********************************************************************
202 * strncasecmp
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;
209 int res;
211 if (!n) return 0;
212 while ((--n > 0) && *ustr1) {
213 if ((res = toupper(*ustr1) - toupper(*ustr2))) return res;
214 ustr1++;
215 ustr2++;
217 return toupper(*ustr1) - toupper(*ustr2);
219 #endif /* HAVE_STRNCASECMP */
221 /***********************************************************************
222 * getsockopt
224 #ifndef HAVE_GETSOCKOPT
225 int getsockopt(int socket, int level, int option_name,
226 void *option_value, size_t *option_len)
228 errno = ENOSYS;
229 return -1;
231 #endif /* !defined(HAVE_GETSOCKOPT) */
233 /***********************************************************************
234 * inet_network
236 #ifndef HAVE_INET_NETWORK
237 unsigned long inet_network(const char *cp)
239 errno = ENOSYS;
240 return 0;
242 #endif /* defined(HAVE_INET_NETWORK) */
244 /***********************************************************************
245 * statfs
247 #ifndef HAVE_STATFS
248 int statfs(const char *name, struct statfs *info)
250 #ifdef __BEOS__
251 dev_t mydev;
252 fs_info fsinfo;
254 if(!info) {
255 errno = ENOSYS;
256 return -1;
259 if ((mydev = dev_for_path(name)) < 0) {
260 errno = ENOSYS;
261 return -1;
264 if (fs_stat_dev(mydev,&fsinfo) < 0) {
265 errno = ENOSYS;
266 return -1;
269 info->f_bsize = fsinfo.block_size;
270 info->f_blocks = fsinfo.total_blocks;
271 info->f_bfree = fsinfo.free_blocks;
272 return 0;
273 #else /* defined(__BEOS__) */
274 errno = ENOSYS;
275 return -1;
276 #endif /* defined(__BEOS__) */
278 #endif /* !defined(HAVE_STATFS) */
281 /***********************************************************************
282 * lstat
284 #ifndef HAVE_LSTAT
285 int lstat(const char *file_name, struct stat *buf)
287 return stat( file_name, buf );
289 #endif /* HAVE_LSTAT */
291 /***********************************************************************
292 * mkstemp
294 #ifndef HAVE_MKSTEMP
295 int mkstemp(char *tmpfn)
297 int tries;
298 char *xstart;
300 xstart = tmpfn+strlen(tmpfn)-1;
301 while ((xstart > tmpfn) && (*xstart == 'X'))
302 xstart--;
303 tries = 10;
304 while (tries--) {
305 char *newfn = mktemp(tmpfn);
306 int fd;
307 if (!newfn) /* something else broke horribly */
308 return -1;
309 fd = open(newfn,O_CREAT|O_RDWR|O_EXCL,0600);
310 if (fd!=-1)
311 return fd;
312 newfn = xstart;
313 /* fill up with X and try again ... */
314 while (*newfn) *newfn++ = 'X';
316 return -1;
318 #endif /* HAVE_MKSTEMP */
321 /***********************************************************************
322 * pread
324 * FIXME: this is not thread-safe
326 #ifndef HAVE_PREAD
327 ssize_t pread( int fd, void *buf, size_t count, off_t offset )
329 ssize_t ret;
330 off_t old_pos;
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 );
338 errno = err;
339 return -1;
341 if (lseek( fd, old_pos, SEEK_SET ) == -1) return -1;
342 return ret;
344 #endif /* HAVE_PREAD */
347 /***********************************************************************
348 * pwrite
350 * FIXME: this is not thread-safe
352 #ifndef HAVE_PWRITE
353 ssize_t pwrite( int fd, const void *buf, size_t count, off_t offset )
355 ssize_t ret;
356 off_t old_pos;
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 );
364 errno = err;
365 return -1;
367 if (lseek( fd, old_pos, SEEK_SET ) == -1) return -1;
368 return ret;
370 #endif /* HAVE_PWRITE */
373 #if defined(__svr4__) || defined(__NetBSD__)
374 /***********************************************************************
375 * try_mmap_fixed
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();
396 pid_t pid;
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. */
402 if ( !addr )
403 return 0;
404 if ( (uintptr_t)addr & (pagesize-1) )
405 return 0;
406 if ( flags & MAP_FIXED )
407 return 0;
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");
419 exit(1);
421 if ( pid == 0 )
423 int i;
424 char vec;
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 )
431 _exit(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 )
437 _exit(0);
439 if ( result != (void *) -1 ) /* This should never happen ... */
440 munmap( result, len );
442 _exit(1);
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;
451 #endif
453 /***********************************************************************
454 * wine_anon_mmap
456 * Portable wrapper for anonymous mmaps
458 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
460 #ifdef HAVE_MMAP
461 static int fdzero = -1;
463 #ifdef MAP_ANON
464 flags |= MAP_ANON;
465 #else
466 if (fdzero == -1)
468 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
470 perror( "/dev/zero: open" );
471 exit(1);
474 #endif /* MAP_ANON */
476 #ifdef MAP_SHARED
477 flags &= ~MAP_SHARED;
478 #endif
480 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
481 #ifdef MAP_PRIVATE
482 flags |= MAP_PRIVATE;
483 #endif
485 #if defined(__svr4__) || defined(__NetBSD__)
486 if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
487 return start;
488 #endif
490 return mmap( start, size, prot, flags, fdzero, 0 );
491 #else
492 return (void *)-1;
493 #endif
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 /***********************************************************************
508 * wine_dlopen
510 void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
512 #ifdef HAVE_DLOPEN
513 void *ret;
514 const char *s;
515 dlerror(); dlerror();
516 ret = dlopen( filename, flag );
517 s = dlerror();
518 if (error)
520 strncpy( error, s ? s : "", errorsize );
521 error[errorsize - 1] = '\0';
523 dlerror();
524 return ret;
525 #else
526 if (error)
528 strncpy( error, "dlopen interface not detected by configure", errorsize );
529 error[errorsize - 1] = '\0';
531 return NULL;
532 #endif
535 /***********************************************************************
536 * wine_dlsym
538 void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
540 #ifdef HAVE_DLOPEN
541 void *ret;
542 const char *s;
543 dlerror(); dlerror();
544 ret = dlsym( handle, symbol );
545 s = dlerror();
546 if (error)
548 strncpy( error, s ? s : "", errorsize );
549 error[errorsize - 1] = '\0';
551 dlerror();
552 return ret;
553 #else
554 if (error)
556 strncpy( error, "dlopen interface not detected by configure", errorsize );
557 error[errorsize - 1] = '\0';
559 return NULL;
560 #endif
563 /***********************************************************************
564 * wine_dlclose
566 int wine_dlclose( void *handle, char *error, int errorsize )
568 #ifdef HAVE_DLOPEN
569 int ret;
570 const char *s;
571 dlerror(); dlerror();
572 ret = dlclose( handle );
573 s = dlerror();
574 if (error)
576 strncpy( error, s ? s : "", errorsize );
577 error[errorsize - 1] = '\0';
579 dlerror();
580 return ret;
581 #else
582 if (error)
584 strncpy( error, "dlopen interface not detected by configure", errorsize );
585 error[errorsize - 1] = '\0';
587 return 1;
588 #endif
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;
601 if (str4==NULL)
602 return NULL;
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;
614 do {
615 *s2=(unsigned short)*str4;
616 s2++;
617 } while (*str4++ != L'\0');
619 return str2;
622 #ifndef HAVE_ECVT
624 * NetBSD 1.5 doesn't have ecvt, fcvt, gcvt. We just check for ecvt, though.
625 * Fix/verify these implementations !
628 /***********************************************************************
629 * ecvt
631 char *ecvt (double number, int ndigits, int *decpt, int *sign)
633 static char buf[40]; /* ought to be enough */
634 char *dec;
635 sprintf(buf, "%.*e", ndigits /* FIXME wrong */, number);
636 *sign = (number < 0);
637 dec = strchr(buf, '.');
638 *decpt = (dec) ? (int)dec - (int)buf : -1;
639 return buf;
642 /***********************************************************************
643 * fcvt
645 char *fcvt (double number, int ndigits, int *decpt, int *sign)
647 static char buf[40]; /* ought to be enough */
648 char *dec;
649 sprintf(buf, "%.*e", ndigits, number);
650 *sign = (number < 0);
651 dec = strchr(buf, '.');
652 *decpt = (dec) ? (int)dec - (int)buf : -1;
653 return buf;
656 /***********************************************************************
657 * gcvt
659 * FIXME: uses both E and F.
661 char *gcvt (double number, size_t ndigit, char *buff)
663 sprintf(buff, "%.*E", (int)ndigit, number);
664 return buff;
666 #endif /* HAVE_ECVT */
669 #ifndef wine_memcpy_unaligned
670 /***********************************************************************
671 * wine_memcpy_unaligned
673 * This is necessary to defeat optimizations of memcpy by gcc.
675 void *wine_memcpy_unaligned( void *dst, const void *src, size_t size )
677 return memcpy( dst, src, size );
679 #endif
682 /***********************************************************************
683 * pthread functions
686 #ifndef HAVE_PTHREAD_GETSPECIFIC
687 void pthread_getspecific() { assert(0); }
688 #endif
690 #ifndef HAVE_PTHREAD_KEY_CREATE
691 void pthread_key_create() { assert(0); }
692 #endif
694 #ifndef HAVE_PTHREAD_MUTEX_LOCK
695 void pthread_mutex_lock() { assert(0); }
696 #endif
698 #ifndef HAVE_PTHREAD_MUTEX_UNLOCK
699 void pthread_mutex_unlock() { assert(0); }
700 #endif
702 #ifndef HAVE_PTHREAD_SETSPECIFIC
703 void pthread_setspecific() { assert(0); }
704 #endif
706 /***********************************************************************
707 * interlocked functions
709 #ifdef __i386__
711 #ifdef __GNUC__
713 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
714 "movl 12(%esp),%eax\n\t"
715 "movl 8(%esp),%ecx\n\t"
716 "movl 4(%esp),%edx\n\t"
717 "lock; cmpxchgl %ecx,(%edx)\n\t"
718 "ret");
719 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
720 "movl 12(%esp),%eax\n\t"
721 "movl 8(%esp),%ecx\n\t"
722 "movl 4(%esp),%edx\n\t"
723 "lock; cmpxchgl %ecx,(%edx)\n\t"
724 "ret");
725 __ASM_GLOBAL_FUNC(interlocked_xchg,
726 "movl 8(%esp),%eax\n\t"
727 "movl 4(%esp),%edx\n\t"
728 "lock; xchgl %eax,(%edx)\n\t"
729 "ret");
730 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
731 "movl 8(%esp),%eax\n\t"
732 "movl 4(%esp),%edx\n\t"
733 "lock; xchgl %eax,(%edx)\n\t"
734 "ret");
735 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
736 "movl 8(%esp),%eax\n\t"
737 "movl 4(%esp),%edx\n\t"
738 "lock; xaddl %eax,(%edx)\n\t"
739 "ret");
741 #elif defined(_MSC_VER)
743 __declspec(naked) long interlocked_cmpxchg( long *dest, long xchg, long compare )
745 __asm mov eax, 12[esp];
746 __asm mov ecx, 8[esp];
747 __asm mov edx, 4[esp];
748 __asm lock cmpxchg [edx], ecx;
749 __asm ret;
752 __declspec(naked) void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
754 __asm mov eax, 12[esp];
755 __asm mov ecx, 8[esp];
756 __asm mov edx, 4[esp];
757 __asm lock cmpxchg [edx], ecx;
758 __asm ret;
761 __declspec(naked) long interlocked_xchg( long *dest, long val )
763 __asm mov eax, 8[esp];
764 __asm mov edx, 4[esp];
765 __asm lock xchg [edx], eax;
766 __asm ret;
769 __declspec(naked) void *interlocked_xchg_ptr( void **dest, void *val )
771 __asm mov eax, 8[esp];
772 __asm mov edx, 4[esp];
773 __asm lock xchg [edx], eax;
774 __asm ret;
777 __declspec(naked) long interlocked_xchg_add( long *dest, long incr )
779 __asm mov eax, 8[esp];
780 __asm mov edx, 4[esp];
781 __asm lock xadd [edx], eax;
782 __asm ret;
785 #else
786 # error You must implement the interlocked* functions for your compiler
787 #endif
789 #elif defined(__powerpc__)
790 void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare)
792 long ret = 0;
793 long scratch;
794 __asm__ __volatile__(
795 "0: lwarx %0,0,%2 ;"
796 " xor. %1,%4,%0;"
797 " bne 1f;"
798 " stwcx. %3,0,%2;"
799 " bne- 0b;"
800 "1: "
801 : "=&r"(ret), "=&r"(scratch)
802 : "r"(dest), "r"(xchg), "r"(compare)
803 : "cr0","memory");
804 return (void*)ret;
807 long interlocked_cmpxchg( long *dest, long xchg, long compare)
809 long ret = 0;
810 long scratch;
811 __asm__ __volatile__(
812 "0: lwarx %0,0,%2 ;"
813 " xor. %1,%4,%0;"
814 " bne 1f;"
815 " stwcx. %3,0,%2;"
816 " bne- 0b;"
817 "1: "
818 : "=&r"(ret), "=&r"(scratch)
819 : "r"(dest), "r"(xchg), "r"(compare)
820 : "cr0","memory");
821 return ret;
824 long interlocked_xchg_add( long *dest, long incr )
826 long ret = 0;
827 long zero = 0;
828 __asm__ __volatile__(
829 "0: lwarx %0, %3, %1;"
830 " add %0, %2, %0;"
831 " stwcx. %0, %3, %1;"
832 " bne- 0b;"
833 : "=&r" (ret)
834 : "r"(dest), "r"(incr), "r"(zero)
835 : "cr0", "memory"
837 return ret-incr;
840 long interlocked_xchg( long* dest, long val )
842 long ret = 0;
843 __asm__ __volatile__(
844 "0: lwarx %0,0,%1 ;"
845 " stwcx. %2,0,%1;"
846 " bne- 0b;"
847 : "=&r"(ret)
848 : "r"(dest), "r"(val)
849 : "cr0","memory");
850 return ret;
853 void* interlocked_xchg_ptr( void** dest, void* val )
855 void *ret = NULL;
856 __asm__ __volatile__(
857 "0: lwarx %0,0,%1 ;"
858 " stwcx. %2,0,%1;"
859 " bne- 0b;"
860 : "=&r"(ret)
861 : "r"(dest), "r"(val)
862 : "cr0","memory");
863 return ret;
866 #elif defined(__sparc__) && defined(__sun__)
869 * As the earlier Sparc processors lack necessary atomic instructions,
870 * I'm simply falling back to the library-provided _lwp_mutex routines
871 * to ensure mutual exclusion in a way appropriate for the current
872 * architecture.
874 * FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
875 * we could use this to speed up the Interlocked operations ...
877 #include <synch.h>
878 static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
880 long interlocked_cmpxchg( long *dest, long xchg, long compare )
882 _lwp_mutex_lock( &interlocked_mutex );
883 if (*dest == compare) *dest = xchg;
884 else compare = *dest;
885 _lwp_mutex_unlock( &interlocked_mutex );
886 return compare;
889 void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
891 _lwp_mutex_lock( &interlocked_mutex );
892 if (*dest == compare) *dest = xchg;
893 else compare = *dest;
894 _lwp_mutex_unlock( &interlocked_mutex );
895 return compare;
898 long interlocked_xchg( long *dest, long val )
900 long retv;
901 _lwp_mutex_lock( &interlocked_mutex );
902 retv = *dest;
903 *dest = val;
904 _lwp_mutex_unlock( &interlocked_mutex );
905 return retv;
908 void *interlocked_xchg_ptr( void **dest, void *val )
910 long retv;
911 _lwp_mutex_lock( &interlocked_mutex );
912 retv = *dest;
913 *dest = val;
914 _lwp_mutex_unlock( &interlocked_mutex );
915 return retv;
918 long interlocked_xchg_add( long *dest, long incr )
920 long retv;
921 _lwp_mutex_lock( &interlocked_mutex );
922 retv = *dest;
923 *dest += incr;
924 _lwp_mutex_unlock( &interlocked_mutex );
925 return retv;
927 #else
928 # error You must implement the interlocked* functions for your CPU
929 #endif