Skip to content

Instantly share code, notes, and snippets.

@adambarta
Created July 11, 2012 15:23
Show Gist options
  • Save adambarta/3091107 to your computer and use it in GitHub Desktop.
Save adambarta/3091107 to your computer and use it in GitHub Desktop.
Mutexes on Linux (x86_64) in userspace using futex
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sysexits.h>
#include <unistd.h>
#include <stdint.h>
#include <limits.h>
#include <asm-generic/mman.h>
#include <linux/futex.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include "mutex.h"
void lock_mutex(mutex *m)
{
int c, i;
for (i=0; i<100; i++){
c = cmpxchg(m, 0, 1);
if (!c)
return;
cpu_relax();
}
if (c == 1)
c = xchg(m, 2);
while (c){
syscall(SYS_futex, m, FUTEX_WAIT, 2, NULL, NULL, 0);
c = xchg(m, 2);
}
return;
}
void unlock_mutex(mutex *m)
{
int i;
if ((*m) == 2){
(*m) = 0;
} else if (xchg(m, 0) == 1){
return;
}
for (i=0; i<200; i++){
if ((*m)){
if (cmpxchg(m, 1, 2)){
return;
}
}
cpu_relax();
}
syscall(SYS_futex, m, FUTEX_WAKE, 1, NULL, NULL, 0);
return;
}
#ifdef TEST_MUTEX
int main(int argc, char *argv[])
{
#define CHILD 30
int i, j;
pid_t cpid;
unsigned long *v;
mutex *key;
key = mmap(NULL, sizeof(unsigned long) + sizeof(mutex), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, (-1),
0);
if (key == NULL)
return 1;
bzero((void*)key, sizeof(unsigned long) + sizeof(mutex));
v = (unsigned long *)(key + sizeof(mutex));
*v = 0;
*key = 0;
for (j=0; j<CHILD; j++){
cpid = fork();
if (cpid < 0){
fprintf(stderr, "fork error %s\n", strerror(errno));
return 1;
}
if (!cpid){
/*THIS IS A CHILD*/
fprintf(stderr, "CHILD [%d] writing\n", getpid());
for (i=0; i<100000; i++){
lock_mutex(key);
int temp = *v;
temp++;
*v = temp;
unlock_mutex(key);
usleep(1);
}
exit(EX_OK);
}
}
i=0;
do {
fprintf(stderr, "parent collected child [%d]\n", wait(NULL));
} while(i++ < CHILD);
fprintf(stderr, "PARENT VALUE [%ld]\n", *v);
munmap((void*) key, sizeof(unsigned long) + sizeof(mutex));
return 0;
}
#endif
#ifndef MUTEX_H
#define MUTEX_H
#define cpu_relax() \
__asm__ __volatile__ ( "pause\n" : : : "memory")
typedef int mutex;
static inline mutex cmpxchg(mutex *ptr, mutex old, mutex new)
{
mutex ret;
asm volatile("lock\n" "cmpxchgl %2,%1\n"
: "=a" (ret), "+m" (*(mutex *)ptr)
: "r" (new), "0" (old)
: "memory");
return ret;
}
static inline mutex xchg(mutex *ptr, mutex x)
{
asm volatile("lock\n" "xchgl %0,%1\n"
:"=r" (x), "+m" (*(mutex*)ptr)
:"0" (x)
:"memory");
return x;
}
void lock_mutex(mutex *m);
void unlock_mutex(mutex *m);
#endif
@adambarta
Copy link
Author

Compile with

cc -ggdb -O3 -Wall -DTEST_MUTEX -o test-mutex mutex.c

should just work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment