Created
July 11, 2012 15:23
-
-
Save adambarta/3091107 to your computer and use it in GitHub Desktop.
Mutexes on Linux (x86_64) in userspace using futex
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Compile with
cc -ggdb -O3 -Wall -DTEST_MUTEX -o test-mutex mutex.c
should just work