All of lore.kernel.org
 help / color / mirror / Atom feed
From: Heinrich Schuchardt <xypron.glpk-Mmb7MZpHnFY@public.gmane.org>
To: mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
Cc: linux-man-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: ftrace.2: example - using a single futex
Date: Fri, 27 Feb 2015 23:06:12 +0100	[thread overview]
Message-ID: <54F0EA54.7030902@gmx.de> (raw)
In-Reply-To: <CAKgNAki1ZaqYQeTmrRvOmCC4Zd4eU6QDPuEFkxxUNSB32Uc1-g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

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-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

           reply	other threads:[~2015-02-27 22:06 UTC|newest]

Thread overview: expand[flat|nested]  mbox.gz  Atom feed
 [parent not found: <CAKgNAki1ZaqYQeTmrRvOmCC4Zd4eU6QDPuEFkxxUNSB32Uc1-g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=54F0EA54.7030902@gmx.de \
    --to=xypron.glpk-mmb7mzphnfy@public.gmane.org \
    --cc=linux-man-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.