示例#1
0
void flower_check(Flower *flower) {
    eventTree_check(flower_getEventTree(flower));

    Flower_GroupIterator *groupIterator = flower_getGroupIterator(flower);
    Group *group;
    while ((group = flower_getNextGroup(groupIterator)) != NULL) {
        group_check(group);
    }
    flower_destructGroupIterator(groupIterator);

    Flower_ChainIterator *chainIterator = flower_getChainIterator(flower);
    Chain *chain;
    while ((chain = flower_getNextChain(chainIterator)) != NULL) {
        chain_check(chain);
    }
    flower_destructCapIterator(chainIterator);

    //We check built trees in here.
    Flower_EndIterator *endIterator = flower_getEndIterator(flower);
    End *end;
    while ((end = flower_getNextEnd(endIterator)) != NULL) {
        end_check(end);
        end_check(end_getReverse(end)); //We will test everything backwards also.
    }
    flower_destructEndIterator(endIterator);

    if (flower_builtFaces(flower)) {
        Flower_FaceIterator *faceIterator = flower_getFaceIterator(flower);
        Face *face;
        while ((face = flower_getNextFace(faceIterator)) != NULL) {
            face_check(face);
        }
        flower_destructFaceIterator(faceIterator);
        face_checkFaces(flower);
    } else {
        cactusCheck(flower_getFaceNumber(flower) == 0);
    }

    if (flower_builtBlocks(flower)) { //Note that a flower for which the blocks are not yet built must be a leaf.
        Flower_BlockIterator *blockIterator = flower_getBlockIterator(flower);
        Block *block;
        while ((block = flower_getNextBlock(blockIterator)) != NULL) {
            block_check(block);
            block_check(block_getReverse(block)); //We will test everything backwards also.
        }
        flower_destructBlockIterator(blockIterator);
    } else {
        cactusCheck(flower_isLeaf(flower)); //Defensive
        cactusCheck(flower_isTerminal(flower)); //Checks that a flower without built blocks is a leaf and does not
        //contain any blocks.
    }

    Flower_SequenceIterator *sequenceIterator = flower_getSequenceIterator(flower);
    Sequence *sequence;
    while ((sequence = flower_getNextSequence(sequenceIterator)) != NULL) {
        sequence_check(sequence);
    }
    flower_destructSequenceIterator(sequenceIterator);
}
示例#2
0
/************************************************************

  Operator function.  This function prints the name and type
  of the object passed to it.  If the object is a group, it
  is first checked against other groups in its path using
  the group_check function, then if it is not a duplicate,
  H5Giterate is called for that group.  This guarantees that
  the program will not enter infinite recursion due to a
  circular path in the file.

 ************************************************************/
herr_t op_func (hid_t loc_id, const char *name, void *operator_data)
{
    herr_t          status, return_val = 0;
    H5G_stat_t      statbuf;
    struct opdata   *od = (struct opdata *) operator_data;
                                /* Type conversion */
    unsigned        spaces = 2*(od->recurs+1);
                                /* Number of whitespaces to prepend
                                   to output */

    /*
     * Get type of the object and display its name and type.
     * The name of the object is passed to this function by
     * the Library.
     */
    status = H5Gget_objinfo (loc_id, name, 0, &statbuf);
    printf ("%*s", spaces, "");     /* Format output */
    switch (statbuf.type) {
        case H5G_GROUP:
            printf ("Group: %s {\n", name);

            /*
             * Check group objno against linked list of operator
             * data structures.  Only necessary if there is more
             * than 1 link to the group.
             */
            if ( (statbuf.nlink > 1) && group_check (od, statbuf.objno) ) {
                printf ("%*s  Warning: Loop detected!\n", spaces, "");
            }
            else {

                /*
                 * Initialize new operator data structure and
                 * begin recursive iteration on the discovered
                 * group.  The new opdata structure is given a
                 * pointer to the current one.
                 */
                struct opdata nextod;
                nextod.recurs = od->recurs + 1;
                nextod.prev = od;
                nextod.groupno[0] = statbuf.objno[0];
                nextod.groupno[1] = statbuf.objno[1];
                return_val = H5Giterate (loc_id, name, NULL, op_func,
                            (void *) &nextod);
            }
            printf ("%*s}\n", spaces, "");
            break;
        case H5G_DATASET:
            printf ("Dataset: %s\n", name);
            break;
        case H5G_TYPE:
            printf ("Datatype: %s\n", name);
            break;
        default:
            printf ( "Unknown: %s\n", name);
    }

    return return_val;
}
示例#3
0
int group_check (struct opdata *od, haddr_t target_addr)
{
    if (od->addr == target_addr)
        return 1;
   else if (!od->recurs)
        return 0;
    else
        return group_check (od->prev, target_addr);
}
示例#4
0
/************************************************************

  This function recursively searches the linked list of
  opdata structures for one whose groupno field matches
  target_groupno.  Returns 1 if a match is found, and 0
  otherwise.

 ************************************************************/
