libwinpr-synch: add unit tests, initial waitable timer support
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Mon, 29 Jul 2013 17:07:39 +0000 (13:07 -0400)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Mon, 29 Jul 2013 17:07:39 +0000 (13:07 -0400)
winpr/libwinpr/synch/CMakeLists.txt
winpr/libwinpr/synch/event.c
winpr/libwinpr/synch/test/.gitignore [new file with mode: 0644]
winpr/libwinpr/synch/test/CMakeLists.txt [new file with mode: 0644]
winpr/libwinpr/synch/test/TestSynchEvent.c [new file with mode: 0644]
winpr/libwinpr/synch/test/TestSynchMutex.c [new file with mode: 0644]
winpr/libwinpr/synch/test/TestSynchSemaphore.c [new file with mode: 0644]
winpr/libwinpr/synch/test/TestSynchWaitableTimer.c [new file with mode: 0644]
winpr/libwinpr/synch/timer.c
winpr/libwinpr/synch/wait.c

index 1554511..885ccc4 100644 (file)
@@ -64,3 +64,6 @@ endif()
 
 set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR")
 
+if(BUILD_TESTING)
+       add_subdirectory(test)
+endif()
index 173afaf..ece585c 100644 (file)
@@ -82,6 +82,9 @@ HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
 
                WINPR_HANDLE_SET_TYPE(event, HANDLE_TYPE_EVENT);
                handle = (HANDLE) event;
+
+               if (bInitialState)
+                       SetEvent(handle);
        }
 
        if (!cs.LockSemaphore)
diff --git a/winpr/libwinpr/synch/test/.gitignore b/winpr/libwinpr/synch/test/.gitignore
new file mode 100644 (file)
index 0000000..7107fa9
--- /dev/null
@@ -0,0 +1,3 @@
+TestSynch
+TestSynch.c
+
diff --git a/winpr/libwinpr/synch/test/CMakeLists.txt b/winpr/libwinpr/synch/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4ea150d
--- /dev/null
@@ -0,0 +1,33 @@
+
+set(MODULE_NAME "TestSynch")
+set(MODULE_PREFIX "TEST_SYNCH")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+       TestSynchEvent.c
+       TestSynchMutex.c
+       TestSynchSemaphore.c
+       TestSynchWaitableTimer.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+       ${${MODULE_PREFIX}_DRIVER}
+       ${${MODULE_PREFIX}_TESTS})
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
+       MONOLITHIC ${MONOLITHIC_BUILD}
+       MODULE winpr
+       MODULES winpr-synch)
+
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+
+set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+       get_filename_component(TestName ${test} NAME_WE)
+       add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
diff --git a/winpr/libwinpr/synch/test/TestSynchEvent.c b/winpr/libwinpr/synch/test/TestSynchEvent.c
new file mode 100644 (file)
index 0000000..1262613
--- /dev/null
@@ -0,0 +1,42 @@
+
+#include <winpr/crt.h>
+#include <winpr/synch.h>
+
+int TestSynchEvent(int argc, char* argv[])
+{
+       HANDLE event;
+
+       event = CreateEvent(NULL, TRUE, TRUE, NULL);
+
+       if (!event)
+       {
+               printf("CreateEvent failure\n");
+               return -1;
+       }
+
+       if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0)
+       {
+               printf("WaitForSingleObject(event, INFINITE) failure\n");
+               return -1;
+       }
+
+       ResetEvent(event);
+
+       if (WaitForSingleObject(event, 0) != WAIT_TIMEOUT)
+       {
+               printf("WaitForSingleObject(event, 0) failure\n");
+               return -1;
+       }
+
+       SetEvent(event);
+
+       if (WaitForSingleObject(event, 0) != WAIT_OBJECT_0)
+       {
+               printf("WaitForSingleObject(event, 0) failure\n");
+               return -1;
+       }
+
+       CloseHandle(event);
+
+       return 0;
+}
diff --git a/winpr/libwinpr/synch/test/TestSynchMutex.c b/winpr/libwinpr/synch/test/TestSynchMutex.c
new file mode 100644 (file)
index 0000000..6d2a5df
--- /dev/null
@@ -0,0 +1,21 @@
+
+#include <winpr/crt.h>
+#include <winpr/synch.h>
+
+int TestSynchMutex(int argc, char* argv[])
+{
+       HANDLE mutex;
+
+       mutex = CreateMutex(NULL, FALSE, NULL);
+
+       if (!mutex)
+       {
+               printf("CreateMutex failure\n");
+               return -1;
+       }
+
+       CloseHandle(mutex);
+
+       return 0;
+}
+
diff --git a/winpr/libwinpr/synch/test/TestSynchSemaphore.c b/winpr/libwinpr/synch/test/TestSynchSemaphore.c
new file mode 100644 (file)
index 0000000..3a9fa16
--- /dev/null
@@ -0,0 +1,21 @@
+
+#include <winpr/crt.h>
+#include <winpr/synch.h>
+
+int TestSynchSemaphore(int argc, char* argv[])
+{
+       HANDLE semaphore;
+
+       semaphore = CreateSemaphore(NULL, 0, 1, NULL);
+
+       if (!semaphore)
+       {
+               printf("CreateSemaphore failure\n");
+               return -1;
+       }
+
+       CloseHandle(semaphore);
+
+       return 0;
+}
+
diff --git a/winpr/libwinpr/synch/test/TestSynchWaitableTimer.c b/winpr/libwinpr/synch/test/TestSynchWaitableTimer.c
new file mode 100644 (file)
index 0000000..472a412
--- /dev/null
@@ -0,0 +1,71 @@
+
+#include <winpr/crt.h>
+#include <winpr/synch.h>
+
+int TestSynchWaitableTimer(int argc, char* argv[])
+{
+       HANDLE timer;
+       LONG period;
+       LARGE_INTEGER due;
+
+       timer = CreateWaitableTimer(NULL, TRUE, NULL);
+
+       if (!timer)
+       {
+               printf("CreateWaitableTimer failure\n");
+               return -1;
+       }
+
+       due.QuadPart = -15000000LL; /* 1.5 seconds */
+
+       if (!SetWaitableTimer(timer, &due, 0, NULL, NULL, 0))
+       {
+               printf("SetWaitableTimer failure\n");
+               return -1;
+       }
+
+       if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0)
+       {
+               printf("WaitForSingleObject(timer, INFINITE) failure\n");
+               return -1;
+       }
+
+       printf("Timer Signaled\n");
+
+       if (WaitForSingleObject(timer, 2000) != WAIT_TIMEOUT)
+       {
+               printf("WaitForSingleObject(timer, 2000) failure\n");
+               return -1;
+       }
+
+       due.QuadPart = 0;
+
+       period = 1200; /* 1.2 seconds */
+
+       if (!SetWaitableTimer(timer, &due, period, NULL, NULL, 0))
+       {
+               printf("SetWaitableTimer failure\n");
+               return -1;
+       }
+
+       if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0)
+       {
+               printf("WaitForSingleObject(timer, INFINITE) failure\n");
+               return -1;
+       }
+
+       printf("Timer Signaled\n");
+
+       if (WaitForMultipleObjects(1, &timer, FALSE, INFINITE) != WAIT_OBJECT_0)
+       {
+               printf("WaitForMultipleObjects(timer, INFINITE) failure\n");
+               return -1;
+       }
+
+       printf("Timer Signaled\n");
+
+       CloseHandle(timer);
+
+       return 0;
+}
+
index 46d719c..10ecc19 100644 (file)
@@ -117,7 +117,7 @@ BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPerio
 #ifdef __linux__
        ZeroMemory(&(timer->timeout), sizeof(struct itimerspec));
 
