#include "iscsi_thread.h"
static void iscsi_threads_entry(void *arg);
iscsi_thread_t *
iscsi_thread_create(dev_info_t *dip, char *name,
iscsi_thread_ep_t entry_point, void *arg)
{
iscsi_thread_t *thread;
thread = kmem_zalloc(sizeof (iscsi_thread_t), KM_SLEEP);
if (thread != NULL) {
thread->tq = ddi_taskq_create(dip, name, 1,
TASKQ_DEFAULTPRI, 0);
if (thread->tq != NULL) {
thread->signature = SIG_ISCSI_THREAD;
thread->dip = dip;
thread->entry_point = entry_point;
thread->arg = arg;
thread->state = ISCSI_THREAD_STATE_STOPPED;
thread->sign.bitmap = 0;
mutex_init(&thread->mgnt.mtx, NULL, MUTEX_DRIVER, NULL);
mutex_init(&thread->sign.mtx, NULL, MUTEX_DRIVER, NULL);
cv_init(&thread->sign.cdv, NULL, CV_DRIVER, NULL);
} else {
kmem_free(thread, sizeof (iscsi_thread_t));
thread = NULL;
}
}
return (thread);
}
void
iscsi_thread_destroy(
iscsi_thread_t *thread
)
{
ASSERT(thread != NULL);
ASSERT(thread->signature == SIG_ISCSI_THREAD);
mutex_enter(&thread->mgnt.mtx);
switch (thread->state) {
case ISCSI_THREAD_STATE_STARTED:
thread->state = ISCSI_THREAD_STATE_DESTROYING;
mutex_enter(&thread->sign.mtx);
if (!(thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL)) {
thread->sign.bitmap |= ISCSI_THREAD_SIGNAL_KILL;
cv_signal(&thread->sign.cdv);
}
mutex_exit(&thread->sign.mtx);
ddi_taskq_wait(thread->tq);
break;
case ISCSI_THREAD_STATE_STOPPED:
thread->state = ISCSI_THREAD_STATE_DESTROYING;
break;
default:
ASSERT(0);
break;
}
mutex_exit(&thread->mgnt.mtx);
ddi_taskq_destroy(thread->tq);
cv_destroy(&thread->sign.cdv);
mutex_destroy(&thread->sign.mtx);
mutex_destroy(&thread->mgnt.mtx);
thread->signature = (uint32_t)~SIG_ISCSI_THREAD;
kmem_free(thread, sizeof (iscsi_thread_t));
}
boolean_t
iscsi_thread_start(
iscsi_thread_t *thread
)
{
boolean_t ret = B_FALSE;
ASSERT(thread != NULL);
ASSERT(thread->signature == SIG_ISCSI_THREAD);
mutex_enter(&thread->mgnt.mtx);
switch (thread->state) {
case ISCSI_THREAD_STATE_STARTED:
mutex_enter(&thread->sign.mtx);
thread->state = ISCSI_THREAD_STATE_STOPPING;
if (!(thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL)) {
thread->sign.bitmap |= ISCSI_THREAD_SIGNAL_KILL;
cv_signal(&thread->sign.cdv);
}
mutex_exit(&thread->sign.mtx);
ddi_taskq_wait(thread->tq);
thread->state = ISCSI_THREAD_STATE_STOPPED;
case ISCSI_THREAD_STATE_STOPPED:
thread->sign.bitmap = 0;
thread->state = ISCSI_THREAD_STATE_STARTING;
if (ddi_taskq_dispatch(thread->tq, iscsi_threads_entry,
thread, DDI_SLEEP) == DDI_SUCCESS) {
thread->state = ISCSI_THREAD_STATE_STARTED;
ret = B_TRUE;
}
break;
default:
ASSERT(0);
break;
}
mutex_exit(&thread->mgnt.mtx);
return (ret);
}
boolean_t
iscsi_thread_stop(
iscsi_thread_t *thread
)
{
boolean_t ret = B_FALSE;
ASSERT(thread != NULL);
ASSERT(thread->signature == SIG_ISCSI_THREAD);
mutex_enter(&thread->mgnt.mtx);
switch (thread->state) {
case ISCSI_THREAD_STATE_STARTED:
mutex_enter(&thread->sign.mtx);
thread->state = ISCSI_THREAD_STATE_STOPPING;
if (!(thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL)) {
thread->sign.bitmap |= ISCSI_THREAD_SIGNAL_KILL;
cv_signal(&thread->sign.cdv);
}
mutex_exit(&thread->sign.mtx);
ddi_taskq_wait(thread->tq);
thread->state = ISCSI_THREAD_STATE_STOPPED;
ret = B_TRUE;
break;
case ISCSI_THREAD_STATE_STOPPED:
ret = B_TRUE;
break;
default:
ASSERT(0);
break;
}
mutex_exit(&thread->mgnt.mtx);
return (ret);
}
void
iscsi_thread_send_kill(
iscsi_thread_t *thread
)
{
ASSERT(thread != NULL);
ASSERT(thread->signature == SIG_ISCSI_THREAD);
mutex_enter(&thread->mgnt.mtx);
switch (thread->state) {
case ISCSI_THREAD_STATE_STARTED:
mutex_enter(&thread->sign.mtx);
if (!(thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL)) {
thread->sign.bitmap |= ISCSI_THREAD_SIGNAL_KILL;
cv_signal(&thread->sign.cdv);
}
mutex_exit(&thread->sign.mtx);
break;
default:
ASSERT(0);
break;
}
mutex_exit(&thread->mgnt.mtx);
}
boolean_t
iscsi_thread_send_wakeup(
iscsi_thread_t *thread
)
{
boolean_t ret = B_FALSE;
ASSERT(thread != NULL);
ASSERT(thread->signature == SIG_ISCSI_THREAD);
mutex_enter(&thread->mgnt.mtx);
switch (thread->state) {
case ISCSI_THREAD_STATE_STARTED:
mutex_enter(&thread->sign.mtx);
if (!(thread->sign.bitmap & ISCSI_THREAD_SIGNAL_WAKEUP)) {
thread->sign.bitmap |= ISCSI_THREAD_SIGNAL_WAKEUP;
cv_signal(&thread->sign.cdv);
}
mutex_exit(&thread->sign.mtx);
ret = B_TRUE;
break;
default:
break;
}
mutex_exit(&thread->mgnt.mtx);
return (ret);
}
uint32_t
iscsi_thread_check_signals(
iscsi_thread_t *thread
)
{
uint32_t bitmap;
ASSERT(thread != NULL);
ASSERT(thread->signature == SIG_ISCSI_THREAD);
mutex_enter(&thread->sign.mtx);
bitmap = thread->sign.bitmap;
mutex_exit(&thread->sign.mtx);
return (bitmap);
}
int
iscsi_thread_wait(
iscsi_thread_t *thread,
clock_t timeout
)
{
int rtn = 1;
ASSERT(thread != NULL);
ASSERT(thread->signature == SIG_ISCSI_THREAD);
mutex_enter(&thread->sign.mtx);
if (thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL) {
goto signal_kill;
} else if (thread->sign.bitmap & ISCSI_THREAD_SIGNAL_WAKEUP) {
goto signal_wakeup;
} else if (timeout == 0) {
goto iscsi_thread_sleep_exit;
}
if (timeout == -1) {
cv_wait(&thread->sign.cdv, &thread->sign.mtx);
} else {
rtn = cv_reltimedwait(&thread->sign.cdv, &thread->sign.mtx,
timeout, TR_CLOCK_TICK);
}
if (thread->sign.bitmap & ISCSI_THREAD_SIGNAL_KILL) {
goto signal_kill;
} else if (thread->sign.bitmap & ISCSI_THREAD_SIGNAL_WAKEUP) {
goto signal_wakeup;
}
iscsi_thread_sleep_exit:
mutex_exit(&thread->sign.mtx);
return (rtn);
signal_kill:
mutex_exit(&thread->sign.mtx);
return (0);
signal_wakeup:
thread->sign.bitmap &= ~ISCSI_THREAD_SIGNAL_WAKEUP;
mutex_exit(&thread->sign.mtx);
return (1);
}
static
void
iscsi_threads_entry(
void *arg
)
{
iscsi_thread_t *thread;
thread = (iscsi_thread_t *)arg;
ASSERT(thread != NULL);
ASSERT(thread->signature == SIG_ISCSI_THREAD);
(thread->entry_point)(thread, thread->arg);
}