#include #include #include #include #include #include #include #include #include static int psize; static void *getsinfo(void *); static void check_stack(caddr_t, caddr_t, uint_t *, uint_t *); static char incore[3072]; int main(int argc, char **argv, char **envp) { pthread_attr_t attr; pthread_t tid; char c; uint_t pres; uint_t awol; void *saddr; psize = getpagesize(); (void) getsinfo("\nmain stack"); /* * Create a thread with the default values */ (void) pthread_attr_init(&attr); (void) pthread_create(&tid, &attr, getsinfo, "\ndefault thread stack"); (void) pthread_join(tid, NULL); /* * Now do a thread with a privately allocated stack * and ensure that stack is faulted in before use * as well as having memory locked down (if we have * sufficient privilege). */ saddr = mmap(0, 68 * 1024, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (saddr != MAP_FAILED) { (void) pthread_attr_setstacksize(&attr, 68 * 1024); (void) pthread_attr_setstackaddr(&attr, saddr); /* * mlocks works only if you're root or have * appropriate privilege. */ (void) mlock(saddr, 68 * 1024); (void) memset(saddr, 0, 68 * 1024); (void) pthread_create(&tid, &attr, getsinfo, "\nallocated thread stack"); (void) pthread_join(tid, NULL); } /* * stop for a moment to gather our breath or use * pmap to poke around. */ (void) read(1, &c, 1); return(0); } static void * getsinfo(void *arg) { stack_t inf; char *str; uint_t i; str = (char *)arg; if (str == NULL) str = "(none)"; inf.ss_sp = 0; inf.ss_size = 0; inf.ss_flags = 0; if (stack_getbounds(&inf) == 0) { caddr_t foo; uint_t pres; uint_t awol; fputs(str, stdout); fputs("\n", stdout); check_stack(inf.ss_sp, inf.ss_sp + inf.ss_size, &pres, &awol); // // inf.ss_sp here is the *bottom* of the stack. // stacks grow downward on x86 (and SPARC) // top of stack is inf.ss_sp + inf.ss_size // printf("\taddr: 0x%p end: 0x%p\n", inf.ss_sp, inf.ss_sp + inf.ss_size); printf("\tss_size: 0x%x %d\n", inf.ss_size, inf.ss_size); printf("\tflags: 0x%x\n", inf.ss_flags); foo = (caddr_t) inf.ss_sp; if (stack_inbounds(foo) == 0) { printf("0x%p out of bounds [1]!\n", foo); } /* * Make it look as if foo is being used... */ printf("", *foo); check_stack(inf.ss_sp, inf.ss_sp + inf.ss_size, &pres, &awol); if (awol != 0) { /* * We should see this on default thread stacks * since the memory is mmaped and is not seen * as stack memory. We will now fault the pages * in and try again. */ uint_t i; uint_t npgs; uint_t tot; tot = 0; npgs = inf.ss_size / psize; for (i = 0; i < npgs; i++) { if (stack_inbounds(foo) != 0) { tot += (uint_t )*foo; foo += psize; } else { printf("0x%p out of bounds![2]\n", foo); break; } } /* * Make it look as if tot is being used so * as to make optimizers leave it alone... */ printf("", tot); check_stack(inf.ss_sp, inf.ss_sp + inf.ss_size, &pres, &awol); } } return(0); } /* * XXX - Use a binary algorithm * * Interesting quirk of mincore() - the address range must be totally * mapped but perhaps not faulted. This is the reason we do the shrinking * stuff to get back to a range where we are totally faulted. * */ static void check_stack(caddr_t saddr, caddr_t eaddr, uint_t *pres, uint_t *awol) { uint_t done; size_t len; (void) printf("check_stack:\n"); done = 0; len = eaddr - saddr; while (done == 0) { if (mincore(saddr, len, incore) == 0) { uint_t i; uint_t res = 0; uint_t nres = 0; uint_t npages; npages = len/psize; for (i = 0; i < npages; i++) { if (incore[i] != 0) res++; else nres++; } printf("\tnpages: %u res: %u nres: %u\n", npages, res, nres); if (pres != NULL) *pres = res; if (awol != NULL) *awol = nres; done = 1; } else if (errno == ENOMEM) { len -= psize; saddr += psize; } } }