ftrace.2: example - using a single futex
From: Heinrich Schuchardt <hidden>
Date: 2015-02-27 22:06:12
On 21.02.2015 07:14, Michael Kerrisk (man-pages) wrote:
quoted
In the example code of futex.2 it remains unclear to me why two futexesquoted
are needed. Wouldn't it be sufficient to have one futex? If it has value A it is parent's turn, if the value is B it is childs's turn?I'm not so sure it's possible with one futex. Want to give it a shot?
In the example below 10 processes collaborate using a single futex.
Best regards
Heinrich Schuchardt
#include <errno.h>
#include <limits.h>
#include <linux/futex.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#define NUMBER_OF_PROCESSES 10
#define NUMBER_OF_WORKPACKAGES 27
#define GRANTED 0
struct info_area {
int futex;
int counter;
};
static int
futex(int *uaddr, int futex_op, int val,
const struct timespec *timeout, int *uaddr2, int val3)
{
return syscall(SYS_futex, uaddr, futex_op, val,
timeout, uaddr, val3);
}
static void
fail(const char *msg, struct info_area *info)
{
/*
* Terminate all processes.
*/
if (info != MAP_FAILED) {
info->counter = 0;
futex(&info->futex, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
}
perror(msg);
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
int id;
int ret;
pid_t pid;
struct info_area *info;
/*
* Create a shared mapped memory area for communication between
* processes.
*/
info = mmap(NULL, sizeof(info), PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_SHARED, -1, 0);
if (info == MAP_FAILED)
fail("mmap", info);
/*
* The main process will not wait for children.
*/
if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
fail("signal", info);
/*
* Process with id=1 shall be first.
*/
info->futex = 1;
/*
* Set number of work packages
*/
info->counter = NUMBER_OF_WORKPACKAGES;
/*
* Create child processes.
*/
for (id = 1; id < NUMBER_OF_PROCESSES; ++id) {
pid = fork();
if (pid == -1)
fail("fork", info);
if (pid == 0)
break;
}
/*
* All processes stay in this loop until the work is done.
*/
for(;;) {
/*
* Leave if all work is done.
*/
if (info->counter <= 0) {
/*
* Wake up all other processes.
*/
futex(&info->futex, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
exit(EXIT_SUCCESS);
}
/*
* If it is the turn of this process, acquire futex.
* The function used is atomic and provides barriers.
*/
ret = __sync_bool_compare_and_swap(&info->futex, id, GRANTED);
if (ret) {
/*
* Output process id.
*/
printf("%02d ", id);
--(info->counter);
if ((NUMBER_OF_WORKPACKAGES - info->counter)
% NUMBER_OF_PROCESSES == 0 || info->counter == 0)
printf("\n");
fflush(stdout);
/*
* Grant access to next process.
*/
__sync_bool_compare_and_swap(&info->futex,
GRANTED, id % NUMBER_OF_PROCESSES + 1);
/*
* Wake up all other processes.
*/
futex(&info->futex, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
if (ret == -1)
fail("FUTEX_WAKE", info);
} else {
/*
* Sleep if futex is granted to another process.
*/
ret = futex(&info->futex, FUTEX_WAIT,
GRANTED, NULL, NULL, 0);
if (ret == -1 && errno != EAGAIN)
fail("FUTEX_WAIT", info);
}
}
}
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html