If devinfo.type != AUDIO_MIXER_CLASS is true, xstatbar will never make progress and loop forever. Fix it by trying the next device. Cope with various changes in OpenBSD since xstatbar was written. Skip cpu% text if there are many cores, to avoid some horizontal overruns. Index: stats.c --- stats.c.orig +++ stats.c @@ -61,118 +61,104 @@ fmtmem(int m) * volume stuff ****************************************************************************/ -int -volume_check_dev(int fd, int class, char *name) +/* + * new control + */ +void +volume_ondesc(void *unused, struct sioctl_desc *d, int val) { - mixer_devinfo_t devinfo; + if (d == NULL) + return; - if (class < 0 || name == NULL) - return (-1); + if (d->addr == volume.left_addr) + volume.left_addr = -1; + if (d->addr == volume.right_addr) + volume.right_addr = -1; - devinfo.index = 0; - while (ioctl(fd, AUDIO_MIXER_DEVINFO, &devinfo) >= 0) { - if ((devinfo.type == AUDIO_MIXER_VALUE) - && (devinfo.mixer_class == class) - && (strncmp(devinfo.label.name, name, MAX_AUDIO_DEV_LEN) == 0)) - return (devinfo.index); + if (d->type == SIOCTL_NUM && + strcmp(d->group, "") == 0 && + strcmp(d->node0.name, "output") == 0 && + strcmp(d->func, "level") == 0) { - devinfo.index++; + switch (d->node0.unit) { + case -1: /* mono */ + case 0: /* left */ + volume.left_addr = d->addr; + volume.left_max = d->maxval; + volume.left = val; + break; + case 1: /* right */ + volume.right_addr = d->addr; + volume.right_max = d->maxval; + volume.right = val; + } } +} - return (-1); +/* + * control value changed + */ +void +volume_onval(void *unused, unsigned int addr, unsigned int value) +{ + if (addr == volume.left_addr) + volume.left = value; + if (addr == volume.right_addr) + volume.right = value; } void volume_init() { - mixer_devinfo_t devinfo; - int oclass_idx, iclass_idx; - volume.is_setup = false; + volume.left_addr = volume.right_addr = -1; - /* open mixer */ - if ((volume.dev_fd = open("/dev/mixer", O_RDWR)) < 0) { - warn("volume: failed to open /dev/mixer"); + if ((volume.hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0)) == NULL) { + warn("volume: failed to open default device"); return; } - /* find the outputs and inputs classes */ - oclass_idx = iclass_idx = -1; - devinfo.index = 0; - while (ioctl(volume.dev_fd, AUDIO_MIXER_DEVINFO, &devinfo) >= 0) { - - if (devinfo.type != AUDIO_MIXER_CLASS) - continue; - - if (strncmp(devinfo.label.name, AudioCoutputs, MAX_AUDIO_DEV_LEN) == 0) - oclass_idx = devinfo.index; - if (strncmp(devinfo.label.name, AudioCinputs, MAX_AUDIO_DEV_LEN) == 0) - iclass_idx = devinfo.index; - - if (oclass_idx != -1 && iclass_idx != -1) - break; - - devinfo.index++; + volume.pfds = calloc(sioctl_nfds(volume.hdl), sizeof(struct pollfd)); + if (volume.pfds == NULL) { + warnx("volume: cannot allocate pfds\n"); + goto bad_close; } + - /* find the master device */ - volume.master_idx = volume_check_dev(volume.dev_fd, oclass_idx, AudioNmaster); - if (volume.master_idx == -1) - volume.master_idx = volume_check_dev(volume.dev_fd, iclass_idx, AudioNdac); - if (volume.master_idx == -1) - volume.master_idx = volume_check_dev(volume.dev_fd, oclass_idx, AudioNdac); - if (volume.master_idx == -1) - volume.master_idx = volume_check_dev(volume.dev_fd, oclass_idx, AudioNoutput); - - if (volume.master_idx == -1) { - warnx("volume: failed to find \"master\" mixer device"); - return; + if (!sioctl_ondesc(volume.hdl, volume_ondesc, NULL)) { + warnx("volume: cannot get descriptions\n"); + goto bad_free; } - devinfo.index = volume.master_idx; - if (ioctl(volume.dev_fd, AUDIO_MIXER_DEVINFO, &devinfo) == -1) { - warn("AUDIO_MIXER_DEVINFO"); - return; + if (!sioctl_onval(volume.hdl, volume_onval, NULL)) { + warnx("volume: cannot get values\n"); + goto bad_free; } - volume.max = AUDIO_MAX_GAIN; - volume.nchan = devinfo.un.v.num_channels; - - /* finished... now close the device and reopen as read only */ - close(volume.dev_fd); - volume.dev_fd = open("/dev/mixer", O_RDONLY); - if (volume.dev_fd < 0) { - warn("volume: failed to re-open /dev/mixer"); - return; - } - volume.is_setup = true; + return; +bad_free: + free(volume.pfds); +bad_close: + sioctl_close(volume.hdl); } void volume_update() { - static mixer_ctrl_t vinfo; + int n; if (!volume.is_setup) return; - /* query info */ - vinfo.dev = volume.master_idx; - vinfo.type = AUDIO_MIXER_VALUE; - vinfo.un.value.num_channels = volume.nchan; - if (ioctl(volume.dev_fd, AUDIO_MIXER_READ, &(vinfo)) < 0) { - warn("volume update: AUDIO_MIXER_READ"); - return; + n = sioctl_pollfd(volume.hdl, volume.pfds, POLLIN); + if (n > 0) { + n = poll(volume.pfds, n, 0); + if (n == -1) + return; + if (n > 0) + sioctl_revents(volume.hdl, volume.pfds); } - - /* record in global struct */ - if (volume.nchan == 1) - volume.left = volume.right = vinfo.un.value.level[AUDIO_MIXER_LEVEL_MONO]; - else { - volume.left = vinfo.un.value.level[AUDIO_MIXER_LEVEL_LEFT]; - volume.right = vinfo.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; - } } void @@ -180,7 +166,7 @@ volume_close() { if (!volume.is_setup) return; - close(volume.dev_fd); + sioctl_close(volume.hdl); } int @@ -199,8 +185,9 @@ volume_draw(XColor color, int x, int y) width = 5; /* get volume as percents */ - left = roundf(100.0 * (float)volume.left / (float)volume.max); - right = roundf(100.0 * (float)volume.right / (float)volume.max); + left = roundf(100.0 * (float)volume.left / (float)volume.left_max); + right = (volume.right_addr == -1) ? + left : roundf(100.0 * (float)volume.right / (float)volume.right_max); /* determine height of green-part of bar graphs */ lheight = (int)(left * (float)XINFO.height / 100.0); @@ -358,7 +345,7 @@ sysinfo_init(int hist_size) err(1, "sysinfo init: memory calloc failed"); for (i = 0; i < hist_size; i++) { - if ((sysinfo.memory[i] = calloc(3, sizeof(int))) == NULL) + if ((sysinfo.memory[i] = calloc(4, sizeof(int))) == NULL) err(1, "sysinfo init: memory[%d] calloc failed", i); for (j = 0; j < 3; j++) @@ -372,6 +359,7 @@ sysinfo_init(int hist_size) /* allocate cpu history */ sysinfo.cpu_raw = calloc(sysinfo.ncpu, sizeof(uint64_t**)); + sysinfo.cpu_online = calloc(sysinfo.ncpu, sizeof(*sysinfo.cpu_online)); sysinfo.cpu_pcnts = calloc(sysinfo.ncpu, sizeof(int**)); if (sysinfo.cpu_raw == NULL || sysinfo.cpu_pcnts == NULL) err(1, "sysinfo init: cpu_raw/cpu_pcnts calloc failed"); @@ -404,10 +392,14 @@ sysinfo_update() { static int mib_nprocs[] = { CTL_KERN, KERN_NPROCS }; static int mib_vm[] = { CTL_VM, VM_METER }; - static int mib_cpus[] = { CTL_KERN, 0, 0 }; + static int mib_cpus[] = { CTL_KERN, KERN_CPTIME2, 0 }; + static int mib_cpustats[] = { CTL_KERN, KERN_CPUSTATS, 0 }; + static int mib_bcstats[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT}; static int diffs[CPUSTATES] = { 0 }; struct vmtotal vminfo; struct swapent *swapdev; + struct bcachestats bcstats; + struct cpustats cpustats; size_t size; int cpu, state; int cur, prev; @@ -431,47 +423,46 @@ sysinfo_update() if (sysctl(mib_vm, 2, &vminfo, &size, NULL, 0) < 0) err(1, "sysinfo update: VM.METER failed"); + /* update bufcache statistics */ + size = sizeof(bcstats); + if (sysctl(mib_bcstats, 3, &bcstats, &size, NULL, 0) < 0) + err(1, "sysinfo update: VFS_BCACHESTAT failed"); + + sysinfo.memory[cur][MEM_ACT] = vminfo.t_arm << sysinfo.pageshift; sysinfo.memory[cur][MEM_TOT] = vminfo.t_rm << sysinfo.pageshift; sysinfo.memory[cur][MEM_FRE] = vminfo.t_free << sysinfo.pageshift; + sysinfo.memory[cur][MEM_CCH] = bcstats.numbufpages << sysinfo.pageshift; - /* get swap status */ - if ((nswaps = swapctl(SWAP_NSWAP, 0, 0)) == 0) - errx(1, "swapctl(SWAP_NSWAP) failed... this shouldn't happen"); - if ((swapdev = calloc(nswaps, sizeof(*swapdev))) == NULL) - err(1, "sysinfo update: swapdev calloc failed (%d)", nswaps); - if (swapctl(SWAP_STATS, swapdev, nswaps) == -1) - err(1, "sysinfo update: swapctl(SWAP_STATS) failed"); - sysinfo.swap_used = sysinfo.swap_total = 0; - for (size = 0; size < nswaps; size++) { - if (swapdev[size].se_flags & SWF_ENABLE) { - sysinfo.swap_used += swapdev[size].se_inuse / (1024 / DEV_BSIZE); - sysinfo.swap_total += swapdev[size].se_nblks / (1024 / DEV_BSIZE); + + /* get swap status if swap is in use */ + if ((nswaps = swapctl(SWAP_NSWAP, 0, 0)) != 0) { + if ((swapdev = calloc(nswaps, sizeof(*swapdev))) == NULL) + err(1, "sysinfo update: swapdev calloc failed (%d)", nswaps); + if (swapctl(SWAP_STATS, swapdev, nswaps) == -1) + err(1, "sysinfo update: swapctl(SWAP_STATS) failed"); + + for (size = 0; size < nswaps; size++) { + if (swapdev[size].se_flags & SWF_ENABLE) { + sysinfo.swap_used += swapdev[size].se_inuse / (1024 / DEV_BSIZE); + sysinfo.swap_total += swapdev[size].se_nblks / (1024 / DEV_BSIZE); + } } + free(swapdev); } - free(swapdev); /* get states for each cpu. note this is raw # of ticks */ size = CPUSTATES * sizeof(int64_t); - if (sysinfo.ncpu > 1) { - mib_cpus[1] = KERN_CPTIME2; - for (cpu = 0; cpu < sysinfo.ncpu; cpu++) { - mib_cpus[2] = cpu; - if (sysctl(mib_cpus, 3, sysinfo.cpu_raw[cpu][cur], &size, NULL, 0) < 0) - err(1, "sysinfo update: KERN.CPTIME2.%d failed", cpu); - } - } else { - int i; - long cpu_raw_tmp[CPUSTATES]; - size = sizeof(cpu_raw_tmp); - mib_cpus[1] = KERN_CPTIME; - - if (sysctl(mib_cpus, 2, cpu_raw_tmp, &size, NULL, 0) < 0) - err(1, "sysinfo update: KERN.CPTIME failed"); - - for (i = 0; i < CPUSTATES; i++) - sysinfo.cpu_raw[0][cur][i] = cpu_raw_tmp[i]; + for (cpu = 0; cpu < sysinfo.ncpu; cpu++) { + mib_cpus[2] = cpu; + if (sysctl(mib_cpus, 3, sysinfo.cpu_raw[cpu][cur], &size, NULL, 0) < 0) + err(1, "sysinfo update: KERN.CPTIME2.%d failed", cpu); + mib_cpustats[2] = cpu; + size = sizeof(cpustats); + if (sysctl(mib_cpustats, 3, &cpustats, &size, NULL, 0) < 0) + err(1, "sysinfo update: KERN.CPUSTATS.%d failed", cpu); + sysinfo.cpu_online[cpu] = (cpustats.cs_flags & CPUSTATS_ONLINE) != 0; } /* convert ticks to percentages */ @@ -506,19 +497,19 @@ sysinfo_close() } int -cpu_draw(int cpu, XColor color, int x, int y) +cpu_draw(int cpu, XColor color, int x, int y, int firstcpu) { static char str[1000]; - static char *cpuStateNames[] = { "u", "n", "s", "i", "I" }; + static char *cpuStateNames[] = { "u", "n", "s", "p", "i", "I" }; static XColor *cpuStateColors[] = { - &COLOR_RED, &COLOR_BLUE, &COLOR_YELLOW, &COLOR_MAGENTA, &COLOR_GREEN + &COLOR_RED, &COLOR_BLUE, &COLOR_YELLOW, &COLOR_CYAN, &COLOR_MAGENTA, &COLOR_GREEN }; int state, startx, time, col, h, i; startx = x; - snprintf(str, sizeof(str), "cpu%d:", cpu); - x += render_text(color, x, y, str) + 1; + if (firstcpu) + x += render_text(color, x, y, "cpu:") + 1; /* for the graph, draw a green rectangle to start with */ XSetForeground(XINFO.disp, XINFO.gc, COLOR_GREEN.pixel); @@ -531,7 +522,7 @@ cpu_draw(int cpu, XColor color, int x, int y) /* user time */ h = 0; - for (i = 0; i < 4; i++) h += sysinfo.cpu_pcnts[cpu][time][i]; + for (i = 0; i < 5; i++) h += sysinfo.cpu_pcnts[cpu][time][i]; h = h * XINFO.height / 100; XSetForeground(XINFO.disp, XINFO.gc, COLOR_RED.pixel); XDrawLine(XINFO.disp, XINFO.buf, XINFO.gc, @@ -540,7 +531,7 @@ cpu_draw(int cpu, XColor color, int x, int y) /* nice time */ h = 0; - for (i = 1; i < 4; i++) h += sysinfo.cpu_pcnts[cpu][time][i]; + for (i = 1; i < 5; i++) h += sysinfo.cpu_pcnts[cpu][time][i]; h = h * XINFO.height / 100; XSetForeground(XINFO.disp, XINFO.gc, COLOR_BLUE.pixel); XDrawLine(XINFO.disp, XINFO.buf, XINFO.gc, @@ -549,15 +540,24 @@ cpu_draw(int cpu, XColor color, int x, int y) /* system time */ h = 0; - for (i = 2; i < 4; i++) h += sysinfo.cpu_pcnts[cpu][time][i]; + for (i = 2; i < 5; i++) h += sysinfo.cpu_pcnts[cpu][time][i]; h = h * XINFO.height / 100; XSetForeground(XINFO.disp, XINFO.gc, COLOR_YELLOW.pixel); XDrawLine(XINFO.disp, XINFO.buf, XINFO.gc, x + col, XINFO.height - h, x + col, XINFO.height); + /* spin time */ + h = 0; + for (i = 3; i < 5; i++) h += sysinfo.cpu_pcnts[cpu][time][i]; + h = h * XINFO.height / 100; + XSetForeground(XINFO.disp, XINFO.gc, COLOR_CYAN.pixel); + XDrawLine(XINFO.disp, XINFO.buf, XINFO.gc, + x + col, XINFO.height - h, + x + col, XINFO.height); + /* interrupt time */ - h = sysinfo.cpu_pcnts[cpu][time][3]; + h = sysinfo.cpu_pcnts[cpu][time][4]; h = h * XINFO.height / 100; XSetForeground(XINFO.disp, XINFO.gc, COLOR_MAGENTA.pixel); XDrawLine(XINFO.disp, XINFO.buf, XINFO.gc, @@ -569,13 +569,15 @@ cpu_draw(int cpu, XColor color, int x, int y) x += sysinfo.hist_size + 1; - /* draw the text */ - time = sysinfo.current; - for (state = 0; state < CPUSTATES; state++) { - snprintf(str, sizeof(str), "%3d%%%s", - sysinfo.cpu_pcnts[cpu][time][state], cpuStateNames[state]); + /* draw text, skip if there are many cpus in which case try to avoid overrunning */ + if (sysinfo.ncpu < 8) { + time = sysinfo.current; + for (state = 0; state < CPUSTATES; state++) { + snprintf(str, sizeof(str), "%3d%%%s", + sysinfo.cpu_pcnts[cpu][time][state], cpuStateNames[state]); - x += render_text(*(cpuStateColors[state]), x, y, str); + x += render_text(*(cpuStateColors[state]), x, y, str); + } } return x - startx; @@ -594,7 +596,8 @@ mem_draw(XColor color, int x, int y) /* determine total memory */ total = sysinfo.memory[cur][MEM_ACT] + sysinfo.memory[cur][MEM_TOT] - + sysinfo.memory[cur][MEM_FRE]; + + sysinfo.memory[cur][MEM_FRE] + + sysinfo.memory[cur][MEM_CCH]; /* start drawing ... */ x += render_text(color, x, y, "mem:") + 1; @@ -610,7 +613,8 @@ mem_draw(XColor color, int x, int y) if ((sysinfo.memory[time][MEM_ACT] != 0) || (sysinfo.memory[time][MEM_TOT] != 0) - || (sysinfo.memory[time][MEM_FRE] != 0)) { + || (sysinfo.memory[time][MEM_FRE] != 0) + || (sysinfo.memory[time][MEM_CCH] != 0)) { /* draw yellow (total) bar */ @@ -627,6 +631,13 @@ mem_draw(XColor color, int x, int y) XDrawLine(XINFO.disp, XINFO.buf, XINFO.gc, x + col, XINFO.height - h, x + col, XINFO.height); + + /* draw magenta (cache) bar */ + h = sysinfo.memory[time][MEM_CCH] * XINFO.height / total; + XSetForeground(XINFO.disp, XINFO.gc, COLOR_MAGENTA.pixel); + XDrawLine(XINFO.disp, XINFO.buf, XINFO.gc, + x + col, XINFO.height - h, + x + col, XINFO.height); } time = (time + 1) % sysinfo.hist_size; @@ -639,6 +650,8 @@ mem_draw(XColor color, int x, int y) x += render_text(COLOR_YELLOW, x, y, fmtmem(sysinfo.memory[cur][MEM_TOT])); x += render_text(color, x, y, "/"); x += render_text(COLOR_GREEN, x, y, fmtmem(sysinfo.memory[cur][MEM_FRE])); + x += render_text(color, x, y, "/"); + x += render_text(COLOR_MAGENTA, x, y, fmtmem(sysinfo.memory[cur][MEM_CCH])); /* draw swap, if any is used */ if (sysinfo.swap_used > 0) {