alarm.cpp
Go to the documentation of this file.
00001 //
00002 //  Copyright (c) Benjamin Kaufmann
00003 //
00004 //  This is free software; you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation; either version 2 of the License, or
00007 //  (at your option) any later version. 
00008 // 
00009 //  This file is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this file; if not, write to the Free Software
00016 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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>        // _beginthreadex, _endthreadex, ...
00035 #include <windows.h>        // WaitForSingleObject, CRITICAL_SECTION, ...
00036 namespace {
00037 typedef CRITICAL_SECTION LOCK;
00038 // Since Windows does not support alarm(),
00039 // we need a separate thread for timeout management.
00040 class AlarmThread {
00041 public:
00042         AlarmThread();
00043         ~AlarmThread();
00044         // Creates a thread that waits for an event to be signaled. If the event
00045         // is not signaled after sec seconds, the alarm handler is called.
00046         int start(unsigned sec);
00047         // Kills a pending alarm. I.e. wakes up the alarm thread and
00048         // waits until it has completed.
00049         void kill();
00050         // Sets the alarm handler
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;  // alarm thread handle
00060         HANDLE  eventHandle;   // wake up event handle
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(); // kill existing timer
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 } // unnamed namespace
00116 
00117 // public alarm functions
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


clasp
Author(s): Benjamin Kaufmann
autogenerated on Thu Aug 27 2015 12:41:38