[Pkg-wmaker-commits] [wmbattery] 01/02: wmbattery: Fix memory leak.
Doug Torrance
dtorrance-guest at moszumanska.debian.org
Mon Nov 6 17:49:43 UTC 2017
This is an automated email from the git hooks/post-receive script.
dtorrance-guest pushed a commit to branch upstream
in repository wmbattery.
commit 3b40acdadbf1543048749a1470f655a9e90c2695
Author: Doug Torrance <dtorrance at piedmont.edu>
Date: Mon Nov 6 09:56:52 2017 -0500
wmbattery: Fix memory leak.
Patch by David Johnson <davijoh3 at cisco.com> to fix Debian bug #816872 [1]:
> wmbattery appears to have a memory leak. When invoked with "wmbattery -w 2"
> it is leaking approx 350KB/minute on my system. Eventually it runs out of
> memory and is killed by kernel.
...
> I've concluded libupower-glib is just super leaky. The below patch
> moves the upower API calls into a child process that doesn't exist for
> long to keep the leaks out of the main process.
> Tested against stretch versions, looks good.
[1] https://bugs.debian.org/816872
---
upower.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 95 insertions(+), 31 deletions(-)
diff --git a/upower.c b/upower.c
index 6db4fd1..71fa896 100644
--- a/upower.c
+++ b/upower.c
@@ -6,13 +6,15 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
#include <upower.h>
#include "apm.h"
#define MAX_RETRIES 3
-static UpClient * up;
-
struct context {
int current;
int needed;
@@ -54,29 +56,11 @@ static void get_devinfo(gpointer device, gpointer result)
}
}
-int upower_supported(void)
-{
- up = up_client_new();
-
- if (!up) {
- return 0;
- } else {
- GPtrArray *devices = up_client_get_devices(up);
-
- if (!devices) {
- return 0;
- } else {
- g_ptr_array_unref(devices);
- return 1;
- }
- }
-}
-
/* Fill the passed apm_info struct. */
-int upower_read(int battery, apm_info *info)
+static int upower_read_child(int battery, apm_info *info)
{
+ UpClient * up;
GPtrArray *devices = NULL;
- static int retries = 0;
up = up_client_new();
@@ -90,15 +74,9 @@ int upower_read(int battery, apm_info *info)
devices = up_client_get_devices(up);
- if (!devices) {
- retries++;
- if (retries < MAX_RETRIES)
- return 0; /* fine immediately after hibernation */
- else
- return -1;
- }
+ if (!devices)
+ return -1;
- retries = 0;
info->battery_flags = 0;
info->using_minutes = 0;
@@ -143,6 +121,92 @@ int upower_read(int battery, apm_info *info)
info->battery_status = BATTERY_STATUS_ABSENT;
}
- g_ptr_array_free(devices, TRUE);
+ g_ptr_array_unref(devices);
+ return 0;
+}
+
+static int upower_read_work(int battery, apm_info *info)
+{
+ int sp[2];
+ int child;
+ int status;
+ ssize_t cv;
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp) < 0) {
+ fprintf(stderr, "socketpair: %s", strerror(errno));
+ goto fail;
+ }
+
+ child = fork();
+ if (child < 0) {
+ fprintf(stderr, "fork: %s", strerror(errno));
+ goto fail_close;
+ }
+
+ if (child == 0) {
+ /* child process does work, writes failure or result back to parent */
+ close(sp[0]);
+ status = upower_read_child(battery, info);
+ if (status < 0) {
+ cv = send(sp[1], &status, sizeof(status), 0);
+ }
+ else {
+ cv = send(sp[1], info, sizeof(*info), 0);
+ }
+ exit(cv < 0);
+ }
+ close(sp[1]);
+
+ child = waitpid(child, &status, 0);
+ if (child < 0) {
+ fprintf(stderr, "waitpid: %s status=%d", strerror(errno), status);
+ goto fail_close0;
+ }
+
+ cv = recv(sp[0], info, sizeof(*info), 0);
+ if (cv < 0) {
+ fprintf(stderr, "recv: %s", strerror(errno));
+ goto fail_close0;
+ }
+ else if (cv == sizeof(status)) {
+ memcpy(&status, info, sizeof(status));
+ goto fail_close0;
+ }
+ else if (cv != sizeof(*info)) {
+ fprintf(stderr, "recv: unexpected size %d", cv);
+ goto fail_close0;
+ }
+
+ close(sp[0]);
+ return 0;
+
+ fail_close:
+ close(sp[1]);
+ fail_close0:
+ close(sp[0]);
+ fail:
+ return -1;
+}
+
+int upower_supported(void)
+{
+ apm_info info;
+ return !(upower_read_work(1, &info) < 0);
+}
+
+
+int upower_read(int battery, apm_info *info)
+{
+ static int retries = 0;
+
+ if (upower_read_work(battery, info) < 0) {
+ retries++;
+ if (retries < MAX_RETRIES)
+ return 0; /* fine immediately after hibernation */
+ else
+ return -1;
+ }
+
+ retries = 0;
return 0;
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-wmaker/wmbattery.git
More information about the Pkg-wmaker-commits
mailing list