Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sysutils/wmmemfree: modernize, unbreak, undeprecate the port (+)
When I ported this dockapp 20 years ago, it was not uncommon to peek inside ``struct vmmeter'' and other kernel structures with kvm_read(3) to obtain various data (e.g. page counters). These interfaces had always been fragile and potentially unsafe (due to sgid-to-kmem requirement), so let's switch to sysctl(3) instead as it provides the same data via documented, stable API. Address another problem while here: the dockapp tried to update the window from the signal handler, and no Xlib function can be safely called within a signal handler*. Do as advised and only raise a "need update" flag upon receiving a signal, then gather new data and redraw the window in the main loop. This approach, however, cannot work without modifying process_events() because of the blocking nature of XNextEvent(3) -- put another select(2) call in front so it can relinquish control to the outer loop. [*] http://www-h.eng.cam.ac.uk/help/tpl/graphics/X/signals.html
- Loading branch information
Alexey Dokuchaev
authored and
Alexey Dokuchaev
committed
Jul 26, 2023
1 parent
69d3a97
commit c8bcf96
Showing
7 changed files
with
135 additions
and
154 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,118 +1,76 @@ | ||
/* | ||
* mem_freebsd.c - get memory status | ||
* | ||
* Copyright (C) 2003 Alexey Dokuchaev <danfe@regency.nsu.ru> | ||
* Parts are Copyright (C) 1993-2003 FreeBSD Project | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. | ||
*/ | ||
|
||
#include <sys/types.h> | ||
#include <sys/vmmeter.h> | ||
#include <fcntl.h> | ||
#include <kvm.h> | ||
#include <nlist.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <time.h> | ||
#include <sys/sysctl.h> | ||
#include <vm/vm_param.h> | ||
#include <unistd.h> | ||
|
||
#include "mem_freebsd.h" | ||
long long int mem_total, mem_used, mem_buffers, mem_cached; | ||
long long int swp_total, swp_used; | ||
|
||
long long int mem_total, mem_used, mem_free, mem_buffers, mem_cached; | ||
long long int swp_total, swp_used, swp_free; | ||
|
||
static kvm_t *kd; | ||
struct nlist nlst[] = { {"_cnt"}, {"_bufspace"}, {0} }; | ||
enum { total, active, laundry, wired, buffers, swap }; | ||
int mib[swap - total + 1][4]; | ||
/* | ||
* Values below are in kilobytes: we don't need higher granulation, | ||
* and it allows to keep numbers relatively small. | ||
*/ | ||
unsigned int mem[swap - total]; | ||
int pagesize; | ||
|
||
void | ||
mem_init(void) | ||
mem_init() | ||
{ | ||
int pagesize; | ||
|
||
if (!(kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open"))) | ||
{ | ||
perror("kvm_open"); | ||
exit(1); | ||
} | ||
size_t len = 4; | ||
|
||
kvm_nlist(kd, nlst); | ||
/* Precache MIB name vectors for faster lookups later */ | ||
sysctlnametomib("vm.stats.vm.v_page_count", mib[total], &len); | ||
sysctlnametomib("vm.stats.vm.v_active_count", mib[active], &len); | ||
sysctlnametomib("vm.stats.vm.v_laundry_count", mib[laundry], &len); | ||
sysctlnametomib("vm.stats.vm.v_wire_count", mib[wired], &len); | ||
|
||
if (!nlst[0].n_type) | ||
{ | ||
perror("kvm_nlist"); | ||
exit(1); | ||
} | ||
len = 2; | ||
sysctlnametomib("vfs.bufspace", mib[buffers], &len); | ||
sysctlnametomib("vm.swap_info", mib[swap], &len); | ||
|
||
seteuid(getuid()); | ||
setegid(getgid()); | ||
pagesize = getpagesize() / 1024; | ||
} | ||
|
||
if (geteuid() != getuid() || getegid() != getgid()) | ||
{ | ||
perror("sete?id"); | ||
exit(1); | ||
static void | ||
get_swap_info() | ||
{ | ||
struct xswdev xsw; | ||
size_t len = sizeof(xsw); | ||
int n; | ||
|
||
for (swp_total = swp_used = n = 0; ; ++n) { | ||
mib[swap][2] = n; | ||
if (sysctl(mib[swap], 3, &xsw, &len, NULL, 0) == -1) | ||
break; | ||
swp_total += pagesize * xsw.xsw_nblks; | ||
swp_used += pagesize * xsw.xsw_used; | ||
} | ||
} | ||
|
||
void | ||
mem_getfree() | ||
{ | ||
struct vmmeter vm; | ||
struct kvm_swap sw; | ||
int bufspace = 0; | ||
unsigned long cnt_offset; | ||
unsigned long bufspace_offset; | ||
|
||
static int firsttime = 1; | ||
static time_t lasttime = 0; | ||
time_t curtime; | ||
|
||
if ((kvm_read(kd, nlst[0].n_value, &vm, sizeof(vm)) | ||
!= sizeof(vm)) || | ||
(kvm_read(kd, nlst[1].n_value, &bufspace, sizeof(bufspace)) | ||
!= sizeof(bufspace))) | ||
{ | ||
perror("kvm_read"); | ||
exit(1); | ||
} | ||
size_t len = 4; | ||
int n; | ||
|
||
mem_total = vm.v_page_count; | ||
mem_free = vm.v_free_count; | ||
mem_used = mem_total - mem_free; | ||
mem_cached = vm.v_cache_count; | ||
mem_buffers = bufspace / vm.v_page_size; | ||
for (n = 0; n < buffers - total; ++n) | ||
sysctl(mib[n], 4, &mem[n], &len, NULL, 0); | ||
sysctl(mib[buffers], 2, &mem[buffers], &len, NULL, 0); | ||
|
||
/* | ||
* Only calculate when first time or when changes took place. | ||
* Do not call it more than 1 time per 2 seconds; otherwise | ||
* it can eat up to 50% of CPU time on heavy swap activity. | ||
* See the following links for explanation which pages we consider | ||
* free and used (cf. Linux vs. FreeBSD): | ||
* https://unix.stackexchange.com/questions/14102/real-memory-usage | ||
* https://unix.stackexchange.com/questions/134862/what-do-the-different-memory-counters-in-freebsd-mean | ||
*/ | ||
|
||
curtime = time(NULL); | ||
|
||
if (firsttime || curtime > lasttime + 5) | ||
{ | ||
if (kvm_getswapinfo(kd, &sw, 1, 0) >= 0 && | ||
sw.ksw_total) | ||
{ | ||
swp_total = sw.ksw_total; | ||
swp_used = sw.ksw_used; | ||
swp_free = swp_total - swp_used; | ||
} | ||
firsttime = 0; | ||
lasttime = curtime; | ||
} | ||
mem_total = pagesize * mem[total]; | ||
/* On FreeBSD, "Laundry" had replaced "Cache" in November 2016 */ | ||
mem_cached = pagesize * mem[laundry]; | ||
mem_buffers = mem[buffers] / 1024; | ||
mem_used = pagesize * (mem[active] + mem[wired]); | ||
mem_used += mem_cached + mem_buffers; | ||
|
||
get_swap_info(); | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- dockapp.c.orig 2003-03-22 18:30:01 UTC | ||
+++ dockapp.c | ||
@@ -41,7 +41,7 @@ | ||
#define WINDOW_HEIGHT 64 | ||
|
||
Display *display; | ||
-int screen; | ||
+int screen, x11fd; | ||
Window iconwindow, window, mapwindow; | ||
Colormap colormap; | ||
GC gc; | ||
@@ -114,6 +114,7 @@ void make_window() | ||
fprintf(stderr, "Could not open display %s\n", opt_display); | ||
exit(1); | ||
} | ||
+ x11fd = ConnectionNumber(display); | ||
screen = DefaultScreen(display); | ||
screenwidth = DisplayWidth(display, screen); | ||
screenheight = DisplayHeight(display, screen); | ||
@@ -254,6 +255,19 @@ void process_events() | ||
XEvent event; | ||
int winx, winy; | ||
|
||
+ XSync(display, False); | ||
+ if(!XPending(display)) | ||
+ { | ||
+ struct timeval timeout; | ||
+ fd_set readset; | ||
+ const int milliseconds = 200; | ||
+ timeout.tv_sec = milliseconds / 1000; | ||
+ timeout.tv_usec = (milliseconds % 1000) * 1000; | ||
+ FD_ZERO(&readset); | ||
+ FD_SET(x11fd, &readset); | ||
+ if(select(x11fd + 1, &readset, NULL, NULL, &timeout) <= 0) | ||
+ return; | ||
+ } | ||
XNextEvent(display, &event); | ||
switch(event.type) | ||
{ |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters