From patchwork Mon Mar 2 09:43:25 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Wagner X-Patchwork-Id: 5911001 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id B04DC9F318 for ; Mon, 2 Mar 2015 09:43:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9CFB22020E for ; Mon, 2 Mar 2015 09:43:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 683BD20211 for ; Mon, 2 Mar 2015 09:43:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751864AbbCBJni (ORCPT ); Mon, 2 Mar 2015 04:43:38 -0500 Received: from mail.bmw-carit.de ([62.245.222.98]:53491 "EHLO linuxmail.bmw-carit.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751160AbbCBJnf (ORCPT ); Mon, 2 Mar 2015 04:43:35 -0500 Received: from localhost (handman.bmw-carit.intra [192.168.101.60]) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (No client certificate requested) (Authenticated sender: daniel.wagner) by linuxmail.bmw-carit.de (Postfix) with ESMTPSA id AE25E401D4; Mon, 2 Mar 2015 08:39:10 +0100 (CET) From: Daniel Wagner To: Jeff Layton Cc: linux-fsdevel@vger.kernel.org, Daniel Wagner Subject: [PATCH v0 2/2] posix04: add new "posix04" test Date: Mon, 2 Mar 2015 10:43:25 +0100 Message-Id: <1425289405-13365-3-git-send-email-daniel.wagner@bmw-carit.de> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1425289405-13365-1-git-send-email-daniel.wagner@bmw-carit.de> References: <1425289405-13365-1-git-send-email-daniel.wagner@bmw-carit.de> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The dinning philosopher locking 'problem'. A given number of clients try to lock on a file its own region and than the region 'right' from its own region. Signed-off-by: Daniel Wagner --- Makefile.am | 2 +- posix04.c | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 posix04.c diff --git a/Makefile.am b/Makefile.am index 4a2ae98..c2eb816 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,6 @@ ACLOCAL_AMFLAGS = -I m4 EXTRA_DIST = m4/gnulib-cache.m4 LDADD = lib/libgnu.a -lrt -bin_PROGRAMS = flock01 flock02 posix01 posix02 posix03 lease01 lease02 +bin_PROGRAMS = flock01 flock02 posix01 posix02 posix03 posix04 lease01 lease02 SUBDIRS = lib/ diff --git a/posix04.c b/posix04.c new file mode 100644 index 0000000..ed862f2 --- /dev/null +++ b/posix04.c @@ -0,0 +1,288 @@ +/* + * POSIX deadlock detection performance test + * + * The dinning philosopher locking 'problem'. A given number of + * clients try to lock on a file its own region and than the region + * 'right' from its own region. + * + * Obviously, We could just give them enough forks or a gun. Both + * solves the problem once for all but that's no fun. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "timespec.h" + +#define DEFAULT_PROCESSES 10 +#define DEFAULT_ITERATIONS 10000 + +#define TFR TEMP_FAILURE_RETRY + +struct child_context +{ + pid_t pid; + struct timespec diff; + unsigned int deadlock; +}; + +static struct child_context *ctxs; + +/* Taken from TDB: LGPLv3 */ +static int fcntl_lock(int fd, int rw, off_t off, off_t len, bool waitflag) +{ + struct flock fl; + + /* + fprintf(stderr, "%d: lock\tfd %d off %5zd len %5zd\n", + getpid(), fd, off, len); + */ + + fl.l_type = rw; + fl.l_whence = SEEK_SET; + fl.l_start = off; + fl.l_len = len; + fl.l_pid = 0; + + if (waitflag) + return fcntl(fd, F_SETLKW, &fl); + else + return fcntl(fd, F_SETLK, &fl); +} + +static int fcntl_unlock(int fd, off_t off, off_t len) +{ + struct flock fl; + fl.l_type = F_UNLCK; + fl.l_whence = SEEK_SET; + fl.l_start = off; + fl.l_len = len; + fl.l_pid = 0; + + /* + fprintf(stderr, "%d: unlock\tfd %d off %5zd len %5zd\n", + getpid(), fd, off, len); + */ + + return fcntl(fd, F_SETLKW, &fl); +} + +static int +lockunlock(int fd, int id, int nproc) +{ + int ret, nid; + off_t off, len; + off_t noff, nlen; + + nid = (id + 1) % nproc; + + off = id * 10; + len = id * 10 + 10; + + noff = nid * 10; + nlen = nid * 10 + 10; + + ret = fcntl_lock(fd, F_WRLCK, off, len, true); + if (ret) + return ret; + + ret = fcntl_lock(fd, F_WRLCK, noff, nlen, true); + if (ret) + goto err; + + if (fcntl_unlock(fd, noff, nlen)) + perror("unlock"); + +err: + if (fcntl_unlock(fd, off, len)) + perror("unlock"); + + return ret; +} + +static int do_child(int fd, int id, int nproc, int to_lockers, int from_lockers) +{ + struct timespec start, end; + unsigned char c; + int ret; + + while(TFR(read(to_lockers, &c, 1)) == 1) { + if (c != 'g') + return 0; + + ret = clock_gettime(CLOCK_MONOTONIC_RAW, &start); + if (ret) { + perror("clock_gettime"); + return ret; + } + + if (lockunlock(fd, id, nproc) != 0) + ctxs[id].deadlock++; + + ret = clock_gettime(CLOCK_MONOTONIC_RAW, &end); + if (ret) { + perror("clock_gettime"); + return ret; + } + + ctxs[id].diff = timespec_add(ctxs[id].diff, + timespec_sub(end, start)); + + if (TFR(write(from_lockers, &c, 1)) != 1) + fprintf(stderr, "Writing to parent"); + } + + return 0; +} + +static int +usage(char *argv0) +{ + errx(1, "Usage: %s [-i iterations] [-n nr_children] [-s] ", argv0); +} + +int main(int argc, char *argv[]) +{ + int nproc = DEFAULT_PROCESSES, i, opt, valid = 0, stats = 0; + int iter = DEFAULT_ITERATIONS; + const char *filename; + int to_lockers[2], from_lockers[2], fd; + struct timespec total = { .tv_sec = 0, + .tv_nsec = 0 }; + unsigned char wc, rc; + unsigned int deadlock = 0; + + total.tv_sec = 0; + total.tv_nsec = 0; + + while ((opt = getopt(argc, argv, "i:n:s")) != -1) { + switch (opt) { + case 'i': + iter = atoi(optarg); + break; + case 'n': + nproc = atoi(optarg); + break; + case 's': + stats = 1; + break; + default: + usage(argv[0]); + } + } + + if (nproc < 2) { + fprintf(stderr, "Invalid argument: at least 2 child process needed\n"); + return 1; + } + + filename = argv[optind]; + if (!filename) + usage(argv[0]); + + ctxs = mmap(0, nproc * sizeof(*ctxs), PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + + if (ctxs == (struct child_context *)-1) { + fprintf(stderr, "Unable to allocate child context array!"); + return 1; + } + + if (pipe(to_lockers)) + err(1, "pipe (to_lockers)"); + if (pipe(from_lockers)) + err(1, "pipe (from_lockers)"); + + fd = open(filename, O_CREAT|O_RDWR, 0644); + if (fd < 0) { + perror("open"); + return 1; + } + + for (i = 0; i < nproc; i++) { + ctxs[i].pid = fork(); + if (!ctxs[i].pid) + return do_child(fd, i, nproc, + to_lockers[0], from_lockers[1]); + } + + close(to_lockers[0]); + close(from_lockers[1]); + + wc = 'g'; /* go */ + while(iter--) { + for (i = 0; i < nproc; i++) { + if (TFR(write(to_lockers[1], &wc, 1)) != 1) { + perror("write"); + } + } + + for (i = 0; i < nproc; i++) { + if (TFR(read(from_lockers[0], &rc, 1)) != 1) + break; + } + } + + wc = '\0'; /* stop */ + for (i = 0; i < nproc; i++) { + if (TFR(write(to_lockers[1], &wc, 1)) != 1) { + perror("write"); + } + } + + for (i = 0; i < nproc; ++i) { + int status; + + if (ctxs[i].pid < 0) { + fprintf(stderr, "process %d failed to fork\n", i); + continue; + } + if (waitpid(ctxs[i].pid, &status, 0) < 0) { + fprintf(stderr, "unable to reap pid %d\n", ctxs[i].pid); + continue; + } + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + fprintf(stderr, "pid %d exited abnormally(0x%x)\n", + ctxs[i].pid, status); + continue; + } + total = timespec_add(total, ctxs[i].diff); + deadlock += ctxs[i].deadlock; + ++valid; + + } + + close(fd); + + if (valid != nproc) { + fprintf(stderr, "Some children didn't run properly -- " + "requested %d but only got %d\n", nproc, valid); + return 1; + } + + if (stats) + printf("deadlocks %u\n", deadlock); + printf("%ld.%09ld\n", total.tv_sec, total.tv_nsec); + + return 0; +}