Hi
I have developed 2 test cases for getcpu() system call, Test cases check minimal functionality of getcpu(). These test cases have a requirement of kernel 2.6.20 and above and glibc 2.6 and above. Currently the system call is implemented on i386 and x86_64 architecture, in x86_64 it is implemented as virtual system call. I felt the best way to call these system calls is to use the interface provided by glibc in x86_64
        Man page of getcpu() can be found here: 
http://www.kernel.org/doc/man-pages/online/pages/man2/getcpu.2.html
========================================================================        
To Do Items
        o Test cases are not tested on x86_64, environment
                - As I am still looking for a system that satisfies all         
                the conditions.
        o Second test case should be run on only i386 environment
- As the interface in x86_64 is very minimal and minimal scope for error checking
        o Not tested on other architectures
                - PPC, Zseries etc

========================================================================        
Please go through the test cases and let me know of your opinion, accordingly I can work on these test cases.

Thanks
Yeehaw




/*
 *
 *   Copyright (c) International Business Machines  Corp., 2001
 *
 *   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
 *	getcpu1.c
 *
 * DESCRIPTION
 *	getcpu01 - call getcpu() and make sure it succeeds
 *
 * ALGORITHM
 *	set cpu affinity of the process 
 *	If setaffinity() fails exit from the test suite
 *	Store the node ID of the cpu which has been set in previous step
 *	Make a call to getcpu() system call
 *	Verify the returned valued with the set value
 *	if they match 
 *	  test is considered PASS
 *	else
 *	  test is considered FAIL
 *
 * USAGE:  <for command-line>
 *  getcpu [-c n] [-f] [-i n] [-I x] [-P x] [-t]
 *     where,  -c n : Run n copies concurrently.
 *             -f   : Turn off functionality Testing.
 *	       -i n : Execute test n times.
 *	       -I x : Execute test for x seconds.
 *	       -P x : Pause for x seconds between iterations.
 *	       -t   : Turn on syscall timing.
 *
 * HISTORY
 *	06/2008 written by Sharyathi Nagesh <[EMAIL PROTECTED]>
 *
 * RESTRICTIONS
 *	none
 */


#define _GNU_SOURCE
#include <sched.h>
#include <errno.h>
#include "test.h"
#include "usctest.h"
#include <sys/types.h>
#include <dirent.h>

#if defined(__i386__) || defined(__x86_64__)
	#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) \
	    && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 6
	#if defined(__x86_64__)
		#include <utmpx.h> 
		#define X86_GETCPU_SUPPORT
	#endif
	int sys_support = 1;
	#elif defined(__i386__)
	int sys_support = 1;
	#else
	int sys_support = 0;
	#endif
#else
int sys_support = 0;
#endif
	
void cleanup(void);
void setup(void);
static inline int getcpu(unsigned int *, unsigned int *, void *);
unsigned int set_cpu_affinity();
unsigned int get_nodeid(unsigned int);
unsigned int max_cpuid(cpu_set_t *);
 
char *TCID= "getcpu01";
int TST_TOTAL = 1;
extern int Tst_count;


