lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 02 Mar 2009 16:23:49 -0800
From:	Darren Hart <dvhltc@...ibm.com>
To:	"lkml, " <linux-kernel@...r.kernel.org>
CC:	Thomas Gleixner <tglx@...utronix.de>,
	Steven Rostedt <srostedt@...hat.com>,
	Sripathi Kodi <sripathik@...ibm.com>,
	John Stultz <johnstul@...ux.vnet.ibm.com>
Subject: [TIP][RFC 7/7] requeue pi testcase

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@...ibm.com>
 *      Darren Hart <dvhltc@...ibm.com>
 *
 * HISTORY
 *      2008-Jan-13: Initial version by Sripathi Kodi <sripathik@...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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