1/*
2 * Copyright (c) 2006 Apple Inc.  All Rights Reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30/*
31 *	Order of Execution
32 *
33 *	benchmark_init
34 *
35 *	benchmark_optswitch
36 *
37 *		benchmark_initrun
38 *
39 *			benchmark_initworker
40 *				benchmark_initbatch
41 *					benchmark
42 *				benchmark_finibatch
43 *				benchmark_initbatch
44 *					benchmark
45 *				benchmark_finibatch, etc.
46 *			benchmark_finiworker
47 *
48 *		benchmark_result
49 *
50 *		benchmark_finirun
51 *
52 *	benchmark_fini
53 */
54
55
56
57#ifdef	__sun
58#pragma ident	"@(#)socket.c	1.3	05/08/04 Apple Inc."
59#endif
60
61
62
63#include <unistd.h>
64#include <stdlib.h>
65#include <stdio.h>
66#include <fcntl.h>
67#include <string.h>
68#include <errno.h>
69
70#include "../libmicro.h"
71
72/*
73 * lmbench routines, etc. brought over for this benchmark
74 */
75int  open_file(void* tsd);
76void server(void* tsd);
77
78
79typedef int (*open_f)(void* tsd);
80/*
81 * end of lmbench support routines
82 */
83
84/*
85 *	Your state variables should live in the tsd_t struct below
86 */
87typedef struct {
88	char	fname[L_tmpnam];
89	open_f	fid_f;
90	pid_t	pid;
91	int	sock;
92	int	fid;
93	int	num;
94	int	max;
95	fd_set  set;
96} tsd_t;
97
98static int 	optt = 1;
99static int 	optn = -1;
100static int 	optp = 1;
101static int	optw = 0;
102
103/*
104 * lmbench routines, etc. brought over for this benchmark
105 */
106
107void
108morefds(void)
109{
110#ifdef  RLIMIT_NOFILE
111        struct  rlimit r;
112
113        getrlimit(RLIMIT_NOFILE, &r);
114        r.rlim_cur = r.rlim_max;
115        setrlimit(RLIMIT_NOFILE, &r);
116#endif
117}
118
119int
120open_file(void* tsd)
121{
122	tsd_t* ts = (tsd_t*)tsd;
123	//(void) fprintf(stderr, "open_file: ts->fname = %s\n",ts->fname);
124	return (int) open(ts->fname, O_RDONLY);
125}
126
127void
128server(void* tsd)
129{
130	int pid;
131	tsd_t* ts = (tsd_t*)tsd;
132
133	pid = getpid();
134	ts->pid = 0;
135	//(void) fprintf(stderr, "server: state->fid_f = %i\n",ts->fid_f);
136
137	if (ts->fid_f == open_file) {
138		/* Create a temporary file for clients to open */
139		sprintf(ts->fname, "/tmp/lat_selectXXXXXX");
140		//(void) fprintf(stderr, "server: ts->fname = %s\n",ts->fname);
141		ts->fid = mkstemp(ts->fname);
142		//(void) fprintf(stderr, "server: ts->fname = %s: ts->fid = %d\n",ts->fname, ts->fid);
143
144		if (ts->fid <= 0) {
145			char buf[L_tmpnam+128];
146			sprintf(buf, "lat_select: Could not create temp file %s", ts->fname);
147			perror(buf);
148			exit(1);
149		}
150		close(ts->fid);
151		return;
152	}
153//
154//	this is all for the tcp version of this test only
155//
156// 	/* Create a socket for clients to connect to */
157// 	state->sock = tcp_server(TCP_SELECT, SOCKOPT_REUSE);
158// 	if (state->sock <= 0) {
159// 		perror("lat_select: Could not open tcp server socket");
160// 		exit(1);
161// 	}
162
163	/* Start a server process to accept client connections */
164// 	switch(state->pid = fork()) {
165// 	case 0:
166// 		/* child server process */
167// 		while (pid == getppid()) {
168// 			int newsock = tcp_accept(state->sock, SOCKOPT_NONE);
169// 			read(newsock, &state->fid, 1);
170// 			close(newsock);
171// 		}
172// 		exit(0);
173// 	case -1:
174// 		/* error */
175// 		perror("lat_select::server(): fork() failed");
176// 		exit(1);
177// 	default:
178// 		break;
179// 	}
180}
181
182
183/*
184 * end of lmbench support routines
185 */
186
187/*ARGSUSED*/
188int
189benchmark_initbatch(void *tsd)
190{
191	/*
192	 * initialize your state variables here second
193	 */
194	return (0);
195}
196
197int
198benchmark_finirun()
199{
200	//(void) fprintf(stderr, "benchmark_finirun\n");
201	return (0);
202}
203
204int
205benchmark_init()
206{
207	//(void) fprintf(stderr, "benchmark_init\n");
208	/*
209	 *	the lm_optstr must be defined here or no options for you
210	 *
211	 * 	...and the framework will throw an error
212	 *
213	 */
214	(void) sprintf(lm_optstr, "p:w:n:t:");
215	/*
216	 *	working hypothesis:
217	 *
218	 * 	tsd_t is the struct that we can pass around our
219	 *	state info in
220	 *
221	 *	lm_tsdsize will allocate the space we need for this
222	 *	structure throughout the rest of the framework
223	 */
224	lm_tsdsize = sizeof (tsd_t);
225
226	(void) sprintf(lm_usage,
227		"       [-p parallelism (default 1)]\n"
228		"       [-w warmup (default 0)]\n"
229		"       [-n number of descriptors (default 1)]\n"
230	    "       [-t int (default 1)]\n"
231	    "notes: measures lmbench_select_file\n");
232	lm_defB = 1;
233	return (0);
234}
235
236int
237benchmark_fini()
238{
239	//(void) fprintf(stderr, "benchmark_fini\n");
240	return (0);
241}
242
243int
244benchmark_finibatch(void *tsd)
245{
246	return (0);
247}
248
249char *
250benchmark_result()
251{
252	static char		result = '\0';
253	//(void) fprintf(stderr, "benchmark_result\n");
254	return (&result);
255}
256
257int
258benchmark_finiworker(void *tsd)
259{
260	tsd_t			*ts = (tsd_t *)tsd;
261	int i;
262	// pulls in the lmbench cleanup code
263	//(void) fprintf(stderr, "benchmark_finiworker\n");
264	for (i = 0; i <= ts->max; ++i) {
265		if (FD_ISSET(i, &(ts->set)))
266			close(i);
267	}
268	FD_ZERO(&(ts->set));
269	unlink(ts->fname);
270	return (0);
271}
272
273int
274benchmark_optswitch(int opt, char *optarg)
275{
276	//(void) fprintf(stderr, "benchmark_optswitch\n");
277
278	switch (opt) {
279	case 't':
280		optt = sizetoint(optarg);
281		break;
282	case 'n':
283		optn = sizetoint(optarg);
284		break;
285	case 'p':
286		optp = sizetoint(optarg);
287		break;
288	case 'w':
289		optw = sizetoint(optarg);
290		break;
291	default:
292		return (-1);
293	}
294	return (0);
295}
296
297int
298benchmark_initworker(void *tsd)
299{
300	// pulls in code from lmbench main and initialize
301	int		n = 0;
302	/*
303	 *	initialize your state variables here first
304	 */
305	tsd_t			*ts = (tsd_t *)tsd;
306	int	N, fid, fd;
307
308	/*
309	 * default number of file descriptors
310	 */
311	//(void) fprintf(stderr, "benchmark_initworker\n");
312	ts->num = 200;
313	if (optn > 0) {
314		ts->num = optn;
315	}
316	N = ts->num;
317	//(void) fprintf(stderr, "benchmark_initworker ts->num is %i\n",ts->num);
318
319	/*
320	 *	grab more file descriptors
321	 */
322
323	morefds();
324
325	ts->fid_f = open_file;
326	server(ts);
327	//(void) fprintf(stderr, "benchmark_initworker: returned from server call\n");
328	/*
329	 * Initialize function from lmbench
330	 * for this test
331	 */
332	fid = (*ts->fid_f)(ts);
333	//(void) fprintf(stderr, "initworker: fid is %i\n",fid);
334	if (fid <= 0) {
335		perror("Could not open device");
336		exit(1);
337	}
338	ts->max = 0;
339	FD_ZERO(&(ts->set));
340	//(void) fprintf(stderr, "initworker FD_ZERO: ts->set result is %i\n",ts->set);
341	//(void) fprintf(stderr, "initworker: N is %i\n",N);
342	for (n = 0; n < N; n++) {
343		//(void) fprintf(stderr, "benchmark_initworker: in the loop - N is %i: n is %i\n",N, n);
344		fd = dup(fid);
345		//(void) fprintf(stderr, "benchmark_initworker: dup result is %i\n",fd);
346		//(void) fprintf(stderr, "benchmark_initworker: errno result is %d - \"%s\"\n",errno, strerror(errno));
347
348		if (fd == -1) break;
349		if (fd > ts->max)
350			ts->max = fd;
351		FD_SET(fd, &(ts->set));
352		//(void) fprintf(stderr, "initworker FD_SET: ts->set result is %i\n",ts->set);
353
354	}
355	//(void) fprintf(stderr, "benchmark_initworker: after second macro/loop\n");
356
357	ts->max++;
358	close(fid);
359	//(void) fprintf(stderr, "benchmark_initworker: N is %i: n is %i\n",N, n);
360	if (n != N)
361		exit(1);
362	/* end of initialize function */
363	//(void) fprintf(stderr, "benchmark_initworker: about to exit\n");
364	return (0);
365}
366
367int
368benchmark_initrun()
369{
370	//(void) fprintf(stderr, "benchmark_initrun\n");
371	return (0);
372}
373
374int
375benchmark(void *tsd, result_t *res)
376{
377	/*
378	 *	initialize your state variables here last
379	 *
380	 * 	and realize that you are paying for your initialization here
381	 *	and it is really a bad idea
382	 */
383	tsd_t			*ts = (tsd_t *)tsd;
384	fd_set		nosave;
385	static struct timeval tv;
386
387	//(void) fprintf(stderr, "benchmark\n");
388
389	int			i;
390	//int 		sel_res;
391	tv.tv_sec = 0;
392	tv.tv_usec = 0;
393
394
395	for (i = 0; i < lm_optB; i++) {
396		 nosave = ts->set;
397		 //(void) fprintf(stderr, "benchmark: nosave is %i\n", nosave);
398
399		 select(ts->num, 0, &nosave, 0, &tv);
400		 //(void) fprintf(stderr, "benchmark: select result is %i\n",sel_res);
401		 //(void) fprintf(stderr, "benchmark: errno result is %d - \"%s\"\n",errno, strerror(errno));
402
403
404	}
405	res->re_count = i;
406	return (0);
407}
408
409