// Work around 9.1 include-file bugs #include #include #include #include #include #include #include #include #include #include #include #include "ioconf.h" #include "deadman.h" typedef struct softc_deadman SOFTC; struct softc_deadman { unsigned int flags; #define SCF_OPEN 0x00000001 #define SCF_ARMED 0x00000002 int inx; callout_t co; int pid; struct work w; } ; static SOFTC softcs[NDEADMAN]; static kmutex_t deadman_mtx; static struct workqueue *wq; static kmutex_t deadman_coremtx; static void deadman_docore(struct work *w, void *arg __attribute__((__unused__))) { int i; struct proc *p; SOFTC *sc; mutex_enter(&deadman_coremtx); printf("workqueue running for %p\n",(void *)w); for (i=NDEADMAN-1;i>=0;i--) { sc = &softcs[i]; if (w == &sc->w) { printf("found as [%d]\n",i); mutex_enter(proc_lock); p = proc_find(sc->pid); mutex_exit(proc_lock); if (! p) { printf("process not found\n"); } else { printf("dumping core\n"); MODULE_HOOK_CALL_VOID(coredump_hook,(LIST_FIRST(&p->p_lwps),0),); } break; } } mutex_exit(&deadman_coremtx); printf("returning\n"); } static void deadman_timeout(void *scv) { SOFTC *sc; sc = scv; printf("deadman timer fired\n"); mutex_enter(&deadman_mtx); sc->flags &= ~SCF_ARMED; mutex_exit(&deadman_mtx); printf("enqueueing %p for %d\n",(void *)&sc->w,sc->inx); workqueue_enqueue(wq,&sc->w,0); } void deadmanattach(int num) { int i; SOFTC *sc; if (num != NDEADMAN) printf("deadmanattach: arg %d != NDEADMAN %d\n",num,NDEADMAN); mutex_init(&deadman_mtx,MUTEX_DEFAULT,IPL_NONE); mutex_init(&deadman_coremtx,MUTEX_DEFAULT,IPL_NONE); for (i=NDEADMAN-1;i>=0;i--) { sc = &softcs[i]; sc->flags = 0; sc->inx = i; callout_init(&sc->co,0); callout_setfunc(&sc->co,&deadman_timeout,sc); } workqueue_create(&wq,"deadman cores",&deadman_docore,0,PRI_IDLE,IPL_SOFTCLOCK,WQ_MPSAFE); } static int deadmanopen(dev_t dev, int flag, int mode, struct lwp *l) { int u; SOFTC *sc; u = minor(dev); if ((u < 0) || (u >= NDEADMAN)) return(ENXIO); sc = &softcs[u]; mutex_enter(&deadman_mtx); if (sc->flags & SCF_OPEN) { mutex_exit(&deadman_mtx); return(EBUSY); } sc->flags |= SCF_OPEN; sc->flags &= ~SCF_ARMED; sc->pid = l->l_proc->p_pid; mutex_exit(&deadman_mtx); return(0); } static int deadmanclose(dev_t dev, int flag, int mode, struct lwp *l) { int u; SOFTC *sc; u = minor(dev); if ((u < 0) || (u >= NDEADMAN)) panic("closing nonexistent deadman"); sc = &softcs[u]; mutex_enter(&deadman_mtx); if (! (sc->flags & SCF_OPEN)) panic("closing non-open deadman"); sc->flags = 0; callout_stop(&sc->co); mutex_exit(&deadman_mtx); return(0); } static int deadmanwrite(dev_t dev, struct uio *uio, int flags) { struct timeval tv; int ticks; SOFTC *sc; int m; if (uio->uio_rw != UIO_WRITE) { // Can this happen? printf("deadmanwrite: direction %d isn't WRITE\n",(int)uio->uio_rw); return(EIO); } if (uio->uio_resid != sizeof(struct timeval)) return(EIO); m = minor(dev); if ((m < 0) || (m >= NDEADMAN)) panic("writing to nonexistent deadman"); sc = &softcs[minor(dev)]; uiomove(&tv,sizeof(tv),uio); if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) { mutex_enter(&deadman_mtx); sc->flags &= ~SCF_ARMED; callout_stop(&sc->co); mutex_exit(&deadman_mtx); printf("deadman %d stopped\n",sc->inx); } else if (tv.tv_sec > 200000) { return(EDOM); printf("deadman %d EDOM\n",sc->inx); } else { ticks = tvtohz(&tv); mutex_enter(&deadman_mtx); sc->flags |= SCF_ARMED; callout_schedule(&sc->co,ticks); mutex_exit(&deadman_mtx); printf("deadman %d armed %d\n",sc->inx,ticks); } return(0); } const struct cdevsw deadman_cdevsw = { .d_open = deadmanopen, .d_close = deadmanclose, .d_read = noread, .d_write = deadmanwrite, .d_ioctl = noioctl, .d_stop = nostop, .d_tty = notty, .d_poll = nopoll, .d_mmap = nommap, .d_kqfilter = nokqfilter, .d_discard = nodiscard, .d_flag = D_OTHER };