File indexing completed on 2024-05-12 05:14:49
0001 /* 0002 * kernelwakealarm.cpp - kernel alarm to wake from suspend 0003 * Program: kalarm 0004 * SPDX-FileCopyrightText: 2023 one-d-wide <one-d-wide@protonmail.com> 0005 * SPDX-FileCopyrightText: 2023 David Jarvie <djarvie@kde.org> 0006 * 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "kernelwakealarm.h" 0011 0012 #include "kalarmcalendar/kadatetime.h" 0013 #include "kalarm_debug.h" 0014 0015 #ifdef Q_OS_LINUX 0016 0017 #include <unistd.h> 0018 #include <errno.h> 0019 #include <time.h> 0020 #include <string.h> 0021 #include <sys/timerfd.h> 0022 0023 int KernelWakeAlarm::mAvailable = 0; // 0 = unchecked, 1 = unavailable, 2 = available 0024 0025 KernelWakeAlarm::KernelWakeAlarm() 0026 { 0027 // `timerfd_create(2)` 0028 int ret = timerfd_create(CLOCK_REALTIME_ALARM, 0); 0029 0030 if (ret >= 0) 0031 { 0032 mTimerFd = ret; 0033 mAvailable = 2; 0034 } 0035 else 0036 { 0037 mAvailable = 1; 0038 switch (errno) 0039 { 0040 case EPERM: 0041 qCWarning(KALARM_LOG) << "Kernel alarm timers not available (no CAP_WAKE_ALARM capability)"; 0042 break; 0043 case EINVAL: 0044 qCWarning(KALARM_LOG) << "Kernel alarm timers not available (CLOCK_REALTIME_ALARM not supported)"; 0045 break; 0046 default: 0047 qCWarning(KALARM_LOG) << "KernelWakeAlarm: Error creating kernel timer:" << strerror(errno); 0048 mAvailable = 2; 0049 break; 0050 } 0051 } 0052 } 0053 0054 KernelWakeAlarm::KernelWakeAlarm(const KernelWakeAlarm& other) 0055 : KernelWakeAlarm() 0056 { 0057 if (other.mTriggerTime > 0) 0058 { 0059 if (arm(other.mTriggerTime)) 0060 mTriggerTime = other.mTriggerTime; 0061 } 0062 } 0063 0064 KernelWakeAlarm::~KernelWakeAlarm() 0065 { 0066 if (mTimerFd) 0067 close(mTimerFd.value()); 0068 } 0069 0070 KernelWakeAlarm& KernelWakeAlarm::operator=(const KernelWakeAlarm& other) 0071 { 0072 if (other.mTriggerTime > 0) 0073 { 0074 if (arm(other.mTriggerTime)) 0075 mTriggerTime = other.mTriggerTime; 0076 } 0077 return *this; 0078 } 0079 0080 bool KernelWakeAlarm::isValid() const 0081 { 0082 return mTimerFd.has_value(); 0083 } 0084 0085 bool KernelWakeAlarm::isAvailable() 0086 { 0087 if (!mAvailable) 0088 KernelWakeAlarm a; 0089 return mAvailable == 2; 0090 } 0091 0092 bool KernelWakeAlarm::arm(const KAlarmCal::KADateTime& triggerTime) 0093 { 0094 if (triggerTime.isValid()) 0095 { 0096 const time_t triggerSeconds = static_cast<time_t>(triggerTime.toSecsSinceEpoch()); 0097 if (arm(triggerSeconds)) 0098 { 0099 mTriggerTime = triggerSeconds; 0100 qCDebug(KALARM_LOG) << "KernelWakeAlarm::arm: Kernel timer set to:" << triggerTime.qDateTime(); 0101 return true; 0102 } 0103 } 0104 return false; 0105 } 0106 0107 bool KernelWakeAlarm::arm(time_t triggerSeconds) 0108 { 0109 if (!mTimerFd) 0110 return false; 0111 if (triggerSeconds && triggerSeconds <= ::time(nullptr)) 0112 return false; // already expired 0113 struct itimerspec time = {}; 0114 time.it_value.tv_sec = triggerSeconds; 0115 0116 // `timerfd_settime(2)` 0117 if (timerfd_settime(mTimerFd.value(), TFD_TIMER_ABSTIME, &time, nullptr) < 0) 0118 { 0119 qCWarning(KALARM_LOG) << "KernelWakeAlarm::arm: Failed to set kernel timer:" << strerror(errno); 0120 0121 return false; 0122 } 0123 return true; 0124 } 0125 0126 void KernelWakeAlarm::disarm() 0127 { 0128 if (arm(0)) 0129 mTriggerTime = 0; 0130 } 0131 0132 #else // not Q_OS_LINUX 0133 0134 KernelWakeAlarm::KernelWakeAlarm() {} 0135 KernelWakeAlarm::KernelWakeAlarm(const KernelWakeAlarm&) {} 0136 KernelWakeAlarm::~KernelWakeAlarm() {} 0137 KernelWakeAlarm& KernelWakeAlarm::operator=(const KernelWakeAlarm&) { return *this; } 0138 bool KernelWakeAlarm::arm(const KAlarmCal::KADateTime&) { return false; } 0139 void KernelWakeAlarm::disarm() {} 0140 bool KernelWakeAlarm::isValid() const { return false; } 0141 bool KernelWakeAlarm::isAvailable() { return false; } 0142 0143 #endif // Q_OS_LINUX 0144 0145 // vim: et sw=4: