/* * pth-stk-test by Davide Libenzi (pthread custom stacks test) * Copyright (C) 2007 Davide Libenzi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * * $ gcc -o pth-stk-test pth-stk-test.c -lpthread * */ #include #include #include #include #include #include #include #define MAX(a, b) ((a) > (b) ? (a): (b)) #define NT_MAX 400 #define NT_TOTAL 1200 #define MAX_MSEC 200 #define STACKSIZE (4096 * 6) #ifdef PTHREAD_STACK_MIN #define THREAD_STACK_MIN MAX(PTHREAD_STACK_MIN, STACKSIZE) #else #define THREAD_STACK_MIN STACKSIZE #endif struct thread_ctx { struct thread_ctx *next; char *stk; int size; pthread_t thid; }; static pthread_cond_t cnd = PTHREAD_COND_INITIALIZER; static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; static struct thread_ctx *tlst; static struct thread_ctx tt[NT_MAX]; static void *thread_proc(void* ptr) { struct thread_ctx *th = (struct thread_ctx *) ptr; long r; fprintf(stdout, "start %p\n", th->stk); if ((char *) &r < th->stk || (char *) &r >= th->stk + th->size) fprintf(stderr, "ERR: stack not set: %p out of [%p, %p)\n", &r, th->stk, th->stk + th->size); r = rand() % 1000; usleep(r * MAX_MSEC); pthread_mutex_lock(&mtx); th->next = tlst; tlst = th; pthread_cond_signal(&cnd); pthread_mutex_unlock(&mtx); return NULL; } int main(int ac, char **av) { int completed, running = 0; int i, err, nt = 128, nt_total = NT_TOTAL, stk_size = THREAD_STACK_MIN; struct thread_ctx *th; pthread_attr_t pa; if (nt > NT_MAX) nt = NT_MAX; for (i = 0; i < nt; i++) { tt[i].size = stk_size; tt[i].stk = mmap(NULL, tt[i].size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (tt[i].stk == MAP_FAILED) { perror("mmap"); exit(1); } pthread_attr_init(&pa); if ((err = pthread_attr_setstack(&pa, tt[i].stk, tt[i].size)) != 0) { fprintf(stderr, "ERR: pthread_attr_setstack failed: %s\n", strerror(err)); exit(1); } if ((err = pthread_create(&tt[i].thid, &pa, thread_proc, &tt[i])) != 0) { fprintf(stderr, "ERR: pthread_create failed: %s\n", strerror(err)); exit(1); } pthread_attr_destroy(&pa); running++; } pthread_mutex_lock(&mtx); for (completed = 0; running > 0;) { pthread_cond_wait(&cnd, &mtx); while ((th = tlst) != NULL) { tlst = tlst->next; pthread_join(th->thid, NULL); fprintf(stdout, "unmap %p\n", th->stk); munmap(th->stk, th->size); completed++; running--; if (completed + running >= nt_total) continue; th->stk = mmap(NULL, th->size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (th->stk == MAP_FAILED) { perror("mmap"); exit(1); } pthread_attr_init(&pa); if ((err = pthread_attr_setstack(&pa, th->stk, th->size)) != 0) { fprintf(stderr, "ERR: pthread_attr_setstack failed: %s\n", strerror(err)); exit(1); } if ((err = pthread_create(&th->thid, &pa, thread_proc, th)) != 0) { fprintf(stderr, "ERR: pthread_create failed: %s\n", strerror(err)); exit(1); } pthread_attr_destroy(&pa); running++; } } pthread_mutex_unlock(&mtx); fprintf(stderr, "Done\n"); return 0; }