int main(int ac, char **av)
{
	int lc;				/* loop counter */
	char *msg;			/* message returned from parse_opts */
	unsigned int cpu_id, node_id = 0 ;
	unsigned int cpu_set, node_set;

	/* Check For Kernel Version */
 	if(((tst_kvercmp(2,6,20)) < 0) || !(sys_support))
          {
             tst_resm(TWARN, "This test can only run on kernels that are ");
             tst_resm(TWARN, "2.6.20 and higher and glibc version 2.6 and above");
             tst_resm(TWARN, "Currently the test case has been");
             tst_resm(TWARN, "developed only for i386 and x86_64");
             exit(0);
          }

	/* parse standard options */
	if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL)
		tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
	

	setup();			/* global setup */

	/* The following loop checks looping state if -i option given */

	for (lc = 0; TEST_LOOPING(lc); lc++) {
		/* reset Tst_count in case we are looping */
		Tst_count = 0;

		/* call the system call with the TEST() macro */
		cpu_set = set_cpu_affinity();
		#ifdef __i386__
			node_set = get_nodeid(cpu_set);
		#endif
		TEST(getcpu(&cpu_id,&node_id,NULL));
		if( TEST_RETURN == 0 ) {
			if ( cpu_id != cpu_set ) {
				tst_resm(TFAIL, "getcpu() returned wrong value"\
				" expected cpuid:%d, returned value cpuid: %d",
				cpu_set,cpu_id);
				tst_exit();
			} 
			#ifdef __i386__
			else if( node_id != node_set ){
				tst_resm(TFAIL, "getcpu() returned wrong value"\
				" expected  node id:%d returned  node id:%d",
				node_set,node_id);
				tst_exit();
			}		
			#endif
			else
				tst_resm(TPASS, "getcpu() returned proper"\
				" cpuid:%d, node id:%d", cpu_id,node_id);
		} else {
			tst_resm(TFAIL, "getcpu() Failed, errno=%d:%s", 
				TEST_ERRNO,strerror(TEST_ERRNO));
				tst_exit();
		}
	}

	cleanup();

	/*NOTREACHED*/	
	return(0);
}

/* 
 * getcpu() - calls the system call
 */
static inline int getcpu(unsigned *cpu_id, unsigned *node_id, void *cache_struct)
{
	#if defined(__i386__)
		return syscall(318, cpu_id,node_id,cache_struct);
	#elif defined(__x86_64__) && defined (X86_GETCPU_SUPPORT)
		return (*cpu_id = sched_getcpu()) ;
	#else
		return 0;
	#endif
}



/*
 * setup() - performs all the ONE TIME setup for this test.
 */
void
setup(void)
{
	/* capture signals */
	/* ?? */	
	/* Pause if that option was specified */
	TEST_PAUSE;
}

/*
 * This will set the affinity to max cpu on which process can run
 * and return that cpu id to the calling process
 */
unsigned int 
set_cpu_affinity()
{
	unsigned cpu_max;
	cpu_set_t set;
	if ( sched_getaffinity(0, sizeof(cpu_set_t), &set) < 0 ){
			tst_resm(TFAIL,"sched_getaffinity:errno:%d",errno); 
			tst_exit();
	}
	cpu_max = max_cpuid(&set);	
	CPU_ZERO(&set);
	CPU_SET(cpu_max,&set);
	if ( sched_setaffinity(0, sizeof(cpu_set_t), &set) < 0 ){
			tst_resm(TFAIL,"sched_setaffinity:errno:%d",errno); 
			tst_exit();
	}
	return cpu_max;	
}	

/*
 * Return the maximum cpu id
 */
#define BITS_PER_BYTE 8
unsigned int
max_cpuid(cpu_set_t *set)
{
	unsigned int index, max = 0;
	for ( index = 0; index < sizeof(cpu_set_t) * BITS_PER_BYTE; index++)
		if(CPU_ISSET(index,set)) max = index;	
	return max;
}


/*
 * get_nodeid(cpuid) - This will return the node to which selected cpu belongs 
 */
unsigned int 
get_nodeid(unsigned int cpu_id)
{
 	DIR *directory_parent, *directory_node;
        struct dirent *de,*dn;
	char directory_path[255];
	unsigned int cpu;
        int node_id = 0;

        directory_parent = opendir("/sys/devices/system/node");
        if (!directory_parent)  {
                tst_resm(TWARN,
                   "/sys not mounted or not a numa system. Assuming one node: %s",
                        strerror(errno));
               	return 0; //By Default assume it to belong to node Zero 
        } else {
                while ((de = readdir(directory_parent)) != NULL) {
                        if (strncmp(de->d_name, "node", 4))
 				continue;
			sprintf(directory_path,"/sys/devices/system/node/%s",de->d_name);
        		directory_node = opendir(directory_path);
			while ((dn = readdir(directory_node)) != NULL) {
			if (strncmp(dn->d_name, "cpu", 3))
				continue;
			cpu = strtoul(dn->d_name+3,NULL,0);
			if ( cpu == cpu_id ){
	                        node_id = strtoul(de->d_name+4, NULL, 0);
				break;
			}
			}
                	closedir(directory_node);
                }
                closedir(directory_parent);
        }
	return node_id;	
}