int group_check (struct opdata *od, unsigned long target_groupno[2])
{
    if ( (od->groupno[0] == target_groupno[0]) &&
                (od->groupno[1] == target_groupno[1]) )
        return 1;       /* Group numbers match */
    else if (!od->recurs)
        return 0;       /* Root group reached with no matches */
    else
        return group_check (od->prev, target_groupno);
                        /* Recursively examine the next node */
}
示例#5
0
herr_t op_func (hid_t loc_id, const char *name, const H5L_info_t *info,
            void *operator_data)
{
    herr_t          status, return_val = 0;
    H5O_info_t      infobuf;
    struct opdata   *od = (struct opdata *) operator_data;
    unsigned        spaces = 2*(od->recurs+1);
    FILE* pfile;
    pfile = fopen(filePathJson.toStdString().c_str(), "a");
    if (!pfile)
    {
       throw GenericExc(QObject::tr("Ошибка открытия json файла"));

    }
    status = H5Oget_info_by_name (loc_id, name, &infobuf, H5P_DEFAULT);
    if (status < 0)
    {
        throw GenericExc(QObject::tr("Ошибка получения информации о файле"));
    }
    switch (infobuf.type) {
        case H5O_TYPE_GROUP: {
            if (countGroup != 0) {
                fprintf (pfile, "{\n");
                fprintf (pfile, "%*s", spaces, "");
            }
            fprintf (pfile, "\"%s\" : ", name);
            countGroup++;
            if ( group_check (od, infobuf.addr) ) {
            }
            else {
                struct opdata nextod;
                nextod.recurs = od->recurs + 1;
                nextod.prev = od;
                nextod.addr = infobuf.addr;
                fclose(pfile);
                return_val = H5Literate_by_name (loc_id, name, H5_INDEX_NAME,
                            H5_ITER_NATIVE, NULL, op_func, (void *) &nextod,
                            H5P_DEFAULT);
            }
            pfile = fopen(filePathJson.toStdString().c_str(), "a");
            if (!pfile)
            {
               throw GenericExc(QObject::tr("Ошибка открытия json файла"));

            }
            if (count == 0) {
                fprintf (pfile, "%*s}\n", spaces, "");
            } else {
                fprintf (pfile, "\n%*s]\n", spaces, "");
                count = 0;
            }
            break;
        }
        case H5O_TYPE_DATASET:
            if (count == 0)
            {
                fprintf (pfile, "[\n");
            } else
            {
                fprintf(pfile, ",\n");
            }
            fprintf (pfile, "%*s", spaces, "");
            fprintf (pfile, "\"%s\"", name);
            count++;
            countGroup = 0;
            break;
        default:
            break;
    }
    fclose(pfile);
    return return_val;
}
示例#6
0
文件: mem.c 项目: liaoqingwei/ltp
void test_ksm_merge_across_nodes(unsigned long nr_pages)
{
	char **memory;
	int i, ret;
	int num_nodes, *nodes;
	unsigned long length;
	unsigned long pagesize;

#if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
	&& HAVE_MPOL_CONSTANTS
	unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 };
