1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  *  FILE        : pth_str02.c
22  *  DESCRIPTION : Create n threads
23  *  HISTORY:
24  *    05/16/2001 Paul Larson (plars@us.ibm.com)
25  *      -Ported
26  *
27  */
28 
29 #include <pthread.h>
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include "test.h"
36 
37 /* Defines
38  *
39  * DEFAULT_NUM_THREADS: Default number of threads to create,
40  * user can specifiy with [-n] command line option.
41  *
42  * USAGE: usage statement
43  */
44 
45 #define DEFAULT_NUM_THREADS 		10
46 #define USAGE	"\nUsage: %s [-l | -n num_threads] [-d]\n\n" \
47 		"\t-l		     Test as many as threads as possible\n" \
48 		"\t-n num_threads    Number of threads to create\n" \
49 		"\t-d                Debug option\n\n"
50 
51 /*
52  * Function prototypes
53  *
54  * sys_error (): System error message function
55  * error (): Error message function
56  * parse_args (): Parses command line arguments
57  */
58 
59 static void sys_error(const char *, int);
60 static void error(const char *, int);
61 static void parse_args(int, char **);
62 void *thread(void *);
63 
64 /*
65  * Global Variables
66  */
67 
68 int num_threads = DEFAULT_NUM_THREADS;
69 int test_limit = 0;
70 int debug = 0;
71 
72 char *TCID = "pth_str02";
73 int TST_TOTAL = 1;
74 
75 /*---------------------------------------------------------------------+
76 |                               main ()                                |
77 | ==================================================================== |
78 |                                                                      |
79 | Function:  Main program  (see prolog for more details)               |
80 |                                                                      |
81 +---------------------------------------------------------------------*/
main(int argc,char ** argv)82 int main(int argc, char **argv)
83 {
84 	/*
85 	 * Parse command line arguments and print out program header
86 	 */
87 	parse_args(argc, argv);
88 
89 	if (test_limit) {
90 		tst_resm(TINFO, "Creating as many threads as possible");
91 	} else {
92 		tst_resm(TINFO, "Creating %d threads", num_threads);
93 	}
94 	thread(0);
95 
96 	/*
97 	 * Program completed successfully...
98 	 */
99 	tst_resm(TPASS, "Test passed");
100 	exit(0);
101 }
102 
103 /*---------------------------------------------------------------------+
104 |                               thread ()                              |
105 | ==================================================================== |
106 |                                                                      |
107 | Function:  Recursively creates threads while num < num_threads       |
108 |                                                                      |
109 +---------------------------------------------------------------------*/
thread(void * parm)110 void *thread(void *parm)
111 {
112 	intptr_t num = (intptr_t) parm;
113 	pthread_t th;
114 	pthread_attr_t attr;
115 	size_t stacksize = 1046528;
116 	int pcrterr;
117 
118 	/*
119 	 * Create threads while num < num_threads...
120 	 */
121 	if (test_limit || (num < num_threads)) {
122 
123 		if (pthread_attr_init(&attr))
124 			sys_error("pthread_attr_init failed", __LINE__);
125 		if (pthread_attr_setstacksize(&attr, stacksize))
126 			sys_error("pthread_attr_setstacksize failed", __LINE__);
127 		if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE))
128 			sys_error("pthread_attr_setdetachstate failed",
129 				  __LINE__);
130 		/************************************************/
131 		/*   pthread_create does not touch errno.  It RETURNS the error
132 		 *   if it fails.  errno has no bearing on this test, so it was
133 		 *   removed and replaced with return value check(see man page
134 		 *   for pthread_create();
135 		 */
136 		pcrterr = pthread_create(&th, &attr, thread, (void *)(num + 1));
137 		if (pcrterr != 0) {
138 			if (test_limit) {
139 				tst_resm(TINFO,
140 					 "Testing pthread limit, %d pthreads created.",
141 					 (int)num);
142 				pthread_exit(0);
143 			}
144 			if (pcrterr == EAGAIN) {
145 				tst_resm(TINFO,
146 					 "Thread [%d]: unable to create more threads!",
147 					 (int)num);
148 				return NULL;
149 			} else
150 				sys_error("pthread_create failed", __LINE__);
151 		}
152 		pthread_join(th, NULL);
153 	}
154 
155 	return 0;
156 	/*
157 	   pthread_exit(0);
158 	 */
159 }
160 
161 /*---------------------------------------------------------------------+
162 |                             parse_args ()                            |
163 | ==================================================================== |
164 |                                                                      |
165 | Function:  Parse the command line arguments & initialize global      |
166 |            variables.                                                |
167 |                                                                      |
168 +---------------------------------------------------------------------*/
parse_args(int argc,char ** argv)169 static void parse_args(int argc, char **argv)
170 {
171 	int i;
172 	int errflag = 0;
173 	char *program_name = *argv;
174 
175 	while ((i = getopt(argc, argv, "dln:?")) != EOF) {
176 		switch (i) {
177 		case 'd':	/* debug option */
178 			debug++;
179 			break;
180 		case 'l':	/* test pthread limit */
181 			test_limit++;
182 			break;
183 		case 'n':	/* number of threads */
184 			num_threads = atoi(optarg);
185 			break;
186 		case '?':
187 			errflag++;
188 			break;
189 		}
190 	}
191 
192 	/* If any errors exit program */
193 	if (errflag) {
194 		fprintf(stderr, USAGE, program_name);
195 		exit(2);
196 	}
197 }
198 
199 /*---------------------------------------------------------------------+
200 |                             sys_error ()                             |
201 | ==================================================================== |
202 |                                                                      |
203 | Function:  Creates system error message and calls error ()           |
204 |                                                                      |
205 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)206 static void sys_error(const char *msg, int line)
207 {
208 	char syserr_msg[256];
209 
210 	sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
211 	error(syserr_msg, line);
212 }
213 
214 /*---------------------------------------------------------------------+
215 |                               error ()                               |
216 | ==================================================================== |
217 |                                                                      |
218 | Function:  Prints out message and exits...                           |
219 |                                                                      |
220 +---------------------------------------------------------------------*/
error(const char * msg,int line)221 static void error(const char *msg, int line)
222 {
223 	fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
224 	tst_resm(TFAIL, "Test failed");
225 	exit(-1);
226 }
227