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