http://www.mail-archive.com/powersave-devel@forge.novell.com/msg00599.html
GpmInhibit, add g_return_if_fail stuff. Search for FIXME and TODO.
--------------------------------------------------------
to hal: + dsd@gentoo.org
Multicore laptops and turning off cores
Now we are playing with cpu frequency scaling, it would make sense in my opinion to expose a OS neutral API to offline and online CPU's.
I think it was Daniel Drake who showed me how to do this at GUADEC by just echoing a value somewhere in sysfs for his new shiny dual-core laptop.
He also showed me this *dramatically* reduced the power usage of the laptop.
I think it went something like this:
echo 0 > /sys/devices/system/cpu/cpuX/online
This is Linux specific, but we can add Solaris and *BSD support easily. Artem, Joe, what are the commands?
I'm guessing that a dual core laptop appears as two processor objects in HAL, in which case it makes it trivial to add methods:
void org.freedesktop.Hal.Device.ProcessorHotplug.SetOnline(bool)
bool org.freedesktop.Hal.Device.ProcessorHotplug.GetOnline(void)
This scheme wouldn't be possible if the processor object disappears from the HAL device tree which I don't think it does. Daniel can you confirm please?
Note: we can see if a CPU is "offlineable" by the presence of the file /sys/devices/system/cpu/cpuX/online - if it does not exist then you can't offline it, and we shouldn't add the methods or the capability 'processor_hotplug'.
Better interface, capability and method names welcome. :-)
Now, I'm imagining this being used on dual core laptops, but the interface shouldn't rule out other machines, such as insanely big SMP servers with x CPU's.
Sound sane / insane? Imagine a checkbox in a typical policy agent preferences program (heh):
When on battery power:
[x] Turn off additional processors
Now, that would ROCK.
--------------------------------------------------------
GpmProxy *proxy_processor;
DBusGProxy *proxy;
proxy = gpm_proxy_assign (proxy_processor, GPM_PROXY_SESSION, "org.freedesktop.Hal", "org.freedesktop.Hal.Device.ProcessorHotplug", "/org/freedesktop/moo");
If (proxy == NULL) {
g_warning ("could not get initial proxy");
has_hardware = FALSE; /* not a new enough HAL */
}
proxy = gpm_proxy_get_proxy (proxy_processor);
If (proxy == NULL) {
g_warning ("not connected");
return;
}
Then GpmProxy class can monitor changes in dbus session and system busses, and keep the state in a non-singleton object:
Then work on a gpm-cpu-hotplug.[c|h]
MAKE SURE WE HAVE UNIX LINE ENDINGS!
--------------------------------------------------------
private:
int number_cpus
gboolean has_hardware;
int gpm_cpu_hotplug_get_number_cpus (GpmCpuHotplug *cpuhotplug)
int gpm_cpu_hotplug_set_number_cpus (GpmCpuHotplug *cpuhotplug, int cpus)
gboolean gpm_cpu_hotplug_has_hardware (GpmCpuHotplug *cpuhotplug)
--------------------------------------------------------
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2006 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU General Public License Version 2
*
* 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 Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <dbus/dbus-glib.h>
#include "gpm-proxy.h"
#include "gpm-debug.h"
static void gpm_proxy_class_init (GpmProxyClass *klass);
static void gpm_proxy_init (GpmProxy *proxy);
static void gpm_proxy_finalize (GObject *object);
#define GPM_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GPM_TYPE_PROXY, GpmProxyPrivate))
/* this is a managed proxy, i.e. a proxy that handles messagebus and DBUS service restarts. */
/* convert:
trivial:
gpm-polkit
gpm-brightness
complex:
gpm-screensaver
gpm-hal
then, rm gpm-dbus-x-monitor.*
*/
/*
<schema>
<key>/schemas/apps/gnome-power-manager/processor_offline_ac</key>
<applyto>/apps/gnome-power-manager/processor_offline_ac</applyto>
<owner>gnome-power-manager</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>Whether or not we should turn off additional processors when on AC power</short>
<long>Whether or not we should turn off any additional processors to save power when on AC power. This setting only affects multiprocessor servers and dual core laptops.</long>
</locale>
</schema>
<schema>
<key>/schemas/apps/gnome-power-manager/processor_offline_battery</key>
<applyto>/apps/gnome-power-manager/processor_offline_battery</applyto>
<owner>gnome-power-manager</owner>
<type>bool</type>
<default>true</default>
<locale name="C">
<short>Whether or not we should turn off additional processors when on battery power</short>
<long>Whether or not we should turn off any additional processors to save power when on battery power. This setting only affects multiprocessor servers and dual core laptops.</long>
</locale>
</schema>
#define GPM_PREF_AC_OFFLINE_CPU GPM_PREF_DIR "/processor_offline_ac"
#define GPM_PREF_BATTERY_OFFLINE_CPU GPM_PREF_DIR "/processor_offline_battery"
*/
struct GpmProxyPrivate
{
GpmProxyBusType bus_type;
char *service;
char *interface;
char *path;
DBusGProxy *proxy;
DBusGProxy *proxy_dbus;
gboolean *assigned;
DBusGConnection *connection;
};
enum {
DAEMON_START,
DAEMON_STOP,
LAST_SIGNAL
};
static guint signals [LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (GpmProxy, gpm_proxy, G_TYPE_OBJECT)
/**
* gpm_proxy_connect:
* @gproxy: This class instance
* Return value: success
**/
static gboolean
gpm_proxy_connect (GpmProxy *gproxy)
{
g_return_val_if_fail (GPM_IS_PROXY (gproxy), FALSE);
/* are already connected? */
if (gproxy->priv->proxy != NULL) {
gpm_debug ("already connected to %s", gproxy->priv->service);
return FALSE;
}
gproxy->priv->proxy = dbus_g_proxy_new_for_name (gproxy->priv->connection,
gproxy->priv->service,
gproxy->priv->path,
gproxy->priv->interface);
/* shouldn't be, but make sure proxy valid */
if (gproxy->priv->proxy == NULL) {
gpm_debug ("proxy is NULL, maybe the daemon responsible for %s is not running?", gproxy->priv->service,);
return FALSE;
}
g_debug ("emitting daemon-start: %s", gproxy->priv->service);
g_signal_emit (screensaver, signals [DAEMON_START], 0);
return TRUE;
}
/**
* gpm_proxy_disconnect:
* @gproxy: This class instance
* Return value: success
**/
static gboolean
gpm_proxy_disconnect (GpmProxy *gproxy)
{
g_return_val_if_fail (GPM_IS_PROXY (gproxy), FALSE);
/* are already disconnected? */
if (gproxy->priv->proxy == NULL) {
gpm_debug ("already disconnected from %s", gproxy->priv->service);
return FALSE;
}
g_object_unref (gproxy->priv->proxy);
g_debug ("emitting daemon-stop: %s", gproxy->priv->service);
g_signal_emit (screensaver, signals [DAEMON_STOP], 0);
return TRUE;
}
/**
* gpm_proxy_dbus_name_owner_changed:
* @proxy: The DBUS_SERVICE_DBUS proxy
* @name: The DBUS name, e.g. org.freedesktop.Hal
* @prev: The previous name, e.g. :0.13
* @new: The new name, e.g. :0.14
* @gproxy: This class instance
*
* The name-owner-changed session DBUS callback.
**/
static void
gpm_proxy_dbus_name_owner_changed (DBusGProxy *proxy,
const char *name,
const char *prev,
const char *new,
GpmProxy *gproxy)
{
g_return_if_fail (GPM_IS_PROXY (gproxy));
gpm_debug ("emitting name-owner-changed : %s (%s->%s)", name, prev, new);
if (strcmp (name, gproxy->priv->service) == 0) {
if (strlen (prev) != 0 && strlen (new) == 0 ) {
gpm_proxy_disconnect (gproxy);
}
if (strlen (prev) == 0 && strlen (new) != 0 ) {
gpm_proxy_connect (gproxy);
}
}
}
/**
* gpm_proxy_assign:
* @gproxy: This class instance
* @bus_type: The bus type, either GPM_PROXY_SESSION or GPM_PROXY_SYSTEM
* @service: The DBUS service name
* @interface: The DBUS interface
* @path: The DBUS path
* Return value: The DBUS proxy, or NULL if we haven't connected yet.
**/
DBusGProxy *
gpm_proxy_assign (GpmProxy *gproxy, GpmProxyBusType bus_type, char *service, char *interface, char *path)
{
GError *error = NULL;
g_return_val_if_fail (GPM_IS_PROXY (gproxy), NULL);
g_return_val_if_fail (service != NULL, NULL);
g_return_val_if_fail (interface != NULL, NULL);
g_return_val_if_fail (path != NULL, NULL);
if (gproxy->priv->assigned == TRUE) {
gpm_warning ("already assigned proxy!");
return NULL;
}
gproxy->priv->service = g_strdup (service);
gproxy->priv->interface = g_strdup (interface);
gproxy->priv->path = g_strdup (path);
gproxy->priv->bus_type = bus_type;
gproxy->priv->assigned == TRUE;
/* get the DBUS connection */
if (bus_type == GPM_PROXY_SESSION) {
gproxy->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
} else {
gproxy->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
}
if (error) {
gpm_warning ("Cannot connect to DBUS daemon: %s", error->message);
g_error_free (error);
return NULL;
}
/* set up dbus callbacks to monitor the service */
gproxy->priv->proxy_dbus = dbus_g_proxy_new_for_name_owner (monitor->priv->connection,
DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
&error);
if (error) {
gpm_warning ("Cannot connect to DBUS manager: %s", error->message);
g_error_free (error);
return NULL;
}
dbus_g_proxy_add_signal (gproxy->priv->proxy, "NameOwnerChanged",
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
dbus_g_proxy_connect_signal (gproxy->priv->proxy, "NameOwnerChanged",
G_CALLBACK (dbus_name_owner_changed),
gproxy, NULL);
/* try to connect and return proxy (or NULL if invalid) */
gpm_proxy_connect (gproxy);
return gproxy->priv->proxy;
}
/**
* gpm_proxy_get_service:
* @gproxy: This class instance
* Return value: The DBUS proxy, or NULL if we are not connected
**/
DBusGProxy *
gpm_proxy_get_proxy (GpmProxy *gproxy)
{
g_return_val_if_fail (GPM_IS_PROXY (gproxy), NULL);
g_return_val_if_fail (gproxy->priv->assigned == TRUE, NULL);
return gproxy->priv->proxy;
}
/**
* gpm_proxy_get_service:
* @gproxy: This class instance
* Return value: The DBUS service name
**/
char *
gpm_proxy_get_service (GpmProxy *gproxy)
{
g_return_val_if_fail (GPM_IS_PROXY (gproxy), NULL);
g_return_val_if_fail (gproxy->priv->assigned == TRUE, NULL);
return gproxy->priv->service;
}
/**
* gpm_proxy_get_interface:
* @gproxy: This class instance
* Return value: The DBUS interface
**/
char *
gpm_proxy_get_interface (GpmProxy *gproxy)
{
g_return_val_if_fail (GPM_IS_PROXY (gproxy), NULL);
g_return_val_if_fail (gproxy->priv->assigned == TRUE, NULL);
return gproxy->priv->interface;
}
/**
* gpm_proxy_get_path:
* @gproxy: This class instance
* Return value: The DBUS path
**/
char *
gpm_proxy_get_path (GpmProxy *gproxy)
{
g_return_val_if_fail (GPM_IS_PROXY (gproxy), NULL);
g_return_val_if_fail (gproxy->priv->assigned == TRUE, NULL);
return gproxy->priv->path;
}
/**
* gpm_proxy_get_bus_type:
* @gproxy: This class instance
* Return value: The bus type, either GPM_PROXY_SESSION or GPM_PROXY_SYSTEM
**/
GpmProxyBusType
gpm_proxy_get_bus_type (GpmProxy *gproxy)
{
g_return_val_if_fail (GPM_IS_PROXY (gproxy), GPM_PROXY_UNKNOWN);
g_return_val_if_fail (gproxy->priv->assigned == TRUE, GPM_PROXY_UNKNOWN);
return gproxy->priv->bus_type;
}
/**
* gpm_proxy_class_init:
* @gproxy: This class instance
**/
static void
gpm_proxy_class_init (GpmProxyClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gpm_proxy_finalize;
g_type_class_add_private (klass, sizeof (GpmProxyPrivate));
signals [DAEMON_START] =
g_signal_new ("daemon-start",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GpmProxyClass, daemon_start),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
signals [DAEMON_STOP] =
g_signal_new ("daemon-stop",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GpmProxyClass, daemon_stop),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
}
/**
* gpm_proxy_init:
* @gproxy: This class instance
**/
static void
gpm_proxy_init (GpmProxy *gproxy)
{
gproxy->priv = GPM_PROXY_GET_PRIVATE (proxy);
gproxy->priv->proxy = NULL;
gproxy->priv->proxy_dbus = NULL;
gproxy->priv->service = NULL;
gproxy->priv->interface = NULL;
gproxy->priv->path = NULL;
gproxy->priv->bus_type = GPM_PROXY_UNKOWN;
gproxy->priv->assigned = FALSE;
}
/**
* gpm_proxy_finalize:
* @object: This class instance
**/
static void
gpm_proxy_finalize (GObject *object)
{
GpmProxy *gproxy;
g_return_if_fail (object != NULL);
g_return_if_fail (GPM_IS_PROXY (object));
gproxy = GPM_PROXY (object);
gproxy->priv = GPM_PROXY_GET_PRIVATE (proxy);
gpm_proxy_disconnect (gproxy);
g_object_unref (gproxy->priv->proxy_dbus);
g_object_unref (gproxy->priv->proxy);
g_free (gproxy->priv->service);
g_free (gproxy->priv->interface;
g_free (gproxy->priv->path);
}
/**
* gpm_proxy_new:
* Return value: new class instance.
**/
GpmProxy *
gpm_proxy_new (void)
{
GpmProxy *proxy;
proxy = g_object_new (GPM_TYPE_PROXY, NULL);
return GPM_PROXY (proxy);
}
--------------------------------------------------------
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2006 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU General Public License Version 2
*
* 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 Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __GPMPROXY_H
#define __GPMPROXY_H
#include <glib-object.h>
G_BEGIN_DECLS
#define GPM_TYPE_PROXY (gpm_proxy_get_type ())
#define GPM_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GPM_TYPE_PROXY, GpmProxy))
#define GPM_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GPM_TYPE_PROXY, GpmProxyClass))
#define GPM_IS_PROXY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GPM_TYPE_PROXY))
#define GPM_IS_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GPM_TYPE_PROXY))
#define GPM_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GPM_TYPE_PROXY, GpmProxyClass))
typedef struct GpmProxyPrivate GpmProxyPrivate;
typedef struct
{
GObject parent;
GpmProxyPrivate *priv;
} GpmProxy;
typedef struct
{
GObjectClass parent_class;
void (* daemon_start) (GpmProxy *proxy);
void (* daemon_stop) (GpmProxy *proxy);
} GpmProxyClass;
typedef emum {
GPM_PROXY_SESSION,
GPM_PROXY_SYSTEM,
GPM_PROXY_UNKNOWN
} GpmProxyBusType;
GType gpm_proxy_get_type (void);
GpmProxy *gpm_proxy_new (void);
DBusGProxy *gpm_proxy_assign (GpmProxy *gproxy,
GpmProxyBusType bus_type,
char *service,
char *interface,
char *path);
DBusGProxy *gpm_proxy_get_proxy (GpmProxy *gproxy);
char *gpm_proxy_get_service (GpmProxy *gproxy);
char *gpm_proxy_get_interface (GpmProxy *gproxy);
char *gpm_proxy_get_path (GpmProxy *gproxy);
GpmProxyBusType gpm_proxy_get_bus_type (GpmProxy *gproxy);
G_END_DECLS
#endif /* __GPMPROXY_H */
---------------------------------------------------
-------------------------------------------------------------