#endif

	ret = get_allowed_nodes_arr(NH_MEMS|NH_CPUS, &num_nodes, &nodes);
	if (ret != 0)
		tst_brkm(TBROK|TERRNO, cleanup, "get_allowed_nodes_arr");
	if (num_nodes < 2) {
		tst_resm(TINFO, "need NUMA system support");
		free(nodes);
		return;
	}

	pagesize = sysconf(_SC_PAGE_SIZE);
	length = nr_pages * pagesize;

	memory = malloc(num_nodes * sizeof(char *));
	for (i = 0; i < num_nodes; i++) {
		memory[i] = mmap(NULL, length, PROT_READ|PROT_WRITE,
			    MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
		if (memory[i] == MAP_FAILED)
			tst_brkm(TBROK|TERRNO, tst_exit, "mmap");
#ifdef HAVE_MADV_MERGEABLE
		if (madvise(memory[i], length, MADV_MERGEABLE) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "madvise");
#endif

#if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H \
	&& HAVE_MPOL_CONSTANTS
		clean_node(nmask);
		set_node(nmask, nodes[i]);
		/*
		 * Use mbind() to make sure each node contains
		 * length size memory.
		 */
		ret = mbind(memory[i], length, MPOL_BIND, nmask, MAXNODES, 0);
		if (ret == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "mbind");
#endif

		memset(memory[i], 10, length);
	}

	SAFE_FILE_PRINTF(cleanup, PATH_KSM "sleep_millisecs", "0");
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "pages_to_scan", "%ld",
			 nr_pages * num_nodes);
	/*
	 * merge_across_nodes setting can be changed only when there
	 * are no ksm shared pages in system, so set run 2 to unmerge
	 * pages first, then to 1 after changing merge_across_nodes,
	 * to remerge according to the new setting.
	 */
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "2");
	wait_ksmd_done();
	tst_resm(TINFO, "Start to test KSM with merge_across_nodes=1");
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "merge_across_nodes", "1");
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "1");
	group_check(1, 1, nr_pages * num_nodes - 1, 0, 0, 0,
		    nr_pages * num_nodes);

	SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "2");
	wait_ksmd_done();
	tst_resm(TINFO, "Start to test KSM with merge_across_nodes=0");
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "merge_across_nodes", "0");
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "1");
	group_check(1, num_nodes, nr_pages * num_nodes - num_nodes,
		    0, 0, 0, nr_pages * num_nodes);

	SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "2");
	wait_ksmd_done();
}
示例#7
0
文件: mem.c 项目: liaoqingwei/ltp
void create_same_memory(int size, int num, int unit)
{
	int i, j, status, *child;
	unsigned long ps, pages;
	struct ksm_merge_data **ksm_data;

	struct ksm_merge_data ksm_data0[] = {
	       {'c', size*MB}, {'c', size*MB}, {'d', size*MB}, {'d', size*MB},
	};
	struct ksm_merge_data ksm_data1[] = {
	       {'a', size*MB}, {'b', size*MB}, {'d', size*MB}, {'d', size*MB-1},
	};
	struct ksm_merge_data ksm_data2[] = {
	       {'a', size*MB}, {'a', size*MB}, {'d', size*MB}, {'d', size*MB},
	};

	ps = sysconf(_SC_PAGE_SIZE);
	pages = MB / ps;

	ksm_data = malloc((num - 3) * sizeof(struct ksm_merge_data *));
	/* Since from third child, the data is same with the first child's */
	for (i = 0; i < num - 3; i++) {
		ksm_data[i] = malloc(4 * sizeof(struct ksm_merge_data));
		for (j = 0; j < 4; j++) {
			ksm_data[i][j].data = ksm_data0[j].data;
			ksm_data[i][j].mergeable_size =
				ksm_data0[j].mergeable_size;
		}
	}

	child = malloc(num * sizeof(int));
	if (child == NULL)
		tst_brkm(TBROK | TERRNO, cleanup, "malloc");

	for (i = 0; i < num; i++) {
		fflush(stdout);
		switch (child[i] = fork()) {
		case -1:
			tst_brkm(TBROK|TERRNO, cleanup, "fork");
		case 0:
			if (i == 0) {
				create_ksm_child(i, size, unit, ksm_data0);
				exit(0);
			} else if (i == 1) {
				create_ksm_child(i, size, unit, ksm_data1);
				exit(0);
			} else if (i == 2) {
				create_ksm_child(i, size, unit, ksm_data2);
				exit(0);
			} else {
				create_ksm_child(i, size, unit, ksm_data[i-3]);
				exit(0);
			}
		}
	}

	stop_ksm_children(child, num);

	tst_resm(TINFO, "KSM merging...");
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "1");
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "pages_to_scan", "%ld",
			 size * pages *num);
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "sleep_millisecs", "0");

	resume_ksm_children(child, num);
	group_check(1, 2, size * num * pages - 2, 0, 0, 0, size * pages * num);

	stop_ksm_children(child, num);
	resume_ksm_children(child, num);
	group_check(1, 3, size * num * pages - 3, 0, 0, 0, size * pages * num);

	stop_ksm_children(child, num);
	resume_ksm_children(child, num);
	group_check(1, 1, size * num * pages - 1, 0, 0, 0, size * pages * num);

	stop_ksm_children(child, num);
	resume_ksm_children(child, num);
	group_check(1, 1, size * num * pages - 2, 0, 1, 0, size * pages * num);

	stop_ksm_children(child, num);

	tst_resm(TINFO, "KSM unmerging...");
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "2");

	resume_ksm_children(child, num);
	group_check(2, 0, 0, 0, 0, 0, size * pages * num);

	tst_resm(TINFO, "stop KSM.");
	SAFE_FILE_PRINTF(cleanup, PATH_KSM "run", "0");
	group_check(0, 0, 0, 0, 0, 0, size * pages * num);

	while (waitpid(-1, &status, WUNTRACED | WCONTINUED) > 0)
		if (WEXITSTATUS(status) != 0)
			tst_resm(TFAIL, "child exit status is %d",
				 WEXITSTATUS(status));
}
示例#8
0
文件: mem.c 项目: sconklin/ltp-tools
void create_same_memory(int size, int num, int unit)
{
	char buf[BUFSIZ], buf2[BUFSIZ];
	int i, j, k;
	int status, fd;
	int *child;
	long ps, pages;

	ps = sysconf(_SC_PAGE_SIZE);
	pages = 1024 * 1024 / ps;

	child = malloc(num);
	if (child == NULL)
		tst_brkm(TBROK|TERRNO, cleanup, "malloc");

	memory = malloc(num * sizeof(**memory));
	if (memory == NULL)
		tst_brkm(TBROK|TERRNO, cleanup, "malloc");

	/* Don't call cleanup in those children. Instead, do a cleanup from the
	   parent after fetched children's status.*/
	switch (child[0] = fork()) {
	case -1:
		tst_brkm(TBROK|TERRNO, cleanup, "fork");
	case 0:
		tst_resm(TINFO, "child 0 stops.");
		if (raise(SIGSTOP) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "kill");

		tst_resm(TINFO, "child 0 continues...");
		tst_resm(TINFO, "child 0 allocates %d MB filled with 'c'.",
			size);
		memory[0] = malloc(size / unit * sizeof(*memory));
		if (memory[0] == NULL)
			tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
		for (j = 0; j * unit < size; j++) {
			memory[0][j] = mmap(NULL, unit * MB,
					PROT_READ|PROT_WRITE,
					MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
			if (memory[0][j] == MAP_FAILED)
				tst_brkm(TBROK|TERRNO, tst_exit, "mmap");

#ifdef HAVE_MADV_MERGEABLE
			if (madvise(memory[0][j], unit * MB, MADV_MERGEABLE)
				== -1)
				tst_brkm(TBROK|TERRNO, tst_exit, "madvise");
#endif
			for (i = 0; i < unit * MB; i++)
				memory[0][j][i] = 'c';
		}
		tst_resm(TINFO, "child 0 stops.");
		if (raise(SIGSTOP) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "kill");

		tst_resm(TINFO, "child 0 continues...");
		verify('c', 0, 0, size / unit, 0, unit * MB);
		tst_resm(TINFO, "child 0 changes memory content to 'd'.");
		for (j = 0; j < size / unit; j++) {
			for (i = 0; i < unit * MB; i++)
				memory[0][j][i] = 'd';
		}
		/* Unmerge. */
		tst_resm(TINFO, "child 0 stops.");
		if (raise(SIGSTOP) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "kill");

		tst_resm(TINFO, "child 0 continues...");
		verify('d', 0, 0, size / unit, 0, unit * MB);
		/* Stop. */
		tst_resm(TINFO, "child 0 stops.");
		if (raise(SIGSTOP) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
		tst_resm(TINFO, "child 0 continues...");
		exit(0);
	}
	switch (child[1] = fork()) {
	case -1:
		tst_brkm(TBROK|TERRNO, cleanup, "fork");
	case 0:
		tst_resm(TINFO, "child 1 stops.");
		if (raise(SIGSTOP) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
		tst_resm(TINFO, "child 1 continues...");
		tst_resm(TINFO, "child 1 allocates %d MB filled with 'a'.",
			size);
		memory[1] = malloc(size / unit * sizeof(*memory));
		if (memory[1] == NULL)
			tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
		for (j = 0; j < size / unit; j++) {
			memory[1][j] = mmap(NULL, unit * MB,
					PROT_READ|PROT_WRITE,
					MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
			if (memory[1][j] == MAP_FAILED)
				tst_brkm(TBROK|TERRNO, tst_exit, "mmap");
#ifdef HAVE_MADV_MERGEABLE
			if (madvise(memory[1][j], unit * MB, MADV_MERGEABLE)
				== -1)
				tst_brkm(TBROK|TERRNO, tst_exit, "madvise");
#endif
			for (i = 0; i < unit * MB; i++)
				memory[1][j][i] = 'a';
		}
		tst_resm(TINFO, "child 1 stops.");
		if (raise(SIGSTOP) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
		tst_resm(TINFO, "child 1 continues...");
		verify('a', 1, 0, size / unit, 0, unit * MB);
		tst_resm(TINFO, "child 1 changes memory content to 'b'.");
		for (j = 0; j < size / unit; j++) {
			for (i = 0; i < unit * MB; i++)
				memory[1][j][i] = 'b';
		}
		tst_resm(TINFO, "child 1 stops.");
		if (raise(SIGSTOP) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
		tst_resm(TINFO, "child 1 continues...");
		verify('b', 1, 0, size / unit, 0, unit * MB);
		tst_resm(TINFO, "child 1 changes memory content to 'd'");
		for (j = 0; j < size / unit; j++) {
			for (i = 0; i < unit * MB; i++)
				memory[1][j][i] = 'd';
		}
		if (raise(SIGSTOP) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "kill");

		tst_resm(TINFO, "child 1 continues...");
		verify('d', 1, 0, size / unit, 0, unit * MB);
		tst_resm(TINFO, "child 1 changes one page to 'e'.");
		memory[1][size / unit - 1][unit * MB - 1] = 'e';

		/* Unmerge. */
		tst_resm(TINFO, "child 1 stops.");
		if (raise(SIGSTOP) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
		tst_resm(TINFO, "child 1 continues...");
		verify('e', 1, size / unit - 1, size / unit,
			unit * MB - 1, unit * MB);
		verify('d', 1, 0, size / unit - 1, 0, unit * MB - 1);

		/* Stop. */
		tst_resm(TINFO, "child 1 stops.");
		if (raise(SIGSTOP) == -1)
			tst_brkm(TBROK|TERRNO, tst_exit, "kill");
		tst_resm(TINFO, "child 1 continues...");
		exit(0);
	}
	for (k = 2; k < num; k++) {
		switch (child[k] = fork()) {
		case -1:
			tst_brkm(TBROK|TERRNO, cleanup, "fork");
		case 0:
			tst_resm(TINFO, "child %d stops.", k);
			if (raise(SIGSTOP) == -1)
				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
			tst_resm(TINFO, "child %d continues...", k);
			tst_resm(TINFO, "child %d allocates %d "
				"MB filled with 'a'.", k, size);
			memory[k] = malloc(size / unit * sizeof(*memory));
			if (memory[k] == NULL)
				tst_brkm(TBROK|TERRNO, tst_exit, "malloc");
			for (j = 0; j < size / unit; j++) {
				memory[k][j] = mmap(NULL, unit * MB,
						PROT_READ|PROT_WRITE,
						MAP_ANONYMOUS
						|MAP_PRIVATE, -1, 0);
				if (memory[k][j] == MAP_FAILED)
					tst_brkm(TBROK|TERRNO, cleanup,
						"mmap");
#ifdef HAVE_MADV_MERGEABLE
				if (madvise(memory[k][j], unit * MB,
						MADV_MERGEABLE) == -1)
					tst_brkm(TBROK|TERRNO, cleanup,
						"madvise");
#endif
				for (i = 0; i < unit * MB; i++)
					memory[k][j][i] = 'a';
			}
			tst_resm(TINFO, "child %d stops.", k);
			if (raise(SIGSTOP) == -1)
				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
			tst_resm(TINFO, "child %d continues...", k);
			tst_resm(TINFO, "child %d changes memory content to "
				"'d'", k);
			for (j = 0; j < size / unit; j++) {
				for (i = 0; i < unit * MB; i++)
					memory[k][j][i] = 'd';
		        }
			/* Unmerge. */
			tst_resm(TINFO, "child %d stops.", k);
			if (raise(SIGSTOP) == -1)
				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
			tst_resm(TINFO, "child %d continues...", k);

			/* Stop. */
			tst_resm(TINFO, "child %d stops.", k);
			if (raise(SIGSTOP) == -1)
				tst_brkm(TBROK|TERRNO, tst_exit, "kill");
			tst_resm(TINFO, "child %d continues...", k);
			exit(0);
		}
	}
	tst_resm(TINFO, "KSM merging...");
	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "run");
	fd = open(buf, O_WRONLY);
	if (fd == -1)
		tst_brkm(TBROK|TERRNO, cleanup, "open");
	if (write(fd, "1", 1) != 1)
		tst_brkm(TBROK|TERRNO, cleanup, "write");
	close(fd);
	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "pages_to_scan");
	snprintf(buf2, BUFSIZ, "%ld", size * pages * num);
	fd = open(buf, O_WRONLY);
	if (fd == -1)
		tst_brkm(TBROK|TERRNO, cleanup, "open");
	if (write(fd, buf2, strlen(buf2)) != strlen(buf2))
		tst_brkm(TBROK|TERRNO, cleanup, "write");
	close(fd);

	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "sleep_millisecs");
	fd = open(buf, O_WRONLY);
	if (fd == -1)
		tst_brkm(TBROK|TERRNO, cleanup, "open");
	if (write(fd, "0", 1) != 1)
		tst_brkm(TBROK|TERRNO, cleanup, "write");
	close(fd);

	tst_resm(TINFO, "wait for all children to stop.");
	for (k = 0; k < num; k++) {
		if (waitpid(child[k], &status, WUNTRACED) == -1)
			tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
		if (!WIFSTOPPED(status))
			tst_brkm(TBROK, cleanup, "child %d was not stopped.",
				k);
	}
	tst_resm(TINFO, "resume all children.");
	for (k = 0; k < num; k++) {
		if (kill(child[k], SIGCONT) == -1)
			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
	}
	group_check(1, 2, size * num * pages - 2, 0, 0, 0, size * pages * num);

	tst_resm(TINFO, "wait for child 1 to stop.");
	if (waitpid(child[1], &status, WUNTRACED) == -1)
		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
	if (!WIFSTOPPED(status))
		tst_brkm(TBROK, cleanup, "child 1 was not stopped.");

	/* Child 1 changes all pages to 'b'. */
	tst_resm(TINFO, "resume child 1.");
	if (kill(child[1], SIGCONT) == -1)
		tst_brkm(TBROK|TERRNO, cleanup, "kill");
	group_check(1, 3, size * num * pages - 3, 0, 0, 0, size * pages * num);

	tst_resm(TINFO, "wait for child 1 to stop.");
	if (waitpid(child[1], &status, WUNTRACED) == -1)
		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
	if (!WIFSTOPPED(status))
		tst_brkm(TBROK, cleanup, "child 1 was not stopped.");

	/* All children change pages to 'd'. */
	tst_resm(TINFO, "resume all children.");
	for (k = 0; k < num; k++) {
		if (kill(child[k], SIGCONT) == -1)
			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
	}
	group_check(1, 1, size * num * pages - 1, 0, 0, 0, size * pages * num);

	tst_resm(TINFO, "wait for all children to stop.");
	for (k = 0; k < num; k++) {
		if (waitpid(child[k], &status, WUNTRACED) == -1)
			tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
		if (!WIFSTOPPED(status))
			tst_brkm(TBROK, cleanup, "child %d was not stopped.",
				k);
	}
	/* Child 1 changes pages to 'e'. */
	tst_resm(TINFO, "resume child 1.");
	if (kill(child[1], SIGCONT) == -1)
		tst_brkm(TBROK|TERRNO, cleanup, "kill");
	group_check(1, 1, size * num * pages - 2, 0, 1, 0, size * pages * num);

	tst_resm(TINFO, "wait for child 1 to stop.");
	if (waitpid(child[1], &status, WUNTRACED) == -1)
		tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
	if (!WIFSTOPPED(status))
		tst_brkm(TBROK, cleanup, "child 1 was not stopped.");

	tst_resm(TINFO, "resume all children.");
	for (k = 0; k < num; k++) {
		if (kill(child[k], SIGCONT) == -1)
			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
	}
	tst_resm(TINFO, "KSM unmerging...");
	snprintf(buf, BUFSIZ, "%s%s", PATH_KSM, "run");
	fd = open(buf, O_WRONLY);
	if (fd == -1)
		tst_brkm(TBROK|TERRNO, cleanup, "open");
	if (write(fd, "2", 1) != 1)
		tst_brkm(TBROK|TERRNO, cleanup, "write");
	group_check(2, 0, 0, 0, 0, 0, size * pages * num);

	tst_resm(TINFO, "wait for all children to stop.");
	for (k = 0; k < num; k++) {
		if (waitpid(child[k], &status, WUNTRACED) == -1)
			tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
		if (!WIFSTOPPED(status))
			tst_brkm(TBROK, cleanup, "child %d was not stopped.",
				k);
	}
	tst_resm(TINFO, "resume all children.");
	for (k = 0; k < num; k++) {
		if (kill(child[k], SIGCONT) == -1)
			tst_brkm(TBROK|TERRNO, cleanup, "kill child[%d]", k);
	}
	tst_resm(TINFO, "stop KSM.");
	if (lseek(fd, 0, SEEK_SET) == -1)
		tst_brkm(TBROK|TERRNO, cleanup, "lseek");
	if (write(fd, "0", 1) != 1)
		tst_brkm(TBROK|TERRNO, cleanup, "write");
	close(fd);
	group_check(0, 0, 0, 0, 0, 0, size * pages * num);
	while (waitpid(-1, &status, WUNTRACED | WCONTINUED) > 0)
		if (WEXITSTATUS(status) != 0)
			tst_resm(TFAIL, "child exit status is %d",
				WEXITSTATUS(status));
}