/*--------------------------------------------------------------------------------* * doit * * Do it. *--------------------------------------------------------------------------------*/ void *doit( void *param ) { c_info *parent = (c_info *) param; int rc, child, my_index; void *status; c_info *info_p; struct timespec timer; if (parent != NULL) { /* Synchronize with our siblings so that all the children at * a given level have been created before we allow those children * to spawn new ones (or do anything else for that matter). */ if (debug) { printf( "non-root child calling synchronize_children\n" ); fflush( stdout ); } my_index = synchronize_children( parent ); if (debug) { printf( "non-root child has been assigned index %d\n", my_index ); fflush( stdout ); } } else { /* The first thread has no one with which to synchronize, so * set some initial values for things. */ if (debug) { printf( "root child\n" ); fflush( stdout ); } cdepth = 1; my_index = 0; node_count = 1; } /* Figure out our place in the pthread array. */ info_p = &child_info[my_index]; if (debug) { printf( "thread %d getting to heart of doit.\n", my_index ); printf( "info_p=%p, cdepth=%d, depth=%d\n", info_p, cdepth, depth ); fflush( stdout ); } if (cdepth <= depth) { /* Since the tree is not yet complete (it is not yet tall enough), * we need to create another level of children. */ tst_resm(TINFO, "thread %d creating kids, cdepth=%d", my_index, cdepth); /* Create breadth children. */ for (child = 0; child < breadth; child++) { if ((rc = pthread_create(&(info_p->threads[child]), &attr, doit, (void *) info_p))) { tst_resm( TINFO, "pthread_create (doit): %s", strerror(rc) ); testexit( 3 ); } else { if (debug) { printf( "pthread_create made thread %p\n", &(info_p->threads[child]) ); fflush( stdout ); } } } if (debug) { printf( "thread %d waits on kids, cdepth=%d\n", my_index, cdepth ); fflush( stdout ); } /* Wait for our children to finish before we exit ourselves. */ for (child = 0; child < breadth; child++) { if (debug) { printf( "attempting join on thread %p\n", &(info_p->threads[child]) ); fflush( stdout ); } if ((rc = pthread_join((info_p->threads[child]), &status))) { if (debug) { printf( "join failed on thread %d, status addr=%p: %s\n", my_index, status, strerror(rc) ); fflush( stdout ); } testexit( 4 ); } else { if (debug) { printf( "thread %d joined child %d ok\n", my_index, child ); fflush( stdout ); } /* Add all childrens indexes to your index value */ info_p->sum += info_p->child_ptrs[child]->sum; tst_resm(TINFO, "thread %d adding child thread %d to sum = %ld", my_index, info_p->child_ptrs[child]->index, (long int)info_p->sum); } } } else { /* This is the leaf node case. These children don't create * any kids; they just talk amongst themselves. */ tst_resm( TINFO, "thread %d is a leaf node, depth=%d", my_index, cdepth ); /* Talk to siblings (children of the same parent node). */ if (breadth > 1) { for (child = 0; child < breadth; child++) { /* Don't talk to yourself. */ if (parent->child_ptrs[child] != info_p) { if (debug) { printf( "thread %d locking talk_mutex\n", my_index ); fflush( stdout ); } pthread_mutex_lock( &(parent->child_ptrs[child]->talk_mutex) ); if (++parent->child_ptrs[child]->talk_count == (breadth - 1)) { if (debug) { printf( "thread %d talk siblings\n", my_index ); fflush( stdout ); } if ((rc = pthread_cond_broadcast( &parent->child_ptrs[child]->talk_condvar))) { tst_resm( TINFO, "pthread_cond_broadcast: %s", strerror(rc) ); testexit( 5 ); } } if (debug) { printf( "thread %d unlocking talk_mutex\n", my_index ); fflush( stdout ); } pthread_mutex_unlock( &(parent->child_ptrs[child]->talk_mutex) ); } } /* Wait until the breadth - 1 siblings have contacted us. */ if (debug) { printf( "thread %d waiting for talk siblings\n", my_index ); fflush( stdout ); } pthread_mutex_lock( &info_p->talk_mutex ); if (info_p->talk_count < (breadth - 1)) { time( &timer.tv_sec ); timer.tv_sec += (unsigned long)timeout * 60; timer.tv_nsec = (unsigned long)0; if ((rc = pthread_cond_timedwait(&info_p->talk_condvar, &info_p->talk_mutex, &timer))) { tst_resm( TINFO, "pthread_cond_timedwait (leaf) %d: %s", my_index, strerror(rc) ); testexit( 6 ); } } pthread_mutex_unlock( &info_p->talk_mutex ); } } /* Our work is done. We're outta here. */ tst_resm(TINFO, "thread %d exiting, depth=%d, status=%d, addr=%p", my_index, cdepth, info_p->status, info_p); pthread_exit( 0 ); }
/* * Parent: wait for kids to get ready, start them, wait for them to * finish, read and accumulate results. */ void parent( int children, int load, char * mix_file, char * iodist_file) { char string[80]; /* for interactive startup */ int result; int invalid_run; /* holds INVALID RUN status */ int runtime_val; /* store Runtime value to be printed later */ int Saveerrno; char *nameptr; #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS)) struct sigaction sig_act, old_sig_act; #endif /* * Setup a SIGCHLD handler in case one of our beloved children dies * before its time. */ #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS)) /* use XOPEN signal handling */ sig_act.sa_handler = sfs_reaper; (void)sigemptyset(&sig_act.sa_mask); sig_act.sa_flags = 0; if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) { perror("sigaction failed: SIGCHLD"); exit(66); } #else (void) signal(SIGCHLD, sfs_reaper); #endif /* Change my name for error logging */ if ((nameptr = strrchr(sfs_Myname, '/')) != NULL) sfs_Myname = ++nameptr; /* * store the Runtime value; to be printed in results */ if (Prime_client) runtime_val = Runtime - MULTICLIENT_OFFSET; else runtime_val = Runtime; /* print logfile header information */ (void) fprintf(stdout,"\n"); (void) fprintf(stdout, "************************************************************************"); (void) fprintf(stdout,"\n"); (void) fflush(stdout); /* print sfs information */ if (Prime_client) { (void) fprintf(stderr, "\nSFS NFS Version %d Benchmark Client Logfile, %s\n", nfs_version, lad_timestamp()); (void) fprintf(stderr, "\tClient hostname = %s\n", lad_hostname); (void) fprintf(stderr, "\tPrime Client hostname = %s\n", Prime_client); } (void) fprintf(stderr, "\nSPEC SFS Benchmark Version %s, Creation - %s\n", SFS_VERSION_NUM, SFS_VERSION_DATE); (void) fprintf(stderr, "NFS Protocol Version %d\n", nfs_version); /* mount test directories */ (void) fprintf(stderr, "%s Mounting %d remote test directories.\n", lad_timestamp(), children); synchronize_children(children); (void) fprintf(stderr, "%s Completed.", lad_timestamp()); /* * if multi-client execution then tell Prime-Client I'm done mounting * test directories. */ if (Prime_client) { (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s Sending DONE-MOUNT message to Prime Client(%s).\n", lad_timestamp(), Prime_client); if ((result = (int) signal_Prime_Client("CLIENT_SIGNAL", "")) == (int) RPC_SUCCESS) { (void) fprintf(stderr, "%s Completed.",lad_timestamp()); (void) fflush(stderr); } else { (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s: error %d sending DONE-MOUNT message to Prime Client\n", sfs_Myname, result); /* cleanup and exit */ #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS)) sig_act.sa_handler = SIG_DFL; (void)sigemptyset(&sig_act.sa_mask); sig_act.sa_flags = 0; if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) { perror("sigaction failed: SIGCHLD"); exit(67); } #else (void) signal(SIGCHLD, SIG_DFL); #endif (void) generic_kill(0, SIGINT); exit(68); } (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s Waiting on DO-INIT message from Prime Client(%s).\n", lad_timestamp(), Prime_client); (void) fflush(stderr); /* * wait for DO-INIT message from Prime Client * sfs_syncd (rpc server) sends a SIGUSR1 signal; * user can also terminate experiment anytime they wish * with SIGINT or SIGTERM signal */ (void) pause(); (void) fprintf(stderr, "%s Received.",lad_timestamp()); (void) fflush(stderr); } /* send DONE-MOUNT and got DO-INIT message */ /* initialize test directories */ (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s Initializing test directories.\n", lad_timestamp()); /* send SIGUSR1 to child processes */ (void) generic_kill(0, SIGUSR1); synchronize_children(children); (void) fprintf(stderr, "%s Completed.", lad_timestamp()); (void) fflush(stderr); /* * if multi-client execution then tell Prime-Client I'm done initializing * and wait for synchronized do warmupmessage. */ if (Prime_client) { (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s Sending DONE-INIT message to Prime Client(%s).\n", lad_timestamp(), Prime_client); if ((result = (int) signal_Prime_Client("CLIENT_SIGNAL","")) == (int) RPC_SUCCESS) { (void) fprintf(stderr, "%s Completed.",lad_timestamp()); (void) fflush(stderr); } else { (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s: error %d sending DONE-INIT message to Prime Client\n", sfs_Myname, result); /* cleanup and exit */ #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS)) sig_act.sa_handler = SIG_DFL; (void)sigemptyset(&sig_act.sa_mask); sig_act.sa_flags = 0; if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) { perror("sigaction failed: SIGCHLD"); exit(69); } #else (void) signal(SIGCHLD, SIG_DFL); #endif (void) generic_kill(0, SIGINT); exit(70); } (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s Waiting on DO-WARMUP message from Prime Client(%s).\n", lad_timestamp(), Prime_client); (void) fflush(stderr); /* * wait for DO-WARMUP message from Prime Client * sfs_syncd (rpc server) sends a SIGUSR1 signal; * user can also terminate experiment anytime they wish * with SIGINT or SIGTERM signal */ (void) pause(); (void) fprintf(stderr, "%s Received.",lad_timestamp()); (void) fflush(stderr); } /* send DONE-INIT and got DO-WARMUP message */ if (Populate_only) { (void) fprintf(stderr, "\nPopulating directories and exiting.\n"); #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS)) sig_act.sa_handler = SIG_DFL; (void)sigemptyset(&sig_act.sa_mask); sig_act.sa_flags = 0; if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) { perror("sigaction failed: SIGCHLD"); exit(71); } #else (void) signal(SIGCHLD, SIG_DFL); #endif (void) generic_kill(0, SIGUSR1); while (wait((int *) 0) != -1) { /* nop */ } return; } /* do warm-up */ if (Warmuptime) { (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s Performing %d seconds pretest warmup.\n", lad_timestamp(), Warmuptime); (void) generic_kill(0, SIGUSR1); (void) sleep(Warmuptime); (void) fprintf(stderr, "%s Completed.", lad_timestamp()); (void) fflush(stderr); } if (Interactive) { (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "Hit <return> when ready to start test ..."); (void) fgets(string,10,stdin); } /* * if multi-client execution then tell Prime-Client I'm done warm-up * and wait for synchronized Start message. */ if (Prime_client) { (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s Sending READY message to Prime Client(%s).\n", lad_timestamp(), Prime_client); if ((result = (int) signal_Prime_Client("CLIENT_SIGNAL","")) == (int) RPC_SUCCESS) { (void) fprintf(stderr, "%s Completed.",lad_timestamp()); (void) fflush(stderr); } else { (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s: error %d sending READY message to Prime Client\n", sfs_Myname, result); /* cleanup and exit */ #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS)) sig_act.sa_handler = SIG_DFL; (void)sigemptyset(&sig_act.sa_mask); sig_act.sa_flags = 0; if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) { perror("sigaction failed: SIGCHLD"); exit(72); } #else (void) signal(SIGCHLD, SIG_DFL); #endif (void) generic_kill(0, SIGINT); exit(73); } (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s Waiting on START message from Prime Client(%s).\n", lad_timestamp(), Prime_client); (void) fflush(stderr); /* * wait for START message from Prime Client * sfs_syncd (rpc server) sends a SIGUSR1 signal; * user can also terminate experiment anytime they wish * with SIGINT or SIGTERM signal */ (void) pause(); (void) fprintf(stderr, "%s Received.",lad_timestamp()); (void) fflush(stderr); } /* send READY and got START message */ (void) fprintf(stderr, "\n"); if (Timed_run) { if (Prime_client) { (void) fprintf(stderr, "%s Starting %d seconds test run.\n", lad_timestamp(), Runtime - MULTICLIENT_OFFSET); } else { (void) fprintf(stderr, "%s Starting %d seconds test run.\n", lad_timestamp(), Runtime); } } else { (void) fprintf(stderr, "%s Starting %d call test run.\n", lad_timestamp(), Ops[TOTAL].target_calls); } (void) fflush(stderr); /* signal child processes to go */ (void) generic_kill(0, SIGUSR1); if (Timed_run) (void) sleep(Runtime); #if (defined(_XOPEN_SOURCE) || defined(USE_POSIX_SIGNALS)) sig_act.sa_handler = SIG_DFL; (void)sigemptyset(&sig_act.sa_mask); sig_act.sa_flags = 0; if (sigaction(SIGCHLD,&sig_act,&old_sig_act) == -1) { perror("sigaction failed: SIGCHLD"); exit(74); } #else (void) signal(SIGCHLD, SIG_DFL); #endif if (Timed_run) { /* * The parent and the prime are both sleeping for Runtime. * If the parent wakes up first, he'll tell the children to stop. * If the prime wakes up first, he'll send an SIGALRM (via syncd) * to the parent. That alarm may arrive while the parent is still * asleep, which is ok, or after he has starting running. Since * the parent SIGARLM catcher does nothing, there is no harm done * by the extra signal in this case. * * Perhaps, if running multi we should just wait (pause()) for * the STOP signal, like we waited for the start signal. It would * be more obvious. The only drawback is the OTW rpc delay in * receiving the stop signal from the prime. */ (void) generic_kill(0, SIGUSR2); /* tell children to finish */ } /* Wait for all the children to finish/die */ while (wait((int *) 0) != -1) { /* nop */ } (void) fprintf(stderr, "%s Completed.", lad_timestamp()); (void) fflush(stdout); (void) fflush(stderr); /* Initialize and sum up counters */ collect_counters(children); if ((invalid_run = check_counters()) == 0) invalid_run = check_parameters(iodist_file, mix_file, runtime_val); /* print test results */ print_results(children, load, mix_file, invalid_run, runtime_val, iodist_file); /* * if multi-client execution then tell Prime client that * I'm done with 'real' work and wait for move-data message * and send data across */ if (Prime_client) { (void) fprintf(stderr, "%s Sending DONE-TEST message to Prime Client(%s).\n", lad_timestamp(), Prime_client); if ((result = (int) signal_Prime_Client("CLIENT_SIGNAL","")) == (int) RPC_SUCCESS) { (void) fprintf(stderr, "%s Completed.", lad_timestamp()); (void) fflush(stderr); } else { Saveerrno = errno; (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s: error %d sending DONE-TEST message to Prime Client\n", sfs_Myname, result); errno = Saveerrno; perror("signal_Prime_Client"); /* cleanup and exit */ (void) generic_kill(0, SIGINT); exit(75); } /* * wait for MOVE-DATA message from Prime Client before * sending send results. */ (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s Waiting on MOVE-DATA message from Prime Client(%s).\n", lad_timestamp(), Prime_client); (void) fflush(stderr); (void) pause(); (void) fprintf(stderr, "%s Received.", lad_timestamp()); (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s Sending results to Prime Client(%s)\n", lad_timestamp(), Prime_client); (void) fflush(stderr); if ((result = (int) signal_Prime_Client("CLIENT_DATA", Client_results)) == (int) RPC_SUCCESS) { (void) fprintf(stderr, "%s Completed.\n", lad_timestamp()); (void) fflush(stderr); } else { Saveerrno = errno; (void) fprintf(stderr, "\n"); (void) fprintf(stderr, "%s: error %d sending client's result to Prime Client\n", sfs_Myname, result); errno = Saveerrno; perror("signal_Prime_Client"); /* cleanup and exit */ (void) generic_kill(0, SIGINT); exit(76); } } /* sent done, got move-data and sent data */ (void) fprintf(stdout,"\n"); (void) fprintf(stdout, "************************************************************************"); (void) fprintf(stdout,"\n"); } /* parent */