All of lore.kernel.org
 help / color / mirror / Atom feed
From: Darren Hart <dvhltc@us.ibm.com>
To: "lkml, " <linux-kernel@vger.kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>,
	Steven Rostedt <srostedt@redhat.com>,
	Sripathi Kodi <sripathik@in.ibm.com>,
	John Stultz <johnstul@linux.vnet.ibm.com>
Subject: [TIP][RFC 7/7] requeue pi testcase
Date: Mon, 02 Mar 2009 16:23:49 -0800	[thread overview]
Message-ID: <49AC7895.2020104@us.ibm.com> (raw)
In-Reply-To: <49AC73A9.4040804@us.ibm.com>

The following is a rough start at a test case to stress the
FUTEX_REQUEUE_PI system call, mimicking a pthread_cond_broadcast and
pthread_cond_signal style wakeup.  The signal style wakeup is where I've
been seeing the failed paging request.

To compile:
$ gcc -D_GNU_SOURCE  -lrt -lpthread  requeue_pi.c   -o requeue_pi


/******************************************************************************
 *
 *   Copyright © International Business Machines  Corp., 2006-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
 *      requeue_pi.c
 *
 * DESCRIPTION
 *      This test excercises the futex syscall op codes needed for requeuing
 *      priority inheritance aware POSIX condition variables and mutexes.
 *
 * USAGE:
 *      test_requeue_pi
 *
 * AUTHORS
 *	Sripathi Kodi <sripathik@in.ibm.com>
 *      Darren Hart <dvhltc@us.ibm.com>
 *
 * HISTORY
 *      2008-Jan-13: Initial version by Sripathi Kodi <sripathik@in.ibm.com>
 *
 *****************************************************************************/

/* TODO
 * o add test for shared futexes
 * o add test for non CMP requeue call
 */

/* SYS_futex arguments vary meaning across op codes
 *
 * u32 __user *uaddr
 * 	user-space futex address
 *
 * int op
 * 	FUTEX_* op code
 *
 * u32 val
 * 	FUTEX_WAIT:            value of the futex prior to the syscall
 *	FUTEX_REQUEUE_PI:      number of threads to wake (nr_wake)
 *	FUTEX_WAIT_REQUEUE_PI: ?
 *
 * struct timespec __user *utime
 * 	FUTEX_WAIT:            struct timespec timeout
 *	FUTEX_REQUEUE_PI:      number of threads to requeue (nr_requeue)
 *	FUTEX_WAIT_REQUEUE_PI: struct timespec timeout
 *
 * u32 __user *uaddr2
 * 	FUTEX_WAIT:            not used (NULL)
 *	FUTEX_REQUEUE_PI:      user-space futex address of requeue target
 *	FUTEX_WAIT_REQUEUE_PI: user-space futex address of requeue target
 *
 * u32 val3)
 * 	FUTEX_WAIT:            not used (0) (set to bitset in kernel)
 *	FUTEX_REQUEUE_PI:      cmpval for uaddr 
 *			       (FIXME: maybe only for FUTEX_CMP_REQUEUE_PI ??)
 *	FUTEX_WAIT_REQUEUE_PI: not used (0) (set to bitset in kernel)
 */

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>

#define FUTEX_WAIT_REQUEUE_PI 11
#define FUTEX_REQUEUE_PI      12
#define FUTEX_CMP_REQUEUE_PI  13

#ifndef SYS_futex
#define SYS_futex 202
#endif

#ifndef FUTEX_WAIT
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
#endif

#define THREAD_MAX 10
pthread_mutex_t mutex;
unsigned int wait_q;


