I'm testing futexes with pthreads. I've written following program:
#include <stdio.h>
#include <pthread.h>
#include <stdint.h>
#include <stdatomic.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
int64_t sum;
pthread_mutex_t mtx;
uint32_t ftx;
int futex(uint32_t *uaddr, int futex_op, uint32_t val, const struct timespec *timeout, uint32_t *uaddr2, uint32_t val3)
{
return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3);
}
void fwait(uint32_t *futx)
{
long st;
uint32_t one = 1;
do {
if (atomic_compare_exchange_strong(futx, &one, 0))
break;
st = futex(futx, FUTEX_WAIT_PRIVATE, 0, NULL, NULL, 0);
if ((st == -1) && (errno != EAGAIN)) {
printf("error-wait-futex\n");
exit(1);
}
} while (1);
}
void fwake(uint32_t *futx)
{
long st;
uint32_t zero = 0;
if (atomic_compare_exchange_strong(futx, &zero, 1)) {
st = futex(futx, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);
if (st == -1) {
printf("error-wake-futex\n");
exit(1);
}
}
}
void lock(void)
{
fwait(&ftx);
}
void unlock(void)
{
fwake(&ftx);
}
void * t1_handler(void *arg)
{
int mod;
uint64_t x;
mod = *(int *)arg;
x = 0;
while (x < 1000000) {
lock();
sum += mod;
x++;
unlock();
}
}
void proc(void)
{
pthread_t t1, t2;
int a1, a2;
sum = 0;
ftx = 1;
a1 = 1;
a2 = -1;
pthread_mutex_init(&mtx, NULL);
pthread_create(&t1, NULL, t1_handler, &a1);
pthread_create(&t2, NULL, t1_handler, &a2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("sum: %lld\n", sum);
}
int main(void)
{
proc();
return 0;
}
And sometimes it returns 0 as a sum which is proper value but sometimes the returned value of sum is different than 0.
My question is why the returned values of "sum" are different than 0? I suspect that there is something wrong with locking but for the moment I cannot figure out what.