blob: bc426532f6462d7852d0569c3bb1d84ad94bc0b9 [file] [log] [blame]
/*
* xchglock.c: Sample atomic-xchg-based lock primitive.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright (c) 2011-2019 Paul E. McKenney, IBM Corporation.
* Copyright (c) 2019 Paul E. McKenney, Facebook.
*/
#include "../api.h"
//\begin{snippet}[labelbase=ln:locking:xchglock:lock_unlock,commandchars=\\\[\]]
typedef int xchglock_t; //\lnlbl{typedef}
//\fcvexclude
#define DEFINE_XCHG_LOCK(n) xchglock_t n = 0 //\lnlbl{initval}
void xchg_lock(xchglock_t *xp) //\lnlbl{lock:b}
{
while (xchg(xp, 1) == 1) { //\lnlbl{lock:atmxchg}
while (READ_ONCE(*xp) == 1) //\lnlbl{lock:inner:b}
continue; //\lnlbl{lock:inner:e}
}
} //\lnlbl{lock:e}
void xchg_unlock(xchglock_t *xp) //\lnlbl{unlock:b}
{
(void)xchg(xp, 0); //\lnlbl{unlock:atmxchg}
} //\lnlbl{unlock:e}
//\end{snippet}
DEFINE_XCHG_LOCK(testlock);
#define GOFLAG_INIT 0
#define GOFLAG_RUN 1
#define GOFLAG_STOP 2
atomic_t nthreadsrunning;
int goflag __attribute__((__aligned__(CACHE_LINE_SIZE))) = GOFLAG_INIT;
int owner = -1;
unsigned long lockacqs;
unsigned long lockerr;
void *test_xchg_lock(void *arg)
{
int me = (long)arg;
run_on(me);
atomic_inc(&nthreadsrunning);
while (READ_ONCE(goflag) == GOFLAG_INIT)
poll(NULL, 0, 1);
while (READ_ONCE(goflag) == GOFLAG_RUN) {
xchg_lock(&testlock);
if (owner != -1)
lockerr++;
lockacqs++;
owner = me;
poll(NULL, 0, 1);
owner = -1;
xchg_unlock(&testlock);
}
return NULL;
}
int main(int argc, char *argv[])
{
int nthreads = 0;
create_thread(test_xchg_lock, (void *)0);
nthreads++;
create_thread(test_xchg_lock, (void *)1);
nthreads++;
smp_mb();
while (atomic_read(&nthreadsrunning) < nthreads)
poll(NULL, 0, 1);
WRITE_ONCE(goflag, GOFLAG_RUN);
smp_mb();
poll(NULL, 0, 10000);
smp_mb();
WRITE_ONCE(goflag, GOFLAG_STOP);
smp_mb();
wait_all_threads();
printf("lockacqs = %lu, lockerr = %lu\n", lockacqs, lockerr);
return 0;
}