Thread (1 message) 1 message, 1 author, 2015-02-27

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 futexes
quoted
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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help