/* ARGSUSED */ static void threadflow_cancel(int arg1) { threadflow_t *threadflow; #ifdef HAVE_LWPS filebench_log(LOG_DEBUG_IMPL, "Thread signal handler on tid %d", _lwp_self()); #endif threadflow = my_procflow->pf_threads; my_procflow->pf_running = 0; while (threadflow) { if (threadflow->tf_tid) { /* make sure thread has been cleaned up */ flowop_destruct_all_flows(threadflow); (void) pthread_cancel(threadflow->tf_tid); filebench_log(LOG_DEBUG_IMPL, "Thread %d cancelled...", threadflow->tf_tid); } threadflow = threadflow->tf_next; } exit(0); }
static void Abort(const char *msg) { ulwp_t *self; struct sigaction act; sigset_t sigmask; lwpid_t lwpid; /* to help with core file debugging */ panicstr = msg; if ((self = __curthread()) != NULL) { panic_thread = self; lwpid = self->ul_lwpid; } else { lwpid = _lwp_self(); } /* set SIGABRT signal handler to SIG_DFL w/o grabbing any locks */ (void) memset(&act, 0, sizeof (act)); act.sa_sigaction = SIG_DFL; (void) __sigaction(SIGABRT, &act, NULL); /* delete SIGABRT from the signal mask */ (void) sigemptyset(&sigmask); (void) sigaddset(&sigmask, SIGABRT); (void) __lwp_sigmask(SIG_UNBLOCK, &sigmask); (void) _lwp_kill(lwpid, SIGABRT); /* never returns */ (void) kill(getpid(), SIGABRT); /* if it does, try harder */ _exit(127); }
static void stop_other_threads() { #if defined(__sun__) lwpid_t self; char path[PATH_MAX]; DIR *root; struct dirent *de, *entry; int size = 0; self = _lwp_self(); snprintf(path, sizeof(path), "/proc/%d/lwp", getpid()); #ifdef _PC_NAME_MAX size = pathconf(path, _PC_NAME_MAX); #endif size = MAX(size, PATH_MAX + 128); de = alloca(size); root = opendir(path); if(!root) return; while(portable_readdir_r(root, de, &entry) == 0 && entry != NULL) { if(entry->d_name[0] >= '1' && entry->d_name[0] <= '9') { lwpid_t tgt; tgt = atoi(entry->d_name); #ifdef UNSAFE_STOP if(tgt != self) _lwp_suspend(tgt); #endif } } closedir(root); #endif }
static void get_tname(ph_thread_t *me, char *buf, uint32_t size) { uint64_t tid; if (me) { ph_snprintf(buf, size, "%s/%d", me->name, me->tid); return; } #if defined(__linux__) tid = syscall(SYS_gettid); #elif defined(__MACH__) pthread_threadid_np(pthread_self(), &tid); #elif defined(__sun__) tid = _lwp_self(); #else tid = (uint64_t)(intptr_t)self; #endif #if defined(__linux__) || defined(__MACH__) if (pthread_getname_np(pthread_self(), buf, size) == 0) { int len = strlen(buf); if (len > 0) { ph_snprintf(buf + len, size - len, "/%" PRIu64, tid); return; } } #endif ph_snprintf(buf, size, "lwp/%" PRIu64, tid); }
static void zend_jit_perf_jitdump_register(const char *name, void *start, size_t size) { if (jitdump_fd >= 0) { static uint64_t id = 1; zend_perf_jitdump_load_record rec; size_t len = strlen(name); uint32_t thread_id; #if defined(__linux__) thread_id = syscall(SYS_gettid); #elif defined(__FreeBSD__) long tid; thr_self(&tid); thread_id = (uint32_t)tid; #elif defined(__OpenBSD__) thread_id = getthrid(); #elif defined(__NetBSD__) thread_id = _lwp_self(); #endif memset(&rec, 0, sizeof(rec)); rec.hdr.event = ZEND_PERF_JITDUMP_RECORD_LOAD; rec.hdr.size = sizeof(rec) + len + 1 + size; rec.hdr.time_stamp = zend_perf_timestamp(); rec.process_id = getpid(); rec.thread_id = thread_id; rec.vma = (uint64_t)(uintptr_t)start; rec.code_address = (uint64_t)(uintptr_t)start; rec.code_size = (uint64_t)size; rec.code_id = id++; zend_quiet_write(jitdump_fd, &rec, sizeof(rec)); zend_quiet_write(jitdump_fd, name, len + 1); zend_quiet_write(jitdump_fd, start, size); } }
/* * Puts current high resolution time in start time entry * for threadflow and may also calculate running filebench * overhead statistics. */ void flowop_beginop(threadflow_t *threadflow, flowop_t *flowop) { #ifdef HAVE_PROCFS if ((filebench_shm->shm_mmode & FILEBENCH_MODE_NOUSAGE) == 0) { if ((noproc == 0) && (threadflow->tf_lwpusagefd == 0)) { char procname[128]; (void) snprintf(procname, sizeof (procname), "/proc/%d/lwp/%d/lwpusage", my_pid, _lwp_self()); threadflow->tf_lwpusagefd = open(procname, O_RDONLY); } (void) pread(threadflow->tf_lwpusagefd, &threadflow->tf_susage, sizeof (struct prusage), 0); /* Compute overhead time in this thread around op */ if (threadflow->tf_eusage.pr_stime.tv_nsec) { flowop->fo_stats.fs_mstate[FLOW_MSTATE_OHEAD] += TIMESPEC_TO_HRTIME(threadflow->tf_eusage.pr_utime, threadflow->tf_susage.pr_utime) + TIMESPEC_TO_HRTIME(threadflow->tf_eusage.pr_ttime, threadflow->tf_susage.pr_ttime) + TIMESPEC_TO_HRTIME(threadflow->tf_eusage.pr_stime, threadflow->tf_susage.pr_stime); } } #endif /* Start of op for this thread */ threadflow->tf_stime = gethrtime(); }
int High_Priority_Task::svc (void) { ACE_hthread_t thr_handle; ACE_Thread::self (thr_handle); int prio; if (ACE_Thread::getprio (thr_handle, prio) == -1) ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getprio failed"), -1); #if defined (ACE_HAS_STHREADS) ACE_DEBUG ((LM_DEBUG, "(%P|%u|%t) High: prio = %d, priority_ = %d\n", _lwp_self (), prio, this->priority_)); #else /* ! ACE_HAS_STHREADS */ ACE_DEBUG ((LM_DEBUG, "(%P|%t) High: prio = %d, priority_ = %d\n", prio, this->priority_)); #endif /* ! ACE_HAS_STHREADS */ ACE_ASSERT (this->priority_ == prio); ACE_Time_Value pause (0, read_period); for (u_int i = 0; i < high_iterations; ++i) { time_ [i] = (u_long) ((ACE_OS::gethrtime () - starttime)/ (ACE_UINT32) 1000000u); ACE_OS::select (0, 0, 0, 0, &pause); } done_ = 1; return 0; }
/*ARGSUSED*/ long brand_unimpl(sysret_t *rv, uintptr_t p1) { sysret_t rval; /* * We'd like to print out some kind of error message here like * "unsupported syscall", but we can't because it's not safe to * assume that stderr or STDERR_FILENO actually points to something * that is a terminal, and if we wrote to those files we could * inadvertantly write to some applications open files, which would * be bad. * * Normally, if an application calls an invalid system call * it get a SIGSYS sent to it. So we'll just go ahead and send * ourselves a signal here. Note that this is far from ideal since * if the application has registered a signal handler, that signal * handler may recieve a ucontext_t as the third parameter to * indicate the context of the process when the signal was * generated, and in this case that context will not be what the * application is expecting. Hence, we should probably create a * brandsys() kernel function that can deliver the signal to us * with the correct ucontext_t. */ (void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGSYS); return (ENOSYS); }
void __assfail(const char *assertion, const char *filename, int line_num) { char buf[800]; /* no assert() message in the library is this long */ ulwp_t *self; lwpid_t lwpid; /* avoid recursion deadlock */ if ((self = __curthread()) != NULL) { if (assert_thread == self) _exit(127); enter_critical(self); (void) _lwp_mutex_lock(&assert_lock); assert_thread = self; lwpid = self->ul_lwpid; } else { self = NULL; (void) _lwp_mutex_lock(&assert_lock); lwpid = _lwp_self(); } /* * This is a hack, but since the Abort function isn't exported * to outside consumers, libzpool's vpanic() function calls * assfail() with a filename set to NULL. In that case, it'd be * best not to print "assertion failed" since it was a panic and * not an assertion failure. */ if (filename == NULL) { (void) strcpy(buf, "failure for thread "); } else { (void) strcpy(buf, "assertion failed for thread "); } ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); (void) strcat(buf, ", thread-id "); ultos((uint64_t)lwpid, 10, buf + strlen(buf)); (void) strcat(buf, ": "); (void) strcat(buf, assertion); if (filename != NULL) { (void) strcat(buf, ", file "); (void) strcat(buf, filename); (void) strcat(buf, ", line "); ultos((uint64_t)line_num, 10, buf + strlen(buf)); } (void) strcat(buf, "\n"); (void) __write(2, buf, strlen(buf)); /* * We could replace the call to Abort() with the following code * if we want just to issue a warning message and not die. * assert_thread = NULL; * _lwp_mutex_unlock(&assert_lock); * if (self != NULL) * exit_critical(self); */ Abort(buf); }
/* * Puts current high resolution time in start time entry * for threadflow and may also calculate running filebench * overhead statistics. */ void flowop_beginop(threadflow_t *threadflow, flowop_t *flowop) { #ifdef HAVE_PROC_PID_LWP if ((filebench_shm->shm_mmode & FILEBENCH_MODE_NOUSAGE) == 0) { if (threadflow->tf_lwpusagefd == 0) { char procname[128]; (void) snprintf(procname, sizeof (procname), "/proc/%d/lwp/%d/lwpusage", (int)my_pid, _lwp_self()); threadflow->tf_lwpusagefd = open(procname, O_RDONLY); } (void) pread(threadflow->tf_lwpusagefd, &threadflow->tf_susage, sizeof (struct prusage), 0); /* Compute overhead time in this thread around op */ if (threadflow->tf_eusage.pr_stime.tv_nsec) { flowop->fo_stats.fs_mstate[FLOW_MSTATE_OHEAD] += TIMESPEC_TO_HRTIME(threadflow->tf_eusage.pr_utime, threadflow->tf_susage.pr_utime) + TIMESPEC_TO_HRTIME(threadflow->tf_eusage.pr_ttime, threadflow->tf_susage.pr_ttime) + TIMESPEC_TO_HRTIME(threadflow->tf_eusage.pr_stime, threadflow->tf_susage.pr_stime); } } #elif defined(HAVE_PROC_PID_STAT) int tid; char fname[128], dummy_str[64]; unsigned long utime, stime; FILE *filep; int ret; tid = gettid(); filebench_log(LOG_DEBUG_SCRIPT, "proc/pid/stat called ==> tid = %d", tid); sprintf(fname,"/proc/%d/stat", tid); filep = fopen(fname, "r"); if (filep) { ret = fscanf(filep, "%s %s %s %s %s %s %s %s %s %s %s %s %s %lu %lu", \ dummy_str, dummy_str, dummy_str, dummy_str, dummy_str, dummy_str, dummy_str, dummy_str, dummy_str, dummy_str, dummy_str, dummy_str, dummy_str, &utime, &stime); flowop->fo_start_usage = (utime + stime) * 10000000; fclose(filep); } else { filebench_log(LOG_ERROR, "Unable to open proc/<pid>/stat file for given thread (errno=%d)", errno); } #endif /* Start of op for this thread */ threadflow->tf_stime = gethrtime(); }
/*ARGSUSED*/ void _brand_abort(int err, const char *msg, const char *file, int line) { sysret_t rval; /* Save the error message into convenient globals */ brand_abort_err = err; brand_abort_msg = msg; brand_abort_file = file; brand_abort_line = line; /* kill ourselves */ abort(); /* If abort() didn't work, try something stronger. */ (void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGKILL); }
static ph_thread_t *ph_thread_init_myself(bool booting) { ph_thread_t *me; ck_epoch_record_t *er; er = ck_epoch_recycle(&misc_epoch); if (er) { me = ph_container_of(er, ph_thread_t, epoch_record); } else { me = calloc(1, sizeof(*me)); if (!me) { ph_panic("fatal OOM in ph_thread_init_myself()"); } ck_epoch_register(&misc_epoch, &me->epoch_record); ck_stack_push_mpmc(&ph_thread_all_threads, &me->thread_linkage); ph_counter_init_thread(me); } #ifdef HAVE___THREAD __ph_thread_self = me; #endif pthread_setspecific(__ph_thread_key, me); PH_STAILQ_INIT(&me->pending_nbio); PH_STAILQ_INIT(&me->pending_pool); me->tid = ck_pr_faa_32(&next_tid, 1); me->thr = pthread_self(); #ifdef __sun__ me->lwpid = _lwp_self(); #endif #if defined(__linux__) || defined(__MACH__) // see if we can discover our thread name from the system pthread_getname_np(me->thr, me->name, sizeof(me->name)); #endif // If we were recycled from a non-phenom thread, and are initializing // a non-phenom thread, it is possible that there are still deferred // items to reap in this record, so get them now. if (er && !booting) { ck_epoch_barrier(&misc_epoch, &me->epoch_record); } return me; }
/* * Report a thread usage error. * Not called if _THREAD_ERROR_DETECTION=0. * Writes message and continues execution if _THREAD_ERROR_DETECTION=1. * Writes message and dumps core if _THREAD_ERROR_DETECTION=2. */ void thread_error(const char *msg) { char buf[800]; uberdata_t *udp; ulwp_t *self; lwpid_t lwpid; /* avoid recursion deadlock */ if ((self = __curthread()) != NULL) { if (assert_thread == self) _exit(127); enter_critical(self); (void) _lwp_mutex_lock(&assert_lock); assert_thread = self; lwpid = self->ul_lwpid; udp = self->ul_uberdata; } else { self = NULL; (void) _lwp_mutex_lock(&assert_lock); lwpid = _lwp_self(); udp = &__uberdata; } (void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: " "thread usage error detected ***\n*** "); (void) strcat(buf, msg); (void) strcat(buf, "\n*** calling thread is "); ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); (void) strcat(buf, " thread-id "); ultos((uint64_t)lwpid, 10, buf + strlen(buf)); (void) strcat(buf, "\n\n"); (void) __write(2, buf, strlen(buf)); if (udp->uberflags.uf_thread_error_detection >= 2) Abort(buf); assert_thread = NULL; (void) _lwp_mutex_unlock(&assert_lock); if (self != NULL) exit_critical(self); }
uint64_t dylan_current_thread_id(void) { #if defined(OPEN_DYLAN_PLATFORM_LINUX) return syscall(SYS_gettid); #elif defined(OPEN_DYLAN_PLATFORM_DARWIN) uint64_t tid; pthread_threadid_np(pthread_self(), &tid); return tid; #elif defined(OPEN_DYLAN_PLATFORM_FREEBSD) return pthread_getthreadid_np(); #elif defined(OPEN_DYLAN_PLATFORM_NETBSD) return _lwp_self(); #elif defined(OPEN_DYLAN_PLATFORM_OPENBSD) return syscall(SYS_getthrid); #elif defined(OPEN_DYLAN_PLATFORM_WINDOWS) return GetCurrentThreadId(); #else #error dylan_current_thread_id is not yet implemented. #endif return 0; }
/* ARGSUSED */ static void threadflow_cancel(int arg1) { threadflow_t *threadflow = my_procflow->pf_threads; #ifdef HAVE_LWPS filebench_log(LOG_DEBUG_IMPL, "Thread signal handler on tid %d", _lwp_self()); #endif my_procflow->pf_running = 0; exit(0); while (threadflow) { if (threadflow->tf_tid) { (void) pthread_cancel(threadflow->tf_tid); filebench_log(LOG_DEBUG_IMPL, "Thread %d cancelled...", threadflow->tf_tid); } threadflow = threadflow->tf_next; } }
int Low_Priority_Task::svc (void) { ACE_hthread_t thr_handle; ACE_Thread::self (thr_handle); int prio; if (ACE_Thread::getprio (thr_handle, prio) == -1) ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getprio failed"), -1); #if defined (ACE_HAS_STHREADS) ACE_DEBUG ((LM_DEBUG, "(%P|%u|%t) Low: prio = %d, priority_ = %d\n", _lwp_self (), prio, this->priority_)); #else /* ! ACE_HAS_STHREADS */ ACE_DEBUG ((LM_DEBUG, "(%P|%t) Low: prio = %d, priority_ = %d\n", prio, this->priority_)); #endif /* ! ACE_HAS_STHREADS */ ACE_ASSERT (this->priority_ == prio); u_long iterations = 0; // Chew up CPU for the entire interval. for (; ! high_priority_task_.done () && iterations < low_iterations; ++iterations) { u_long n = 1279ul; /* Takes about 40.2 usecs on a 168 MHz Ultra2. */ ACE::is_prime (n, 2ul /* min_factor */, n/2 /* max_factor */); if (low_yield) ACE_OS::thr_yield (); } ACE_DEBUG ((LM_INFO, "Low completed %u iterations\n", iterations)); return 0; }
/*********************************************************************** * get_unix_tid * * Retrieve the Unix tid to use on the server side for the current thread. */ static int get_unix_tid(void) { int ret = -1; #ifdef HAVE_PTHREAD_GETTHREADID_NP ret = pthread_getthreadid_np(); #elif defined(linux) ret = syscall( __NR_gettid ); #elif defined(__sun) ret = pthread_self(); #elif defined(__APPLE__) ret = mach_thread_self(); mach_port_deallocate(mach_task_self(), ret); #elif defined(__NetBSD__) ret = _lwp_self(); #elif defined(__FreeBSD__) long lwpid; thr_self( &lwpid ); ret = lwpid; #elif defined(__DragonFly__) ret = lwp_gettid(); #endif return ret; }
/* do_work: process array's data with locking, based on array->strategy */ void * do_work(void *v) { Workblk *array; struct scripttab *k; int i; volatile double x; #ifdef SOLARIS thread_t mytid = thr_self(); #endif #ifdef POSIX pthread_t mytid = pthread_self(); #endif #if OS(Solaris) /* check for signal masked */ check_sigmask(0); #endif /* OS(Solaris) */ /* delay to ensure that a tick passes, so that the * first profile packet doesn't show the thread startup time * attributed to the accounting functions */ x = 0; for (i = 0; i < 2000000; i++) { x = x + 1.0; } for(;;) { /* fetch a workblk */ array = fetch_work(); if(array == NULL) { /* we're done */ break; } array->lock = mutex_initializer; array->proffail = 0; array->tid = mytid; #if OS(Solaris) array->ilwpid = _lwp_self(); #else array->ilwpid = getpid() /* pthread_self()*/ ; #endif /* OS(Solaris) */ array->lwpid = -1; /* initialise to inappropriate value */ #if 0 printf("thread %d, initial lwp %d, block #%d, strategy = %d\n", array->tid, array->ilwpid, array->index, array->strategy); #endif array->start = gethrtime(); array->vstart = gethrvtime(); k = &scripttab[array->strategy]; (k->test_func)(array, k); array->done = gethrtime(); array->vdone = gethrvtime(); #if OS(Solaris) array->lwpid = _lwp_self(); #else array->lwpid = getpid() /* pthread_self()*/ ; #endif /* OS(Solaris) */ #if defined(BOUND) assert(array->lwpid == array->ilwpid); #endif #if OS(Solaris) if(check_sigmask(1) != 0) { /* set flag in the array */ array->proffail = 1; } #endif /* OS(Solaris) */ } return NULL; }
/* * 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 = FILEBENCH_OK; set_thread_ioprio(threadflow); #ifdef HAVE_PROC_PID_LWP char procname[128]; long ctl[2] = {PCSET, PR_MSACCT}; int pfd; (void) snprintf(procname, sizeof (procname), "/proc/%d/lwp/%d/lwpctl", (int)my_pid, _lwp_self()); pfd = open(procname, O_WRONLY); (void) pwrite(pfd, &ctl, sizeof (ctl), 0); (void) close(pfd); #endif (void) ipc_mutex_lock(&controlstats_lock); if (!controlstats_zeroed) { (void) memset(&controlstats, 0, sizeof (controlstats)); controlstats_zeroed = 1; } (void) ipc_mutex_unlock(&controlstats_lock); flowop = threadflow->tf_thrd_fops; /* Hold the flowop find lock as reader to prevent lookups */ (void) pthread_rwlock_rdlock(&filebench_shm->shm_flowop_find_lock); /* Create the runtime flowops from those defined by the script */ (void) ipc_mutex_lock(&filebench_shm->shm_flowop_lock); if (flowop_create_runtime_flowops(threadflow, &threadflow->tf_thrd_fops) != FILEBENCH_OK) { (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock); filebench_shutdown(1); return; } (void) ipc_mutex_unlock(&filebench_shm->shm_flowop_lock); /* Release the find lock as reader to allow lookups */ (void) pthread_rwlock_unlock(&filebench_shm->shm_flowop_find_lock); /* Set to the start of the new flowop list */ flowop = threadflow->tf_thrd_fops; memsize = (size_t)threadflow->tf_constmemsize; /* If we are going to use ISM, allocate later */ if (threadflow->tf_attrs & THREADFLOW_USEISM) { threadflow->tf_mem = ipc_ismmalloc(memsize); } else { threadflow->tf_mem = malloc(memsize); } (void) memset(threadflow->tf_mem, 0, memsize); filebench_log(LOG_DEBUG_SCRIPT, "Thread allocated %d bytes", memsize); #ifdef HAVE_LWPS filebench_log(LOG_DEBUG_SCRIPT, "Thread %zx (%d) started", threadflow, _lwp_self()); #endif /* * Now we set tf_running flag to indicate to the main process * that the worker thread is running. However, the thread is * still not executing the workload, as it is blocked by the * shm_run_lock. Main thread will release this lock when all * threads set their tf_running flag to 1. */ threadflow->tf_abort = 0; threadflow->tf_running = 1; /* * 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->shm_run_lock); (void) pthread_rwlock_unlock(&filebench_shm->shm_run_lock); /* Main filebench worker loop */ while (ret == FILEBENCH_OK) { int i, count; /* Abort if asked */ if (threadflow->tf_abort || filebench_shm->shm_f_abort) break; /* Be quiet while stats are gathered */ if (filebench_shm->shm_bequiet) { (void) sleep(1); continue; } /* Take it easy until everyone is ready to go */ if (!filebench_shm->shm_procs_running) { (void) sleep(1); continue; } if (flowop == NULL) { filebench_log(LOG_ERROR, "flowop_read null flowop"); return; } /* Execute the flowop for fo_iters times */ count = (int)avd_get_int(flowop->fo_iters); for (i = 0; i < count; 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); /* * Return value FILEBENCH_ERROR means "flowop * failed, stop the filebench run" */ if (ret == FILEBENCH_ERROR) { filebench_log(LOG_ERROR, "%s-%d: flowop %s-%d failed", threadflow->tf_name, threadflow->tf_instance, flowop->fo_name, flowop->fo_instance); (void) ipc_mutex_lock(&threadflow->tf_lock); threadflow->tf_abort = 1; filebench_shm->shm_f_abort = FILEBENCH_ABORT_ERROR; (void) ipc_mutex_unlock(&threadflow->tf_lock); break; } /* * Return value of FILEBENCH_NORSC means "stop * the filebench run" if in "end on no work mode", * otherwise it indicates an error */ if (ret == FILEBENCH_NORSC) { (void) ipc_mutex_lock(&threadflow->tf_lock); threadflow->tf_abort = FILEBENCH_DONE; if (filebench_shm->shm_rmode == FILEBENCH_MODE_Q1STDONE) { filebench_shm->shm_f_abort = FILEBENCH_ABORT_RSRC; } else if (filebench_shm->shm_rmode != FILEBENCH_MODE_QALLDONE) { filebench_log(LOG_ERROR1, "WARNING! Run stopped early:\n " " flowop %s-%d could " "not obtain a file. Please\n " " reduce runtime, " "increase fileset entries " "($nfiles), or switch modes.", flowop->fo_name, flowop->fo_instance); filebench_shm->shm_f_abort = FILEBENCH_ABORT_ERROR; } (void) ipc_mutex_unlock(&threadflow->tf_lock); break; } /* * Return value of FILEBENCH_DONE means "stop * the filebench run without error" */ if (ret == FILEBENCH_DONE) { (void) ipc_mutex_lock(&threadflow->tf_lock); threadflow->tf_abort = FILEBENCH_DONE; filebench_shm->shm_f_abort = FILEBENCH_ABORT_DONE; (void) ipc_mutex_unlock(&threadflow->tf_lock); break; } /* * If we get here and the return is something other * than FILEBENCH_OK, it means a spurious code * was returned, so treat as major error. This * probably indicates a bug in the flowop. */ if (ret != FILEBENCH_OK) { filebench_log(LOG_ERROR, "Flowop %s unexpected return value = %d\n", flowop->fo_name, ret); filebench_shm->shm_f_abort = FILEBENCH_ABORT_ERROR; break; } } /* advance to next flowop */ flowop = flowop->fo_exec_next; /* but if at end of list, start over from the beginning */ if (flowop == NULL) { flowop = threadflow->tf_thrd_fops; threadflow->tf_stats.fs_count++; } } #ifdef HAVE_LWPS filebench_log(LOG_DEBUG_SCRIPT, "Thread %d exiting", _lwp_self()); #endif /* Tell flowops to destroy locally acquired state */ flowop_destruct_all_flows(threadflow); pthread_exit(&threadflow->tf_abort); }
/* * 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); }
static void *my_server_thread(void *arg) { server_lwpid = _lwp_self(); door_return(NULL, 0, NULL, 0); return NULL; }
static int dill_ismain() { return _lwp_self() == 1; }
/* * Report application lock usage error for mutexes and condvars. * Not called if _THREAD_ERROR_DETECTION=0. * Continue execution if _THREAD_ERROR_DETECTION=1. * Dump core if _THREAD_ERROR_DETECTION=2. */ void lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg) { mutex_t mcopy; char buf[800]; uberdata_t *udp; ulwp_t *self; lwpid_t lwpid; pid_t pid; /* * Take a snapshot of the mutex before it changes (we hope!). * Use memcpy() rather than 'mcopy = *mp' in case mp is unaligned. */ (void) memcpy(&mcopy, mp, sizeof (mcopy)); /* avoid recursion deadlock */ if ((self = __curthread()) != NULL) { if (assert_thread == self) _exit(127); enter_critical(self); (void) _lwp_mutex_lock(&assert_lock); assert_thread = self; lwpid = self->ul_lwpid; udp = self->ul_uberdata; pid = udp->pid; } else { self = NULL; (void) _lwp_mutex_lock(&assert_lock); lwpid = _lwp_self(); udp = &__uberdata; pid = getpid(); } (void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n"); (void) strcat(buf, who); (void) strcat(buf, "("); if (cv != NULL) { ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf)); (void) strcat(buf, ", "); } ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf)); (void) strcat(buf, ")"); if (msg != NULL) { (void) strcat(buf, ": "); (void) strcat(buf, msg); } else if (!mutex_held(&mcopy)) { (void) strcat(buf, ": calling thread does not own the lock"); } else if (mcopy.mutex_rcount) { (void) strcat(buf, ": mutex rcount = "); ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf)); } else { (void) strcat(buf, ": calling thread already owns the lock"); } (void) strcat(buf, "\ncalling thread is "); ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); (void) strcat(buf, " thread-id "); ultos((uint64_t)lwpid, 10, buf + strlen(buf)); if (msg != NULL || mutex_held(&mcopy)) /* EMPTY */; else if (mcopy.mutex_lockw == 0) (void) strcat(buf, "\nthe lock is unowned"); else if (!(mcopy.mutex_type & USYNC_PROCESS)) { (void) strcat(buf, "\nthe lock owner is "); ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf)); } else { (void) strcat(buf, " in process "); ultos((uint64_t)pid, 10, buf + strlen(buf)); (void) strcat(buf, "\nthe lock owner is "); ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf)); (void) strcat(buf, " in process "); ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf)); } (void) strcat(buf, "\n\n"); (void) __write(2, buf, strlen(buf)); if (udp->uberflags.uf_thread_error_detection >= 2) Abort(buf); assert_thread = NULL; (void) _lwp_mutex_unlock(&assert_lock); if (self != NULL) exit_critical(self); }
/* * Report application lock usage error for rwlocks. * Not called if _THREAD_ERROR_DETECTION=0. * Continue execution if _THREAD_ERROR_DETECTION=1. * Dump core if _THREAD_ERROR_DETECTION=2. */ void rwlock_error(const rwlock_t *rp, const char *who, const char *msg) { rwlock_t rcopy; uint32_t rwstate; char buf[800]; uberdata_t *udp; ulwp_t *self; lwpid_t lwpid; pid_t pid; int process; /* * Take a snapshot of the rwlock before it changes (we hope!). * Use memcpy() rather than 'rcopy = *rp' in case rp is unaligned. */ (void) memcpy(&rcopy, rp, sizeof (rcopy)); /* avoid recursion deadlock */ if ((self = __curthread()) != NULL) { if (assert_thread == self) _exit(127); enter_critical(self); (void) _lwp_mutex_lock(&assert_lock); assert_thread = self; lwpid = self->ul_lwpid; udp = self->ul_uberdata; pid = udp->pid; } else { self = NULL; (void) _lwp_mutex_lock(&assert_lock); lwpid = _lwp_self(); udp = &__uberdata; pid = getpid(); } rwstate = (uint32_t)rcopy.rwlock_readers; process = (rcopy.rwlock_type & USYNC_PROCESS); (void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n"); (void) strcat(buf, who); (void) strcat(buf, "("); ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf)); (void) strcat(buf, "): "); (void) strcat(buf, msg); (void) strcat(buf, "\ncalling thread is "); ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); (void) strcat(buf, " thread-id "); ultos((uint64_t)lwpid, 10, buf + strlen(buf)); if (process) { (void) strcat(buf, " in process "); ultos((uint64_t)pid, 10, buf + strlen(buf)); } if (rwstate & URW_WRITE_LOCKED) { (void) strcat(buf, "\nthe writer lock owner is "); ultos((uint64_t)rcopy.rwlock_owner, 16, buf + strlen(buf)); if (process) { (void) strcat(buf, " in process "); ultos((uint64_t)rcopy.rwlock_ownerpid, 10, buf + strlen(buf)); } } else if (rwstate & URW_READERS_MASK) { (void) strcat(buf, "\nthe reader lock is held by "); ultos((uint64_t)(rwstate & URW_READERS_MASK), 10, buf + strlen(buf)); (void) strcat(buf, " readers"); } else { (void) strcat(buf, "\nthe lock is unowned"); } if (rwstate & URW_HAS_WAITERS) (void) strcat(buf, "\nand the lock appears to have waiters"); (void) strcat(buf, "\n\n"); (void) __write(2, buf, strlen(buf)); if (udp->uberflags.uf_thread_error_detection >= 2) Abort(buf); assert_thread = NULL; (void) _lwp_mutex_unlock(&assert_lock); if (self != NULL) exit_critical(self); }