/* * * Copyright (c) International Business Machines Corp., 2001 * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * FILE : pth_str02.c * DESCRIPTION : Create n threads * HISTORY: * 05/16/2001 Paul Larson (plars@us.ibm.com) * -Ported * */ #include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "test.h" /* Defines * * DEFAULT_NUM_THREADS: Default number of threads to create, * user can specifiy with [-n] command line option. * * USAGE: usage statement */ #define DEFAULT_NUM_THREADS 10 #define USAGE "\nUsage: %s [-l | -n num_threads] [-d]\n\n" \ "\t-l Test as many as threads as possible\n" \ "\t-n num_threads Number of threads to create\n" \ "\t-d Debug option\n\n" /* * Function prototypes * * sys_error (): System error message function * error (): Error message function * parse_args (): Parses command line arguments */ static void sys_error(const char *, int); static void error(const char *, int); static void parse_args(int, char **); void *thread(void *); /* * Global Variables */ int num_threads = DEFAULT_NUM_THREADS; int test_limit = 0; int debug = 0; char *TCID = "pth_str02"; int TST_TOTAL = 1; /*---------------------------------------------------------------------+ | main () | | ==================================================================== | | | | Function: Main program (see prolog for more details) | | | +---------------------------------------------------------------------*/ int main(int argc, char **argv) { /* * Parse command line arguments and print out program header */ parse_args(argc, argv); if (test_limit) { tst_resm(TINFO, "Creating as many threads as possible"); } else { tst_resm(TINFO, "Creating %d threads", num_threads); } thread(0); /* * Program completed successfully... */ tst_resm(TPASS, "Test passed"); exit(0); } /*---------------------------------------------------------------------+ | thread () | | ==================================================================== | | | | Function: Recursively creates threads while num < num_threads | | | +---------------------------------------------------------------------*/ void *thread(void *parm) { intptr_t num = (intptr_t) parm; pthread_t th; pthread_attr_t attr; size_t stacksize = 1046528; int pcrterr; /* * Create threads while num < num_threads... */ if (test_limit || (num < num_threads)) { if (pthread_attr_init(&attr)) sys_error("pthread_attr_init failed", __LINE__); if (pthread_attr_setstacksize(&attr, stacksize)) sys_error("pthread_attr_setstacksize failed", __LINE__); if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)) sys_error("pthread_attr_setdetachstate failed", __LINE__); /************************************************/ /* pthread_create does not touch errno. It RETURNS the error * if it fails. errno has no bearing on this test, so it was * removed and replaced with return value check(see man page * for pthread_create(); */ pcrterr = pthread_create(&th, &attr, thread, (void *)(num + 1)); if (pcrterr != 0) { if (test_limit) { tst_resm(TINFO, "Testing pthread limit, %d pthreads created.", (int)num); pthread_exit(0); } if (pcrterr == EAGAIN) { tst_resm(TINFO, "Thread [%d]: unable to create more threads!", (int)num); return NULL; } else sys_error("pthread_create failed", __LINE__); } pthread_join(th, NULL); } return 0; /* pthread_exit(0); */ } /*---------------------------------------------------------------------+ | parse_args () | | ==================================================================== | | | | Function: Parse the command line arguments & initialize global | | variables. | | | +---------------------------------------------------------------------*/ static void parse_args(int argc, char **argv) { int i; int errflag = 0; char *program_name = *argv; while ((i = getopt(argc, argv, "dln:?")) != EOF) { switch (i) { case 'd': /* debug option */ debug++; break; case 'l': /* test pthread limit */ test_limit++; break; case 'n': /* number of threads */ num_threads = atoi(optarg); break; case '?': errflag++; break; } } /* If any errors exit program */ if (errflag) { fprintf(stderr, USAGE, program_name); exit(2); } } /*---------------------------------------------------------------------+ | sys_error () | | ==================================================================== | | | | Function: Creates system error message and calls error () | | | +---------------------------------------------------------------------*/ static void sys_error(const char *msg, int line) { char syserr_msg[256]; sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno)); error(syserr_msg, line); } /*---------------------------------------------------------------------+ | error () | | ==================================================================== | | | | Function: Prints out message and exits... | | | +---------------------------------------------------------------------*/ static void error(const char *msg, int line) { fprintf(stderr, "ERROR [line: %d] %s\n", line, msg); tst_resm(TFAIL, "Test failed"); exit(-1); }