void dev_sio_stop(struct dev *d) { if (!sio_eof(d->sio.hdl) && !sio_stop(d->sio.hdl)) { if (log_level >= 1) { dev_log(d); log_puts(": failed to stop device\n"); } return; } #ifdef DEBUG if (log_level >= 3) { dev_log(d); log_puts(": stopped, load avg = "); log_puti(d->sio.sum_utime / 1000); log_puts(" / "); log_puti(d->sio.sum_wtime / 1000); log_puts("\n"); } #endif timo_del(&d->sio.watchdog); }
void dev_sio_onmove(void *arg, int delta) { struct dev *d = arg; #ifdef DEBUG if (log_level >= 4) { dev_log(d); log_puts(": tick, delta = "); log_puti(delta); log_puts("\n"); } d->sio.sum_utime += file_utime - d->sio.utime; d->sio.sum_wtime += file_wtime - d->sio.wtime; d->sio.wtime = file_wtime; d->sio.utime = file_utime; if (d->mode & MODE_PLAY) d->sio.pused -= delta; if (d->mode & MODE_REC) d->sio.rused += delta; #endif dev_onmove(d, delta); }
static int fdpass_send(struct fdpass *f, int cmd, int num, int mode, int fd) { struct fdpass_msg data; struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr hdr; unsigned char buf[CMSG_SPACE(sizeof(int))]; } cmsgbuf; struct iovec iov; ssize_t n; data.cmd = cmd; data.num = num; data.mode = mode; iov.iov_base = &data; iov.iov_len = sizeof(struct fdpass_msg); memset(&msg, 0, sizeof(msg)); msg.msg_iov = &iov; msg.msg_iovlen = 1; if (fd >= 0) { msg.msg_control = &cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsg) = fd; } n = sendmsg(f->fd, &msg, 0); if (n < 0) { if (log_level >= 1) { fdpass_log(f); log_puts(": sendmsg failed\n"); } fdpass_close(f); return 0; } if (n != sizeof(struct fdpass_msg)) { if (log_level >= 1) { fdpass_log(f); log_puts(": short write\n"); } fdpass_close(f); return 0; } #ifdef DEBUG if (log_level >= 3) { fdpass_log(f); log_puts(": send: cmd = "); log_puti(cmd); log_puts(", num = "); log_puti(num); log_puts(", mode = "); log_puti(mode); log_puts(", fd = "); log_puti(fd); log_puts("\n"); } #endif if (fd >= 0) close(fd); return 1; }
static int fdpass_recv(struct fdpass *f, int *cmd, int *num, int *mode, int *fd) { struct fdpass_msg data; struct msghdr msg; struct cmsghdr *cmsg; union { struct cmsghdr hdr; unsigned char buf[CMSG_SPACE(sizeof(int))]; } cmsgbuf; struct iovec iov; ssize_t n; iov.iov_base = &data; iov.iov_len = sizeof(struct fdpass_msg); memset(&msg, 0, sizeof(msg)); msg.msg_control = &cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); msg.msg_iov = &iov; msg.msg_iovlen = 1; n = recvmsg(f->fd, &msg, MSG_WAITALL); if (n < 0 && errno == EMSGSIZE) { if (log_level >= 1) { fdpass_log(f); log_puts(": out of fds\n"); } /* * ancillary data (ie the fd) is discarded, * retrieve the message */ n = recvmsg(f->fd, &msg, MSG_WAITALL); } if (n < 0) { if (log_level >= 1) { fdpass_log(f); log_puts(": recvmsg failed\n"); } fdpass_close(f); return 0; } if (n == 0) { if (log_level >= 3) { fdpass_log(f); log_puts(": recvmsg eof\n"); } fdpass_close(f); return 0; } if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { if (log_level >= 1) { fdpass_log(f); log_puts(": truncated\n"); } fdpass_close(f); return 0; } cmsg = CMSG_FIRSTHDR(&msg); for (;;) { if (cmsg == NULL) { *fd = -1; break; } if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { *fd = *(int *)CMSG_DATA(cmsg); break; } cmsg = CMSG_NXTHDR(&msg, cmsg); } *cmd = data.cmd; *num = data.num; *mode = data.mode; #ifdef DEBUG if (log_level >= 3) { fdpass_log(f); log_puts(": recv: cmd = "); log_puti(*cmd); log_puts(", num = "); log_puti(*num); log_puts(", mode = "); log_puti(*mode); log_puts(", fd = "); log_puti(*fd); log_puts("\n"); } #endif return 1; }
void dev_sio_run(void *arg) { struct dev *d = arg; unsigned char *data, *base; unsigned int n; /* * sio_read() and sio_write() would block at the end of the * cycle so we *must* return and restart poll()'ing. Otherwise * we may trigger dev_cycle() which would make all clients * underrun (ex, on a play-only device) */ for (;;) { if (d->pstate != DEV_RUN) return; switch (d->sio.cstate) { case DEV_SIO_READ: #ifdef DEBUG if (!(d->sio.events & POLLIN)) { dev_log(d); log_puts(": recording, but POLLIN not set\n"); panic(); } if (d->sio.todo == 0) { dev_log(d); log_puts(": can't read data\n"); panic(); } if (d->prime > 0) { dev_log(d); log_puts(": unexpected data\n"); panic(); } #endif base = d->decbuf ? d->decbuf : (unsigned char *)d->rbuf; data = base + d->rchan * d->round * d->par.bps - d->sio.todo; n = sio_read(d->sio.hdl, data, d->sio.todo); d->sio.todo -= n; #ifdef DEBUG if (log_level >= 4) { dev_log(d); log_puts(": read "); log_putu(n); log_puts(": bytes, todo "); log_putu(d->sio.todo); log_puts("/"); log_putu(d->round * d->rchan * d->par.bps); log_puts("\n"); } #endif if (d->sio.todo > 0) return; #ifdef DEBUG d->sio.rused -= d->round; if (log_level >= 2) { if (d->sio.rused >= d->round) { dev_log(d); log_puts(": rec hw xrun, rused = "); log_puti(d->sio.rused); log_puts("/"); log_puti(d->bufsz); log_puts("\n"); } if (d->sio.rused < 0 || d->sio.rused >= d->bufsz) { dev_log(d); log_puts(": out of bounds rused = "); log_puti(d->sio.rused); log_puts("/"); log_puti(d->bufsz); log_puts("\n"); } } #endif d->sio.cstate = DEV_SIO_CYCLE; break; case DEV_SIO_CYCLE: timo_del(&d->sio.watchdog); timo_add(&d->sio.watchdog, WATCHDOG_USEC); #ifdef DEBUG /* * check that we're called at cycle boundary: * either after a recorded block, or when POLLOUT is * raised */ if (!((d->mode & MODE_REC) && d->prime == 0) && !(d->sio.events & POLLOUT)) { dev_log(d); log_puts(": cycle not at block boundary\n"); panic(); } #endif dev_cycle(d); if (d->mode & MODE_PLAY) { d->sio.cstate = DEV_SIO_WRITE; d->sio.todo = d->round * d->pchan * d->par.bps; break; } else { d->sio.cstate = DEV_SIO_READ; d->sio.todo = d->round * d->rchan * d->par.bps; return; } case DEV_SIO_WRITE: #ifdef DEBUG if (d->sio.todo == 0) { dev_log(d); log_puts(": can't write data\n"); panic(); } #endif base = d->encbuf ? d->encbuf : (unsigned char *)DEV_PBUF(d); data = base + d->pchan * d->round * d->par.bps - d->sio.todo; n = sio_write(d->sio.hdl, data, d->sio.todo); d->sio.todo -= n; #ifdef DEBUG if (log_level >= 4) { dev_log(d); log_puts(": wrote "); log_putu(n); log_puts(" bytes, todo "); log_putu(d->sio.todo); log_puts("/"); log_putu(d->round * d->pchan * d->par.bps); log_puts("\n"); } #endif if (d->sio.todo > 0) return; #ifdef DEBUG d->sio.pused += d->round; if (log_level >= 2) { if (d->prime == 0 && d->sio.pused <= d->bufsz - d->round) { dev_log(d); log_puts(": play hw xrun, pused = "); log_puti(d->sio.pused); log_puts("/"); log_puti(d->bufsz); log_puts("\n"); } if (d->sio.pused < 0 || d->sio.pused > d->bufsz) { /* device driver or libsndio bug */ dev_log(d); log_puts(": out of bounds pused = "); log_puti(d->sio.pused); log_puts("/"); log_puti(d->bufsz); log_puts("\n"); } } #endif d->poffs += d->round; if (d->poffs == d->psize) d->poffs = 0; if ((d->mode & MODE_REC) && d->prime == 0) { d->sio.cstate = DEV_SIO_READ; d->sio.todo = d->round * d->rchan * d->par.bps; } else d->sio.cstate = DEV_SIO_CYCLE; return; } } }