int create_pi_mutex(pthread_mutex_t *mutex)
{
	int ret;
	pthread_mutexattr_t mutexattr;

	if ((ret = pthread_mutexattr_init(&mutexattr)) != 0) {
		printf("pthread_mutexattr_init: %s\n", strerror(ret));
		return -1;
	}
	if ((ret = pthread_mutexattr_setprotocol(&mutexattr, PTHREAD_PRIO_INHERIT)) != 0) {
		printf("pthread_mutexattr_setprotocol: %s\n", strerror(ret));
		pthread_mutexattr_destroy(&mutexattr);
		return -1;
	}
	if ((ret = pthread_mutex_init(mutex, &mutexattr)) != 0) {
		printf("pthread_mutex_init: %s\n", strerror(ret));
		pthread_mutexattr_destroy(&mutexattr);
		return -1;
	}
	return 0;
}

int create_rt_thread(pthread_t *pth, void*(*func)(void*), void *arg, int policy, int prio)
{
	int ret;
	struct sched_param schedp;
	pthread_attr_t attr;
	
	pthread_attr_init(&attr);
	memset(&schedp, 0, sizeof(schedp));

	if ((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) {
		printf("pthread_attr_setinheritsched: %s\n", strerror(ret));
		return -1;
	}

	if ((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) {
		printf("pthread_attr_setschedpolicy: %s\n", strerror(ret));
		return -1;
	}

	schedp.sched_priority = prio;
	if ((ret = pthread_attr_setschedparam(&attr, &schedp)) != 0) {
		printf("pthread_attr_setschedparam: %s\n", strerror(ret));
		return -1;
	}

	if ((ret = pthread_create(pth, &attr, func, arg)) != 0) {
		printf("pthread_create: %s\n", strerror(ret));
		return -1;
	}
	return 0;
}


void *waiterfn(void *threadnum)
{
	unsigned int old_val;
	int ret;

	printf("Waiter %ld: running\n", (long)threadnum);
	/* Each thread sleeps for a different amount of time
	 * This is to avoid races, because we don't lock the
	 * external mutex here */
	usleep(1000 * (long)threadnum);

	/* FIXME: need to hold the mutex prior to waiting right?... sort of... */

	printf("Waiter %ld: calling FUTEX_WAIT_REQUEUE_PI\n", (long)threadnum);
	/* cond_wait */
	old_val = wait_q;
	if (ret = syscall(SYS_futex, &wait_q, FUTEX_WAIT_REQUEUE_PI, old_val,
			  NULL, &(mutex.__data.__lock), 0)) {
		perror("waiterfn:");
	}
	pthread_mutex_unlock(&mutex);

	printf("Waiter %ld: returned from FUTEX_WAIT_REQUEUE_PI with %d\n", (long)threadnum, ret);
	return (void*)(long)ret;
}

void *broadcast_wakerfn(void *arg)
{
	unsigned int old_val;
	int nr_wake = 1;
	int nr_requeue = INT_MAX;
	int ret = 0;
	sleep(1); /* FIXME: need a real sync mechanism - barrier maybe? */
	printf("Waker: Calling broadcast\n");

	pthread_mutex_lock(&mutex);
	/* cond_broadcast */
	old_val = wait_q;
	ret = syscall(SYS_futex, &wait_q, FUTEX_CMP_REQUEUE_PI, nr_wake,
		      nr_requeue, &(mutex.__data.__lock), old_val);
	pthread_mutex_unlock(&mutex);

	printf("Waker: exiting\n");
	return (void *)(long)ret;;
}

void *signal_wakerfn(void *arg)
{
	unsigned int old_val;
	int nr_wake = 1;
	int nr_requeue = 0;
	int i;
	int ret = 0;
	sleep(2);
	for (i = 0; i < THREAD_MAX; i++) {
		pthread_mutex_lock(&mutex);
		printf("Waker: Calling signal\n");
		/* cond_signal */
		old_val = wait_q;
		ret = syscall(SYS_futex, &wait_q, FUTEX_CMP_REQUEUE_PI, nr_wake,
			      nr_requeue, &(mutex.__data.__lock), old_val);
		pthread_mutex_unlock(&mutex);
		sleep(1); /* eliminate once the waiter takes/drops the lock */
	}

	printf("Waker: exiting\n");
	return (void *)(long)ret;
}
	
/* Create a PI mutex  and a condvar*/
/* Make 10 threads wait on the condvar */
/* Make a thread call broadcast on it */
int main()
{
	pthread_t waiter[10];
	pthread_t waker;	
	long i, ret;

	if ((ret = create_pi_mutex(&mutex)) != 0) {
		printf("Creating pi mutex failed\n");
		exit(1);
	}

	/* pthread_cond_broadcast type test */
	printf("\npthread_cond_broadcast style wakeup.\n");
	for (i=0; i<THREAD_MAX; i++) {
		if (ret = create_rt_thread(&waiter[i], waiterfn, (void *)i, SCHED_FIFO, 1)) {
			printf("Creating thread failed\n");
			exit(1);
		}
	}
	if (ret = create_rt_thread(&waker, broadcast_wakerfn, NULL, SCHED_FIFO, 1)) {
		printf("Creating thread failed\n");
		exit(1);
	}

	/* Wait for threads to finish */
	for (i=0; i<THREAD_MAX; i++) {
		pthread_join(waiter[i], NULL);
	}
	pthread_join(waker, NULL);

	/* pthread_cond_signal type test */
	printf("\npthread_cond_signal style wakeup.\n");
	for (i=0; i<THREAD_MAX; i++) {
		if (ret = create_rt_thread(&waiter[i], waiterfn, (void *)i, SCHED_FIFO, 1)) {
			printf("Creating thread failed\n");
			exit(1);
		}
	}
	if (ret = create_rt_thread(&waker, signal_wakerfn, NULL, SCHED_FIFO, 1)) {
		printf("Creating thread failed\n");
		exit(1);
	}

	/* Wait for threads to finish */
	for (i=0; i<THREAD_MAX; i++) {
		pthread_join(waiter[i], NULL);
	}
	pthread_join(waker, NULL);
}

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

      parent reply	other threads:[~2009-03-03  0:24 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-03-03  0:02 [TIP][RFC 0/7] requeue pi implemenation Darren Hart
2009-03-03  0:09 ` [TIP][RFC 1/7] futex: futex_wait_queue_me() Darren Hart
2009-03-03  0:11 ` [TIP][RFC 2/7] futex: futex_top_waiter() Darren Hart
2009-03-07 15:16   ` Thomas Gleixner
2009-03-09 18:04     ` Darren Hart
2009-03-03  0:13 ` [TIP][RFC 3/7] futex: futex_lock_pi_atomic() Darren Hart
2009-03-03 13:03   ` Peter Zijlstra
2009-03-03 17:29     ` Darren Hart
2009-03-03  0:14 ` [TIP][RFC 4/7] futex: finish_futex_lock_pi() Darren Hart
2009-03-07 15:30   ` Thomas Gleixner
2009-03-09 18:05     ` Darren Hart
2009-03-03  0:16 ` [TIP][RFC 5/7] rt_mutex: add proxy lock routines Darren Hart
2009-03-07 15:44   ` Thomas Gleixner
2009-03-09 18:31     ` Darren Hart
2009-03-03  0:20 ` [TIP][RFC 6/7] futex: add requeue_pi calls Darren Hart
2009-03-04  7:53   ` Darren Hart
2009-03-05 16:51     ` Darren Hart
2009-03-06  1:42       ` Darren Hart
2009-03-06  2:21         ` Steven Rostedt
2009-03-06  5:27           ` Darren Hart
2009-03-07 15:50             ` Thomas Gleixner
2009-03-09 19:55               ` Darren Hart
2009-03-07  6:03         ` Sripathi Kodi
2009-03-09  9:48   ` Thomas Gleixner
2009-03-10  4:50     ` Darren Hart
2009-03-10 13:39       ` Thomas Gleixner
2009-03-03  0:23 ` Darren Hart [this message]

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=49AC7895.2020104@us.ibm.com \
    --to=dvhltc@us.ibm.com \
    --cc=johnstul@linux.vnet.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sripathik@in.ibm.com \
    --cc=srostedt@redhat.com \
    --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.