Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/18/84; site ut-sally.UUCP Path: utzoo!watmath!clyde!burl!ulysses!gatech!seismo!ut-sally!std-unix From: std-unix@ut-sally.UUCP (Moderator, John Quarterman) Newsgroups: mod.std.unix Subject: limits Message-ID: <3575@ut-sally.UUCP> Date: Tue, 19-Nov-85 18:38:14 EST Article-I.D.: ut-sally.3575 Posted: Tue Nov 19 18:38:14 1985 Date-Received: Thu, 21-Nov-85 04:12:38 EST Organization: IEEE/P1003 Portable Operating System Environment Committee Lines: 225 Approved: jsq@ut-sally.UUCP [ One thing to remember in this discussion is that standards committees are loath to attempt to standardize and innovate at the same time. In this particular posting (as in any others), note that parenthetical remarks in square brackets are those of the moderator only if they end with -mod ] Date: Tue, 19 Nov 85 10:00:44 cst From: allegra!jpl > Date: Sat, 16 Nov 85 15:11:46 est > From: seismo!hadron!jsdy (Joseph S. D. Yao) > > Reading in limits on a per-machine basis is a good idea. > However, the idea of reading in a struct or using a numerical > ID for limits both constrain expandability. I also have > problems with reading directly from limits.h. Let's do it > from a file like /etc/limits. Let's kick it around a little first. I agree with your decision to keep this out of the kernel, but I'll amplify to avoid misunderstandings. 1) I want a general mechanism that applies to all include files, not just limits.h. 2) The kernel is a lousy place to store the limits.h information. It is preposterous to have a separate system call for each value. If you return a structure that includes all the values, you trash existing binaries whenever you make the returned structure larger by adding another value. If you use an index to return a single value, you can only port to systems that agree with you on the index values. 3) It is unworkable. If I want to run my code on a kernel where the maintainers (wisely) refused to clutter up their system, not only can I not port my binaries, I can't even port my source code. KEEP THIS AT USER LEVEL WHERE IT BELONGS! AND WHERE WE CAN CONTROL IT!!! [Pardon me, I seem to be getting carried away in a moderated newsgroup.] [ Now that you mention it.... -mod ] My major gripe with Joseph's solution is point 1) above [although his program can be made to serve for other include files] together with a hard-earned awareness that duplicating information from limit.s in a file like /etc/limits WITHOUT ENFORCING THE CONSISTENCY OF THAT INFORMATION is a sure recipe for disaster. So let's try to address the problems with reading directly from limits.h. To keep the discussion concrete, I have a first-cut at such a program at the end of this diatribe. Type lines like _NFILE NULL frobaz at it, and it will tell you what the values of _NFILE, NULL and frobaz are according to include file . If you actually run the program, you will recognize one problem. It's slow. I claim this is a non-problem: look up your values once, and then run nice and fast. If you READ the program (unencumbered as it is by comments), you will discover more serious problems. 1) The program uses ``cc -E'' and ``sed'' to extract the information. I can't glibly laugh this one off. If you don't have cc (the sed part could be built into the program) on the target machine, you can't look up the values. I see this as by far the most serious problem, even though all the machines I use have cc. 2) It relies on unpromised characteristics of the C preprocessor. The value to be looked up gets sandwiched between ``=== '' and `` ===\n'', and sed expects to find the value on a line of this form. The preprocessor is free to tamper with the format of the line, although, on all the machines I have tried it on, it leaves the format alone. This is not such a big deal. In a practical implementation, the action of sed should probably be replaced by more robust [and efficient] code in the lookup routine. Another alternative would be to generate a real C program, compile it and execute it to generate the results. This would eliminate any peculiarities of the preprocessor, but it would mean that the include file be syntactically complete. For example, you couldn't have any undefined externs, or undeclared types. [I have railed elsewhere on the value of of making all #include files idempotent, and then always including everything you need. I'll spare you a playback.] 3) It only applies to #defined constants. Another non-problem. Variables should be initialized using #defined constants anyway, so there should be a #defined constant around to use. 4) The runtime environment is lacking all sorts of -D and -I arguments and the working directory that may make a difference at compile time. Two answers: if they REALLY make a difference, neither a kernel-based nor a fixed table-based solution will do any better. In fact, it would be real nice if this information were available in symbolic form at compile time, so one could drop the information in the object code, as one does with SCCS or RCS information. It would often be invaluable to be able to snuffle through a binary and determine what compile-time options were used to produce it. If that were possible (I won't hold my breath), the lookup routine could more nearly duplicate what happened at compile time, and address the gripe about the lack of #if's. Enough from me for now. The promised code follows. John P. Linderman Better Living through Portability allegra!jpl #include static char ** mkvect(file, lines) char *file; int lines; { FILE *iop; char **pp, *p; char *malloc(); char **retval = (char **) NULL; int c; int chars = 0; int vects = 1; if ((lines > 0) && ((iop = fopen(file, "r")) != NULL)) { while ((c = getc(iop)) != EOF) { chars++; if (c == '\n') vects++; } if ((ferror(iop) == 0) && (lines == vects)) { retval = (char **) malloc((vects * sizeof(char *)) + chars); if (retval != (char **) NULL) { (void) clearerr(iop); (void) rewind(iop); p = (char *)(retval + vects); pp = retval; *pp++ = p; do { if ((c = getc(iop)) == EOF) { (void) free((char *) retval); retval = (char **) NULL; break; } if (c == '\n') { *p++ = '\0'; *pp++ = p; } else *p++ = c; } while (--chars); if (c != EOF) *--pp = (char *) NULL; } } (void) fclose(iop); } return (retval); } char ** rtlook(inc, val) char *inc; char **val; { #define NAMEZ 12 static char tmplate[NAMEZ] = "/tmp/XXXXXX"; char ifile[NAMEZ]; char ofile[NAMEZ]; char commnd[512]; char *strcpy(), *mktemp(); char **retval = (char **) NULL; int n = 1; FILE *iop, *popen(); (void) strcpy(ifile, tmplate); (void) mktemp(ifile); if ((iop = fopen(ifile, "w")) != NULL) { (void) strcpy(ofile, tmplate); (void) mktemp(ofile); (void) fprintf(iop, "#include %s\n", inc); for (; (*val != NULL) && (**val != '\0'); n++, val++) { (void) fprintf(iop, "\n#ifdef %s\n", *val); (void) fprintf(iop, "=== %s ===\n", *val); (void) fprintf(iop, "#else\n"); (void) fprintf(iop, "=== ===\n"); (void) fprintf(iop, "#endif\n"); } if ((fflush(iop) != EOF) && !ferror(iop) && (fclose(iop) != EOF)) { (void) sprintf(commnd, "cc -E %s | sed -n '/^=== \\(.*\\) ===$/s//\\1/p' > %s", ifile, ofile); (void) system(commnd); retval = mkvect(ofile, n); (void) unlink(ofile); } (void) unlink(ifile); } return (retval); } #include main() { char line[512]; char *p, **qq, **pp, *q[300]; int n; while (gets(line) != NULL) { for (p = line, pp = q; *p;) { while (isspace(*p)) *p++ = '\0'; if (*p) { *pp++ = p; do p++; while(*p && !isspace(*p)); } } *pp = NULL; if (pp != q) { if ((qq = rtlook(q[0], q+1)) == NULL) { (void) printf("lookup failed\n"); } else { n = 0; for (pp = q+1; (*pp != (char *) NULL) && **pp; pp++, n++) { (void) printf("%s => %s\n", *pp, qq[n]); } (void) free((char *) qq); } } } } Volume-Number: Volume 3, Number 27