static int flowop_create_runtime_flowops(threadflow_t *threadflow, flowop_t **ops_list_ptr) { flowop_t *flowop = *ops_list_ptr; char *name; while (flowop) { flowop_t *newflowop; if (flowop == *ops_list_ptr) *ops_list_ptr = NULL; newflowop = flowop_define_common(threadflow, flowop->fo_name, flowop, ops_list_ptr, 1, 0); if (newflowop == NULL) return (FILEBENCH_ERROR); /* check for fo_filename attribute, and resolve if present */ if (flowop->fo_filename) { name = avd_get_str(flowop->fo_filename); newflowop->fo_fileset = fileset_find(name); if (newflowop->fo_fileset == NULL) { filebench_log(LOG_ERROR, "flowop %s: file %s not found", newflowop->fo_name, name); filebench_shutdown(1); } } /* check for fo_possetname attribute, and resolve if present */ if (flowop->fo_possetname) { name = avd_get_str(flowop->fo_possetname); newflowop->fo_posset = posset_find(name); if (newflowop->fo_posset == NULL) { filebench_log(LOG_ERROR, "flowop %s: posset %s not found", newflowop->fo_name, name); filebench_shutdown(1); } } if (flowop_initflow(newflowop) < 0) { filebench_log(LOG_ERROR, "Flowop init of %s failed", newflowop->fo_name); } flowop = flowop->fo_exec_next; } return (FILEBENCH_OK); }
/* * Calls flowop_define_common() to allocate and initialize a * flowop, and holds the shared flowop_lock during the call. * It releases the created flowop's fo_lock when done. */ flowop_t * flowop_define(threadflow_t *threadflow, char *name, flowop_t *inherit, flowop_t **flowoplist_hdp, int instance, int type) { flowop_t *flowop; (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock); flowop = flowop_define_common(threadflow, name, inherit, flowoplist_hdp, instance, type); (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock); if (flowop == NULL) return (NULL); (void) ipc_mutex_unlock(&flowop->fo_lock); return (flowop); }
/* * Calls flowop_define_common() to allocate and initialize a * composite flowop, and holds the shared flowop_lock during the call. * It releases the created flowop's fo_lock when done. */ flowop_t * flowop_new_composite_define(char *name) { flowop_t *flowop; (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock); flowop = flowop_define_common(NULL, name, NULL, NULL, 0, FLOW_TYPE_COMPOSITE); (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock); if (flowop == NULL) return (NULL); flowop->fo_func = flowop_composite; flowop->fo_init = flowop_composite_init; flowop->fo_destruct = flowop_composite_destruct; (void) ipc_mutex_unlock(&flowop->fo_lock); return (flowop); }
/* * The final initialization and main execution loop for the * worker threads. Sets threadflow and flowop start times, * waits for all process to start, then creates the runtime * flowops from those defined by the F language workload * script. It does some more initialization, then enters a * loop to repeatedly execute the flowops on the flowop list * until an abort condition is detected, at which time it exits. * This is the starting routine for the new worker thread * created by threadflow_createthread(), and is not currently * called from anywhere else. */ void flowop_start(threadflow_t *threadflow) { flowop_t *flowop; size_t memsize; int ret = 0; pid = getpid(); #ifdef HAVE_PROCFS if (noproc == 0) { char procname[128]; long ctl[2] = {PCSET, PR_MSACCT}; int pfd; (void) snprintf(procname, sizeof (procname), "/proc/%d/lwp/%d/lwpctl", pid, _lwp_self()); pfd = open(procname, O_WRONLY); (void) pwrite(pfd, &ctl, sizeof (ctl), 0); (void) close(pfd); } #endif if (!controlstats_zeroed) { (void) memset(&controlstats, 0, sizeof (controlstats)); controlstats_zeroed = 1; } flowop = threadflow->tf_ops; threadflow->tf_stats.fs_stime = gethrtime(); flowop->fo_stats.fs_stime = gethrtime(); /* Hold the flowop find lock as reader to prevent lookups */ (void) pthread_rwlock_rdlock(&filebench_shm->flowop_find_lock); /* * Block until all processes have started, acting like * a barrier. The original filebench process initially * holds the run_lock as a reader, preventing any of the * threads from obtaining the writer lock, and hence * passing this point. Once all processes and threads * have been created, the original process unlocks * run_lock, allowing each waiting thread to lock * and then immediately unlock it, then begin running. */ (void) pthread_rwlock_wrlock(&filebench_shm->run_lock); (void) pthread_rwlock_unlock(&filebench_shm->run_lock); /* Create the runtime flowops from those defined by the script */ (void) ipc_mutex_lock(&filebench_shm->flowop_lock); while (flowop) { flowop_t *newflowop; if (flowop == threadflow->tf_ops) threadflow->tf_ops = NULL; newflowop = flowop_define_common(threadflow, flowop->fo_name, flowop, 1, 0); if (newflowop == NULL) return; if (flowop_initflow(newflowop) < 0) { filebench_log(LOG_ERROR, "Flowop init of %s failed", newflowop->fo_name); } flowop = flowop->fo_threadnext; } (void) ipc_mutex_unlock(&filebench_shm->flowop_lock); filebench_log(LOG_DEBUG_SCRIPT, "Thread started"); /* Release the find lock as reader to allow lookups */ (void) pthread_rwlock_unlock(&filebench_shm->flowop_find_lock); /* Set to the start of the new flowop list */ flowop = threadflow->tf_ops; threadflow->tf_abort = 0; threadflow->tf_running = 1; /* If we are going to use ISM, allocate later */ if (threadflow->tf_attrs & THREADFLOW_USEISM) { threadflow->tf_mem = ipc_ismmalloc((size_t)*threadflow->tf_memsize); } else { threadflow->tf_mem = malloc((size_t)*threadflow->tf_memsize); } if (threadflow->tf_mem == NULL) { filebench_log(LOG_ERROR, "Thread failed to allocate %zd bytes", threadflow->tf_memsize); return; } memsize = *threadflow->tf_memsize; filebench_log(LOG_DEBUG_SCRIPT, "Thread allocated %lld bytes at %llx", memsize, threadflow->tf_mem); (void) memset(threadflow->tf_mem, 0, memsize); filebench_log(LOG_DEBUG_SCRIPT, "Thread zeroed %lld bytes", memsize); #ifdef HAVE_LWPS filebench_log(LOG_DEBUG_SCRIPT, "Thread %zx (%d) started", threadflow, _lwp_self()); #else filebench_log(LOG_DEBUG_SCRIPT, "Thread %zx started", threadflow); #endif /* Main filebench worker loop */ /* CONSTCOND */ while (1) { int i; /* Abort if asked */ if (threadflow->tf_abort || filebench_shm->f_abort) { (void) ipc_mutex_lock(&threadflow->tf_lock); threadflow->tf_running = 0; (void) ipc_mutex_unlock(&threadflow->tf_lock); filebench_log(LOG_DEBUG_SCRIPT, "%s: aborting thread %s on request of a flowop", threadflow->tf_name); break; } /* Be quiet while stats are gathered */ if (filebench_shm->bequiet) { (void) sleep(1); continue; } /* Take it easy until everyone is ready to go */ if (!filebench_shm->allrunning) (void) sleep(1); if (flowop->fo_stats.fs_stime == 0) flowop->fo_stats.fs_stime = gethrtime(); if (flowop == NULL) { filebench_log(LOG_ERROR, "flowop_read null flowop"); return; } if (threadflow->tf_memsize == 0) { filebench_log(LOG_ERROR, "Zero memory size for thread %s", threadflow->tf_name); return; } /* Execute the flowop for fo_iters times */ for (i = 0; i < *flowop->fo_iters; i++) { filebench_log(LOG_DEBUG_SCRIPT, "%s: executing flowop " "%s-%d", threadflow->tf_name, flowop->fo_name, flowop->fo_instance); ret = (*flowop->fo_func)(threadflow, flowop); filebench_log(LOG_DEBUG_SCRIPT, "%s: finished flowop " "%s-%d", threadflow->tf_name, flowop->fo_name, flowop->fo_instance); /* Return value > 0 means "stop the filebench run" */ if (ret > 0) { filebench_log(LOG_VERBOSE, "%s: exiting flowop %s-%d", threadflow->tf_name, flowop->fo_name, flowop->fo_instance); (void) ipc_mutex_lock(&threadflow->tf_lock); threadflow->tf_abort = 1; filebench_shm->f_abort = 1; threadflow->tf_running = 0; (void) ipc_mutex_unlock(&threadflow->tf_lock); break; } /* * Return value < 0 means "flowop failed, stop the * filebench run" */ if (ret < 0) { filebench_log(LOG_ERROR, "flowop %s failed", flowop->fo_name); (void) ipc_mutex_lock(&threadflow->tf_lock); threadflow->tf_abort = 1; filebench_shm->f_abort = 1; threadflow->tf_running = 0; (void) ipc_mutex_unlock(&threadflow->tf_lock); break; } } /* advance to next flowop */ flowop = flowop->fo_threadnext; /* but if at end of list, start over from the beginning */ if (flowop == NULL) { flowop = threadflow->tf_ops; threadflow->tf_stats.fs_count++; } } #ifdef HAVE_LWPS filebench_log(LOG_DEBUG_SCRIPT, "Thread %d exiting", _lwp_self()); #else filebench_log(LOG_DEBUG_SCRIPT, "Thread exiting"); #endif pthread_exit(&ret); }