ftrace.2: example - using a single futex

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 21.02.2015 07:14, Michael Kerrisk (man-pages) wrote:
>> In the example code of futex.2 it remains unclear to me why two futexes
>> > 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@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux