Date: Sun, 04 Dec 2005 10:53:01 +0800 From: David Xu <davidxu@freebsd.org> To: David Xu <davidxu@freebsd.org> Cc: Jason Evans <jasone@canonware.com>, current@freebsd.org Subject: Re: New libc malloc patch Message-ID: <43925A0D.8070906@freebsd.org> In-Reply-To: <43924917.3070506@freebsd.org> References: <B6653214-2181-4342-854D-323979D23EE8@canonware.com> <Pine.LNX.4.53.0511291121360.27754@regurgitate.ugcs.caltech.edu> <0B746373-8C29-4ADF-9218-311AE08F3834@canonware.com> <4391569A.7080808@freebsd.org> <D1B3ED90-7936-41AA-93D3-AAC7E1615CDA@canonware.com> <43924917.3070506@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
Here is sample code to implement a mutex by using umtx syscalls:
#include <errno.h>
#include <stddef.h>
#include <sys/ucontext.h>
#include <sys/umtx.h>
#include <sys/types.h>
#include <machine/atomic.h>
#include <pthread.h>
#define LCK_UNLOCKED 0
#define LCK_LOCKED 1
#define LCK_CONTENDED 2
void
lock_mtx(struct umtx *mtx)
{
volatile uintptr_t *m = (volatile uintptr_t *)mtx;
for (;;) {
/* try to lock it. */
if (atomic_cmpset_acq_ptr(m, LCK_UNLOCKED, LCK_LOCKED))
return;
if (atomic_load_acq_ptr(m) == LCK_LOCKED) {
/*
* if it was locked by single thread, try to
* set it to contented state.
*/
if (!atomic_cmpset_acq_ptr(m, LCK_LOCKED, LCK_CONTENDED))
continue;
}
/* if in contented state, wait it to be unlocked. */
if (atomic_load_acq_ptr(m) == LCK_CONTENDED)
_umtx_op((struct umtx *)m, UMTX_OP_WAIT, LCK_CONTENDED, 0,
NULL);
}
}
void
unlock_mtx(struct umtx *mtx)
{
volatile uintptr_t *m = (volatile uintptr_t *)mtx;
for (;;) {
if (atomic_load_acq_ptr(m) == LCK_UNLOCKED)
err(1, "unlock a unlocked mutex\n");
if (atomic_load_acq_ptr(m) == LCK_LOCKED) {
if (atomic_cmpset_acq_ptr(m, LCK_LOCKED, LCK_UNLOCKED))
return;
}
if (atomic_load_acq_ptr(m) == LCK_CONTENDED) {
atomic_store_rel_ptr(m, LCK_UNLOCKED);
_umtx_op((struct umtx *)m, UMTX_OP_WAKE, 1, NULL, NULL);
break;
}
}
}
struct umtx m;
void *
lock_test(void *arg)
{
int i = 0;
for (i = 0; i < 10000; ++i) {
lock_mtx(&m);
pthread_yield();
unlock_mtx(&m);
}
return (0);
}
int main()
{
pthread_t td1, td2;
pthread_create(&td1, NULL, lock_test, NULL);
pthread_create(&td2, NULL, lock_test, NULL);
pthread_join(td1, NULL);
pthread_join(td2, NULL);
return (0);
}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?43925A0D.8070906>
