Release 20020904.
[wine/gsoc-2012-control.git] / library / port.c
blob0f21e8390dc44fc6cb50df6a71930675f22f2992
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, unsigned int 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 /***********************************************************************
670 * interlocked functions
672 #ifdef __i386__
674 #ifdef __GNUC__
676 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
677 "movl 12(%esp),%eax\n\t"
678 "movl 8(%esp),%ecx\n\t"
679 "movl 4(%esp),%edx\n\t"
680 "lock; cmpxchgl %ecx,(%edx)\n\t"
681 "ret");
682 __ASM_GLOBAL_FUNC(interlocked_cmpxchg_ptr,
683 "movl 12(%esp),%eax\n\t"
684 "movl 8(%esp),%ecx\n\t"
685 "movl 4(%esp),%edx\n\t"
686 "lock; cmpxchgl %ecx,(%edx)\n\t"
687 "ret");
688 __ASM_GLOBAL_FUNC(interlocked_xchg,
689 "movl 8(%esp),%eax\n\t"
690 "movl 4(%esp),%edx\n\t"
691 "lock; xchgl %eax,(%edx)\n\t"
692 "ret");
693 __ASM_GLOBAL_FUNC(interlocked_xchg_ptr,
694 "movl 8(%esp),%eax\n\t"
695 "movl 4(%esp),%edx\n\t"
696 "lock; xchgl %eax,(%edx)\n\t"
697 "ret");
698 __ASM_GLOBAL_FUNC(interlocked_xchg_add,
699 "movl 8(%esp),%eax\n\t"
700 "movl 4(%esp),%edx\n\t"
701 "lock; xaddl %eax,(%edx)\n\t"
702 "ret");
704 #elif defined(_MSC_VER)
706 __declspec(naked) long interlocked_cmpxchg( long *dest, long xchg, long compare )
708 __asm mov eax, 12[esp];
709 __asm mov ecx, 8[esp];
710 __asm mov edx, 4[esp];
711 __asm lock cmpxchg [edx], ecx;
712 __asm ret;
715 __declspec(naked) void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
717 __asm mov eax, 12[esp];
718 __asm mov ecx, 8[esp];
719 __asm mov edx, 4[esp];
720 __asm lock cmpxchg [edx], ecx;
721 __asm ret;
724 __declspec(naked) long interlocked_xchg( long *dest, long val )
726 __asm mov eax, 8[esp];
727 __asm mov edx, 4[esp];
728 __asm lock xchg [edx], eax;
729 __asm ret;
732 __declspec(naked) void *interlocked_xchg_ptr( void **dest, void *val )
734 __asm mov eax, 8[esp];
735 __asm mov edx, 4[esp];
736 __asm lock xchg [edx], eax;
737 __asm ret;
740 __declspec(naked) long interlocked_xchg_add( long *dest, long incr )
742 __asm mov eax, 8[esp];
743 __asm mov edx, 4[esp];
744 __asm lock xadd [edx], eax;
745 __asm ret;
748 #else
749 # error You must implement the interlocked* functions for your compiler
750 #endif
752 #elif defined(__powerpc__)
753 void* interlocked_cmpxchg_ptr( void **dest, void* xchg, void* compare)
755 long ret = 0;
756 long scratch;
757 __asm__ __volatile__(
758 "0: lwarx %0,0,%2 ;"
759 " xor. %1,%4,%0;"
760 " bne 1f;"
761 " stwcx. %3,0,%2;"
762 " bne- 0b;"
763 "1: "
764 : "=&r"(ret), "=&r"(scratch)
765 : "r"(dest), "r"(xchg), "r"(compare)
766 : "cr0","memory");
767 return (void*)ret;
770 long interlocked_cmpxchg( long *dest, long xchg, long compare)
772 long ret = 0;
773 long scratch;
774 __asm__ __volatile__(
775 "0: lwarx %0,0,%2 ;"
776 " xor. %1,%4,%0;"
777 " bne 1f;"
778 " stwcx. %3,0,%2;"
779 " bne- 0b;"
780 "1: "
781 : "=&r"(ret), "=&r"(scratch)
782 : "r"(dest), "r"(xchg), "r"(compare)
783 : "cr0","memory");
784 return ret;
787 long interlocked_xchg_add( long *dest, long incr )
789 long ret = 0;
790 long zero = 0;
791 __asm__ __volatile__(
792 "0: lwarx %0, %3, %1;"
793 " add %0, %2, %0;"
794 " stwcx. %0, %3, %1;"
795 " bne- 0b;"
796 : "=&r" (ret)
797 : "r"(dest), "r"(incr), "r"(zero)
798 : "cr0", "memory"
800 return ret-incr;
803 long interlocked_xchg( long* dest, long val )
805 long ret = 0;
806 __asm__ __volatile__(
807 "0: lwarx %0,0,%1 ;"
808 " stwcx. %2,0,%1;"
809 " bne- 0b;"
810 : "=&r"(ret)
811 : "r"(dest), "r"(val)
812 : "cr0","memory");
813 return ret;
816 void* interlocked_xchg_ptr( void** dest, void* val )
818 void *ret = NULL;
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 #elif defined(__sparc__) && defined(__sun__)
832 * As the earlier Sparc processors lack necessary atomic instructions,
833 * I'm simply falling back to the library-provided _lwp_mutex routines
834 * to ensure mutual exclusion in a way appropriate for the current
835 * architecture.
837 * FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
838 * we could use this to speed up the Interlocked operations ...
840 #include <synch.h>
841 static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
843 long interlocked_cmpxchg( long *dest, long xchg, long compare )
845 _lwp_mutex_lock( &interlocked_mutex );
846 if (*dest == compare) *dest = xchg;
847 else compare = *dest;
848 _lwp_mutex_unlock( &interlocked_mutex );
849 return compare;
852 void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare )
854 _lwp_mutex_lock( &interlocked_mutex );
855 if (*dest == compare) *dest = xchg;
856 else compare = *dest;
857 _lwp_mutex_unlock( &interlocked_mutex );
858 return compare;
861 long interlocked_xchg( long *dest, long val )
863 long retv;
864 _lwp_mutex_lock( &interlocked_mutex );
865 retv = *dest;
866 *dest = val;
867 _lwp_mutex_unlock( &interlocked_mutex );
868 return retv;
871 void *interlocked_xchg_ptr( void **dest, void *val )
873 long retv;
874 _lwp_mutex_lock( &interlocked_mutex );
875 retv = *dest;
876 *dest = val;
877 _lwp_mutex_unlock( &interlocked_mutex );
878 return retv;
881 long interlocked_xchg_add( long *dest, long incr )
883 long retv;
884 _lwp_mutex_lock( &interlocked_mutex );
885 retv = *dest;
886 *dest += incr;
887 _lwp_mutex_unlock( &interlocked_mutex );
888 return retv;
890 #else
891 # error You must implement the interlocked* functions for your CPU
892 #endif