Removed some unused types.
[wine.git] / library / port.c
blob25fd4b739603daf26b1f3bb9cd4007004a05e6dc
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 * interlocked functions
685 #ifdef __i386__
687 #ifdef __GNUC__
689 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
690 "movl 12(%esp),%eax\n\t"
691 "movl 8(%esp),%ecx\n\t"
692 "movl 4(%esp),%edx\n\t"
693 "lock; cmpxchgl %ecx,(%edx)\n\t"
694 "ret");
695 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
696 "movl 12(%esp),%eax\n\t"
697 "movl 8(%esp),%ecx\n\t"
698 "movl 4(%esp),%edx\n\t"
699 "lock; cmpxchgl %ecx,(%edx)\n\t"
700 "ret");
701 __ASM_GLOBAL_FUNC(interlocked_xchg,
702 "movl 8(%esp),%eax\n\t"
703 "movl 4(%esp),%edx\n\t"
704 "lock; xchgl %eax,(%edx)\n\t"
705 "ret");
706 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
707 "movl 8(%esp),%eax\n\t"
708 "movl 4(%esp),%edx\n\t"
709 "lock; xchgl %eax,(%edx)\n\t"
710 "ret");
711 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
712 "movl 8(%esp),%eax\n\t"
713 "movl 4(%esp),%edx\n\t"
714 "lock; xaddl %eax,(%edx)\n\t"
715 "ret");
717 #elif defined(_MSC_VER)
719 __declspec(naked) long interlocked_cmpxchg( long *dest, long xchg, long compare )
721 __asm mov eax, 12[esp];
722 __asm mov ecx, 8[esp];
723 __asm mov edx, 4[esp];
724 __asm lock cmpxchg [edx], ecx;
725 __asm ret;
728 __declspec(naked) void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
730 __asm mov eax, 12[esp];
731 __asm mov ecx, 8[esp];
732 __asm mov edx, 4[esp];
733 __asm lock cmpxchg [edx], ecx;
734 __asm ret;
737 __declspec(naked) long interlocked_xchg( long *dest, long val )
739 __asm mov eax, 8[esp];
740 __asm mov edx, 4[esp];
741 __asm lock xchg [edx], eax;
742 __asm ret;
745 __declspec(naked) void *interlocked_xchg_ptr( void **dest, void *val )
747 __asm mov eax, 8[esp];
748 __asm mov edx, 4[esp];
749 __asm lock xchg [edx], eax;
750 __asm ret;
753 __declspec(naked) long interlocked_xchg_add( long *dest, long incr )
755 __asm mov eax, 8[esp];
756 __asm mov edx, 4[esp];
757 __asm lock xadd [edx], eax;
758 __asm ret;
761 #else
762 # error You must implement the interlocked* functions for your compiler
763 #endif
765 #elif defined(__powerpc__)
766 void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare)
768 long ret = 0;
769 long scratch;
770 __asm__ __volatile__(
771 "0: lwarx %0,0,%2 ;"
772 " xor. %1,%4,%0;"
773 " bne 1f;"
774 " stwcx. %3,0,%2;"
775 " bne- 0b;"
776 "1: "
777 : "=&r"(ret), "=&r"(scratch)
778 : "r"(dest), "r"(xchg), "r"(compare)
779 : "cr0","memory");
780 return (void*)ret;
783 long interlocked_cmpxchg( long *dest, long xchg, long compare)
785 long ret = 0;
786 long scratch;
787 __asm__ __volatile__(
788 "0: lwarx %0,0,%2 ;"
789 " xor. %1,%4,%0;"
790 " bne 1f;"
791 " stwcx. %3,0,%2;"
792 " bne- 0b;"
793 "1: "
794 : "=&r"(ret), "=&r"(scratch)
795 : "r"(dest), "r"(xchg), "r"(compare)
796 : "cr0","memory");
797 return ret;
800 long interlocked_xchg_add( long *dest, long incr )
802 long ret = 0;
803 long zero = 0;
804 __asm__ __volatile__(
805 "0: lwarx %0, %3, %1;"
806 " add %0, %2, %0;"
807 " stwcx. %0, %3, %1;"
808 " bne- 0b;"
809 : "=&r" (ret)
810 : "r"(dest), "r"(incr), "r"(zero)
811 : "cr0", "memory"
813 return ret-incr;
816 long interlocked_xchg( long* dest, long val )
818 long ret = 0;
819 __asm__ __volatile__(
820 "0: lwarx %0,0,%1 ;"
821 " stwcx. %2,0,%1;"
822 " bne- 0b;"
823 : "=&r"(ret)
824 : "r"(dest), "r"(val)
825 : "cr0","memory");
826 return ret;
829 void* interlocked_xchg_ptr( void** dest, void* val )
831 void *ret = NULL;
832 __asm__ __volatile__(
833 "0: lwarx %0,0,%1 ;"
834 " stwcx. %2,0,%1;"
835 " bne- 0b;"
836 : "=&r"(ret)
837 : "r"(dest), "r"(val)
838 : "cr0","memory");
839 return ret;
842 #elif defined(__sparc__) && defined(__sun__)
845 * As the earlier Sparc processors lack necessary atomic instructions,
846 * I'm simply falling back to the library-provided _lwp_mutex routines
847 * to ensure mutual exclusion in a way appropriate for the current
848 * architecture.
850 * FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
851 * we could use this to speed up the Interlocked operations ...
853 #include <synch.h>
854 static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
856 long interlocked_cmpxchg( long *dest, long xchg, long compare )
858 _lwp_mutex_lock( &interlocked_mutex );
859 if (*dest == compare) *dest = xchg;
860 else compare = *dest;
861 _lwp_mutex_unlock( &interlocked_mutex );
862 return compare;
865 void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
867 _lwp_mutex_lock( &interlocked_mutex );
868 if (*dest == compare) *dest = xchg;
869 else compare = *dest;
870 _lwp_mutex_unlock( &interlocked_mutex );
871 return compare;
874 long interlocked_xchg( long *dest, long val )
876 long retv;
877 _lwp_mutex_lock( &interlocked_mutex );
878 retv = *dest;
879 *dest = val;
880 _lwp_mutex_unlock( &interlocked_mutex );
881 return retv;
884 void *interlocked_xchg_ptr( void **dest, void *val )
886 long retv;
887 _lwp_mutex_lock( &interlocked_mutex );
888 retv = *dest;
889 *dest = val;
890 _lwp_mutex_unlock( &interlocked_mutex );
891 return retv;
894 long interlocked_xchg_add( long *dest, long incr )
896 long retv;
897 _lwp_mutex_lock( &interlocked_mutex );
898 retv = *dest;
899 *dest += incr;
900 _lwp_mutex_unlock( &interlocked_mutex );
901 return retv;
903 #else
904 # error You must implement the interlocked* functions for your CPU
905 #endif