/*
 * cleanup() - performs all the ONE TIME cleanup for this test at completion
 * 	       or premature exit.
 */
void
cleanup(void)
{
	/*
	 * print timing stats if that option was specified.
	 * print errno log if that option was specified.
	 */
	TEST_CLEANUP;
	/* exit with return code appropriate for results */
	tst_exit();
}

/*
 *
 *   Copyright (c) International Business Machines  Corp., 2001
 *
 *   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
 *	getcpu2.c
 *
 * DESCRIPTION
 *	getcpu02 - call getcpu() with incorrect arguments check the error msg
 *
 * ALGORITHM
 *	Call get cpu with wrong arguments 
 *
 * USAGE:  <for command-line>
 *  getcpu [-c n] [-f] [-i n] [-I x] [-P x] [-t]
 *     where,  -c n : Run n copies concurrently.
 *             -f   : Turn off functionality Testing.
 *	       -i n : Execute test n times.
 *	       -I x : Execute test for x seconds.
 *	       -P x : Pause for x seconds between iterations.
 *	       -t   : Turn on syscall timing.
 *
 * HISTORY
 *	06/2008 written by Sharyathi Nagesh <[EMAIL PROTECTED]>
 *
 * RESTRICTIONS
 *	none
 */

#define _GNU_SOURCE
#include "test.h"
#include "usctest.h"
#include <errno.h>


#if defined(__i386__) 
	int sys_support = 1;
#else
	int sys_support = 0;
#endif
#define __NR_getcpu 318

void cleanup(void);
void setup(void);
static inline int getcpu(unsigned *cpu_id, unsigned *node_id, void *cache_struct);

char *TCID= "getcpu02";
int TST_TOTAL = 1;
extern int Tst_count;


int main(int ac, char **av)
{
	int lc;				/* loop counter */
	char *msg;			/* message returned from parse_opts */
	unsigned int node_id;
	unsigned int *invalid_add = (unsigned int *) 0xff;	
	/* Check For Kernel Version */
 	if(((tst_kvercmp(2,6,20)) < 0) || !(sys_support))
          {
             tst_resm(TWARN, "This test can only run on kernels that are ");
             tst_resm(TWARN, "2.6.20 and higher and on i386 architecture");
             exit(0);
          }

	/* parse standard options */
	if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL)
		tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);

	setup();			/* global setup */

	/* The following loop checks looping state if -i option given */
	for (lc = 0; TEST_LOOPING(lc); lc++) {
		/* reset Tst_count in case we are looping */
		Tst_count = 0;

		/*
		 * call the system call with the TEST() macro
		 * with an illegal PID value
		 */

		TEST(getcpu(invalid_add, &node_id, NULL));
  	        if (TEST_RETURN == 0) {
			tst_resm(TFAIL, "call succeed when failure expected");
			continue;
		}
	
		switch (TEST_ERRNO) {
		case EFAULT:
			tst_resm(TPASS, "expected failure - errno = %d - %s",
				 TEST_ERRNO, strerror(TEST_ERRNO));
			break;
		default:
			tst_resm(TFAIL, "call failed to produce "
				 "expected error - errno = %d - %s",
				 TEST_ERRNO, strerror(TEST_ERRNO));
			break;
		}
	}

	cleanup();

	return(0);
}

/* 
 * getcpu() - calls the system call
 */
static inline int getcpu(unsigned *cpu_id, unsigned *node_id, void *cache_struct)
{
		return syscall(__NR_getcpu, cpu_id,node_id,cache_struct);
}

/*
 * setup() - performs all the ONE TIME setup for this test.
 */
void
setup(void)
{
	/* Pause if that option was specified */
	TEST_PAUSE;
}

/*
 * cleanup() - performs all the ONE TIME cleanup for this test at completion
 * 	       or premature exit.
 */
void
cleanup(void)
{
	/*
	 * print timing stats if that option was specified.
	 * print errno log if that option was specified.
	 */
	TEST_CLEANUP;
	/* exit with return code appropriate for results */
	tst_exit();
}

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list

Reply via email to