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); }
/************************************************************ 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; }
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); }
/************************************************************ 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 */ }
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; }
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(); }
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)); }
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)); }