git: c8bcf96c005b - main - sysutils/wmmemfree: modernize, unbreak, undeprecate the port (+)

From: Alexey Dokuchaev <danfe_at_FreeBSD.org>
Date: Wed, 26 Jul 2023 14:11:50 UTC
The branch main has been updated by danfe:

URL: https://cgit.FreeBSD.org/ports/commit/?id=c8bcf96c005b148e5a3074c53b6a5909958e37a4

commit c8bcf96c005b148e5a3074c53b6a5909958e37a4
Author:     Alexey Dokuchaev <danfe@FreeBSD.org>
AuthorDate: 2023-07-26 14:10:34 +0000
Commit:     Alexey Dokuchaev <danfe@FreeBSD.org>
CommitDate: 2023-07-26 14:10:34 +0000

    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
---
 sysutils/wmmemfree/Makefile                |  12 +--
 sysutils/wmmemfree/files/mem_freebsd.c     | 150 +++++++++++------------------
 sysutils/wmmemfree/files/mem_freebsd.h     |  32 ------
 sysutils/wmmemfree/files/patch-Makefile    |   2 +-
 sysutils/wmmemfree/files/patch-dockapp.c   |  39 ++++++++
 sysutils/wmmemfree/files/patch-draw.c      |  11 ---
 sysutils/wmmemfree/files/patch-wmmemfree.c |  43 ++++++++-
 7 files changed, 135 insertions(+), 154 deletions(-)

diff --git a/sysutils/wmmemfree/Makefile b/sysutils/wmmemfree/Makefile
index 37ffa81f9091..e2119be083f7 100644
--- a/sysutils/wmmemfree/Makefile
+++ b/sysutils/wmmemfree/Makefile
@@ -4,21 +4,15 @@ PORTREVISION=	4
 CATEGORIES=	sysutils windowmaker
 MASTER_SITES=	SUNSITE/X11/xutils
 
-MAINTAINER=	ports@FreeBSD.org
+MAINTAINER=	danfe@FreeBSD.org
 COMMENT=	Memory and swap monitoring dockapp
 
-DEPRECATED=	Broken on all supported FreeBSD releases for more than an year
-EXPIRATION_DATE=	2023-08-16
-BROKEN_FreeBSD_12=	fails to compile: read_mem.c: invalid use of undefined type 'struct vmmeter'
-BROKEN_FreeBSD_13=	fails to compile: read_mem.c: invalid use of undefined type 'struct vmmeter'
-BROKEN_FreeBSD_14=	fails to compile: read_mem.c: invalid use of undefined type 'struct vmmeter'
-BROKEN_mips=		fails to compile: mem_freebsd.c: storage size of 'vm' isn't known
-BROKEN_mips64=		fails to compile: mem_freebsd.c: storage size of 'vm' isn't known
+LICENSE=	GPLv2+
 
 USES=		localbase tar:bzip2 xorg
 USE_XORG=	x11 xext xpm
 
-PLIST_FILES=	"@(,kmem,2555) bin/wmmemfree" man/man1/${PORTNAME}.1.gz
+PLIST_FILES=	bin/${PORTNAME} man/man1/${PORTNAME}.1.gz
 
 post-patch:
 	@${CP} ${FILESDIR}/mem_freebsd.* ${WRKSRC}
diff --git a/sysutils/wmmemfree/files/mem_freebsd.c b/sysutils/wmmemfree/files/mem_freebsd.c
index 5575ee31792c..a639a5d8157c 100644
--- a/sysutils/wmmemfree/files/mem_freebsd.c
+++ b/sysutils/wmmemfree/files/mem_freebsd.c
@@ -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();
 }
