xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.lib/in.dhcpd/tests/test_dstore.c (revision 1914:8a8c5f225b1b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdio_ext.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <sys/time.h>
34 #include <fcntl.h>
35 #include <sys/fcntl.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <limits.h>
39 #include <sys/socket.h>
40 #include <net/if.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <thread.h>
44 #include <tnf/probe.h>
45 
46 #include <netinet/dhcp.h>
47 #include <locale.h>
48 #include <signal.h>
49 #include <tnf/probe.h>
50 
51 #include <dhcp_svc_confopt.h>
52 #include <dhcp_svc_private.h>
53 #include <dhcp_impl.h>
54 
55 #ifdef	DEBUG
56 #include <mtmalloc.h>
57 #endif				/* DEBUG */
58 
59 /*
60  * Global variables.
61  */
62 int		verbose = 0;
63 thread_t	*tp;
64 cond_t		never;
65 volatile time_t *timp;
66 volatile int    tms;
67 char		*fl;
68 mutex_t		mtx;
69 mutex_t		thread_mtx;
70 volatile ulong_t ops_outstanding;
71 
72 static volatile ulong_t tops, otops;
73 static volatile ulong_t minops[6];
74 static volatile time_t mintim[6];
75 static volatile int minind;
76 long		sample_time = 10L;
77 long		nsamples = 2;
78 
79 static volatile time_t start, ostart;
80 volatile time_t ustart;
81 volatile int    time_to_go;
82 volatile int    spawn_helper;
83 char		b[1024 * 1024];
84 volatile double slp;
85 volatile int    worktype;
86 thread_t	sigthread;
87 volatile int    old, new, unstarted;
88 volatile uint_t	threads;
89 volatile unsigned int douwork = 0;
90 volatile int    dofsync = 0;
91 volatile int    domalloc = 0;
92 volatile int    dofork = 0;
93 thread_t	opnthread;
94 volatile int	doopen = 0;
95 
96 dsvc_datastore_t datastore;	/* Datastore for container access */
97 
98 #define	MAXTABLE	1024
99 int		ntable;
100 
101 dn_rec_list_t  *thread_dncp[MAXTABLE];
102 dsvc_handle_t   dh[MAXTABLE];	/* data handle */
103 struct in_addr  net[MAXTABLE];
104 uint_t		nrecords[MAXTABLE];
105 char		*network;
106 
107 typedef struct work {
108 	boolean_t	isthreaded;
109 	int		thread;
110 	cond_t		cv;
111 	mutex_t		mtx;
112 	dn_rec_t	*dnp;
113 }work_t;
114 
115 void
free_work_t(work_t * wptr)116 free_work_t(work_t *wptr) {
117 	free(wptr->dnp);
118 	free(wptr);
119 }
120 /*
121  * Simulated binary datastore work
122  */
123 /* ARGSUSED */
124 static void    *
uwork(void * argp)125 uwork(void *argp)
126 {
127 	int		i;
128 	int		err;
129 	int		fd;
130 	long		block;
131 	work_t		*wptr = argp;
132 	char		*ptr;
133 	size_t		size = ((random() & (domalloc - 1)) + 0x200) &
134 				~(0x200 - 1);
135 	int		wtype;
136 
137 	if (domalloc)
138 		ptr = malloc(size);
139 	else
140 		ptr = b;
141 
142 	if (wptr->isthreaded) {
143 		(void) mutex_lock(&wptr->mtx);
144 	}
145 	i = wptr->thread;
146 
147 	TNF_PROBE_1(uwork, "work", "uwork%debug 'in function work'",
148 		    tnf_long, size, size);
149 
150 	wtype = worktype == 0 ? random() & 0x7 : worktype;
151 	block = (random() & (douwork - 1)) + (tms / 0x200) + 1;
152 
153 	/* prewrite legal records */
154 	if (timp[i] == NULL && ustart == 0) {
155 		ustart = time(NULL);
156 		wtype = 4;
157 		block = (tms / 0x200) + 1;
158 		size = sizeof (b);
159 		ptr = b;
160 	}
161 	timp[i] = time(NULL);
162 	fd = open(fl, O_RDWR);
163 	(void) write(fd, (char *)timp, tms);
164 	(void) close(fd);
165 
166 	if (wtype == 4) {
167 
168 		TNF_PROBE_2(uwork_write, "work",
169 			    "uwork_write%debug 'in function work'",
170 			    tnf_long, block, block,
171 			    tnf_long, size, size);
172 
173 		fd = open(fl, O_RDWR);
174 		(void) lseek(fd, block * 0x200, 0L);
175 		err = write(fd, ptr, size);
176 		(void) close(fd);
177 
178 		TNF_PROBE_1(uwork_write_end, "work",
179 			    "uwork_write_end%debug 'in function work'",
180 			    tnf_long, err, err);
181 
182 	} else if (wtype == 3 && dofsync) {
183 
184 		TNF_PROBE_0(uwork_fsync, "work",
185 			    "uwork_fsync%debug 'in function work'");
186 
187 		fd = open(fl, O_RDWR);
188 		err = fsync(fd);
189 		(void) close(fd);
190 
191 		TNF_PROBE_1(uwork_fsync_end, "work",
192 			    "uwork_fsync_end%debug 'in function work'",
193 			    tnf_long, err, err);
194 	} else {
195 		TNF_PROBE_2(uwork_read, "work",
196 			    "uwork_read%debug 'in function work'",
197 			    tnf_long, block, block,
198 			    tnf_long, size, size);
199 
200 		fd = open(fl, O_RDWR);
201 		(void) lseek(fd, block * 0x200, 0L);
202 		err = read(fd, ptr, size);
203 		(void) close(fd);
204 
205 		TNF_PROBE_1(uwork_read_end, "work",
206 			    "uwork_read_end%debug 'in function work'",
207 			    tnf_long, err, err);
208 
209 	}
210 	if (domalloc && ptr != b)
211 		free(ptr);
212 
213 	if (wptr->isthreaded) {
214 		(void) mutex_unlock(&wptr->mtx);
215 		cond_signal(&wptr->cv);
216 		TNF_PROBE_0(work_end, "work", "");
217 		thr_exit(NULL);
218 	}
219 	TNF_PROBE_0(uwork_end, "work", "");
220 
221 	return ((void *) NULL);
222 }
223 
224 /*
225  * Simulated datastore work
226  */
227 static void    *
work(void * argp)228 work(void *argp)
229 {
230 	int		i, j;
231 	dn_rec_t	*dnp;
232 	int		err;
233 	work_t		*wptr = argp;
234 	uchar_t		cid_len;
235 	char		*ptr;
236 	uint32_t	query;
237 	dn_rec_t	dn, ndn;
238 	dn_rec_list_t	*dncp = NULL;
239 	uint_t		crecords, irecords;
240 	int		wtype;
241 	int		firsttime = 0;
242 	int		op;
243 	size_t		size = ((random() & (domalloc - 1)) + 0x100) &
244 			~(0x1000 - 1);
245 	int		table;
246 
247 	if (domalloc)
248 		ptr = malloc(size);
249 	else
250 		ptr = b;
251 
252 	irecords = (random() & 0xff) + 1;
253 	if (irecords == 12) {
254 		irecords = (uint_t)-1;
255 	}
256 	if (wptr->isthreaded) {
257 		(void) mutex_lock(&wptr->mtx);
258 	}
259 	i = wptr->thread;
260 	dnp = wptr->dnp;
261 
262 	table = i % ntable;
263 	dn = *dnp;
264 
265 	cid_len = 7;
266 
267 	if (worktype == 0) {
268 		wtype = random() & 0x7;
269 		if (wtype == 4)
270 			wtype--;
271 	} else
272 		wtype = worktype;
273 
274 	/* preload a legal record */
275 	if (timp[i] == NULL) {
276 		wtype = 3;
277 		firsttime = 1;
278 		irecords = threads * 2;
279 		(void) mutex_lock(&thread_mtx);
280 		if ((dncp = thread_dncp[table]) != NULL) {
281 			thread_dncp[table] = dncp->dnl_next;
282 			*dnp = *(dncp->dnl_rec);
283 			dncp->dnl_next = NULL;
284 			wtype = -1;
285 			(void) mutex_unlock(&thread_mtx);
286 		}
287 	}
288 	TNF_PROBE_2(work, "work", "work%debug 'in function work'",
289 		    tnf_ulong, worktype, wtype,
290 		    tnf_ulong, irecords, irecords);
291 
292 	timp[i] = time(NULL);
293 	crecords = 0;
294 	DSVC_QINIT(query);
295 	switch (wtype) {
296 	case -1:
297 		break;
298 	case 1:
299 		switch (random() & 0x7) {
300 		case 1:
301 			for (j = 0; j < cid_len; j++)
302 				dn.dn_cid[j] = random() & 0xff;
303 			break;
304 		case 2:
305 			for (j = 0; j < cid_len; j++)
306 				dn.dn_cid[j] = '\0';
307 			dn.dn_cid_len = 1;
308 			break;
309 		}
310 		DSVC_QEQ(query, DN_QCID);
311 
312 		/* LINTED */
313 		TNF_PROBE_2(work_cid, "work work_cid",
314 			    "work_cid%debug 'in function work'",
315 			    tnf_ulong, cid, *(ulong_t *)&dn.dn_cid,
316 			    tnf_ulong, cid_len, dn.dn_cid_len);
317 
318 		err = lookup_dd(dh[table], B_TRUE, query, -1,
319 			    (const void *)&dn, (void **)&dncp, &crecords);
320 
321 		TNF_PROBE_2(work_cid_end, "work work_cid",
322 			    "work_cid_end%debug 'in function work'",
323 			    tnf_ulong, err, err,
324 			    tnf_ulong, crecords, crecords);
325 
326 		if (crecords > 0 && dncp)
327 			*dnp = *(dncp->dnl_rec);
328 		break;
329 
330 	case 2:
331 		switch (random() & 0x7) {
332 		case 1:
333 			dn.dn_cip.s_addr = random();
334 			break;
335 		case 2:
336 			dn.dn_cip.s_addr = net[table].s_addr |
337 				(random() & (nrecords[table] - 1));
338 			break;
339 		}
340 
341 		DSVC_QEQ(query, DN_QCIP);
342 
343 		TNF_PROBE_1(work_cip, "work work_cip",
344 			    "work_cip%debug 'in function work'",
345 			    tnf_ulong, cip, dn.dn_cip.s_addr);
346 
347 		err = lookup_dd(dh[table], B_TRUE, query, -1,
348 			    (const void *)&dn, (void **)&dncp, &crecords);
349 
350 		TNF_PROBE_2(work_cip_end, "work work_cip",
351 			    "work_cip_end%debug 'in function work'",
352 			    tnf_ulong, err, err,
353 			    tnf_ulong, crecords, crecords);
354 
355 		if (crecords > 0 && dncp)
356 			*dnp = *(dncp->dnl_rec);
357 		break;
358 	case 3:
359 		op = random() & 0x7;
360 		if (firsttime)
361 			op = 2;
362 
363 		switch (op) {
364 		case 1:
365 			DSVC_QNEQ(query, DN_QLEASE);
366 			dn.dn_lease = 0;
367 			break;
368 		case 2:
369 			DSVC_QEQ(query, DN_QCID);
370 			for (j = 0; j < cid_len; j++)
371 				dn.dn_cid[j] = '\0';
372 			dn.dn_cid_len = 1;
373 			break;
374 		}
375 
376 		TNF_PROBE_2(work_read, "work work_read",
377 			    "work_read%debug 'in function work'",
378 			    tnf_ulong, query, query,
379 			    tnf_ulong, cid_len, dn.dn_cid_len);
380 
381 		err = lookup_dd(dh[table], B_TRUE, query, irecords,
382 			    (const void *)&dn, (void **)&dncp, &crecords);
383 
384 		TNF_PROBE_2(work_read_end, "work work_read",
385 			    "work_read_end%debug 'in function work'",
386 			    tnf_ulong, err, err,
387 			    tnf_ulong, crecords, crecords);
388 
389 		if (crecords > 0 && dncp) {
390 			*dnp = *(dncp->dnl_rec);
391 			if (firsttime) {
392 				thread_dncp[table] = dncp->dnl_next;
393 				dncp->dnl_next = NULL;
394 				mutex_unlock(&thread_mtx);
395 			}
396 		}
397 		break;
398 	case 4:
399 		op = dnp->dn_lease & 0x3;
400 		switch (op) {
401 		case 0:
402 			/* write record w/ cid */
403 			ndn = *dnp;
404 			ndn.dn_lease = (htonl(time(NULL)) & ~0x3) + 1;
405 			ndn.dn_cid_len = 14;
406 			for (j = 0; j < ndn.dn_cid_len; j++)
407 				ndn.dn_cid[j] = random() & 0xff;
408 
409 			/* LINTED */
410 			TNF_PROBE_2(work1_modify, "work work1_modify",
411 				    "work1_modify%debug 'in function work'",
412 				    tnf_ulong, cid, *(ulong_t *)&ndn.dn_cid,
413 				    tnf_ulong, cid_len, ndn.dn_cid_len);
414 
415 			err = modify_dd_entry(dh[table], dnp, &ndn);
416 			if (err != DSVC_SUCCESS && verbose) {
417 				fprintf(stderr, "work: %d %d error %d\n",
418 					wtype, op, err);
419 			}
420 
421 			TNF_PROBE_1(work1_modify_end, "work work1_modify_end",
422 				    "work1_modify_end%debug 'in function work'",
423 				    tnf_ulong, err, err);
424 			*dnp = ndn;
425 			break;
426 		case 1:
427 			/* re-read record w/ cid */
428 			DSVC_QEQ(query, DN_QCID);
429 			TNF_PROBE_2(work_read1, "work work_read1",
430 				    "work_read1%debug 'in function work'",
431 				    tnf_ulong, query, query,
432 				    tnf_ulong, cid_len, dn.dn_cid_len);
433 
434 			err = lookup_dd(dh[table], B_TRUE, query, - 1,
435 					(const void *)dnp, (void **)&dncp,
436 					&crecords);
437 			TNF_PROBE_2(work_read1_end, "work work_read1",
438 				    "work_read1_end%debug 'in function work'",
439 				    tnf_ulong, err, err,
440 				    tnf_ulong, crecords, crecords);
441 
442 			if ((err != DSVC_SUCCESS || crecords < 1) && verbose) {
443 				fprintf(stderr, "work: %d %d error %d %d\n",
444 					wtype, op, err, crecords);
445 			}
446 			dnp->dn_lease++;
447 			break;
448 		case 2:
449 			/* write free record */
450 			dnp->dn_lease--;
451 			ndn = *dnp;
452 			DSVC_QEQ(query, DN_QCID);
453 			for (j = 0; j < cid_len; j++)
454 				ndn.dn_cid[j] = '\0';
455 			ndn.dn_cid_len = 1;
456 			ndn.dn_lease = 0;
457 
458 			TNF_PROBE_2(work_modify2, "work work_modify2",
459 				    "work_modify2%debug 'in function work'",
460 				    tnf_ulong, cid, *(ulong_t *)&ndn.dn_cid,
461 				    tnf_ulong, cid_len, ndn.dn_cid_len);
462 
463 			err = modify_dd_entry(dh[table], dnp, &ndn);
464 
465 			TNF_PROBE_1(work_modify2_end, "work work_modify2_end",
466 			    "work_modify2_end%debug 'in function work'",
467 				    tnf_ulong, err, err);
468 
469 			if (err != DSVC_SUCCESS && verbose) {
470 				fprintf(stderr, "work: %d %d error %d\n",
471 					wtype, op, err);
472 			}
473 			*dnp = ndn;
474 			break;
475 		}
476 		break;
477 
478 
479 	default:
480 		ndn = *dnp;
481 		ndn.dn_cid_len = cid_len;
482 		switch (random() & 0x1) {
483 		case 0:
484 			for (j = 0; j < cid_len; j++)
485 				ndn.dn_cid[j] = random() & 0xff;
486 			break;
487 		case 1:
488 			for (j = 0; j < cid_len; j++)
489 				ndn.dn_cid[j] = '\0';
490 			ndn.dn_cid_len = 1;
491 			break;
492 		}
493 		ndn.dn_lease = htonl(time(NULL));
494 
495 		/* LINTED */
496 		TNF_PROBE_2(work_modify, "work work_modify",
497 			    "work_modify%debug 'in function work'",
498 			    tnf_ulong, cid, *(ulong_t *)&ndn.dn_cid,
499 			    tnf_ulong, cid_len, ndn.dn_cid_len);
500 
501 		err = modify_dd_entry(dh[table], dnp, &ndn);
502 		if (err != DSVC_SUCCESS && err != DSVC_COLLISION) {
503 			if (verbose)
504 				fprintf(stderr, "modify: error %d\n", err);
505 		}
506 
507 		TNF_PROBE_1(work_modify_end, "work work_modify_end",
508 			    "work_modify_end%debug 'in function work'",
509 			    tnf_ulong, err, err);
510 
511 		*dnp = ndn;
512 		break;
513 	}
514 
515 	if (domalloc)
516 		free(ptr);
517 
518 	if (wptr->isthreaded) {
519 		(void) mutex_unlock(&wptr->mtx);
520 		cond_signal(&wptr->cv);
521 		TNF_PROBE_2(work_end, "work", "work_end%debug 'in function "
522 				"work'", tnf_ulong, err, err,
523 				tnf_ulong, crecords, crecords);
524 		thr_exit(NULL);
525 	}
526 	if (dncp)
527 		free_dd_list(dh[table], dncp);
528 
529 	TNF_PROBE_2(work_end, "work", "work_end%debug 'in function work'",
530 		    tnf_ulong, err, err,
531 		    tnf_ulong, crecords, crecords);
532 
533 	return ((void *) NULL);
534 }
535 
536 /*
537  * Worker thread.
538  */
539 static void    *
dowork(void * argp)540 dowork(void *argp)
541 {
542 	int		i = (int)argp;
543 	timestruc_t	to;
544 	work_t		*wptr;
545 	dn_rec_t 	dn;
546 
547 	(void) memset((char *)&dn, '\0', sizeof (dn));
548 	(void) mutex_lock(&mtx);
549 	for (; time_to_go == 0; ) {
550 		TNF_PROBE_1(dowork, "dowork",
551 			    "dowork%debug 'in function dowork'",
552 			    tnf_long, thread_number, i);
553 
554 		to.tv_sec = time(NULL) + random() & 0x3;
555 		to.tv_nsec = 0;
556 
557 		if (slp > 0.0) {
558 			to.tv_sec = time(NULL) + slp;
559 			to.tv_nsec = (slp - (double)((int)slp)) * 1000000000.0;
560 		} else if (slp < 0.0) {
561 			to.tv_sec = time(NULL) + abs((int)slp);
562 			to.tv_nsec = (slp + abs((double)((int)slp))) *
563 				1000000000.0;
564 		}
565 		/* give up processor */
566 		if (slp != 0.0) {
567 			(void) mutex_unlock(&mtx);
568 			(void) cond_timedwait(&never, &mtx, &to);
569 		}
570 		ops_outstanding++;
571 		(void) mutex_unlock(&mtx);
572 
573 		if (spawn_helper) {
574 			wptr = (work_t *)malloc(sizeof (work_t));
575 			wptr->thread = i * 2;
576 			wptr->isthreaded = B_TRUE;
577 			(void) cond_init(&wptr->cv, USYNC_THREAD, NULL);
578 			(void) mutex_init(&wptr->mtx, USYNC_THREAD, NULL);
579 			(void) mutex_lock(&wptr->mtx);
580 
581 			/* fire up helper thread */
582 			if (thr_create(NULL, 0, douwork ? uwork : work,
583 					(void *)wptr, 0, &tp[i * 2]) != 0)
584 				fprintf(stderr, "can't spawn lthread %d\n", i);
585 
586 			/* wait for completion */
587 			(void) cond_wait(&wptr->cv, &wptr->mtx);
588 			(void) mutex_unlock(&wptr->mtx);
589 			(void) thr_join(tp[i * 2], NULL, NULL);
590 			free_work_t(wptr);
591 		} else {
592 			wptr = (work_t *)malloc(sizeof (work_t));
593 			wptr->isthreaded = B_FALSE;
594 			wptr->thread = i;
595 			wptr->dnp = &dn;
596 			if (douwork) {
597 				(void) uwork((void *)wptr);
598 			} else {
599 				(void) work((void *)wptr);
600 			}
601 			free_work_t(wptr);
602 		}
603 		(void) mutex_lock(&mtx);
604 		tops++;
605 		ops_outstanding--;
606 		TNF_PROBE_0(dowork_end, "dowork", "");
607 	}
608 	(void) mutex_unlock(&mtx);
609 	thr_exit(NULL);
610 
611 	return ((void *) NULL);
612 }
613 
614 /*
615  * Signal handler routine. All signals handled by calling thread.
616  */
617 /* ARGSUSED */
618 static void    *
sig_handle(void * arg)619 sig_handle(void *arg)
620 {
621 	int		i;
622 	int		sig;
623 	sigset_t	set;
624 	timespec_t	ts;
625 	siginfo_t	si;
626 	int		go;
627 	int		oldi;
628 	ulong_t		minavg;
629 	time_t		minstime;
630 
631 	(void) sigfillset(&set); /* catch all signals */
632 
633 	ts.tv_sec = sample_time;
634 	ts.tv_nsec = 0L;
635 
636 	for (;;) {
637 		(void) mutex_lock(&mtx);
638 		go = time_to_go;
639 		(void) mutex_unlock(&mtx);
640 		if (go)
641 			break;
642 
643 		switch (sig = sigtimedwait(&set, &si, &ts)) {
644 		case -1:
645 		case SIGHUP:
646 			old = time(NULL);
647 			oldi = new = unstarted = 0;
648 			for (i = 0; i < threads; i++) {
649 				if (timp[i] == NULL)
650 					unstarted++;
651 				if (timp[i] && timp[i] < old) {
652 					old = timp[i];
653 					oldi = i;
654 				}
655 				if (timp[i] && timp[i] > new)
656 					new = timp[i];
657 			}
658 
659 			if (start == 0) {
660 				/* toss initial sample */
661 				ostart = start = time(NULL);
662 				(void) mutex_lock(&mtx);
663 				otops = tops = 0;
664 				(void) mutex_unlock(&mtx);
665 				minind = 0;
666 			} else {
667 				minops[minind] = tops - otops;
668 				mintim[minind] = ostart;
669 				otops = tops;
670 				ostart = time(NULL);
671 				minind = minind + 1 > nsamples - 1 ? 0 :
672 				    minind + 1;
673 				minstime = 0;
674 				minavg = 0;
675 				for (i = 0; i < nsamples; i++) {
676 					if (mintim[i])
677 						minavg += minops[i];
678 					if (minstime == 0)
679 						minstime = mintim[i];
680 					else if (mintim[i] &&
681 					    mintim[i] < minstime)
682 						minstime = mintim[i];
683 				}
684 
685 				fprintf(stderr, "%9.9d: Totops %d Curr %d "\
686 				    "Persec %4.2f (%4.2f) Oldest %d (%d) "\
687 				    "Gap %d Unstarted %d\n",
688 					time(NULL),
689 					tops,
690 					ops_outstanding,
691 					(double)tops / (double)(time(NULL)
692 						- start),
693 					(double)minavg / (double)(time(NULL)
694 						- minstime),
695 					time(NULL) - old,
696 					oldi,
697 					new - old,
698 					unstarted);
699 			}
700 			break;
701 		default:
702 			(void) mutex_lock(&mtx);
703 			time_to_go++;
704 			(void) mutex_unlock(&mtx);
705 			break;
706 		}
707 	}
708 	thr_exit(NULL);
709 	return ((void *) sig);	/* NOTREACHED */
710 }
711 
712 int	fd[0x10000];
713 /*
714  * open handler routine.
715  */
716 /* ARGSUSED */
717 static void    *
open_handle(void * arg)718 open_handle(void *arg)
719 {
720 	int	i;
721 
722 	for (;;) {
723 		for (i = 0; i < doopen; i++)
724 			fd[i] = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
725 		for (i = 0; i < doopen; i++)
726 			if (fd[i] >= 0)
727 				(void) close(fd[i]);
728 	}
729 	return ((void *) NULL);	/* NOTREACHED */
730 }
731 /*
732  * test_dstore network[,network] worktype[,worktype] <thr_create flags>
733  *	 <spawn_helper> <nlwp> <nthread> <file> <sleeptype>
734  *
735  * network - list of network containers, comma-separated
736  * worktypes:
737  *	0 - random
738  *	1 - cid reads
739  *	2 - cip reads
740  *	3 - whole db reads
741  *	4 - write read write (simulate simple test)
742  *	5 - modify writes
743  * sleeptypes:
744  * 	N == * condwait N sec.nsec period
745  * 	-N == condwait a random 1-N sec.nsec period
746  */
main(int c,char ** v)747 main(int c, char **v)
748 {
749 	int		i;
750 	timespec_t	to;
751 	uint_t		flags;
752 	int		err;
753 	sigset_t	set;
754 	dhcp_confopt_t *dsp = NULL;
755 	uint32_t	query;
756 	dn_rec_t	dn;
757 	dn_rec_list_t  *dncp = NULL;
758 	struct rlimit   rl;
759 	char		*np;
760 
761 #ifdef	DEBUG
762 	mallocctl(MTDEBUGPATTERN, 1);
763 	mallocctl(MTINITBUFFER, 1);
764 #endif				/* DEBUG */
765 
766 	srandom(time(NULL));
767 
768 	if (dofork)
769 		if (fork() != 0)
770 			exit(0);
771 
772 	if ((err = getrlimit(RLIMIT_NOFILE, &rl)) < 0) {
773 		(void) fprintf(stderr, "Cannot get open file limit: %s\n",
774 				strerror(errno));
775 	}
776 	/* handle cases where limit is infinity */
777 	if (rl.rlim_cur == RLIM_INFINITY) {
778 		rl.rlim_cur = (rl.rlim_max == RLIM_INFINITY) ?
779 			OPEN_MAX : rl.rlim_max;
780 	}
781 	/* set NOFILE to unlimited */
782 	rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
783 	if ((err = setrlimit(RLIMIT_NOFILE, &rl)) < 0) {
784 		(void) fprintf(stderr, "Cannot set open file limit: %s\n",
785 				strerror(errno));
786 	}
787 	(void) enable_extended_FILE_stdio(-1, -1);
788 
789 	if (c == 1) {
790 		(void) fprintf(stderr,
791 				"/*\n"\
792 				" * test_dstore network[,network] worktype[,"\
793 					"worktype] <thr_create flags>\n"\
794 				" *	 <spawn_helper> <nlwp> <nthread> "\
795 					"<file> <sleeptype>\n"\
796 				" *\n"\
797 				" * network - list of network containers, "\
798 					"comma-separated\n"\
799 				" * worktypes:\n"\
800 				" *	0 - random\n"\
801 				" *	1 - cid reads\n"\
802 				" *	2 - cip reads\n"\
803 				" *	3 - whole db reads\n"\
804 				" *	4 - write read write (simulate simple"\
805 					" test)\n"\
806 				" *	5 - modify writes\n"\
807 				" * sleeptypes:\n"\
808 				" * 	N == * condwait N sec.nsec period\n"\
809 				" * 	-N == condwait a random 1-N sec.nsec "\
810 					"period\n"\
811 				" */\n");
812 		return (0);
813 	}
814 	network = v[1];
815 
816 	worktype = strtoul(v[2], 0L, 0L);
817 	flags = strtoul(v[3], 0L, 0L);
818 	spawn_helper = strtoul(v[4], 0L, 0L);
819 	if (strtoul(v[5], 0L, 0L) > 0)
820 		(void) thr_setconcurrency(strtoul(v[5], 0L, 0L));
821 	threads = strtoul(v[6], 0L, 0L);
822 	fl = v[7];
823 	if (c > 8)
824 		slp = atof(v[8]);
825 
826 	if (douwork == 0) {
827 		/* Load current datastore. */
828 		(void) read_dsvc_conf(&dsp);
829 		if ((i = confopt_to_datastore(dsp, &datastore))
830 			!= DSVC_SUCCESS) {
831 			(void) fprintf(stderr, "Invalid datastore: %s\n",
832 					dhcpsvc_errmsg(i));
833 			return (EINVAL);
834 		}
835 		for (i = 0, np = strtok(network, ","); np; i++,
836 			np = strtok(NULL, ",")) {
837 			net[i].s_addr = inet_addr(np);
838 
839 			err = open_dd(&dh[i], &datastore, DSVC_DHCPNETWORK, np,
840 					DSVC_READ | DSVC_WRITE);
841 
842 			if (err != DSVC_SUCCESS) {
843 				(void) fprintf(stderr, "Invalid network: "\
844 						"%s %s\n", np,
845 						dhcpsvc_errmsg(err));
846 				return (err);
847 			}
848 			/*
849 			 * XXXX: bug: currently can't get the count as
850 			 * advertised
851 			 */
852 			(void) memset(&dn, '\0', sizeof (dn));
853 			DSVC_QINIT(query);
854 			err = lookup_dd(dh[i], B_FALSE, query, -1,
855 				(const void *) &dn, (void **) &dncp,
856 				&nrecords[i]);
857 			if (dncp)
858 				free_dd_list(dh[i], dncp);
859 
860 			if (err != DSVC_SUCCESS) {
861 				(void) fprintf(stderr, "Bad nrecords: %s "
862 					"[%d]\n", dhcpsvc_errmsg(err),
863 					nrecords[i]);
864 				return (err);
865 			}
866 		}
867 		ntable = i;
868 	}
869 	TNF_PROBE_2(main, "main",
870 		    "main%debug 'in function main'",
871 		    tnf_ulong, threads, threads,
872 		    tnf_ulong, nrecords, nrecords[i]);
873 
874 	(void) sigfillset(&set);
875 
876 	(void) sigdelset(&set, SIGABRT);	/* allow for user abort */
877 
878 	(void) thr_sigsetmask(SIG_SETMASK, &set, NULL);
879 
880 	tms = threads * sizeof (thread_t);
881 	if (spawn_helper)
882 		tms *= 2;
883 	tp = malloc(tms);
884 	tms = (threads * sizeof (time_t) + 0x200) & ~(0x200 - 1);
885 	if (spawn_helper)
886 		tms *= 2;
887 	timp = malloc(tms);
888 	(void) memset((char *)timp, NULL, tms);
889 
890 	(void) mutex_init(&mtx, USYNC_THREAD, 0);
891 
892 	/*
893 	 * Create signal handling thread. XXXX: due to threads library
894 	 * limitations, this must currently be directly called in the main
895 	 * program thread.
896 	 */
897 	if ((err = thr_create(NULL, 0, sig_handle, NULL,
898 				THR_NEW_LWP | THR_DAEMON | THR_BOUND |
899 				THR_DETACHED, &sigthread)) != 0) {
900 		(void) fprintf(stderr,
901 		gettext("Cannot start signal handling thread, error: %d\n"),
902 			err);
903 		return (err);
904 	}
905 	for (i = 0; i < threads; i++)
906 		/* fire up monitor thread */
907 		if (thr_create(NULL, 0, dowork, (void *) i,
908 			flags, &tp[i]) != 0)
909 			fprintf(stderr, "can't spawn thread %d\n", i);
910 
911 	/*
912 	 * Create open handling thread.
913 	 */
914 	if (doopen && (err = thr_create(NULL, 0, open_handle, NULL,
915 			THR_NEW_LWP | THR_DAEMON | THR_BOUND | THR_DETACHED,
916 			&opnthread)) != 0) {
917 		(void) fprintf(stderr,
918 		gettext("Cannot start open handling thread, error: %d\n"),
919 			err);
920 		return (err);
921 	}
922 
923 	(void) mutex_lock(&mtx);
924 	for (; time_to_go == 0; ) {
925 		to.tv_sec = time(NULL) + 10;
926 		to.tv_nsec = 0L;
927 		(void) cond_timedwait(&never, &mtx, &to);
928 		(void) mutex_unlock(&mtx);
929 	}
930 
931 	/*
932 	 * Attempt to join threads.
933 	 */
934 	for (i = 0; i < threads; i++)
935 		(void) thr_join(tp[i], NULL, NULL);
936 
937 	(void) sleep(5);
938 
939 	TNF_PROBE_0(main_end, "main", "");
940 
941 	return (0);
942 }
943