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 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 * 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 * 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 * 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 * 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 * 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 */ 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 }