diff --git a/sysutils/wmmemfree/files/mem_freebsd.h b/sysutils/wmmemfree/files/mem_freebsd.h
deleted file mode 100644
index d0f86dc328a5..000000000000
--- a/sysutils/wmmemfree/files/mem_freebsd.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  mem_freebsd.h
- *
- *  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.
- */
-
-#ifndef __MEM_FREEBSD_H__
-#define __MEM_FREEBSD_H__
-
-extern long long int mem_total, mem_used;
-extern long long int mem_shared, mem_buffers, mem_cached;
-extern long long int swp_total, swp_used;
-
-void mem_init();
-void mem_getfree();
-
-#endif /* __MEM_FREEBSD_H__ */
diff --git a/sysutils/wmmemfree/files/patch-Makefile b/sysutils/wmmemfree/files/patch-Makefile
index 26f34c806042..0b775f3fc0b6 100644
--- a/sysutils/wmmemfree/files/patch-Makefile
+++ b/sysutils/wmmemfree/files/patch-Makefile
@@ -18,7 +18,7 @@
  INST=install
  MANUAL=$(PROG).1
 -LIBS=-L/usr/X11R6/lib -lX11 -lXext -lXpm
-+LIBS+=-lX11 -lXext -lXpm -lkvm
++LIBS+=-lX11 -lXext -lXpm
  
  all: $(PROG)
  
diff --git a/sysutils/wmmemfree/files/patch-dockapp.c b/sysutils/wmmemfree/files/patch-dockapp.c
new file mode 100644
index 000000000000..94d51d597205
--- /dev/null
+++ b/sysutils/wmmemfree/files/patch-dockapp.c
@@ -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)
+  {
diff --git a/sysutils/wmmemfree/files/patch-draw.c b/sysutils/wmmemfree/files/patch-draw.c
deleted file mode 100644
index 1e107ac48a6e..000000000000
--- a/sysutils/wmmemfree/files/patch-draw.c
+++ /dev/null
@@ -1,11 +0,0 @@
---- draw.c.orig	Fri Apr 11 12:47:47 2003
-+++ draw.c	Fri Apr 11 12:47:54 2003
-@@ -24,7 +24,7 @@
- 
- #include "dockapp.h"
- #include "draw.h"
--#include "mem_linux.h"
-+#include "mem_freebsd.h"
- #include "options.h"
- 
- void draw_window()
diff --git a/sysutils/wmmemfree/files/patch-wmmemfree.c b/sysutils/wmmemfree/files/patch-wmmemfree.c
index 62f224511132..0193cc03bea5 100644
--- a/sysutils/wmmemfree/files/patch-wmmemfree.c
+++ b/sysutils/wmmemfree/files/patch-wmmemfree.c
@@ -1,10 +1,27 @@
---- wmmemfree.c.orig	Fri Apr 11 12:48:52 2003
-+++ wmmemfree.c	Fri Apr 11 12:50:05 2003
-@@ -43,10 +43,11 @@
+--- wmmemfree.c.orig	2003-03-21 20:47:14 UTC
++++ wmmemfree.c
+@@ -27,15 +27,18 @@
+ #include "draw.h"
+ #include "options.h"
+ 
++void mem_init();
++
+ int    argc;
+ char **argv;
+ int    exitloop = 0;
++volatile sig_atomic_t need_update = 0;
+ 
+ void handle_timer(int sig)
  {
-  struct itimerval tv;
+  if(sig == SIGALRM)
+  {
+-  draw_window();
++  need_update = 1;
+  }
+ }
+ 
+@@ -45,8 +48,8 @@ void start_timer()
  
-+ mem_init();
   tv.it_value.tv_sec = 2; /* give 2 seconds for safety */
   tv.it_value.tv_usec = 0;
 - tv.it_interval.tv_sec = 0;
@@ -14,3 +31,19 @@
   signal(SIGALRM, handle_timer);
   setitimer(ITIMER_REAL, &tv, NULL);
  }
+@@ -69,9 +72,15 @@ int main(int carg, char **varg)
+  argv = varg;
+  parse_args();
+  make_window();
++ mem_init();
+  start_timer();
+  while(!exitloop)
+  {
++  if(need_update)
++  {
++   draw_window();
++   need_update = 0;
++  }
+   process_events();
+  }
+  stop_timer();