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 * * 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 #include #include #include #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.* */ /* /schemas/apps/gnome-power-manager/processor_offline_ac /apps/gnome-power-manager/processor_offline_ac gnome-power-manager bool true Whether or not we should turn off additional processors when on AC power 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. /schemas/apps/gnome-power-manager/processor_offline_battery /apps/gnome-power-manager/processor_offline_battery gnome-power-manager bool true Whether or not we should turn off additional processors when on battery power 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. #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 * * 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 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 */ --------------------------------------------------- -------------------------------------------------------------