| 242 | } |
| 243 | |
| 244 | THREAD_ENTRY_DECLARE TimerEntry::timeThread(THREAD_ENTRY_PARAM) |
| 245 | { |
| 246 | #ifdef WIN_NT |
| 247 | // The timer thread could unload plugins. Plugins almost always linked with |
| 248 | // dispatcher (fbclient.dll) thus, when plugin unloaded it decrement usage |
| 249 | // count of fbclient.dll. If application unload fbclient.dll not calling |
| 250 | // fb_shutdown, then last unloaded plugin will finally unload fbclient.dll |
| 251 | // and the code that is currently running, leading to AV. |
| 252 | // To prevent such scenario we increment usage count of fbclient.dll and |
| 253 | // will decrement it in safe way at the end of the timer thread. |
| 254 | |
| 255 | char buff[MAX_PATH]; |
| 256 | GetModuleFileName(hDllInst, buff, sizeof(buff)); |
| 257 | HMODULE hDll = LoadLibrary(buff); |
| 258 | #endif |
| 259 | |
| 260 | while (stopTimerThread.value() == 0 |
| 261 | #ifdef WIN_NT |
| 262 | && Firebird::dDllUnloadTID == 0 |
| 263 | #endif |
| 264 | ) |
| 265 | { |
| 266 | ISC_UINT64 microSeconds = 0; |
| 267 | |
| 268 | { |
| 269 | MutexLockGuard pauseGuard(timerPause, FB_FUNCTION); |
| 270 | MutexLockGuard guard(timerAccess, FB_FUNCTION); |
| 271 | |
| 272 | const ISC_UINT64 cur = curTime(); |
| 273 | |
| 274 | if (timerQueue->getCount() > 0) |
| 275 | { |
| 276 | TimerEntry e(timerQueue->operator[](0)); |
| 277 | |
| 278 | if (e.fireTime <= cur) |
| 279 | { |
| 280 | timerQueue->remove((FB_SIZE_T) 0); |
| 281 | |
| 282 | // We must leave timerAccess mutex here to avoid deadlocks |
| 283 | MutexUnlockGuard ug(timerAccess, FB_FUNCTION); |
| 284 | |
| 285 | e.timer->handler(); |
| 286 | e.timer->release(); |
| 287 | continue; |
| 288 | } |
| 289 | else |
| 290 | { |
| 291 | microSeconds = e.fireTime - cur; |
| 292 | } |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | if (microSeconds) |
| 297 | { |
| 298 | timerWakeup->tryEnter(0, microSeconds / 1000); |
| 299 | } |
| 300 | else |
| 301 | { |