Changeset View
Changeset View
Standalone View
Standalone View
sys/compat/linuxkpi/common/src/linux_tasklet.c
Context not available. | |||||
#define TASKLET_ST_BUSY 1 | #define TASKLET_ST_BUSY 1 | ||||
#define TASKLET_ST_EXEC 2 | #define TASKLET_ST_EXEC 2 | ||||
#define TASKLET_ST_LOOP 3 | #define TASKLET_ST_LOOP 3 | ||||
#define TASKLET_ST_PAUSED 4 | |||||
#define TASKLET_ST_CMPSET(ts, old, new) \ | #define TASKLET_ST_CMPSET(ts, old, new) \ | ||||
atomic_cmpset_ptr((volatile uintptr_t *)&(ts)->entry.tqe_prev, old, new) | atomic_cmpset_int((volatile u_int *)&(ts)->_state, old, new) | ||||
#define TASKLET_ST_SET(ts, new) \ | #define TASKLET_ST_SET(ts, new) \ | ||||
WRITE_ONCE(*(volatile uintptr_t *)&(ts)->entry.tqe_prev, new) | WRITE_ONCE(*(volatile u_int *)&(ts)->_state, new) | ||||
#define TASKLET_ST_GET(ts) \ | #define TASKLET_ST_GET(ts) \ | ||||
READ_ONCE(*(volatile uintptr_t *)&(ts)->entry.tqe_prev) | READ_ONCE(*(volatile u_int *)&(ts)->_state) | ||||
#define TASKLET_ST_TESTANDSET(ts, new) \ | |||||
atomic_testandset_int((volatile u_int *)&(ts)->_state, new) | |||||
struct tasklet_worker { | struct tasklet_worker { | ||||
struct mtx mtx; | struct mtx mtx; | ||||
Context not available. | |||||
tasklet_handler(void *arg) | tasklet_handler(void *arg) | ||||
{ | { | ||||
struct tasklet_worker *tw = (struct tasklet_worker *)arg; | struct tasklet_worker *tw = (struct tasklet_worker *)arg; | ||||
struct tasklet_struct *ts; | struct tasklet_struct *ts, *first; | ||||
hselaskyUnsubmitted Done Inline Actionshselasky: ```
struct tasklet_struct *ts;
struct tasklet_struct *last;
``` | |||||
linux_set_current(curthread); | linux_set_current(curthread); | ||||
TASKLET_WORKER_LOCK(tw); | TASKLET_WORKER_LOCK(tw); | ||||
first = TAILQ_FIRST(&tw->head); | |||||
hselaskyUnsubmitted Done Inline Actionslast = TAILQ_LAST(&tw->head); hselasky: ```
last = TAILQ_LAST(&tw->head);
``` | |||||
while (1) { | while (1) { | ||||
ts = TAILQ_FIRST(&tw->head); | ts = TAILQ_FIRST(&tw->head); | ||||
if (ts == NULL) | if (ts == NULL) | ||||
break; | break; | ||||
TAILQ_REMOVE(&tw->head, ts, entry); | TAILQ_REMOVE(&tw->head, ts, entry); | ||||
TASKLET_WORKER_UNLOCK(tw); | if (!atomic_read(&ts->count)) { | ||||
do { | TASKLET_WORKER_UNLOCK(tw); | ||||
/* reset executing state */ | do { | ||||
TASKLET_ST_SET(ts, TASKLET_ST_EXEC); | /* reset executing state */ | ||||
TASKLET_ST_SET(ts, TASKLET_ST_EXEC); | |||||
ts->func(ts->data); | |||||
ts->func(ts->data); | |||||
} while (TASKLET_ST_CMPSET(ts, TASKLET_ST_EXEC, TASKLET_ST_IDLE) == 0); | |||||
TASKLET_WORKER_LOCK(tw); | } while (TASKLET_ST_CMPSET(ts, TASKLET_ST_EXEC, | ||||
TASKLET_ST_IDLE) == 0); | |||||
TASKLET_WORKER_LOCK(tw); | |||||
} else { | |||||
TAILQ_INSERT_TAIL(&tw->head, ts, entry); | |||||
} | |||||
if (TAILQ_FIRST(&tw->head) == first) | |||||
hselaskyUnsubmitted Done Inline Actionsif (ts == last) break; hselasky: ```
if (ts == last)
break;
``` | |||||
hselaskyUnsubmitted Done Inline ActionsYour assumption that TAILQ_FIRST() will always go into the TAILQ_INSERT_TAIL() case does not hold. Please update the code like suggested. hselasky: Your assumption that TAILQ_FIRST() will always go into the TAILQ_INSERT_TAIL() case does not… | |||||
johalunAuthorUnsubmitted Done Inline ActionsOh yes, I see now what you mean. johalun: Oh yes, I see now what you mean. | |||||
break; | |||||
} | } | ||||
TASKLET_WORKER_UNLOCK(tw); | TASKLET_WORKER_UNLOCK(tw); | ||||
} | } | ||||
Context not available. | |||||
ts->entry.tqe_next = NULL; | ts->entry.tqe_next = NULL; | ||||
ts->func = func; | ts->func = func; | ||||
ts->data = data; | ts->data = data; | ||||
ts->_state = TASKLET_ST_IDLE; | |||||
hselaskyUnsubmitted Done Inline Actionsatomic_set(&ts->_state, TASKLET_ST_IDLE); hselasky: atomic_set(&ts->_state, TASKLET_ST_IDLE); | |||||
atomic_set(&ts->count, 0); | |||||
} | } | ||||
void | void | ||||
Context not available. | |||||
tasklet_schedule(struct tasklet_struct *ts) | tasklet_schedule(struct tasklet_struct *ts) | ||||
{ | { | ||||
/* tasklet is paused */ | |||||
if (atomic_read(&ts->count)) | |||||
return; | |||||
if (TASKLET_ST_CMPSET(ts, TASKLET_ST_EXEC, TASKLET_ST_LOOP)) { | if (TASKLET_ST_CMPSET(ts, TASKLET_ST_EXEC, TASKLET_ST_LOOP)) { | ||||
/* tasklet_handler() will loop */ | /* tasklet_handler() will loop */ | ||||
} else if (TASKLET_ST_CMPSET(ts, TASKLET_ST_IDLE, TASKLET_ST_BUSY)) { | } else if (TASKLET_ST_CMPSET(ts, TASKLET_ST_IDLE, TASKLET_ST_BUSY)) { | ||||
Context not available. | |||||
void | void | ||||
tasklet_enable(struct tasklet_struct *ts) | tasklet_enable(struct tasklet_struct *ts) | ||||
{ | { | ||||
(void) TASKLET_ST_CMPSET(ts, TASKLET_ST_PAUSED, TASKLET_ST_IDLE); | |||||
barrier(); | |||||
hselaskyUnsubmitted Done Inline Actionsatomic already has a barrier. I think this one can be removed. hselasky: atomic already has a barrier. I think this one can be removed. | |||||
atomic_dec(&ts->count); | |||||
} | |||||
bool | |||||
tasklet_is_enabled(struct tasklet_struct *ts) | |||||
{ | |||||
return !atomic_read(&ts->count); | |||||
} | } | ||||
void | void | ||||
tasklet_disable(struct tasklet_struct *ts) | tasklet_disable(struct tasklet_struct *ts) | ||||
{ | { | ||||
while (1) { | |||||
if (TASKLET_ST_GET(ts) == TASKLET_ST_PAUSED) | atomic_inc(&ts->count); | ||||
break; | barrier(); | ||||
hselaskyUnsubmitted Done Inline ActionsDitto. hselasky: Ditto. | |||||
if (TASKLET_ST_CMPSET(ts, TASKLET_ST_IDLE, TASKLET_ST_PAUSED)) | tasklet_unlock_wait(ts); | ||||
break; | mb(); | ||||
} | |||||
int | |||||
tasklet_trylock(struct tasklet_struct *ts) | |||||
{ | |||||
return (!TASKLET_ST_TESTANDSET(ts, TASKLET_ST_BUSY)); | |||||
} | |||||
void | |||||
tasklet_unlock(struct tasklet_struct *ts) | |||||
{ | |||||
TASKLET_ST_SET(ts, TASKLET_ST_IDLE); | |||||
} | |||||
void | |||||
tasklet_unlock_wait(struct tasklet_struct *ts) | |||||
{ | |||||
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "tasklet_kill() can sleep"); | |||||
/* wait until tasklet is no longer busy */ | |||||
while (TASKLET_ST_GET(ts) != TASKLET_ST_IDLE) | |||||
pause("W", 1); | pause("W", 1); | ||||
} | |||||
} | } | ||||
Context not available. |