Add kthread parking support to the LinuxKPI.

Submitted by:	kmacy (original version)
Reviewed by:	hselasky
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D11264
This commit is contained in:
markj 2017-06-18 19:22:05 +00:00
parent f9fdd41ebc
commit d656eefc9c
4 changed files with 78 additions and 16 deletions

View File

@ -48,15 +48,26 @@
__task; \
})
#define in_atomic() ({ \
linux_in_atomic(); \
})
int linux_kthread_stop(struct task_struct *);
bool linux_kthread_should_stop_task(struct task_struct *);
bool linux_kthread_should_stop(void);
int linux_kthread_park(struct task_struct *);
void linux_kthread_parkme(void);
bool linux_kthread_should_park(void);
void linux_kthread_unpark(struct task_struct *);
void linux_kthread_fn(void *);
struct task_struct *linux_kthread_setup_and_run(struct thread *,
linux_task_fn_t *, void *arg);
int linux_in_atomic(void);
extern int kthread_stop(struct task_struct *);
extern bool kthread_should_stop_task(struct task_struct *);
extern bool kthread_should_stop(void);
extern void linux_kthread_fn(void *);
extern struct task_struct *linux_kthread_setup_and_run(struct thread *, linux_task_fn_t *, void *arg);
extern int linux_in_atomic(void);
#define kthread_stop(task) linux_kthread_stop(task)
#define kthread_should_stop() linux_kthread_should_stop()
#define kthread_should_stop_task(task) linux_kthread_should_stop_task(task)
#define kthread_park(task) linux_kthread_park(task)
#define kthread_parkme() linux_kthread_parkme()
#define kthread_should_park() linux_kthread_should_park()
#define kthread_unpark(task) linux_kthread_unpark(task)
#endif /* _LINUX_KTHREAD_H_ */
#define in_atomic() linux_in_atomic()
#endif /* _LINUX_KTHREAD_H_ */

View File

@ -54,6 +54,7 @@
#define TASK_UNINTERRUPTIBLE 0x0002
#define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
#define TASK_WAKING 0x0100
#define TASK_PARKED 0x0200
struct task_struct {
struct thread *task_thread;

View File

@ -28,6 +28,7 @@
__FBSDID("$FreeBSD$");
#include <linux/compat.h>
#include <linux/completion.h>
#include <linux/mm.h>
#include <linux/kthread.h>
@ -68,6 +69,8 @@ linux_alloc_current(struct thread *td, int flags)
ts->pid = td->td_tid;
atomic_set(&ts->usage, 1);
ts->state = TASK_RUNNING;
init_completion(&ts->parked);
init_completion(&ts->exited);
proc = td->td_proc;

View File

@ -43,21 +43,21 @@ enum {
};
bool
kthread_should_stop_task(struct task_struct *task)
linux_kthread_should_stop_task(struct task_struct *task)
{
return (atomic_read(&task->kthread_flags) & KTHREAD_SHOULD_STOP_MASK);
}
bool
kthread_should_stop(void)
linux_kthread_should_stop(void)
{
return (atomic_read(&current->kthread_flags) & KTHREAD_SHOULD_STOP_MASK);
}
int
kthread_stop(struct task_struct *task)
linux_kthread_stop(struct task_struct *task)
{
int retval;
@ -66,6 +66,7 @@ kthread_stop(struct task_struct *task)
* kthread_stop():
*/
atomic_or(KTHREAD_SHOULD_STOP_MASK, &task->kthread_flags);
kthread_unpark(task);
wake_up_process(task);
wait_for_completion(&task->exited);
@ -78,6 +79,53 @@ kthread_stop(struct task_struct *task)
return (retval);
}
int
linux_kthread_park(struct task_struct *task)
{
atomic_or(KTHREAD_SHOULD_PARK_MASK, &task->kthread_flags);
wake_up_process(task);
wait_for_completion(&task->parked);
return (0);
}
void
linux_kthread_parkme(void)
{
struct task_struct *task;
task = current;
set_task_state(task, TASK_PARKED | TASK_UNINTERRUPTIBLE);
while (linux_kthread_should_park()) {
while ((atomic_fetch_or(KTHREAD_IS_PARKED_MASK,
&task->kthread_flags) & KTHREAD_IS_PARKED_MASK) == 0)
complete(&task->parked);
schedule();
set_task_state(task, TASK_PARKED | TASK_UNINTERRUPTIBLE);
}
atomic_andnot(KTHREAD_IS_PARKED_MASK, &task->kthread_flags);
set_task_state(task, TASK_RUNNING);
}
bool
linux_kthread_should_park(void)
{
struct task_struct *task;
task = current;
return (atomic_read(&task->kthread_flags) & KTHREAD_SHOULD_PARK_MASK);
}
void
linux_kthread_unpark(struct task_struct *task)
{
atomic_andnot(KTHREAD_SHOULD_PARK_MASK, &task->kthread_flags);
if ((atomic_fetch_andnot(KTHREAD_IS_PARKED_MASK, &task->kthread_flags) &
KTHREAD_IS_PARKED_MASK) != 0)
wake_up_state(task, TASK_PARKED);
}
struct task_struct *
linux_kthread_setup_and_run(struct thread *td, linux_task_fn_t *task_fn, void *arg)
{
@ -104,10 +152,10 @@ linux_kthread_fn(void *arg __unused)
{
struct task_struct *task = current;
if (kthread_should_stop_task(task) == 0)
if (linux_kthread_should_stop_task(task) == 0)
task->task_ret = task->task_fn(task->task_data);
if (kthread_should_stop_task(task) != 0) {
if (linux_kthread_should_stop_task(task) != 0) {
struct thread *td = curthread;
/* let kthread_stop() free data */
@ -118,4 +166,3 @@ linux_kthread_fn(void *arg __unused)
}
kthread_exit();
}