2 * Copyright (c) 2013 Larisa Grigore <larisagrigore@gmail.com>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/sysmsg.h>
34 #include <sys/sysproto.h>
37 #include <sys/malloc.h>
38 #include <sys/ctype.h>
40 #include <sys/device.h>
41 #include <sys/fcntl.h>
42 #include <machine/varargs.h>
43 #include <sys/module.h>
46 #include <sys/filedesc.h>
47 #include <sys/queue.h>
48 #include <sys/spinlock2.h>
50 #include <sys/sysvipc.h>
54 #include <vm/vm_pager.h>
55 #include <vm/vm_param.h>
56 #include <vm/vm_map.h>
58 static cdev_t sysvipc_dev;
59 static d_open_t sysvipc_dev_open;
60 static d_close_t sysvipc_dev_close;
61 //static d_read_t sysvipc_dev_read;
62 //static d_write_t sysvipc_dev_write;
63 static d_ioctl_t sysvipc_dev_ioctl;
64 static d_kqfilter_t sysvipc_dev_kqfilter;
66 static struct dev_ops sysvipc_dev_ops = {
68 .d_open = sysvipc_dev_open,
69 .d_close = sysvipc_dev_close,
70 .d_ioctl = sysvipc_dev_ioctl,
71 .d_kqfilter = sysvipc_dev_kqfilter,
77 TAILQ_ENTRY(sysvipc_req) req_link;
80 TAILQ_HEAD(_req_list, sysvipc_req);
82 struct sysvipc_softc {
84 struct kqinfo sysvipc_rkq;
86 struct _req_list consumed_list;
87 struct _req_list req_list;
88 struct lock consumed_mtx;
90 struct thread *sysvipc_daemon_thread;
94 sysvipc_register(cdev_t dev)
96 struct sysvipc_softc *sysv;
98 if (dev->si_drv1 != NULL)
101 kprintf("aloc sysv\n");
102 dev->si_drv1 = sysv = (struct sysvipc_softc *)
103 kmalloc(sizeof(*sysv), M_TEMP,
105 sysv->sysvipc_dev = dev;
106 TAILQ_INIT(&sysv->req_list);
107 TAILQ_INIT(&sysv->consumed_list);
108 lockinit(&sysv->req_mtx, "sysvlkr", 0, LK_CANRECURSE);
109 lockinit(&sysv->consumed_mtx, "sysvlkc", 0, LK_CANRECURSE);
110 sysv->sysvipc_daemon_thread = curthread;
116 sysvipc_unregister(cdev_t dev)
118 struct sysvipc_softc *sysv = dev->si_drv1;
130 sysvipc_dev_open(struct dev_open_args *ap)
136 sysvipc_dev_close(struct dev_close_args *ap)
141 static void filt_sysvipc_detach(struct knote *);
142 static int filt_sysvipc_read(struct knote *, long);
144 static struct filterops sysvipc_read_filtops =
145 { FILTEROP_ISFD, NULL, filt_sysvipc_detach, filt_sysvipc_read };
148 sysvipc_dev_kqfilter(struct dev_kqfilter_args *ap)
150 cdev_t dev = ap->a_head.a_dev;
151 struct knote *kn = ap->a_kn;
152 struct sysvipc_softc *sysv = dev->si_drv1;
156 kprintf("error read\n");
159 kprintf("kqfilter\n");
162 list = &sysv->sysvipc_rkq.ki_note;
165 switch(kn->kn_filter) {
167 kprintf("event read\n");
168 kn->kn_fop = &sysvipc_read_filtops;
169 kn->kn_hook = (void *)sysv;
172 ap->a_result = EOPNOTSUPP;
176 knote_insert(list, kn);
181 /* TODO: kernel panic at line 181. it is called after unregister_daemon.*/
183 filt_sysvipc_detach(struct knote *kn)
185 /*kprintf("detach\n");
188 kprintf("detach 1\n");
190 struct sysvipc_softc * sysv =
191 (struct sysvipc_softc *)kn->kn_hook;
195 kprintf("detach 2\n");
197 knote_remove(&sysv->sysvipc_rkq.ki_note, kn);
198 kprintf("end detach\n");
203 filt_sysvipc_read(struct knote *kn, long hint)
205 struct sysvipc_softc * sysv =
206 (struct sysvipc_softc *)kn->kn_hook;
209 //TODO what type of lock should I use?!?!
210 lockmgr(&sysv->req_mtx, LK_EXCLUSIVE);
211 ready = !(TAILQ_EMPTY(&sysv->req_list));
212 lockmgr(&sysv->req_mtx, LK_RELEASE);
217 sysvipc_install_fd(struct proc *p_from, struct proc *p_to, int fd)
219 struct filedesc *fdp_from = p_from->p_fd;
220 struct filedesc *fdp_to = p_to->p_fd;
227 * Get the file corresponding to fd from the process p_from.
229 spin_lock(&fdp_from->fd_spin);
230 if ((unsigned)fd >= fdp_from->fd_nfiles || fdp_from->fd_files[fd].fp == NULL) {
231 spin_unlock(&fdp_from->fd_spin);
235 fp = fdp_from->fd_files[fd].fp;
236 flags = fdp_from->fd_files[fd].fileflags;
237 fhold(fp); /* MPSAFE - can be called with a spinlock held */
238 spin_unlock(&fdp_from->fd_spin);
241 * Reserve a fd in the process p_to.
243 error = fdalloc(p_to, 1, &newfd);
250 * Set fd for the fp file.
252 fsetfd(fdp_to, fp, newfd);
253 fdp_to->fd_files[newfd].fileflags = flags;
259 static struct sysvipc_req*
260 sysvipc_find_req(struct _req_list *list,
261 struct lock *req_mtx, pid_t pid)
263 struct sysvipc_req *reqtmp;
264 lockmgr(req_mtx, LK_EXCLUSIVE);
265 TAILQ_FOREACH(reqtmp, list, req_link) {
266 if(reqtmp->proc->p_pid == pid) {
267 lockmgr(req_mtx, LK_RELEASE);
271 lockmgr(req_mtx, LK_RELEASE);
276 get_proc_shm_cred(struct proc *p, struct ipc_perm *perm)
281 perm->cuid = perm->uid = cred->cr_uid;
282 perm->cgid = perm->gid = cred->cr_gid;
288 sysvipc_dev_ioctl(struct dev_ioctl_args *ap)
292 struct proc *proc_to, *proc_from;
293 struct sysvipc_req *req;
294 cdev_t dev = ap->a_head.a_dev;
295 struct sysvipc_softc *sysv = dev->si_drv1;
296 struct client_shm_data *client_data;
301 case REGISTER_DAEMON:
302 kprintf("[driver] register daemon\n");
303 sysvipc_register(dev);
305 case UNREGISTER_DAEMON:
306 sysvipc_unregister(dev);
309 kprintf("[driver] install pipe\n");
311 if(curthread != sysv->sysvipc_daemon_thread)
314 cl = (struct client *)ap->a_data;
316 //kprintf("sysv ipc pid = %d fd 0 = %d fd 1 = %d!\n",
317 //cl->pid, cl->fd[0], cl->fd[1]);
322 proc_from = curthread->td_proc;
323 proc_to = pfind(cl->pid);
325 /* Find the request associated with the client. */
326 req = sysvipc_find_req(&sysv->consumed_list,
327 &sysv->consumed_mtx, cl->pid);
331 /* Install for the client two file descriptors.
332 * The first one is used for read and the second one for
335 req->fd[0] = sysvipc_install_fd(proc_from,
337 req->fd[1] = sysvipc_install_fd(proc_from,
341 /* Wakeup the client. */
345 case REGISTER_TO_DAEMON:
350 if(curthread == sysv->sysvipc_daemon_thread)
353 kprintf("[driver] register to daemon\n");
354 cl = (struct client *)ap->a_data;
356 /* Allocate a struture for the request. */
357 req = (struct sysvipc_req*)kmalloc( sizeof(*req),
358 M_TEMP, M_ZERO | M_WAITOK);
360 req->proc = curthread->td_proc;
362 /* Add the request to the list used read be daemon. */
363 lockmgr(&sysv->req_mtx, LK_EXCLUSIVE);
364 TAILQ_INSERT_HEAD(&sysv->req_list, req, req_link);
365 lockmgr(&sysv->req_mtx, LK_RELEASE);
367 /* Wake up daemon to process the request. */
369 KNOTE(&sysv->sysvipc_rkq.ki_note, 0);
371 /* Wait so that the daemon processes the request and
372 * installs the two new file descriptors.
374 tsleep(req, 0, "regist", 0);
376 //kprintf("client wake up %d %d\n", req->fd[0], req->fd[1]);
377 cl->fd[0] = req->fd[0];
378 cl->fd[1] = req->fd[1];
380 /* Remove the request from the list of consumed requests. */
381 lockmgr(&sysv->consumed_mtx, LK_EXCLUSIVE);
382 TAILQ_REMOVE(&sysv->consumed_list, req, req_link);
383 lockmgr(&sysv->consumed_mtx, LK_RELEASE);
387 case CONSUME_REQUEST:
388 if(curthread != sysv->sysvipc_daemon_thread)
391 /* Wait for new requests. */
392 lockmgr(&sysv->req_mtx, LK_EXCLUSIVE);
393 while(TAILQ_EMPTY(&sysv->req_list))
394 lksleep(sysv, &sysv->req_mtx, 0, "sysv", 0);
395 kprintf("wake up to consume request\n");
397 /* Remove the request from the req_list and add it to the
398 * list of consumed requests.
400 req = TAILQ_LAST( &sysv->req_list, _req_list);
403 TAILQ_REMOVE(&sysv->req_list, req, req_link);
404 lockmgr(&sysv->req_mtx, LK_RELEASE);
406 lockmgr(&sysv->consumed_mtx, LK_EXCLUSIVE);
407 TAILQ_INSERT_HEAD(&sysv->consumed_list, req, req_link);
408 kprintf("pid received = %d\n", req->proc->p_pid);
409 *(pid_t *)ap->a_data = req->proc->p_pid;
410 lockmgr(&sysv->consumed_mtx, LK_RELEASE);
414 if(curthread != sysv->sysvipc_daemon_thread)
417 kprintf("[driver] install fd\n");
418 client_data = (struct client_shm_data *)ap->a_data;
420 /* Get process structure. */
421 proc_from = curthread->td_proc;
422 proc_to = pfind(client_data->pid);
424 /* Get client's credentials. */
425 //get_proc_shm_cred(proc_to, &client_data->shm_perm);
427 /* Install for the client the file descriptor. */
428 client_data->fd = sysvipc_install_fd(proc_from,
429 proc_to, client_data->fd);
443 sysvipc_modevent(module_t mod, int type, void *unused)
445 struct sysvipc_softc *sysv;
449 sysvipc_dev = make_dev(&sysvipc_dev_ops,
456 kprintf("sysv ipc driver ready!\n");
460 sysv = sysvipc_dev->si_drv1;
462 sysvipc_unregister(sysvipc_dev);
463 destroy_dev(sysvipc_dev);
464 kprintf("sysv ipc driver unloaded.\n");
471 static moduledata_t sysvipc_mod = {
477 DECLARE_MODULE(sysvipc, sysvipc_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
478 MODULE_VERSION(sysvipc, 1);