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:
parent
f9fdd41ebc
commit
d656eefc9c
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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(¤t->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();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user