/* When flag is set do not use a new thread for the debug dump */ int spl_debug_dumplog(int flags) { struct task_struct *tsk; dumplog_priv_t dp; init_waitqueue_head(&dp.dp_waitq); dp.dp_pid = current->pid; dp.dp_flags = flags; atomic_set(&dp.dp_done, 0); if (dp.dp_flags & DL_NOTHREAD) { spl_debug_dumplog_internal(&dp); } else { tsk = spl_kthread_create(spl_debug_dumplog_thread,(void *)&dp,"spl_debug"); if (tsk == NULL) return -ENOMEM; wake_up_process(tsk); wait_event(dp.dp_waitq, atomic_read(&dp.dp_done)); } return 0; }
static int splat_condvar_test2(struct file *file, void *arg) { int i, count = 0, rc = 0; condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT]; condvar_priv_t cv; cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC; cv.cv_file = file; mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL); cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL); /* Create some threads, the exact number isn't important just as * long as we know how many we managed to create and should expect. */ for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { ct[i].ct_cvp = &cv; ct[i].ct_name = SPLAT_CONDVAR_TEST2_NAME; ct[i].ct_rc = 0; ct[i].ct_thread = spl_kthread_create(splat_condvar_test12_thread, &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i); if (!IS_ERR(ct[i].ct_thread)) { wake_up_process(ct[i].ct_thread); count++; } } /* Wait until all threads are waiting on the condition variable */ while (atomic_read(&cv.cv_condvar.cv_waiters) != count) schedule(); /* Wake all threads waiting on the condition variable */ cv_broadcast(&cv.cv_condvar); /* Wait until all threads have exited */ while ((atomic_read(&cv.cv_condvar.cv_waiters) > 0) || mutex_owner(&cv.cv_mtx)) schedule(); splat_vprint(file, SPLAT_CONDVAR_TEST2_NAME, "Correctly woke all " "%d sleeping threads at once\n", count); /* Wake everything for the failure case */ cv_destroy(&cv.cv_condvar); /* wait for threads to exit */ for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { if (!IS_ERR(ct[i].ct_thread)) kthread_stop(ct[i].ct_thread); } mutex_destroy(&cv.cv_mtx); return rc; }
/* thread_create() may block forever if it cannot create a thread or * allocate memory. This is preferable to returning a NULL which Solaris * style callers likely never check for... since it can't fail. */ kthread_t * __thread_create(caddr_t stk, size_t stksize, thread_func_t func, const char *name, void *args, size_t len, proc_t *pp, int state, pri_t pri) { thread_priv_t *tp; struct task_struct *tsk; char *p; /* Option pp is simply ignored */ /* Variable stack size unsupported */ ASSERT(stk == NULL); tp = kmem_alloc(sizeof(thread_priv_t), KM_PUSHPAGE); if (tp == NULL) return (NULL); tp->tp_magic = TP_MAGIC; tp->tp_name_size = strlen(name) + 1; tp->tp_name = kmem_alloc(tp->tp_name_size, KM_PUSHPAGE); if (tp->tp_name == NULL) { kmem_free(tp, sizeof(thread_priv_t)); return (NULL); } strncpy(tp->tp_name, name, tp->tp_name_size); /* Strip trailing "_thread" from passed name which will be the func * name since the exposed API has no parameter for passing a name. */ p = strstr(tp->tp_name, "_thread"); if (p) p[0] = '\0'; tp->tp_func = func; tp->tp_args = args; tp->tp_len = len; tp->tp_state = state; tp->tp_pri = pri; tsk = spl_kthread_create(thread_generic_wrapper, (void *)tp, "%s", tp->tp_name); if (IS_ERR(tsk)) return (NULL); wake_up_process(tsk); return ((kthread_t *)tsk); }
static int splat_condvar_test1(struct file *file, void *arg) { int i, count = 0, rc = 0; condvar_thr_t ct[SPLAT_CONDVAR_TEST_COUNT]; condvar_priv_t cv; cv.cv_magic = SPLAT_CONDVAR_TEST_MAGIC; cv.cv_file = file; mutex_init(&cv.cv_mtx, SPLAT_CONDVAR_TEST_NAME, MUTEX_DEFAULT, NULL); cv_init(&cv.cv_condvar, NULL, CV_DEFAULT, NULL); /* Create some threads, the exact number isn't important just as * long as we know how many we managed to create and should expect. */ for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { ct[i].ct_cvp = &cv; ct[i].ct_name = SPLAT_CONDVAR_TEST1_NAME; ct[i].ct_rc = 0; ct[i].ct_thread = spl_kthread_create(splat_condvar_test12_thread, &ct[i], "%s/%d", SPLAT_CONDVAR_TEST_NAME, i); if (!IS_ERR(ct[i].ct_thread)) { wake_up_process(ct[i].ct_thread); count++; } } /* Wait until all threads are waiting on the condition variable */ while (atomic_read(&cv.cv_condvar.cv_waiters) != count) schedule(); /* Wake a single thread at a time, wait until it exits */ for (i = 1; i <= count; i++) { cv_signal(&cv.cv_condvar); while (atomic_read(&cv.cv_condvar.cv_waiters) > (count - i)) schedule(); /* Correct behavior 1 thread woken */ if (atomic_read(&cv.cv_condvar.cv_waiters) == (count - i)) continue; splat_vprint(file, SPLAT_CONDVAR_TEST1_NAME, "Attempted to " "wake %d thread but work %d threads woke\n", 1, count - atomic_read(&cv.cv_condvar.cv_waiters)); rc = -EINVAL; break; } if (!rc) splat_vprint(file, SPLAT_CONDVAR_TEST1_NAME, "Correctly woke " "%d sleeping threads %d at a time\n", count, 1); /* Wait until that last nutex is dropped */ while (mutex_owner(&cv.cv_mtx)) schedule(); /* Wake everything for the failure case */ cv_broadcast(&cv.cv_condvar); cv_destroy(&cv.cv_condvar); /* wait for threads to exit */ for (i = 0; i < SPLAT_CONDVAR_TEST_COUNT; i++) { if (!IS_ERR(ct[i].ct_thread)) kthread_stop(ct[i].ct_thread); } mutex_destroy(&cv.cv_mtx); return rc; }