New libc malloc patch
David Xu
davidxu at freebsd.org
Sat Dec 3 18:52:48 PST 2005
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);
}
More information about the freebsd-current
mailing list