From: <mie...@us...> - 2013-02-11 00:31:46
|
Revision: 8969 http://sourceforge.net/p/oorexx/code-0/8969 Author: miesfeld Date: 2013-02-11 00:31:43 +0000 (Mon, 11 Feb 2013) Log Message: ----------- Feature Requests: #370 Replace ooDialog WinTimer with a waitable time See ticket [Feature-requests:#370] Modified Paths: -------------- ooDialog/trunk/ooDialog/oodRoutines.cpp Modified: ooDialog/trunk/ooDialog/oodRoutines.cpp =================================================================== --- ooDialog/trunk/ooDialog/oodRoutines.cpp 2013-02-10 05:12:54 UTC (rev 8968) +++ ooDialog/trunk/ooDialog/oodRoutines.cpp 2013-02-11 00:31:43 UTC (rev 8969) @@ -707,14 +707,42 @@ return result; } + /** winTimer() * * The classic Rexx external function, WinTimer() was documented prior to 4.0.0 - * and therefore needs to be retained for backward compatibility. This - * implementation is poor. PeekMessage() returns immediately if there are no - * messages. Since there are probably no windows on this thread, the WAIT - * function spins in a busy loop consuming 100% of the CPU. + * and therefore needs to be retained for backward compatibility. * + * The original implementation was poor, using SetTimer() / KillTimer(). For + * the wait mode, it used this loop: + * + * else if ( stricmp("WAIT", mode) == 0 ) + * { + * while ( !PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE) + * { + * ; // do nothing + * } + * return 0; + * } + * + * PeekMessage() returns immediately if there are no messages. Since there + * were probably no windows on the thread, the WAIT function spun in a busy + * loop consuming 100% of the CPU. + * + * svn revision 8968 and previous contains the original implementation if there + * is a need to review that code. + * + * The original implmentation was replaced in ooDialog 4.2.2 with this + * implementation using waitable timers instead. It is backwards compatible + * with the original implementation, and needs to remain that way. + * + * For very small periods, SetTimer replaces the specified time with + * USER_TIMER_MINIMUM. So when Rexx programmers specified 1 or 2 or 6 + * milliseconds, the got USER_TIMER_MINIMUM instead. We mimic that behaviour + * here, otherwise programs using a delay of 1 millisecond do not work the + * same. We actually use 1.5 times USER_TIMER_MINIMUM because it seems to work + * the best. + * * @param mode Keyword for what is to be done. START creates the timer and * starts it. WAIT waits on the timer. STOP destroys the * timer. @@ -724,28 +752,64 @@ * * @return The timer ID for the START mode, or success / error return code for * the other modes. + * + * @notes Sets the .SystemErrorCode. For the STOP and WAIT modes the system + * error code value is returned in addition to setting the + * .SystemErrorCode. + * + * @remarks If this routine was being implemented from scratch, it would be + * done differently. However since it is being used to preserve + * backwards compatibility, this implementation serves best. An + * enhancement creating a new Waitable object class would be nice. */ RexxRoutine2(uintptr_t, winTimer_rtn, CSTRING, mode, uintptr_t, msOrId) { - MSG msg; + oodResetSysErrCode(context->threadContext); if ( stricmp("START", mode) == 0 ) { - return SetTimer(NULL, 1001, (unsigned int)msOrId, NULL); + HANDLE hTimer = NULL; + LARGE_INTEGER liDueTime; + + if ( msOrId < USER_TIMER_MINIMUM + 5 ) + { + msOrId = USER_TIMER_MINIMUM + 5; + } + + liDueTime.QuadPart = msOrId * -10000; + + hTimer = CreateWaitableTimer(NULL, FALSE, NULL); + if ( hTimer == NULL ) + { + oodSetSysErrCode(context->threadContext); + return 0; + } + + if ( ! SetWaitableTimer(hTimer, &liDueTime, (int32_t)msOrId, NULL, NULL, FALSE) ) + { + oodSetSysErrCode(context->threadContext); + return 0; + } + + return (uintptr_t)hTimer; } else if ( stricmp("STOP", mode) == 0 ) { - if ( KillTimer(NULL, msOrId) == 0 ) + if ( CancelWaitableTimer((HANDLE)msOrId) == 0 ) { - return GetLastError(); + uint32_t rc = GetLastError(); + oodSetSysErrCode(context->threadContext, rc); + return rc; } return 0; } else if ( stricmp("WAIT", mode) == 0 ) { - while ( !PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE) || (msg.wParam != msOrId) ) + if ( WaitForSingleObject((HANDLE)msOrId, INFINITE) != WAIT_OBJECT_0 ) { - ; // do nothing + uint32_t rc = GetLastError(); + oodSetSysErrCode(context->threadContext, rc); + return rc; } return 0; } |