Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <program_opts/detail/alarm.h>
00019 #if !defined(_WIN32) && !defined(_WIN64)
00020 #include <unistd.h>
00021 void setAlarmHandler(void(*f)(int)) {
00022 signal(SIGALRM, f);
00023 }
00024 int setAlarm(unsigned sec) {
00025 alarm(sec);
00026 return 1;
00027 }
00028 unsigned long initMainThread() { return 0; }
00029 void resetMainThread(){}
00030 void protectMainThread(bool) {}
00031 #else
00032 #define WIN32_LEAN_AND_MEAN // exclude APIs such as Cryptography, DDE, RPC, Shell, and Windows Sockets.
00033 #define NOMINMAX // do not let windows.h define macros min and max
00034 #include <process.h>
00035 #include <windows.h>
00036 namespace {
00037 typedef CRITICAL_SECTION LOCK;
00038
00039
00040 class AlarmThread {
00041 public:
00042 AlarmThread();
00043 ~AlarmThread();
00044
00045
00046 int start(unsigned sec);
00047
00048
00049 void kill();
00050
00051 void setCallback( void(*f)(int) ) {
00052 callback = f;
00053 }
00054 static void ign(int) {}
00055 static HANDLE mainHandle_s;
00056 static DWORD mainId_s;
00057 static LOCK* signalLock_s;
00058 private:
00059 HANDLE threadHandle;
00060 HANDLE eventHandle;
00061 void (*callback)(int);
00062 unsigned sec;
00063 static unsigned __stdcall run(void* p);
00064 };
00065
00066 HANDLE AlarmThread::mainHandle_s = INVALID_HANDLE_VALUE;
00067 DWORD AlarmThread::mainId_s = 0;
00068 LOCK* AlarmThread::signalLock_s = 0;
00069 static struct LockInit {
00070 LockInit() { InitializeCriticalSection((AlarmThread::signalLock_s=new CRITICAL_SECTION)); }
00071 ~LockInit(){ DeleteCriticalSection(AlarmThread::signalLock_s); delete AlarmThread::signalLock_s; }
00072 } lock_s;
00073
00074 AlarmThread::AlarmThread() : threadHandle(0), callback(&AlarmThread::ign) {
00075 eventHandle = CreateEvent(0, FALSE, FALSE, TEXT("KillAlarmEvent"));
00076 }
00077 AlarmThread::~AlarmThread() {
00078 if (eventHandle != INVALID_HANDLE_VALUE) {
00079 CloseHandle(eventHandle);
00080 }
00081 resetMainThread();
00082 }
00083 int AlarmThread::start(unsigned int sec) {
00084 if (!initMainThread()) { return 0; }
00085 if (eventHandle != INVALID_HANDLE_VALUE) {
00086 if (threadHandle) kill();
00087 if (!callback) callback = &AlarmThread::ign;
00088 this->sec = sec;
00089 threadHandle= (HANDLE)_beginthreadex(0, 0, &AlarmThread::run, this, 0, 0);
00090 }
00091 return threadHandle != 0;
00092 }
00093 void AlarmThread::kill() {
00094 if (threadHandle) {
00095 SetEvent(eventHandle);
00096 WaitForSingleObject(threadHandle, INFINITE);
00097 threadHandle = 0;
00098 }
00099 }
00100 unsigned __stdcall AlarmThread::run(void* p) {
00101 AlarmThread* self = (AlarmThread*)p;
00102 if (WaitForSingleObject(self->eventHandle, self->sec * 1000) == WAIT_TIMEOUT) {
00103 struct ScopedProtect {
00104 ScopedProtect() { protectMainThread(true); }
00105 ~ScopedProtect(){ protectMainThread(false);}
00106 void raise(AlarmThread* x) { x->callback(SIGALRM); }
00107 };
00108 ScopedProtect().raise(self);
00109 }
00110 return 0;
00111 }
00112
00113 void (*alarmHandler)(int) = &AlarmThread::ign;
00114
00115 }
00116
00117
00118
00119 void setAlarmHandler(void(*f)(int)) {
00120 alarmHandler = f;
00121 }
00122
00123 int setAlarm(unsigned sec) {
00124 static AlarmThread alarmT;
00125 if (sec > 0) {
00126 alarmT.setCallback(alarmHandler);
00127 return alarmT.start(sec);
00128 }
00129 else {
00130 alarmT.kill();
00131 return 1;
00132 }
00133 }
00134 void lockAlarm() { if (AlarmThread::signalLock_s) EnterCriticalSection(AlarmThread::signalLock_s); }
00135 void unlockAlarm() { if (AlarmThread::signalLock_s) LeaveCriticalSection(AlarmThread::signalLock_s); }
00136
00137 unsigned long initMainThread() {
00138 if (AlarmThread::mainHandle_s != INVALID_HANDLE_VALUE && GetCurrentThreadId() != AlarmThread::mainId_s) {
00139 resetMainThread();
00140 }
00141 if (AlarmThread::mainHandle_s == INVALID_HANDLE_VALUE) {
00142 if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &AlarmThread::mainHandle_s, 0, FALSE, DUPLICATE_SAME_ACCESS) == 0) {
00143 return 0;
00144 }
00145 AlarmThread::mainId_s = GetCurrentThreadId();
00146 }
00147 return AlarmThread::mainId_s;
00148 }
00149 void resetMainThread() {
00150 if (AlarmThread::mainHandle_s != INVALID_HANDLE_VALUE) {
00151 CloseHandle(AlarmThread::mainHandle_s);
00152 AlarmThread::mainHandle_s = INVALID_HANDLE_VALUE;
00153 AlarmThread::mainId_s = 0;
00154 }
00155 }
00156 void protectMainThread(bool protect) {
00157 if (AlarmThread::mainHandle_s != INVALID_HANDLE_VALUE && GetCurrentThreadId() != AlarmThread::mainId_s) {
00158 if (protect) { lockAlarm(); SuspendThread(AlarmThread::mainHandle_s); }
00159 else { unlockAlarm(); ResumeThread(AlarmThread::mainHandle_s); }
00160 }
00161 }
00162 #endif