Commit 2f54aac3 authored by Christoph Gerum's avatar Christoph Gerum

Add m5thread for exercise 5

parent 142d7fe2
dcec9ee72f99eac5f7ffea6ff92a5b68dcf49868 8
dcec9ee72f99eac5f7ffea6ff92a5b68dcf49868 default
[paths]
default = http://repo.gem5.org/m5threads/
dotencode
fncache
revlogv1
store
data/pthread_defs.h.i
data/profiling_hooks.h.i
data/tests/Makefile.i
data/tests/test_stackgrow.cpp.i
data/tests/test_barrier.cpp.i
data/tests/test_lock.cpp.i
data/Makefile.i
data/tls_defs.h.i
data/tests/test_malloc.cpp.i
data/tests/test_omp.cpp.i
data/tests/test_atomic.cpp.i
data/pthread.c.i
data/LICENSE.i
data/spinlock_x86.h.i
data/tests/test_pthreadbasic.cpp.i
data/tests/test___thread.cpp.i
data/spinlock_arm.h.i
data/spinlock_alpha.h.i
data/README.i
data/tests/test_pthread.cpp.i
data/spinlock_sparc.h.i
data/tests/test_sieve.cpp.i
default
\ No newline at end of file
0
pull
http://repo.gem5.org/m5threads/
This diff is collapsed.
CC = gcc
CFLAGS = -O3 -static
.PHONY: all clean
all: libpthread.a(pthread.o)
clean:
$(RM) *.o libpthread.a
m5threads -- A pthread library for the M5 simulator
===================================================
Daniel Sanchez, Stanford University
Changelog
---------
14-Feb-09
- Added support for OpenMP in SPARC.
- Fixed stack guard to work in SPARC64 (stack bias was insufficient).
- Added optional profiling hooks to measure synchronization use. Compile with -DM5_PROFILING to use M5 profiling syscalls.
- The Makefile now builds test programs linked with both m5threads (test_XXX) and the standard pthread library (test_XXX_p). This is done for debugging purposes, but note that **the _p binaries won't work in M5**.
27-Jan-09
- Added support for TLS in SPARC and x86-64 in static binaries. Alpha no longer works due to having unimplemented TLS support.
- Fixed a race condition in rwlocks and condition variables.
- Added support for detached threads.
- Added thread-specific data (TSD) functions: key_create/delete/getspecific/setspecific.
- Integrated with NPTL/LinuxThreads-based glibc (libc aliases, specific functions, intialization routines, and libc-specific TSD). libc calls are now MT-safe and the library runs the full test suite correctly. Tested on SPARC/glibc2.3.6/Linux 2.6.11 (LinuxThreads) in M5, and x86-64/glibc2.6/Linux 2.6.26 (NPTL) in an 8-core machine.
- Added support for OpenMP programs (see test_opm.cpp) -- for now, works in x86 (real machine and M5), but not in SPARC.
- Licensed under GPLv2.
- Extended this README.
23-Jan-2009
- Added support for SPARC in pthread_exit
- Substituted tree barriers by counter barriers. Now barriers work regardless of which threads take them.
21-Jan-2009
- Initial version
License
-------
This software is licensed under the GPLv2. See the LICENSE file for a full copy of the license.
This software contains portions of code from the Linux kernel and glibc 2.3.6. Both are redistributed under the terms of the GPL.
Description
-----------
This library enables M5 to simulate multithreaded apps in system call emulation mode. It is intended as a replacement of NPTL/LinuxThreads implementations of libpthread. Instead of using a large portion of the Linux system calls, this library does as much as possible in user-level code. It requires just two system calls: clone, to spawn a new process, and exit, to finish a thread. As a result, it is easy to support in a syscall-emulation simulator. However, this is not a full implementation of pthreads, and the library lacks a thread scheduler. In M5, you will not be able to schedule more threads than thread contexts.
This library works in M5, but in real systems too. Both x86-64 and SPARC systems running Linux should execute programs correctly. In real systems, you will be able to allocate more threads than CPUs, but performance will degrade in this case since there is no thread scheduler (and thread switching occurs at the granularity of the OS scheduler).
Only a subset of the pthread specification is supported. This includes:
- Creation and join of joinable and detached threads; pthread_exit
- Regular mutexes (NOT recursive or other rare modes)
- Regular read-write locks
- Barriers
- Condition variables
- Keys (key_create/delete, get/setspecific)
- Miscellaneous functions:
In particular, the following thinks are not supported:
- pthread_cancel and related functions
- pthread_kill
- Anything else that has to do with signals
- pthread_cleanup_XXX, pthread_unwind
If your program uses a non-implemented pthread function, it will fail an assertion.
This library should compile with GNU toolchains implementing LinuxThreads (Linux <=2.4 or 2.6) or NPTL (2.6 only) pthreads. If you compile it with an NPTL glibc, you may get futex() system calls if you try to do concurrent calls to multithreaded-safe glibc functions (e.g. printf). These are unimplemented in M5. To avoid them, enclose these calls in a global lock. Additionally, NPTL apps tend to use more system calls, so it is recommended to use M5 with a glibc compiled with LinuxThreads. Performance should be practically identical with both versions, as we are substituting the threading library.
This library includes support for thread-local storage (TLS), but only for the SPARC and x86-64 ABIs (which are nearly identical). Alpha is no longer supported. Supporting Alpha would require implementing its TLS ABI.
Compiling & using
-----------------
Applications compiled with this library should be built statically, and should link against the built pthread.o object file. Again, see the Makefile in the tests/ directory for the exact commands used.
By default, the tests/Makefile builds all the tests using your system's g++. You can build sparc binaries by building a cross-compiler.
TODOs
-----
- Ticket/MCS locks
- Tree barriers
- Add a scheduler, turning the library to an M:N model
Implementation details
======================
What follows is recommended reading if you want to understand how the library works in more detail and extend it.
This library implements mutexes as TTS spinlocks (taken from the Linux source code tree), and barriers as counter barriers. Compatibility with NPTL and LinuxThreads data structures is maintained by using a variety of macros, defined in pthread_defs.h
All the memory regions needed to spawn a thread are contained in a single memory segment, the thread block, which has the following format:
---------------------- <- lower addresses
Thread Control Block
----------------------
TLS data
---------------------- <- TLS pointer
(Unused) "real" TCB
----------------------
[empty space]
----------------------
Stack
---------------------- <- Initial stack pointer (grows to lower addresses)
Stack Guard
---------------------- <- upper addresses
The thread control block contains the information relative to the current thread (status, flags, etc). The thread ID (returned by pthread_self()) is simply a pointer to the TCB. This enables distributed thread create/join, and there are no global structures for tracking thread data.
The "real" TCB is the TCB defined by LinuxThreads or NPTL. We don't use it directly and initialize its contents to 0, but reserve some space because some variables (most notably errno) are in this area.
The thread block conforms to the TLS ABI for x86-64 and SPARC architectures, which follows variant II as described in http://people.redhat.com/drepper/tls.pdf If you wish to extend this to other architectures, e.g. Alpha, be sure to read sections 1-3 of that document. Also, most of the code for the TLS part of the library is taken from glibc2.3.6 (search for the __libc_setup_tls function).
In pthread_create, the parent mmaps the thread block, populates the TCB, and spawns a new child. The child sets up TLS before starting execution. In joinable threads, it is the responsibility of the parent to munmap the thread block. If the thread is detached, it will munmap its own thread block when exiting. The thread block is allocated with mmap because 1) it is a sizable chunk of memory and 2) this way, the child can delete its own stack (since munmap is a system call, not a function call, a stack is not required on return).
The library includes function aliases, extra definitions, libc-specific keys and initialization code to work correctly with glibc. When linking with this library, glibc function calls *should* be MT-safe. However, how libc and libpthread interact has changed over time, and this may not work correctly with glibc versions >2.6. Modifying the code to support other versions of glibc should be straightworward, if you have some idea for what you are doing. I recommend using nm (to see what symbols are defined) and objdump (to dissasemble) on whatever version of libc.a you'll be using, and see if there is any mismatch with the "glibc glue" code in the library (mostly, at the end of pthread.c).
/*
m5threads, a pthread library for the M5 simulator
Copyright (C) 2009, Stanford University
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Author: Daniel Sanchez
*/
/* Profiling hooks used by m5threads to measure synchronization usage */
//TODO: Profiling hooks for non-M5 mode
#if defined(M5_PROFILING)
/* M5 profiling syscall asm */
#if defined (__sparc)
#define m5_prof_syscall(syscall_num, arg) __asm__ __volatile__ ( \
"mov " #syscall_num ", %%g1\n\t" \
"mov %0, %%o0\n\t" \
"ta 0x6d\n\t" \
:: "r"(arg) : "g1", "o0" \
);
#else
#error "M5 profiling hooks not implemented for your architecture, write them"
#endif
#define PROFILE_LOCK_START(addr) m5_prof_syscall(1040, addr)
#define PROFILE_LOCK_END(addr) m5_prof_syscall(1041, addr)
#define PROFILE_UNLOCK_START(addr) m5_prof_syscall(1042, addr)
#define PROFILE_UNLOCK_END(addr) m5_prof_syscall(1043, addr)
#define PROFILE_BARRIER_WAIT_START(addr) m5_prof_syscall(1044, addr)
#define PROFILE_BARRIER_WAIT_END(addr) m5_prof_syscall(1045, addr)
#define PROFILE_COND_WAIT_START(addr) m5_prof_syscall(1046, addr)
#define PROFILE_COND_WAIT_END(addr) m5_prof_syscall(1047, addr)
#else
/* Empty hooks */
#define PROFILE_LOCK_START(addr)
#define PROFILE_LOCK_END(addr)
#define PROFILE_UNLOCK_START(addr)
#define PROFILE_UNLOCK_END(addr)
#define PROFILE_BARRIER_WAIT_START(addr)
#define PROFILE_BARRIER_WAIT_END(addr)
#define PROFILE_COND_WAIT_START(addr)
#define PROFILE_COND_WAIT_END(addr)
#endif
This diff is collapsed.
/*
m5threads, a pthread library for the M5 simulator
Copyright (C) 2009, Stanford University
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __PTHREAD_DEFS_H__
#define __PTHREAD_DEFS_H__
/*typedef struct {
volatile int value;
long _padding[15]; // to prevent false sharing
} tree_barrier_t;*/
// old LinuxThreads needs different magic than newer NPTL implementation
// definitions for LinuxThreads
#ifdef __linux__
//XOPEN2K and UNIX98 defines to avoid for rwlocks/barriers when compiling with gcc...
//see <bits/pthreadtypes.h>
#if !defined(__USE_UNIX98) && !defined(__USE_XOPEN2K) && !defined(__SIZEOF_PTHREAD_MUTEX_T)
/* Read-write locks. */
typedef struct _pthread_rwlock_t
{
struct _pthread_fastlock __rw_lock; /* Lock to guarantee mutual exclusion */
int __rw_readers; /* Number of readers */
_pthread_descr __rw_writer; /* Identity of writer, or NULL if none */
_pthread_descr __rw_read_waiting; /* Threads waiting for reading */
_pthread_descr __rw_write_waiting; /* Threads waiting for writing */
int __rw_kind; /* Reader/Writer preference selection */
int __rw_pshared; /* Shared between processes or not */
} pthread_rwlock_t;
/* Attribute for read-write locks. */
typedef struct
{
int __lockkind;
int __pshared;
} pthread_rwlockattr_t;
#endif
#if !defined(__USE_XOPEN2K) && !defined(__SIZEOF_PTHREAD_MUTEX_T)
/* POSIX spinlock data type. */
typedef volatile int pthread_spinlock_t;
/* POSIX barrier. */
typedef struct {
struct _pthread_fastlock __ba_lock; /* Lock to guarantee mutual exclusion */
int __ba_required; /* Threads needed for completion */
int __ba_present; /* Threads waiting */
_pthread_descr __ba_waiting; /* Queue of waiting threads */
} pthread_barrier_t;
/* barrier attribute */
typedef struct {
int __pshared;
} pthread_barrierattr_t;
#endif
#ifndef __SIZEOF_PTHREAD_MUTEX_T
#define PTHREAD_MUTEX_T_COUNT __m_count
#define PTHREAD_COND_T_FLAG(cond) (*(volatile int*)(&(cond->__c_lock.__status)))
#define PTHREAD_COND_T_THREAD_COUNT(cond) (*(volatile int*)(&(cond-> __c_waiting)))
#define PTHREAD_COND_T_COUNT_LOCK(cond) (*(volatile int*)(&(cond->__c_lock.__spinlock)))
#define PTHREAD_RWLOCK_T_LOCK(rwlock) (*(volatile int*)(&rwlock->__rw_lock))
#define PTHREAD_RWLOCK_T_READERS(rwlock) (*(volatile int*)(&rwlock->__rw_readers))
#define PTHREAD_RWLOCK_T_WRITER(rwlock) (*(volatile pthread_t*)(&rwlock->__rw_kind))
//For tree barriers
//#define PTHREAD_BARRIER_T_NUM_THREADS(barrier) (*(int*)(&barrier->__ba_lock.__spinlock))
//#define PTHREAD_BARRIER_T_BARRIER_PTR(barrier) (*(tree_barrier_t**)(&barrier->__ba_required))
#define PTHREAD_BARRIER_T_SPINLOCK(barrier) (*(volatile int*)(&barrier->__ba_lock.__spinlock))
#define PTHREAD_BARRIER_T_NUM_THREADS(barrier) (*((volatile int*)(&barrier->__ba_required)))
#define PTHREAD_BARRIER_T_COUNTER(barrier) (*((volatile int*)(&barrier->__ba_present)))
#define PTHREAD_BARRIER_T_DIRECTION(barrier) (*((volatile int*)(&barrier->__ba_waiting)))
// definitions for NPTL implementation
#else /* __SIZEOF_PTHREAD_MUTEX_T defined */
#define PTHREAD_MUTEX_T_COUNT __data.__count
#define PTHREAD_RWLOCK_T_LOCK(rwlock) (*(volatile int*)(&rwlock->__data.__lock))
#define PTHREAD_RWLOCK_T_READERS(rwlock) (*(volatile int*)(&rwlock->__data.__nr_readers))
#define PTHREAD_RWLOCK_T_WRITER(rwlock) (*(volatile int*)(&rwlock->__data.__writer))
#if defined(__GNUC__) && __GNUC__ >= 4
#define PTHREAD_COND_T_FLAG(cond) (*(volatile int*)(&(cond->__data.__lock)))
#define PTHREAD_COND_T_THREAD_COUNT(cond) (*(volatile int*)(&(cond-> __data.__futex)))
#define PTHREAD_COND_T_COUNT_LOCK(cond) (*(volatile int*)(&(cond->__data.__nwaiters)))
//For tree barriers
//#define PTHREAD_BARRIER_T_NUM_THREADS(barrier) (*((int*)(barrier->__size+(0*sizeof(int)))))
//#define PTHREAD_BARRIER_T_BARRIER_PTR(barrier) (*(tree_barrier_t**)(barrier->__size+(1*sizeof(int))))
#define PTHREAD_BARRIER_T_SPINLOCK(barrier) (*((volatile int*)(barrier->__size+(0*sizeof(int)))))
#define PTHREAD_BARRIER_T_NUM_THREADS(barrier) (*((volatile int*)(barrier->__size+(1*sizeof(int)))))
#define PTHREAD_BARRIER_T_COUNTER(barrier) (*((volatile int*)(barrier->__size+(2*sizeof(int)))))
#define PTHREAD_BARRIER_T_DIRECTION(barrier) (*((volatile int*)(barrier->__size+(3*sizeof(int)))))
//Tree barrier-related
#if 0
#ifndef __SIZEOF_PTHREAD_BARRIER_T
#error __SIZEOF_PTHREAD_BARRIER_T not defined
#endif
#if ((4/*fields*/*4/*sizeof(int32)*/) > __SIZEOF_PTHREAD_BARRIER_T)
#error barrier size __SIZEOF_PTHREAD_BARRIER_T not large enough for our implementation
#endif
#endif
#else // gnuc >= 4
//gnuc < 4
#error "This library requires gcc 4.0+ (3.x should work, but you'll need to change pthread_defs.h)"
#endif // gnuc >= 4
#endif // LinuxThreads / NPTL
// non-linux definitions... fill this in?
#else // !__linux__
#error "Non-Linux pthread definitions not available"
#endif //!__linux__
#endif // __PTHREAD_DEFS_H__
/*
m5threads, a pthread library for the M5 simulator
Copyright (C) 2009, Stanford University
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __SPINLOCK_ALPHA_H__
#define __SPINLOCK_ALPHA_H__
// routines adapted from /usr/src/linux/include/asm-alpha/spinlock.h
static __inline__ void spin_lock (volatile int* lock) {
long tmp;
__asm__ __volatile__(
"1: ldl_l %0,%1\n"
" bne %0,2f\n"
" lda %0,1\n"
" stl_c %0,%1\n"
" beq %0,2f\n"
" mb\n"
".subsection 2\n"
"2: ldl %0,%1\n"
" bne %0,2b\n"
" br 1b\n"
".previous"
: "=&r" (tmp), "=m" (*lock)
: "m"(*lock) : "memory");
}
static __inline__ void spin_unlock (volatile int* lock) {
__asm__ __volatile__ ("mb\n");
*lock = 0;
}
static __inline__ int trylock (volatile int* lock) {
long regx;
int success;
__asm__ __volatile__(
"1: ldl_l %1,%0\n"
" lda %2,0\n"
" bne %1,2f\n"
" lda %2,1\n"
" stl_c %2,%0\n"
" beq %2,6f\n"
"2: mb\n"
".subsection 2\n"
"6: br 1b\n"
".previous"
: "=m" (*lock), "=&r" (regx), "=&r" (success)
: "m" (*lock) : "memory");
return success;
}
#endif // __SPINLOCK_H__
/*
m5threads, a pthread library for the M5 simulator
Copyright (C) 2009, Stanford University
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __SPINLOCK_ARM_H__
#define __SPINLOCK_ARM_H__
static __inline__ void spin_lock (volatile int* lock) {
unsigned long tmp;
__asm__ __volatile__(
"1: ldrex %0, [%1]\n"
" cmp %0, #0\n"
" strexeq %0, %2, [%1]\n"
" cmpeq %0, #0\n"
" bne 1b\n"
" dmb\n"
: "=&r" (tmp)
: "r" (lock), "r" (1)
: "cc");
}
static __inline__ void spin_unlock (volatile int* lock) {
__asm__ __volatile__(
" dmb\n"
" str %1, [%0]\n"
:
: "r" (lock), "r" (0)
: "cc");
}
static __inline__ int trylock (volatile int* lock) {
unsigned long tmp;
__asm__ __volatile__(
" ldrex %0, [%1]\n"
" cmp %0, #0\n"
" strexeq %0, %2, [%1]\n"
" eor %0, %0, #1\n"
" bne fail\n"
" dmb\n"
"fail: nop\n"
: "=&r" (tmp)
: "r" (lock), "r" (1)
: "cc", "memory");
return tmp;
}
#endif // __SPINLOCK_ARM_H__
/*
m5threads, a pthread library for the M5 simulator
Copyright (C) 2009, Stanford University
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __SPINLOCK_SPARC_H__
#define __SPINLOCK_SPARC_H__
// routines from /usr/src/linux/include/asm-sparc/spinlock_64.h
// Note: these work even with RMO, but a few barriers could be eliminated for TSO
static __inline__ void spin_lock(volatile int* lock)
{
unsigned long tmp;
__asm__ __volatile__(
"1: ldstub [%1], %0\n"
" membar #StoreLoad | #StoreStore\n"
" brnz,pn %0, 2f\n"
" nop\n"
" .subsection 2\n"
"2: ldub [%1], %0\n"
" membar #LoadLoad\n"
" brnz,pt %0, 2b\n"
" nop\n"
" ba,a,pt %%xcc, 1b\n"
" .previous"
: "=&r" (tmp)
: "r" (lock)
: "memory");
}
static __inline__ int trylock(volatile int* lock)
{
unsigned long result;
__asm__ __volatile__(
" ldstub [%1], %0\n"
" membar #StoreLoad | #StoreStore"
: "=r" (result)
: "r" (lock)
: "memory");
return (result == 0);
}
static __inline__ void spin_unlock(volatile int* lock)
{
__asm__ __volatile__(
" membar #StoreStore | #LoadStore\n"
" stb %%g0, [%0]"
: // No outputs
: "r" (lock)
: "memory");
}
#endif // __SPINLOCK_SPARC_H__
/*
m5threads, a pthread library for the M5 simulator
Copyright (C) 2009, Stanford University
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __SPINLOCK_X86_H__
#define __SPINLOCK_X86_H__
// routines from /usr/src/linux/include/asm-x86/spinlock.h
static __inline__ void spin_lock (volatile int* lock) {
char oldval;
__asm__ __volatile__
(
"\n1:\t" \
"cmpb $0,%1\n\t" \
"ja 1b\n\t" \
"xchgb %b0, %1\n\t" \
"cmpb $0,%0\n" \
"ja 1b\n\t"
:"=q"(oldval), "=m"(*lock)
: "0"(1)
: "memory");
}
static __inline__ void spin_unlock (volatile int* lock) {
__asm__ __volatile__
("movb $0,%0" \
:"=m" (*lock) : : "memory");
}
static __inline__ int trylock (volatile int* lock) {
char oldval;
__asm__ __volatile__
(
"xchgb %b0,%1"
:"=q" (oldval),
"=m" (*lock)
:"0" (1)
: "memory");
return oldval == 0;
}