All of lore.kernel.org
 help / color / mirror / Atom feed
From: Darren Hart <dvhltc@us.ibm.com>
To: "lkml, " <linux-kernel@vger.kernel.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	Peter Zijlstra <peterz@infradead.org>,
	Ingo Molnar <mingo@elte.hu>,
	Eric Dumazet <eric.dumazet@gmail.com>,
	Dinakar Guniguntala <dino@in.ibm.com>,
	"Stultz, John" <johnstul@us.ibm.com>
Subject: Re: [PATCH] RFC: futex: make futex_lock_pi interruptible
Date: Mon, 26 Oct 2009 17:32:35 -0700	[thread overview]
Message-ID: <4AE63FA3.8040208@us.ibm.com> (raw)
In-Reply-To: <4AE63E3D.8030903@us.ibm.com>

Darren Hart wrote:
>  From 9ea67856951c87a03a5177e1382d836622642521 Mon Sep 17 00:00:00 2001
> From: Darren Hart <dvhltc@us.ibm.com>
> Date: Mon, 26 Oct 2009 17:15:54 -0700
> Subject: [PATCH] RFC: futex: make futex_lock_pi interruptible
> 

The following C test case demonstrates how this patch could be used to
implement interruptible locking. There is an awful lot of debug code and
some other relics of a hacked together test in there now, but if anyone
wanted to test the futex changes, this will do the trick.


/******************************************************************************
 *
 *   Copyright © International Business Machines  Corp., 2009
 *
 *   This program is free software;  you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program;  if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * NAME
 *      mutexint.c
 *
 * DESCRIPTION
 *      Provide an interruptible PI-aware locking construct.
 *
 * AUTHOR
 *      Darren Hart <dvhltc@us.ibm.com>
 *
 * HISTORY
 *      2009-Oct-26: Initial version by Darren Hart <dvhltc@us.ibm.com>
 *
 *****************************************************************************/

#include <pthread.h>
#include <stdio.h>
#include <signal.h>
#include <syscall.h>
#include <sys/types.h>
#include <linux/futex.h>
#include <errno.h>

/*
 * The futex() call has been removed from the include/futex.h header, implement
 * our own version.
 */
//#define SYS_futex 202
#define FUTEX_PRIVATE 128
#define FUTEX_INTERRUPTIBLE 512
#define futex(uaddr, op, val, timeout, uaddr2, val3) \
	syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3)

#define futex_lock_pi(uaddr, val, timeout) \
	futex(uaddr, FUTEX_LOCK_PI|FUTEX_INTERRUPTIBLE|FUTEX_PRIVATE, \
	      val, timeout, NULL, 0)

#define futex_unlock_pi(uaddr, val) \
	futex(uaddr, FUTEX_UNLOCK_PI|FUTEX_PRIVATE, val, NULL, NULL, 0)

#define gettid() syscall(SYS_gettid)

#define SIGMUTEXINT SIGRTMIN

/*
 * Implement cmpxchg using gcc atomic builtins.
 * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
 */
static inline int cmpxchg(volatile int32_t *addr, int32_t old, int32_t new)
{
	return __sync_val_compare_and_swap(addr, old, new);
}

struct mutexint {
	volatile int32_t lock_val;
};

struct mutexint_attr {
	/* placeholder for future expansion */
	u_int32_t flags;
};

void sigmutexint_handler(int signo)
{
	printf("handled cancel signal: %d\n", signo);
}

int mutexint_init(struct mutexint *mutex, struct mutexint_attr *attr)
{
	mutex->lock_val = 0;
	/* future: process attr->flags */
	return 0;
}

