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