Skip site navigation (1)Skip section navigation (2)
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>