int mutexint_lock(struct mutexint *mutex)
{
	int32_t val;
	int ret = 0;
	pid_t tid = gettid();
	printf("%s: initial lock_val: 0x%x\n", __FUNCTION__, mutex->lock_val);
	if ((val = cmpxchg(&mutex->lock_val, 0, tid)) != 0) {
		printf("\tfirst cmpxchg old_val: 0x%x lock_val: 0x%x\n", val, mutex->lock_val);
		do {
			printf("\tdo cmpxchg old_val: 0x%x\n", val);
			if ((val & FUTEX_WAITERS) || 
				(val = cmpxchg(&mutex->lock_val, val, val | FUTEX_WAITERS))) {
				printf("\tinner cmpxchg old_val: 0x%x lock_val: 0x%x\n", val, mutex->lock_val);
				printf("\tcalling futex_lock_pi:\n");
				printf("\top: 0x%x\n", FUTEX_LOCK_PI | FUTEX_PRIVATE | FUTEX_INTERRUPTIBLE);
				printf("\t&lock_val: %p\n", &mutex->lock_val);
				ret = futex_lock_pi(&mutex->lock_val, val, NULL);
				if (ret == -1) {
					ret = -errno;
					printf("futex_lock_pi returned -1, errno is %d\n", ret);
				}
				/*
				 * If -EINTR is returned, the lock may no longer
				 * have owners, but we have no good way to detect that.
				 */
				printf("\tfutex_lock_pi returned. ret=%d lock_val=0x%x\n",
				       ret, mutex->lock_val);
				if (ret != -EWOULDBLOCK)
					break;
			}
		} while ((val = cmpxchg(&mutex->lock_val, 0, tid)) != 0);
	}

	/* 
	 * Catch the case where futex_lock_pi() returns EWOULDBLOCK, but the
	 * while conditional acquires the lock atomically and reset ret.
	 */
	if ((val & ~FUTEX_WAITERS) == tid)
		ret = 0;

	printf("%s: returning: %d\n", __FUNCTION__, ret);
	return ret;
}

int mutexint_unlock(struct mutexint *mutex)
{
	int32_t val;
	int ret = 0;
	pid_t tid = gettid();
	if ((val = cmpxchg(&mutex->lock_val, tid, 0)) != 0) {
		ret = futex_unlock_pi(&mutex->lock_val, val);
	}
	return ret;
}

int mutexint_interrupt(pthread_t pthread, struct mutexint *mutex)
{
	/* 
	 * FIXME: return -EINVAL if the pthread is blocked on a different
	 * thread ?
	 */
	return pthread_kill(pthread, SIGMUTEXINT);
}

int mutexint_prepare()
{
	struct sigaction sa;
	sa.sa_handler = sigmutexint_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if (sigaction(SIGMUTEXINT, &sa, NULL)) {
		perror("sigaction");
		return 1;
	}
	return 0;
}

/* unit test */
#define UNIT_TEST 1
#ifdef UNIT_TEST

struct mutexint mutex;

void *child_thread(void *arg)
{
	int ret;
	mutexint_prepare();

	printf("\tchild acquiring the mutex (will block)\n");
	ret = mutexint_lock(&mutex);
	printf("\tchild returned %d\n", ret);

	*(int *)arg = ret;
	return NULL;
}

int main(int argc, char *argv[])
{
	struct mutexint_attr m_attr;
	pthread_t child;
	int child_ret;
	int ret = 0;

	/* prepare the mutex, ensuring we use PROCESS_PRIVATE */
	mutexint_init(&mutex, &m_attr);

	printf("\nTesting canceled mutex lock scenario.\n");
	printf("\tmain() acquiring the mutex\n");
	mutexint_lock(&mutex);
	/* prepare and start the child thread */
	ret = pthread_create(&child, NULL, child_thread, &child_ret);
	if (ret) {
		perror("Failed to create pthread");
		return ret;
	}

	/* ensure the child has blocked on the lock */
	sleep(3);

	/* cancel the child thread blocking on the mutex */
	printf("\tmain() canceling the child\n");
	ret = mutexint_interrupt(child, &mutex);
	printf("\tmain() pthread_kill returned %d\n", ret);
	
	pthread_join(child, NULL);

	printf("Result: %s\n", child_ret == -EINTR ? "PASS" : "FAIL");
	return ret;
}
#endif

-- 
Darren Hart
IBM Linux Technology Center
Real-Time Linux Team

  reply	other threads:[~2009-10-27  0:32 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-10-27  0:26 [PATCH] RFC: futex: make futex_lock_pi interruptible Darren Hart
2009-10-27  0:32 ` Darren Hart [this message]
2009-10-29  8:39   ` Arnd Bergmann
2009-10-30  1:19     ` Darren Hart
2009-10-30  1:45       ` Darren Hart
2009-10-30  9:13         ` Arnd Bergmann
2009-10-30 16:23           ` Darren Hart
2009-10-30 17:39             ` Arnd Bergmann
2009-10-30 17:55         ` Chris Friesen
2009-10-31  0:31           ` Darren Hart

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=4AE63FA3.8040208@us.ibm.com \
    --to=dvhltc@us.ibm.com \
    --cc=dino@in.ibm.com \
    --cc=eric.dumazet@gmail.com \
    --cc=johnstul@us.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=peterz@infradead.org \
    --cc=tglx@linutronix.de \
    /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.