-       if (lpDueTime < 0)
+       if (lpDueTime->QuadPart < 0)
        {
                LONGLONG due = lpDueTime->QuadPart * (-1);
 
@@ -126,24 +126,40 @@ BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER* lpDueTime, LONG lPerio
                seconds = (due / 10000000);
                nanoseconds = ((due % 10000000) * 100);
        }
+       else if (lpDueTime->QuadPart == 0)
+       {
+               seconds = nanoseconds = 0;
+       }
        else
        {
                printf("SetWaitableTimer: implement absolute time\n");
+               return FALSE;
        }
 
-       timer->timeout.it_value.tv_sec = seconds; /* seconds */
-       timer->timeout.it_value.tv_nsec = nanoseconds; /* nanoseconds */
-
        if (lPeriod > 0)
        {
                timer->timeout.it_interval.tv_sec = (lPeriod / 1000); /* seconds */
                timer->timeout.it_interval.tv_nsec = ((lPeriod % 1000) * 1000000); /* nanoseconds */
        }
 
+       if (lpDueTime->QuadPart != 0)
+       {
+               timer->timeout.it_value.tv_sec = seconds; /* seconds */
+               timer->timeout.it_value.tv_nsec = nanoseconds; /* nanoseconds */
+       }
+       else
+       {
+               timer->timeout.it_value.tv_sec = timer->timeout.it_interval.tv_sec; /* seconds */
+               timer->timeout.it_value.tv_nsec = timer->timeout.it_interval.tv_nsec; /* nanoseconds */
+       }
+
        status = timerfd_settime(timer->fd, 0, &(timer->timeout), NULL);
 
        if (status)
+       {
+               printf("SetWaitableTimer timerfd_settime failure: %d\n", status);
                return FALSE;
+       }
 #endif
 
        return TRUE;
index 2c73d48..320b282 100644 (file)
@@ -168,8 +168,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
                if (timer->fd != -1)
                {
                        int status;
-                       int length;
                        fd_set rfds;
+                       UINT64 expirations;
                        struct timeval timeout;
 
                        FD_ZERO(&rfds);
@@ -189,6 +189,11 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
 
                        if (status != 1)
                                return WAIT_TIMEOUT;
+
+                       status = read(timer->fd, (void*) &expirations, sizeof(UINT64));
+
+                       if (status != 8)
+                               return WAIT_TIMEOUT;
                }
                else
                {
@@ -304,11 +309,23 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
                {
                        if (Type == HANDLE_TYPE_SEMAPHORE)
                        {
-                               int length = read(fd, &length, 1);
+                               int length;
+
+                               length = read(fd, &length, 1);
 
                                if (length != 1)
                                        return WAIT_FAILED;
                        }
+                       else if (Type == HANDLE_TYPE_TIMER)
+                       {
+                               int length;
+                               UINT64 expirations;
+
+                               length = read(fd, (void*) &expirations, sizeof(UINT64));
+
+                               if (length != 8)
+                                       return WAIT_FAILED;
+                       }
 
                        return (WAIT_OBJECT_0 + index);
                }