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); }Received on Sun Dec 04 2005 - 01:52:48 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:48 UTC