From ce3f2520c5046c7b7703742dd5c7481b5f98c52e Mon Sep 17 00:00:00 2001 From: Radek Novacek Date: Mon, 23 Jul 2012 13:41:47 +0200 Subject: Restructure Power provider * get rid of src/ subdirectory in power/ * cleanup CMake * use konkretcmpi_generate macro --- src/power/power.c | 518 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 518 insertions(+) create mode 100644 src/power/power.c (limited to 'src/power/power.c') diff --git a/src/power/power.c b/src/power/power.c new file mode 100644 index 0000000..3210a37 --- /dev/null +++ b/src/power/power.c @@ -0,0 +1,518 @@ +#include "power.h" + +#include +#include + +#include + +#include "Linux_AssociatedPowerManagementService.h" +#include "Linux_ConcreteJob.h" + +#ifdef HAS_UPOWER +#include +#endif + +struct _Power { + unsigned int instances; + unsigned short requestedPowerState; + unsigned short transitioningToPowerState; + const CMPIBroker *broker; + CMPI_MUTEX_TYPE mutex; + GList *jobs; // list of PowerStateChangeJob +#ifdef HAS_UPOWER + UpClient *up; +#endif +}; + +#define MUTEX_LOCK(power) power->broker->xft->lockMutex(power->mutex) +#define MUTEX_UNLOCK(power) power->broker->xft->unlockMutex(power->mutex) + +struct _PowerStateChangeJob { + const CMPIBroker *broker; + Power *power; + unsigned short requestedPowerState; + unsigned short jobState; + int timeOfLastChange; + int timeBeforeRemoval; + int cancelled; + int superseded; // There is another job that overrides this job + char *error; + CMPI_THREAD_TYPE thread; + CMPI_MUTEX_TYPE mutex; +}; + +Power *_power = NULL; + + +// This is just for debugging purposes, remove later +#include +#include +#include +void print_backtrace(int signal) +{ + fprintf(stderr, "BackTrace\n"); + void *buffer[32]; + int count = backtrace(buffer, 32); + fprintf(stderr, "Size: %d\n", count); + backtrace_symbols_fd(buffer, count, stderr->_fileno); + fprintf(stderr, "Segfault detected, process id: %d. Entering infinite loop.\n", getpid()); + volatile int end = 0; + while (!end) { + sleep(1); + } +} + +Power *power_new(const CMPIBroker *_cb) +{ + signal(SIGSEGV, print_backtrace); + fprintf(stderr, "BackTrace handler registered\n"); + + Power *power = malloc(sizeof(Power)); + power->broker = _cb; + power->instances = 0; + power->requestedPowerState = Linux_AssociatedPowerManagementService_RequestedPowerState_Unknown; + power->transitioningToPowerState = Linux_AssociatedPowerManagementService_TransitioningToPowerState_No_Change; + power->mutex = _cb->xft->newMutex(0); + power->jobs = NULL; +#ifdef HAS_UPOWER + g_type_init(); + power->up = up_client_new(); +#endif + return power; +} + +void power_destroy(Power *power) +{ +#ifdef HAS_UPOWER + free(power->up); +#endif +} + +Power *power_ref(const CMPIBroker *_cb) +{ + if (_power == NULL) { + _power = power_new(_cb); + } + MUTEX_LOCK(_power); + _power->instances++; + MUTEX_UNLOCK(_power); + return _power; +} + +void power_unref(Power *power) +{ + MUTEX_LOCK(power); + power->instances--; + MUTEX_UNLOCK(power); + if (power->instances == 0) { + power_destroy(power); + power = NULL; + _power = NULL; + } +} + +unsigned short power_requested_power_state(Power *power) +{ + return power->requestedPowerState; +} + +unsigned short power_transitioning_to_power_state(Power *power) +{ + return power->transitioningToPowerState; +} + +void *state_change_thread(void *data) +{ + PowerStateChangeJob *powerStateChangeJob = data; + MUTEX_LOCK(powerStateChangeJob); + powerStateChangeJob->jobState = Linux_ConcreteJob_JobState_Running; + powerStateChangeJob->timeOfLastChange = time(NULL); + MUTEX_UNLOCK(powerStateChangeJob); + + + // Check if the job was cancelled + if (powerStateChangeJob->cancelled) { + MUTEX_LOCK(powerStateChangeJob); + powerStateChangeJob->jobState = Linux_ConcreteJob_JobState_Terminated; + powerStateChangeJob->timeOfLastChange = time(NULL); + MUTEX_UNLOCK(powerStateChangeJob); + + if (!powerStateChangeJob->superseded) { + // There is no job that replaced this job + MUTEX_LOCK(powerStateChangeJob->power); + powerStateChangeJob->power->transitioningToPowerState = Linux_AssociatedPowerManagementService_TransitioningToPowerState_No_Change; + MUTEX_UNLOCK(powerStateChangeJob->power); + } + + fprintf(stderr, "state_change_thread cancelled\n"); + return NULL; + } + + // Execute the job +#ifdef HAS_UPOWER + GError *error = NULL; +#endif + + int succeeded = 0; + switch (powerStateChangeJob->requestedPowerState) { + case Linux_AssociatedPowerManagementService_PowerState_Sleep__Deep: + // Sleep +#ifdef HAS_UPOWER + succeeded = up_client_suspend_sync(powerStateChangeJob->power->up, NULL, &error); +#else + succeeded = system("pm-suspend") == 0; +#endif + break; + case Linux_AssociatedPowerManagementService_PowerState_Power_Cycle_Off___Soft: + // Reboot (without shutting down programs) +#ifdef HAS_SYSTEMCTL + succeeded = system("systemctl --force reboot &") == 0; +#else + succeeded = system("reboot --force &") == 0; +#endif + break; + case Linux_AssociatedPowerManagementService_PowerState_Hibernate_Off___Soft: + // Hibernate +#ifdef HAS_UPOWER + succeeded = up_client_hibernate_sync(powerStateChangeJob->power->up, NULL, &error); +#else + succeeded = system("pm-hibernate") == 0; +#endif + break; + case Linux_AssociatedPowerManagementService_PowerState_Off___Soft: + // Poweroff (without shutting down programs) +#ifdef HAS_SYSTEMCTL + succeeded = system("systemctl --force poweroff &") == 0; +#else + succeeded = system("shutdown --halt now &") == 0; +#endif + break; + case Linux_AssociatedPowerManagementService_PowerState_Off___Soft_Graceful: + // Poweroff (shut down programs first) +#ifdef HAS_SYSTEMCTL + succeeded = system("systemctl poweroff &") == 0; +#else + succeeded = system("shutdown --poweroff now &") == 0; +#endif + break; + case Linux_AssociatedPowerManagementService_PowerState_Power_Cycle_Off___Soft_Graceful: + // Reboot (shut down programs first) +#ifdef HAS_SYSTEMCTL + succeeded = system("systemctl reboot &") == 0; +#else + succeeded = system("shutdown --reboot now &") == 0; +#endif + break; + } + + MUTEX_LOCK(powerStateChangeJob->power); + powerStateChangeJob->power->transitioningToPowerState = Linux_AssociatedPowerManagementService_TransitioningToPowerState_No_Change; + MUTEX_UNLOCK(powerStateChangeJob->power); + + MUTEX_LOCK(powerStateChangeJob); + if (succeeded) { + powerStateChangeJob->jobState = Linux_ConcreteJob_JobState_Completed; + } else { + powerStateChangeJob->jobState = Linux_ConcreteJob_JobState_Exception; +#ifdef HAS_UPOWER + if (error != NULL) { + powerStateChangeJob->error = error->message; + } +#endif + } + powerStateChangeJob->timeOfLastChange = time(NULL); + MUTEX_UNLOCK(powerStateChangeJob); + + fprintf(stderr, "state_change_thread finished\n"); + return NULL; +} + +int power_request_power_state(Power *power, unsigned short state) +{ + int rc = CMPI_RC_OK; + + int count, found = 0; + unsigned short *states = power_available_requested_power_states(power, &count); + for (int i = 0; i < count; ++i) { + if (states[i] == state) { + found = 1; + break; + } + } + free(states); + if (!found) { + fprintf(stderr, "Invalid state: %d\n", state); + return CMPI_RC_ERR_INVALID_PARAMETER; + } + + PowerStateChangeJob *powerStateChangeJob = malloc(sizeof(PowerStateChangeJob)); + powerStateChangeJob->broker = power->broker; + powerStateChangeJob->power = power; + powerStateChangeJob->mutex = power->broker->xft->newMutex(0); + powerStateChangeJob->requestedPowerState = state; + powerStateChangeJob->jobState = Linux_ConcreteJob_JobState_New; + powerStateChangeJob->cancelled = 0; + powerStateChangeJob->superseded = 0; + powerStateChangeJob->timeOfLastChange = time(NULL); + powerStateChangeJob->timeBeforeRemoval = 300; + powerStateChangeJob->error = NULL; + + MUTEX_LOCK(power); + power->requestedPowerState = state; + power->transitioningToPowerState = state; + + PowerStateChangeJob *job; + GList *plist = power->jobs; + while (plist) { + job = plist->data; + MUTEX_LOCK(job); + if (job->jobState != Linux_ConcreteJob_JobState_Suspended && + job->jobState != Linux_ConcreteJob_JobState_Killed && + job->jobState != Linux_ConcreteJob_JobState_Terminated) { + + job->cancelled = 1; + job->superseded = 1; + job->jobState = Linux_ConcreteJob_JobState_Shutting_Down; + job->timeOfLastChange = time(NULL); + } + MUTEX_UNLOCK(job); + plist = g_list_next(plist); + } + powerStateChangeJob->thread = power->broker->xft->newThread(state_change_thread, powerStateChangeJob, 1); + power->jobs = g_list_append(power->jobs, powerStateChangeJob); + MUTEX_UNLOCK(power); + fprintf(stderr, "State change thread started\n"); + + return rc; +} + +unsigned short *power_available_requested_power_states(Power *power, int *count) +{ + unsigned short *list = malloc(17 * sizeof(unsigned short)); + int i = 0; + + /* 1 Other + * Linux_AssociatedPowerManagementService_PowerState_Other + */ + + /* 2 On + * corresponding to ACPI state G0 or S0 or D0. + * + * Bring system to full On from any state (Sleep, Hibernate, Off) + * + * Linux_AssociatedPowerManagementService_PowerState_On + */ + // not supported + + /* 3 Sleep - Light + * corresponding to ACPI state G1, S1/S2, or D1. + * + * Standby + * + * Linux_AssociatedPowerManagementService_PowerState_Sleep___Light + */ + // not supported + + /* 4 Sleep - Deep + * corresponding to ACPI state G1, S3, or D2. + * + * Suspend + * + * Linux_AssociatedPowerManagementService_PowerState_Sleep__Deep + */ + // Sleep +#ifdef HAS_UPOWER + if (up_client_get_can_suspend(power->up)) { + list[i++] = Linux_AssociatedPowerManagementService_PowerState_Sleep__Deep; + } +#else + if (system("pm-is-supported --suspend") == 0) { + list[i++] = Linux_AssociatedPowerManagementService_PowerState_Sleep__Deep; + } +#endif + + /* 5 Power Cycle (Off - Soft) + * corresponding to ACPI state G2, S5, or D3, but where the managed + * element is set to return to power state "On" at a pre-determined time. + * + * Reset system without removing power + * + * Linux_AssociatedPowerManagementService_PowerState_Power_Cycle_Off___Soft + */ + // Reboot (without shutting down programs) + list[i++] = Linux_AssociatedPowerManagementService_PowerState_Power_Cycle_Off___Soft; + + /* 6 Off - Hard + * corresponding to ACPI state G3, S5, or D3. + * + * Power Off performed through mechanical means like unplugging + * power cable or UPS On + * + * Linux_AssociatedPowerManagementService_PowerState_Off___Hard + */ + + /* 7 Hibernate (Off - Soft) + * corresponding to ACPI state S4, where the state of the managed element + * is preserved and will be recovered upon powering on. + * + * System context and OS image written to non-volatile storage; + * system and devices powered off + * + * Linux_AssociatedPowerManagementService_PowerState_Hibernate_Off___Soft + */ + // Hibernate +#ifdef HAS_UPOWER + if (up_client_get_can_hibernate(power->up)) { + list[i++] = Linux_AssociatedPowerManagementService_PowerState_Hibernate_Off___Soft; + } +#else + if (system("pm-is-supported --hibernate") == 0) { + list[i++] = Linux_AssociatedPowerManagementService_PowerState_Hibernate_Off___Soft; + } +#endif + + /* 8 Off - Soft + * corresponding to ACPI state G2, S5, or D3. + * + * System power off but auxiliary or flea power may be available + * + * Linux_AssociatedPowerManagementService_PowerState_Off___Soft + */ + // Poweroff (without shutting down programs) + list[i++] = Linux_AssociatedPowerManagementService_PowerState_Off___Soft; + + /* 9 Power Cycle (Off-Hard) + * corresponds to the managed element reaching the ACPI state G3 + * followed by ACPI state S0. + * + * Equivalent to Off–Hard followed by On + * + * Linux_AssociatedPowerManagementService_PowerState_Power_Cycle_Off_Hard + */ + // not implemented + + /* 10 Master Bus Reset + * corresponds to the system reaching ACPI state S5 followed by ACPI + * state S0. This is used to represent system master bus reset. + * + * Hardware reset + * + * Linux_AssociatedPowerManagementService_PowerState_Master_Bus_Reset + */ + // not implemented + + /* 11 Diagnostic Interrupt (NMI) + * corresponding to the system reaching ACPI state S5 followed by ACPI + * state S0. This is used to represent system non-maskable interrupt. + * + * Hardware reset + * + * Linux_AssociatedPowerManagementService_PowerState_Diagnostic_Interrupt_NMI + */ + // not implemented + + /* 12 Off - Soft Graceful + * equivalent to Off Soft but preceded by a request to the managed element + * to perform an orderly shutdown. + * + * System power off but auxiliary or flea power may be available but preceded + * by a request to the managed element to perform an orderly shutdown. + * + * Linux_AssociatedPowerManagementService_PowerState_Off___Soft_Graceful + */ + // Poweroff (shut down programs first) + list[i++] = Linux_AssociatedPowerManagementService_PowerState_Off___Soft_Graceful; + + /* 13 Off - Hard Graceful + * equivalent to Off Hard but preceded by a request to the managed element + * to perform an orderly shutdown. + * + * Power Off performed through mechanical means like unplugging power cable + * or UPS On but preceded by a request to the managed element to perform + * an orderly shutdown. + * + * Linux_AssociatedPowerManagementService_PowerState_Off___Hard_Graceful + */ + // not implemented + + /* 14 Master Bus Rest Graceful + * equivalent to Master Bus Reset but preceded by a request to the managed + * element to perform an orderly shutdown. + * + * Hardware reset but preceded by a request to the managed element + * to perform an orderly shutdown. + * + * Linux_AssociatedPowerManagementService_PowerState_Master_Bus_Reset_Graceful + */ + // not implemented + + /* 15 Power Cycle (Off - Soft Graceful) + * equivalent to Power Cycle (Off - Soft) but preceded by a request + * to the managed element to perform an orderly shutdown. + * + * Reset system without removing power but preceded by a request + * to the managed element to perform an orderly shutdown. + * + * Linux_AssociatedPowerManagementService_PowerState_Power_Cycle_Off___Soft_Graceful + */ + // Reboot (shut down programs first) + list[i++] = Linux_AssociatedPowerManagementService_PowerState_Power_Cycle_Off___Soft_Graceful; + + /* 16 Power Cycle (Off - Hard Graceful) + * equivalent to Power Cycle (Off - Hard) but preceded by a request + * to the managed element to perform an orderly shutdown. + * + * Equivalent to Off–Hard followed by On but preceded by a request + * to the managed element to perform an orderly shutdown. + * + * Linux_AssociatedPowerManagementService_PowerState_Power_Cycle_Off___Hard_Graceful + */ + // not implemented + + *count = i; + return list; +} + +void job_free(PowerStateChangeJob *job) +{ + job->broker->xft->destroyMutex(job->mutex); +} + +GList *power_get_jobs(Power *power) +{ + PowerStateChangeJob *powerStateChangeJob; + GList *plist = power->jobs; + while (plist) { + powerStateChangeJob = plist->data; + MUTEX_LOCK(powerStateChangeJob); + if ((powerStateChangeJob->jobState == Linux_ConcreteJob_JobState_Completed || + powerStateChangeJob->jobState == Linux_ConcreteJob_JobState_Killed || + powerStateChangeJob->jobState == Linux_ConcreteJob_JobState_Terminated) && + time(NULL) - powerStateChangeJob->timeOfLastChange > powerStateChangeJob->timeBeforeRemoval) { + + MUTEX_LOCK(power); + power->jobs = g_list_remove_link(power->jobs, plist); + MUTEX_UNLOCK(power); + job_free(powerStateChangeJob); + } + MUTEX_UNLOCK(powerStateChangeJob); + plist = g_list_next(plist); + } + return power->jobs; +} + +unsigned short job_state(PowerStateChangeJob *state) +{ + return state->jobState; +} + +int job_timeOfLastChange(PowerStateChangeJob *state) +{ + return state->timeOfLastChange; +} + +int job_timeBeforeRemoval(PowerStateChangeJob *state) +{ + return state->timeBeforeRemoval; +} + -- cgit