aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linuxkpi
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2017-06-18 19:22:05 +0000
committerMark Johnston <markj@FreeBSD.org>2017-06-18 19:22:05 +0000
commit8504aa98527b7f2078980ec5b650a06063bf079a (patch)
treeb117022c3483eab2683eba6ce1b1b7bb048560e9 /sys/compat/linuxkpi
parentd4e3484bd9166cab99605f864d8c3b102c754953 (diff)
downloadsrc-8504aa98527b7f2078980ec5b650a06063bf079a.tar.gz
src-8504aa98527b7f2078980ec5b650a06063bf079a.zip
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
Notes
Notes: svn path=/head/; revision=320078
Diffstat (limited to 'sys/compat/linuxkpi')
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kthread.h31
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sched.h1
-rw-r--r--sys/compat/linuxkpi/common/src/linux_current.c3
-rw-r--r--sys/compat/linuxkpi/common/src/linux_kthread.c59
4 files changed, 78 insertions, 16 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/kthread.h b/sys/compat/linuxkpi/common/include/linux/kthread.h
index 8c7e3c899829..3afd21dc9356 100644
--- a/sys/compat/linuxkpi/common/include/linux/kthread.h
+++ b/sys/compat/linuxkpi/common/include/linux/kthread.h
@@ -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);
+
+#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)
-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 in_atomic() linux_in_atomic()
-#endif /* _LINUX_KTHREAD_H_ */
+#endif /* _LINUX_KTHREAD_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/sched.h b/sys/compat/linuxkpi/common/include/linux/sched.h
index da30db96d6b1..589c0f1e50db 100644
--- a/sys/compat/linuxkpi/common/include/linux/sched.h
+++ b/sys/compat/linuxkpi/common/include/linux/sched.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;
diff --git a/sys/compat/linuxkpi/common/src/linux_current.c b/sys/compat/linuxkpi/common/src/linux_current.c
index f64c8c731947..f0d1e199e816 100644
--- a/sys/compat/linuxkpi/common/src/linux_current.c
+++ b/sys/compat/linuxkpi/common/src/linux_current.c
@@ -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;
diff --git a/sys/compat/linuxkpi/common/src/linux_kthread.c b/sys/compat/linuxkpi/common/src/linux_kthread.c
index aa24e30d61f2..198082615076 100644
--- a/sys/compat/linuxkpi/common/src/linux_kthread.c
+++ b/sys/compat/linuxkpi/common/src/linux_kthread.c
@@ -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();
}
-