// LAB2: below code is used to check the first fit allocation algorithm (your EXERCISE 1) // NOTICE: You SHOULD NOT CHANGE basic_check, default_check functions! static void default_check(void) { int count = 0, total = 0; list_entry_t *le = &free_list; while ((le = list_next(le)) != &free_list) { struct Page *p = le2page(le, page_link); assert(PageProperty(p)); count ++, total += p->property; } assert(total == nr_free_pages()); basic_check(); struct Page *p0 = alloc_pages(5), *p1, *p2; assert(p0 != NULL); assert(!PageProperty(p0)); list_entry_t free_list_store = free_list; list_init(&free_list); assert(list_empty(&free_list)); assert(alloc_page() == NULL); unsigned int nr_free_store = nr_free; nr_free = 0; free_pages(p0 + 2, 3); assert(alloc_pages(4) == NULL); assert(PageProperty(p0 + 2) && p0[2].property == 3); assert((p1 = alloc_pages(3)) != NULL); assert(alloc_page() == NULL); assert(p0 + 2 == p1); p2 = p0 + 1; free_page(p0); free_pages(p1, 3); assert(PageProperty(p0) && p0->property == 1); assert(PageProperty(p1) && p1->property == 3); assert((p0 = alloc_page()) == p2 - 1); free_page(p0); assert((p0 = alloc_pages(2)) == p2 + 1); free_pages(p0, 2); free_page(p2); assert((p0 = alloc_pages(5)) != NULL); assert(alloc_page() == NULL); assert(nr_free == 0); nr_free = nr_free_store; free_list = free_list_store; free_pages(p0, 5); le = &free_list; while ((le = list_next(le)) != &free_list) { struct Page *p = le2page(le, page_link); count --, total -= p->property; } assert(count == 0); assert(total == 0); }
static void check_prop(GLuint prog, GLenum programInterface, int index, const char *name, void *inputs, struct check_t c, bool *pass) { int values[10], parent_idx, i; char subsubtest[150]; GLsizei length, tmp = -1; char buf[21]; GLenum pif; GLuint loc; /* skip the test if it is not supported */ if(!check_extensions_prop(c.prop)) { return; } /* generate the name of the subsubtest for error-reporting purposes */ snprintf(subsubtest, sizeof(subsubtest), "%s: %s on %s", name, piglit_get_gl_enum_name(c.prop), piglit_get_gl_enum_name(programInterface)); /* retrieve the property */ glGetProgramResourceiv(prog, programInterface, index, 1, &c.prop, 10, &length, values); if (!piglit_check_gl_error(GL_NO_ERROR)) { printf(" Latest error generated while running '%s'\n", subsubtest); *pass = false; return; } /* check the return value */ switch (c.prop) { case GL_OFFSET: case GL_ARRAY_STRIDE: case GL_ATOMIC_COUNTER_BUFFER_INDEX: basic_check(subsubtest, values[0], c.values[0], pass); break; case GL_BLOCK_INDEX: /* check that the index of the parent matches the name * of the parent */ switch (programInterface) { case GL_UNIFORM: pif = GL_UNIFORM_BLOCK; break; case GL_BUFFER_VARIABLE: pif = GL_SHADER_STORAGE_BLOCK; break; default: assert(!"unexpected programInterface value"); pif = GL_NONE; } parent_idx = glGetProgramResourceIndex(prog, pif, (char*)inputs); piglit_check_gl_error(GL_NO_ERROR); if (parent_idx != values[0]) { glGetProgramResourceName(prog, programInterface, values[0], sizeof(buf), NULL, buf); fprintf(stderr, "'%s' expected parent name to be %s" "(idx = %i) but got parent name %s(idx = %i)\n", subsubtest, (char*)inputs, parent_idx, buf, values[0]); *pass = false; } break; case GL_BUFFER_BINDING: if (values[0] < 0) { fprintf(stderr, "'%s' invalid buffer binding point\n", subsubtest); *pass = false; } /* Binding index is necessary for ATOMIC_COUNTER_BUFFER */ if (programInterface == GL_ATOMIC_COUNTER_BUFFER) { if (values[0] != c.values[0]) { fprintf(stderr, "'%s' expected binding point %i" " but got %i\n", subsubtest, c.values[0], values[0]); *pass = false; } break; } /* check against another API call */ if (programInterface != GL_UNIFORM_BLOCK) { break; } glGetActiveUniformBlockiv(prog, index, GL_UNIFORM_BLOCK_BINDING, &tmp); piglit_check_gl_error(GL_NO_ERROR); if (tmp != values[0]) { fprintf(stderr, "'%s' inconsistent buffer binding point" "(%i) with glGetActiveUniformBlockiv" "(%i)\n", subsubtest, values[0], tmp); *pass = false; } break; case GL_ACTIVE_VARIABLES: case GL_COMPATIBLE_SUBROUTINES: switch (programInterface) { case GL_UNIFORM_BLOCK: pif = GL_UNIFORM; break; case GL_SHADER_STORAGE_BLOCK: pif = GL_BUFFER_VARIABLE; break; case GL_VERTEX_SUBROUTINE_UNIFORM: pif = GL_VERTEX_SUBROUTINE; break; case GL_TESS_CONTROL_SUBROUTINE_UNIFORM: pif = GL_TESS_CONTROL_SUBROUTINE; break; case GL_COMPUTE_SUBROUTINE_UNIFORM: pif = GL_COMPUTE_SUBROUTINE; break; case GL_ATOMIC_COUNTER_BUFFER: /* do nothing */ break; default: assert(!"unexpected programInterface value"); pif = GL_NONE; } /* check that the return count is as expected */ if (c.count != length) { fprintf(stderr, "'%s' expected %zu entries but got %i" "\n", subsubtest, c.count, length); length = 1; *pass = false; break; } /* harcode the index test for GL_ATOMIC_COUNTER_BUFFER */ if (programInterface == GL_ATOMIC_COUNTER_BUFFER) { if (values[0] != 0) { fprintf(stderr, "'%s' expected index 0 but got " "%i", subsubtest, values[0]); *pass = false; } break; } for (i = 0; i < length; i++) { buf[0] = '\0'; glGetProgramResourceName(prog, pif, values[i], sizeof(buf), NULL, buf); piglit_check_gl_error(GL_NO_ERROR); if (!is_resource_in_list(inputs, buf, i, false)) { fprintf(stderr, "'%s' could not find active " "resource '%s' (idx = %i) in the active" " list\n", subsubtest, buf, values[i]); *pass = false; } } break; case GL_BUFFER_DATA_SIZE: /* Nothing we can check here... */ break; case GL_LOCATION: loc = glGetProgramResourceLocation(prog, programInterface, name); piglit_check_gl_error(GL_NO_ERROR); if (loc != values[0]) { fprintf(stderr, "'%s' inconsistent value between " "glGetProgramResourceiv(%i) and " "glGetProgramResourceLocation(%i).\n", subsubtest, values[0], loc); *pass = false; break; } if (prog == prog_loc && values[0] != c.values[0]) { fprintf(stderr, "'%s' expected location %i but got " "%i\n", subsubtest, c.values[0], values[0]); *pass = false; break; } /* continue by testing the (in)validity of the index */ basic_check(subsubtest, values[0], c.values[0], pass); break; case GL_LOCATION_INDEX: loc = glGetProgramResourceLocationIndex(prog, programInterface, name); piglit_check_gl_error(GL_NO_ERROR); if (loc != values[0]) { fprintf(stderr, "'%s' inconsistent value between " "glGetProgramResourceiv(%i) and " "glGetProgramResourceLocationIndex(%i)." "\n", subsubtest, values[0], loc); *pass = false; break; } /* continue by testing the (in)validity of the index */ basic_check(subsubtest, values[0], c.values[0], pass); break; default: /* check that the return count is as expected */ if (c.count != length) { fprintf(stderr, "'%s' expected %zu entries but got %i" "\n", subsubtest, c.count, length); length = 1; *pass = false; break; } /* go through all the values returned */ for (i = 0; i < length; i++) { if (values[i] != c.values[i]) { fprintf(stderr, "'%s' expected %i but got %i at" " index %i\n", subsubtest, c.values[i], values[i], i); *pass = false; } } break; } }
int main(int argc, char **argv) { const char *av = NULL; int func_total, file_total; char arg_dbpath[MAXPATHLEN]; const char *index = NULL; int optchar; int option_index = 0; STATISTICS_TIME *tim; arg_dbpath[0] = 0; basic_check(); /* * Setup GTAGSCONF and GTAGSLABEL environment variable * according to the --gtagsconf and --gtagslabel option. */ preparse_options(argc, argv); /* * Load configuration values. */ if (!vgetcwd(cwdpath, sizeof(cwdpath))) die("cannot get current directory."); openconf(cwdpath); configuration(); /* * setup_langmap() is needed to use decide_lang(). */ setup_langmap(langmap); save_environment(argc, argv); /* * insert htags_options at the head of argv. */ setenv_from_config(); { char *env = getenv("HTAGS_OPTIONS"); if (env && *env) argv = prepend_options(&argc, argv, env); } while ((optchar = getopt_long(argc, argv, "acd:DfFghIm:nNoqst:Tvwx", long_options, &option_index)) != EOF) { switch (optchar) { case 0: /* already flags set */ break; case OPT_AUTO_COMPLETION: auto_completion = 1; if (optarg) { if (atoi(optarg) > 0) auto_completion_limit = optarg; else die("The option value of --auto-completion must be numeric."); } break; case OPT_CFLOW: call_file = optarg; break; case OPT_CALL_TREE: call_file = optarg; break; case OPT_CALLEE_TREE: callee_file = optarg; break; case OPT_CVSWEB: cvsweb_url = optarg; break; case OPT_CVSWEB_CVSROOT: cvsweb_cvsroot = optarg; break; case OPT_GTAGSCONF: case OPT_GTAGSLABEL: /* These options are already parsed in preparse_options() */ break; case OPT_INSERT_FOOTER: insert_footer = optarg; break; case OPT_INSERT_HEADER: insert_header = optarg; break; case OPT_HTML_HEADER: { STATIC_STRBUF(sb); if (!test("r", optarg)) die("file '%s' not found.", optarg); strbuf_clear(sb); loadfile(optarg, sb); html_header = strbuf_value(sb); } break; case OPT_ITEM_ORDER: item_order = optarg; break; case OPT_TABS: if (atoi(optarg) > 0) tabs = atoi(optarg); else die("--tabs option requires numeric value."); break; case OPT_NCOL: if (atoi(optarg) > 0) ncol = atoi(optarg); else die("--ncol option requires numeric value."); break; case OPT_TREE_VIEW: tree_view = 1; if (optarg) tree_view_type = optarg; break; case 'a': aflag++; break; case 'd': strlimcpy(arg_dbpath, optarg, sizeof(arg_dbpath)); break; case 'D': dynamic = 1; break; case 'f': fflag++; break; case 'F': Fflag++; break; case 'g': gflag++; break; case 'h': definition_header = AFTER_HEADER; if (optarg) { if (!strcmp(optarg, "before")) definition_header = BEFORE_HEADER; else if (!strcmp(optarg, "right")) definition_header = RIGHT_HEADER; else if (!strcmp(optarg, "after")) definition_header = AFTER_HEADER; else die("The option value of --func-header must be one of 'before', 'right' and 'after'."); } break; case 'I': Iflag++; break; case 'm': main_func = optarg; break; case 'n': nflag++; if (optarg) { if (atoi(optarg) > 0) ncol = atoi(optarg); else die("The option value of --line-number must be numeric."); } break; case 'o': other_files = 1; break; case 's': symbol = 1; break; case 'T': table_flist = 1; if (optarg) { if (atoi(optarg) > 0) flist_fields = atoi(optarg); else die("The option value of the --table-flist must be numeric."); } break; case 't': title = optarg; break; case 'q': qflag++; setquiet(); break; case 'v': vflag++; setverbose(); break; case 'w': wflag++; break; default: usage(); break; } } /* * Leaving everything to htags. * Htags selects popular options for you. */ if (suggest2) suggest = 1; if (suggest) { int gtags_not_found = 0; char dbpath[MAXPATHLEN]; aflag = Iflag = nflag = vflag = 1; setverbose(); definition_header = AFTER_HEADER; other_files = symbol = show_position = table_flist = fixed_guide = 1; if (arg_dbpath[0]) { if (!test("f", makepath(arg_dbpath, dbname(GTAGS), NULL))) gtags_not_found = 1; } else if (gtagsexist(".", dbpath, sizeof(dbpath), 0) == 0) { gtags_not_found = 1; } if (gtags_not_found) gflag = 1; } if (suggest2) { Fflag = 1; /* uses frame */ fflag = dynamic = 1; /* needs a HTTP server */ auto_completion = tree_view = 1; /* needs javascript */ } if (call_file && !test("fr", call_file)) die("cflow file not found. '%s'", call_file); if (callee_file && !test("fr", callee_file)) die("cflow file not found. '%s'", callee_file); if (insert_header && !test("fr", insert_header)) die("page header file '%s' not found.", insert_header); if (insert_footer && !test("fr", insert_footer)) die("page footer file '%s' not found.", insert_footer); if (!fflag) auto_completion = 0; argc -= optind; argv += optind; if (!av) av = (argc > 0) ? *argv : NULL; if (debug) setdebug(); settabs(tabs); /* setup tab skip */ if (qflag) { setquiet(); vflag = 0; } if (show_version) version(av, vflag); if (show_help) help(); /* * Invokes gtags beforehand. */ if (gflag) { STRBUF *sb = strbuf_open(0); strbuf_puts(sb, gtags_path); if (vflag) strbuf_puts(sb, " -v"); if (wflag) strbuf_puts(sb, " -w"); if (suggest2 && enable_idutils && usable("mkid")) strbuf_puts(sb, " -I"); if (arg_dbpath[0]) { strbuf_putc(sb, ' '); strbuf_puts(sb, arg_dbpath); } if (system(strbuf_value(sb))) die("cannot execute gtags(1) command."); strbuf_close(sb); } /* * get dbpath. */ if (arg_dbpath[0]) { strlimcpy(dbpath, arg_dbpath, sizeof(dbpath)); } else { int status = setupdbpath(0); if (status < 0) die_with_code(-status, "%s", gtags_dbpath_error); strlimcpy(dbpath, get_dbpath(), sizeof(dbpath)); } if (!title) { char *p = strrchr(cwdpath, sep); title = p ? p + 1 : cwdpath; } if (cvsweb_url && test("d", "CVS")) use_cvs_module = 1; /* * decide directory in which we make hypertext. */ if (av) { char realpath[MAXPATHLEN]; if (!test("dw", av)) die("'%s' is not writable directory.", av); if (chdir(av) < 0) die("directory '%s' not found.", av); if (!vgetcwd(realpath, sizeof(realpath))) die("cannot get current directory"); if (chdir(cwdpath) < 0) die("cannot return to original directory."); snprintf(distpath, sizeof(distpath), "%s/HTML", realpath); } else { snprintf(distpath, sizeof(distpath), "%s/HTML", cwdpath); } /* * Existence check of tag files. */ { int i; const char *path; GTOP *gtop; for (i = GPATH; i < GTAGLIM; i++) { path = makepath(dbpath, dbname(i), NULL); gtags_exist[i] = test("fr", path); } /* * Real GRTAGS includes virtual GSYMS. */ gtags_exist[GSYMS] = symbol ? 1 : 0; if (!gtags_exist[GPATH] || !gtags_exist[GTAGS] || !gtags_exist[GRTAGS]) die("GPATH, GTAGS and/or GRTAGS not found. Please reexecute htags with the -g option."); /* * version check. * Do nothing, but the version of tag file will be checked. */ gtop = gtags_open(dbpath, cwdpath, GTAGS, GTAGS_READ, 0); gtags_close(gtop); /* * Check whether GRTAGS is empty. */ gtop = gtags_open(dbpath, cwdpath, GRTAGS, GTAGS_READ, 0); if (gtags_first(gtop, NULL, 0) == NULL) grtags_is_empty = 1; gtags_close(gtop); } /* * make dbpath absolute. */ { char buf[MAXPATHLEN]; if (realpath(dbpath, buf) == NULL) die("cannot get realpath of dbpath."); strlimcpy(dbpath, buf, sizeof(dbpath)); } /* * The older version (4.8.7 or former) of GPATH doesn't have files * other than source file. The oflag requires new version of GPATH. */ if (other_files) { GFIND *gp = gfind_open(dbpath, NULL, 0, 0); if (gp->version < 2) die("GPATH is old format. Please remake it by invoking gtags(1)."); gfind_close(gp); } /* * for global(1) and gtags(1). */ set_env("GTAGSROOT", cwdpath); set_env("GTAGSDBPATH", dbpath); set_env("GTAGSLIBPATH", ""); /*------------------------------------------------------------------ * MAKE FILES *------------------------------------------------------------------ * HTML/cgi-bin/global.cgi ... CGI program (1) * HTML/cgi-bin/ghtml.cgi ... unzip script (1) * HTML/.htaccess ... skeleton of .htaccess (1) * HTML/help.html ... help file (2) * HTML/R/ ... references (3) * HTML/D/ ... definitions (3) * HTML/search.html ... search index (4) * HTML/defines.html ... definitions index (5) * HTML/defines/ ... definitions index (5) * HTML/files/ ... file index (6) * HTML/index.html ... index file (7) * HTML/mains.html ... main index (8) * HTML/null.html ... main null html (8) * HTML/S/ ... source files (9) * HTML/I/ ... include file index (9) * HTML/rebuild.sh ... rebuild script (10) * HTML/style.css ... style sheet (11) *------------------------------------------------------------------ */ /* for clean up */ signal_setup(); sethandler(clean); HTML = normal_suffix; message("[%s] Htags started", now()); init_statistics(); /* * (#) check if GTAGS, GRTAGS is the latest. */ if (get_dbpath()) message(" Using %s/GTAGS.", get_dbpath()); if (grtags_is_empty) message(" GRTAGS is empty."); if (gpath_open(dbpath, 0) < 0) die("GPATH not found."); if (!w32) { /* UNDER CONSTRUCTION */ } if (auto_completion || tree_view) { STATIC_STRBUF(sb); strbuf_clear(sb); strbuf_puts_nl(sb, "<script type='text/javascript' src='js/jquery.js'></script>"); if (auto_completion) loadfile(makepath(datadir, "gtags/jscode_suggest", NULL), sb); if (tree_view) loadfile(makepath(datadir, "gtags/jscode_treeview", NULL), sb); jscode = strbuf_value(sb); } /* * (0) make directories */ message("[%s] (0) making directories ...", now()); if (!test("d", distpath)) if (mkdir(distpath, 0777) < 0) die("cannot make directory '%s'.", distpath); make_directory_in_distpath("files"); make_directory_in_distpath("defines"); make_directory_in_distpath(SRCS); make_directory_in_distpath(INCS); make_directory_in_distpath(INCREFS); if (!dynamic) { make_directory_in_distpath(DEFS); make_directory_in_distpath(REFS); if (symbol) make_directory_in_distpath(SYMS); } if (fflag || dynamic) make_directory_in_distpath("cgi-bin"); if (Iflag) make_directory_in_distpath("icons"); if (auto_completion || tree_view) make_directory_in_distpath("js"); /* * (1) make CGI program */ if (fflag || dynamic) { char cgidir[MAXPATHLEN]; snprintf(cgidir, sizeof(cgidir), "%s/cgi-bin", distpath); message("[%s] (1) making CGI program ...", now()); if (fflag || dynamic) makeprogram(cgidir, "global.cgi", 0755); if (auto_completion) makeprogram(cgidir, "completion.cgi", 0755); makehtaccess(cgidir, ".htaccess", 0644); } else { message("[%s] (1) making CGI program ...(skipped)", now()); } if (av) { const char *path = makepath(distpath, "GTAGSROOT", NULL); FILE *op = fopen(path, "w"); if (op == NULL) die("cannot make file '%s'.", path); fputs(cwdpath, op); fputc('\n', op); fclose(op); } /* * (2) make help file */ message("[%s] (2) making help.html ...", now()); makehelp("help.html"); /* * (#) load GPATH */ load_gpath(dbpath); /* * (3) make function entries (D/ and R/) * MAKING TAG CACHE */ message("[%s] (3) making tag lists ...", now()); cache_open(); tim = statistics_time_start("Time of making tag lists"); func_total = makedupindex(); statistics_time_end(tim); message("Total %d functions.", func_total); /* * (4) search index. (search.html) */ if (Fflag && fflag) { message("[%s] (4) making search index ...", now()); makesearchindex("search.html"); } { STRBUF *defines = strbuf_open(0); STRBUF *files = strbuf_open(0); /* * (5) make definition index (defines.html and defines/) * PRODUCE @defines */ message("[%s] (5) making definition index ...", now()); tim = statistics_time_start("Time of making definition index"); func_total = makedefineindex("defines.html", func_total, defines); statistics_time_end(tim); message("Total %d functions.", func_total); /* * (6) make file index (files.html and files/) * PRODUCE @files, %includes */ message("[%s] (6) making file index ...", now()); init_inc(); tim = statistics_time_start("Time of making file index"); file_total = makefileindex("files.html", files); statistics_time_end(tim); message("Total %d files.", file_total); html_count += file_total; /* * (7) make call tree using cflow(1)'s output (cflow.html) */ if (call_file || callee_file) { message("[%s] (7) making cflow index ...", now()); tim = statistics_time_start("Time of making cflow index"); if (call_file) if (makecflowindex("call.html", call_file) < 0) call_file = NULL; if (callee_file) if (makecflowindex("callee.html", callee_file) < 0) callee_file = NULL; statistics_time_end(tim); } /* * [#] make include file index. */ message("[%s] (#) making include file index ...", now()); tim = statistics_time_start("Time of making include file index"); makeincludeindex(); statistics_time_end(tim); /* * [#] make a common part for mains.html and index.html * USING @defines @files */ message("[%s] (#) making a common part ...", now()); index = makecommonpart(title, strbuf_value(defines), strbuf_value(files)); strbuf_close(defines); strbuf_close(files); } /* * (7)make index file (index.html) */ message("[%s] (7) making index file ...", now()); makeindex("index.html", title, index); /* * (8) make main index (mains.html) */ message("[%s] (8) making main index ...", now()); makemainindex("mains.html", index); /* * (9) make HTML files (SRCS/) * USING TAG CACHE, %includes and anchor database. */ message("[%s] (9) making hypertext from source code ...", now()); tim = statistics_time_start("Time of making hypertext"); makehtml(file_total); statistics_time_end(tim); /* * (10) rebuild script. (rebuild.sh) * * Don't grant execute permission to rebuild script. */ makerebuild("rebuild.sh"); if (chmod(makepath(distpath, "rebuild.sh", NULL), 0640) < 0) die("cannot chmod rebuild script."); /* * (11) style sheet file (style.css) */ if (enable_xhtml) { char src[MAXPATHLEN]; char dist[MAXPATHLEN]; snprintf(src, sizeof(src), "%s/gtags/style.css", datadir); snprintf(dist, sizeof(dist), "%s/style.css", distpath); copyfile(src, dist); } if (auto_completion || tree_view) { char src[MAXPATHLEN]; char dist[MAXPATHLEN]; snprintf(src, sizeof(src), "%s/gtags/jquery", datadir); snprintf(dist, sizeof(dist), "%s/js", distpath); copydirectory(src, dist); snprintf(src, sizeof(src), "%s/gtags/jquery/images", datadir); snprintf(dist, sizeof(dist), "%s/js/images", distpath); copydirectory(src, dist); } message("[%s] Done.", now()); if (vflag && (fflag || dynamic || auto_completion)) { message("\n[Information]\n"); message(" o Htags was invoked with the -f, -c, -D or --auto-completion option. You should"); message(" start http server so that cgi-bin/*.cgi is executed as a CGI script."); message("\n If you are using Apache, 'HTML/.htaccess' might be helpful for you.\n"); message(" Good luck!\n"); } if (Iflag) { char src[MAXPATHLEN]; char dist[MAXPATHLEN]; snprintf(src, sizeof(src), "%s/gtags/icons", datadir); snprintf(dist, sizeof(dist), "%s/icons", distpath); copydirectory(src, dist); } gpath_close(); /* * Print statistics information. */ print_statistics(statistics); clean(); return 0; }
// LAB2: below code is used to check the first fit allocation algorithm (your EXERCISE 1) // NOTICE: You SHOULD NOT CHANGE basic_check, default_check functions! static void default_check(void) { // 好吧,我们现在来看一下默认的测试吧! int count = 0, total = 0; list_entry_t *le = &free_list; // free_list应该是一个文件头吧! while ((le = list_next(le)) != &free_list) { // 开始遍历 struct Page *p = le2page(le, page_link); assert(PageProperty(p)); count ++, total += p->property; // counter表示一个有多少个page,total表示一共有多少个空闲页 } assert(total == nr_free_pages()); basic_check(); struct Page *p0 = alloc_pages(5), *p1, *p2; // 分配5个页面给p0 assert(p0 != NULL); assert(!PageProperty(p0)); list_entry_t free_list_store = free_list; list_init(&free_list); assert(list_empty(&free_list)); assert(alloc_page() == NULL); // 然后分配一个页面应该为空,确实应该为空 unsigned int nr_free_store = nr_free; // 空闲的页面的数目 nr_free = 0; // 然后将他们全部变为0 free_pages(p0 + 2, 3); // 这个玩意能free吗? assert(alloc_pages(4) == NULL); // 因为nr_free=3 assert(PageProperty(p0 + 2) && p0[2].property == 3); assert((p1 = alloc_pages(3)) != NULL); // 给p1分配3块,现在nr_free=0 assert(alloc_page() == NULL); assert(p0 + 2 == p1); p2 = p0 + 1; free_page(p0); // 好吧,释放一个页面, nr_free=1 free_pages(p1, 3); // 现在nr_free = 4 assert(PageProperty(p0) && p0->property == 1); assert(PageProperty(p1) && p1->property == 3); /** p0 p2 p1 end * | | | | | | * ------------------------------- * | N N N N | * | | * ------------------------------- */ assert((p0 = alloc_page()) == p2 - 1); // 这里出错了。我倒是要看一看啦!这里应该不会出错啊,参照上面的图,重新分配的话,会分配p0,恰好是p2-1 free_page(p0); assert((p0 = alloc_pages(2)) == p2 + 1); // 这里是测试first fit的 /** start p2 p0 end * | | | | | | * ------------------------------- * | N N | * | | * ------------------------------- */ free_pages(p0, 2); free_page(p2); /** start p2 p0 end * | | | | | | * ------------------------------- * | N N N N N | * | | * ------------------------------- */ assert((p0 = alloc_pages(5)) != NULL); assert(alloc_page() == NULL); assert(nr_free == 0); nr_free = nr_free_store; // 恢复原来的样子 free_list = free_list_store; free_pages(p0, 5); le = &free_list; while ((le = list_next(le)) != &free_list) { // 又要开始遍历了,这里主要是测试经过这么折腾之后,没有出现页丢失的情况 struct Page *p = le2page(le, page_link); count --, total -= p->property; } assert(count == 0); assert(total == 0); }