···11+/*
22+ * Darling Mach Linux Kernel Module
33+ * Copyright (C) 2015 Lubos Dolezel
44+ *
55+ * This program is free software; you can redistribute it and/or
66+ * modify it under the terms of the GNU General Public License
77+ * as published by the Free Software Foundation; either version 2
88+ * of the License, or (at your option) any later version.
99+ *
1010+ * This program is distributed in the hope that it will be useful,
1111+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313+ * GNU General Public License for more details.
1414+ *
1515+ * You should have received a copy of the GNU General Public License
1616+ * along with this program; if not, write to the Free Software
1717+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1818+ */
1919+#include "psynch_cv.h"
2020+#include "../mach_includes.h"
2121+#include <linux/sched.h>
2222+#include <linux/wait.h>
2323+#include <linux/list.h>
2424+#include <linux/uaccess.h>
2525+#include <linux/slab.h>
2626+#include "../darling_task.h"
2727+#include "../debug.h"
2828+#include <stdbool.h>
2929+#include <linux/jiffies.h>
3030+#include "psynch_mutex.h"
3131+3232+struct pthread_cv
3333+{
3434+ struct hlist_node node;
3535+ uint64_t pointer;
3636+ wait_queue_head_t wq;
3737+ struct list_head waiting;
3838+ unsigned int refcount;
3939+};
4040+typedef struct pthread_cv pthread_cv_t;
4141+4242+struct pthread_waiter
4343+{
4444+ struct list_head entry;
4545+ int wakeup;
4646+ uint32_t
4747+};
4848+4949+static pthread_cv_t* cv_get(mach_task_t* task, uint64_t address,
5050+ bool no_create);
5151+static void cv_put(mach_task_t* task, pthread_cv_t* cv);
5252+5353+int psynch_cvwait_trap(mach_task_t* task,
5454+ struct psynch_cvwait_args* in_args)
5555+{
5656+ struct psynch_cvwait_args args;
5757+ struct pthread_waiter waiter;
5858+ pthread_cv_t* cv;
5959+ int retval;
6060+6161+ if (copy_from_user(&args, in_args, sizeof(args)))
6262+ return -EFAULT;
6363+6464+ debug_msg("psynch_cvwait(): cv=%p, mutex=%p\n",
6565+ args.cv, args.mutex);
6666+ if (args.mutex != 0)
6767+ psynch_mutexdrop(task, args.mutex, args.mgen, args.ugen);
6868+6969+ spin_lock(&task->cv_wq_lock);
7070+7171+ cv = cv_get(task, args.cv, false);
7272+ BUG_ON(cv == NULL);
7373+7474+ waiter.wakeup = 0;
7575+ list_add_tail(&waiter.entry, &cv->waiting);
7676+7777+ spin_unlock(&task->cv_wq_lock);
7878+7979+ // NOTE: args.usec seems to actually contain nsecs
8080+ debug_msg("\tWaiting(%p)\n", &waiter);
8181+ if (args.sec > 0 || args.usec > 0)
8282+ {
8383+ retval = wait_event_interruptible_timeout(cv->wq, waiter.wakeup != 0,
8484+ usecs_to_jiffies(args.sec * USEC_PER_SEC + args.usec / 1000));
8585+ }
8686+ else
8787+ {
8888+ retval = wait_event_interruptible(cv->wq, waiter.wakeup != 0);
8989+ }
9090+9191+ debug_msg("\tWoken up(%p)\n", &waiter);
9292+9393+ spin_lock(&task->cv_wq_lock);
9494+ cv_put(task, cv);
9595+ spin_unlock(&task->cv_wq_lock);
9696+9797+ return retval;
9898+}
9999+100100+int psynch_cvbroad_trap(mach_task_t* task,
101101+ struct psynch_cvbroad_args* in_args)
102102+{
103103+ struct psynch_cvbroad_args args;
104104+ pthread_cv_t* cv;
105105+ struct list_head* item;
106106+107107+ if (copy_from_user(&args, in_args, sizeof(args)))
108108+ return -EFAULT;
109109+110110+ debug_msg("psynch_cvbroad_trap(): cv=%p\n", args.cv);
111111+ spin_lock(&task->cv_wq_lock);
112112+113113+ cv = cv_get(task, args.cv, true);
114114+115115+ if (cv == NULL)
116116+ {
117117+ // Nobody is waiting
118118+ spin_unlock(&task->cv_wq_lock);
119119+ return 0;
120120+ }
121121+122122+ list_for_each(item, &cv->waiting)
123123+ {
124124+ struct pthread_waiter* waiter;
125125+126126+ waiter = list_entry(item, typeof(*waiter), entry);
127127+ debug_msg("\tWake up waiter %p\n", waiter);
128128+ waiter->wakeup = 1;
129129+ }
130130+ INIT_LIST_HEAD(&cv->waiting);
131131+132132+ wake_up_interruptible(&cv->wq);
133133+ cv_put(task, cv);
134134+ spin_unlock(&task->cv_wq_lock);
135135+136136+ return 0x100 /* PTHRW_INC */;
137137+}
138138+139139+int psynch_cvsignal_trap(mach_task_t* task,
140140+ struct psynch_cvsignal_args* in_args)
141141+{
142142+ struct psynch_cvsignal_args args;
143143+ pthread_cv_t* cv;
144144+ struct pthread_waiter* waiter;
145145+146146+ if (copy_from_user(&args, in_args, sizeof(args)))
147147+ return -EFAULT;
148148+149149+ debug_msg("psynch_cvsignal_trap(): cv=%p\n", args.cv);
150150+151151+ spin_lock(&task->cv_wq_lock);
152152+153153+ cv = cv_get(task, args.cv, true);
154154+155155+ if (cv == NULL)
156156+ {
157157+ // Nobody is waiting
158158+ spin_unlock(&task->cv_wq_lock);
159159+ return 0;
160160+ }
161161+162162+ waiter = list_first_entry(&cv->waiting, typeof(*waiter), entry);
163163+ waiter->wakeup = 1;
164164+ debug_msg("\tWake up waiter %p\n", waiter);
165165+ list_del(&waiter->entry);
166166+167167+ wake_up_interruptible(&cv->wq);
168168+ cv_put(task, cv);
169169+ spin_unlock(&task->cv_wq_lock);
170170+171171+ return 0x100 /* PTHRW_INC */;
172172+}
173173+174174+pthread_cv_t* cv_get(mach_task_t* task, uint64_t address, bool no_create)
175175+{
176176+ pthread_cv_t* node;
177177+ hash_for_each_possible(task->cv_wq, node, node, address)
178178+ {
179179+ if (node->pointer != address)
180180+ continue;
181181+182182+ node->refcount++;
183183+ return node;
184184+ }
185185+186186+ if (no_create)
187187+ return NULL;
188188+189189+ node = (pthread_cv_t*) kmalloc(sizeof(pthread_cv_t), GFP_KERNEL);
190190+ node->refcount = 1;
191191+ node->pointer = address;
192192+193193+ init_waitqueue_head(&node->wq);
194194+ INIT_LIST_HEAD(&node->waiting);
195195+ hash_add(task->cv_wq, &node->node, address);
196196+197197+ return node;
198198+}
199199+200200+void cv_put(mach_task_t* task, pthread_cv_t* cv)
201201+{
202202+ cv->refcount--;
203203+204204+ if (cv->refcount == 0)
205205+ {
206206+ hash_del(&cv->node);
207207+ kfree(cv);
208208+ }
209209+}
+33
src/lkm/psynch/psynch_cv.h
···11+/*
22+ * Darling Mach Linux Kernel Module
33+ * Copyright (C) 2015 Lubos Dolezel
44+ *
55+ * This program is free software; you can redistribute it and/or
66+ * modify it under the terms of the GNU General Public License
77+ * as published by the Free Software Foundation; either version 2
88+ * of the License, or (at your option) any later version.
99+ *
1010+ * This program is distributed in the hope that it will be useful,
1111+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1212+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313+ * GNU General Public License for more details.
1414+ *
1515+ * You should have received a copy of the GNU General Public License
1616+ * along with this program; if not, write to the Free Software
1717+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1818+ */
1919+2020+#ifndef PSYNCH_CV_H
2121+#define PSYNCH_CV_H
2222+#include "../api.h"
2323+#include "../ipc_types.h"
2424+2525+int psynch_cvwait_trap(mach_task_t* task,
2626+ struct psynch_cvwait_args* args);
2727+int psynch_cvbroad_trap(mach_task_t* task,
2828+ struct psynch_cvbroad_args* args);
2929+int psynch_cvsignal_trap(mach_task_t* task,
3030+ struct psynch_cvsignal_args* args);
3131+3232+#endif /* PSYNCH_CV_H */
3333+
+15-7
src/lkm/psynch/psynch_mutex.c
···65656666 if (mutex->mgen != 0)
6767 {
6868- spin_unlock(&task->mutex_wq_lock);
6868+ retval = mutex->mgen;
69697070 // Put the mutex twice, because the waker did not put the mutex
7171 // in order to keep the information around
7272 mutex_put(task, mutex);
7373 mutex_put(task, mutex);
7474+7575+ spin_unlock(&task->mutex_wq_lock);
74767575- retval = mutex->mgen;
7677 goto out;
7778 }
7879···103104int psynch_mutexdrop_trap(mach_task_t* task,
104105 struct psynch_mutexdrop_args* in_args)
105106{
106106- pthread_mutex_t* mutex;
107107 struct psynch_mutexdrop_args args;
108108109109 if (copy_from_user(&args, in_args, sizeof(args)))
110110 return -EFAULT;
111111112112- debug_msg("psynch_mutexdrop_trap(%d): mutex=0x%llx, mgen=0x%x\n",
113113- current->pid, args.mutex, args.mgen);
112112+ return psynch_mutexdrop(task, args.mutex, args.mgen, args.ugen);
113113+}
114114+115115+int psynch_mutexdrop(mach_task_t* task, uint64_t in_mutex, uint32_t mgen,
116116+ uint32_t ugen)
117117+{
118118+ pthread_mutex_t* mutex;
119119+120120+ debug_msg("psynch_mutexdrop(%d): mutex=0x%llx, mgen=0x%x\n",
121121+ current->pid, in_mutex, mgen);
114122 spin_lock(&task->mutex_wq_lock);
115123116116- mutex = mutex_get(task, args.mutex);
117117- mutex->mgen = args.mgen;
124124+ mutex = mutex_get(task, in_mutex);
125125+ mutex->mgen = mgen;
118126119127 if (!list_empty(&mutex->waiting))
120128 {