--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "conditional-wait.h"
+
+// EXTERNAL INCLUDES
+#include <pthread.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+} // unnamed namespace
+
+struct ConditionalWait::ConditionalWaitImpl
+{
+ pthread_mutex_t mutex;
+ pthread_cond_t condition;
+ volatile bool wait;
+};
+
+ConditionalWait::ConditionalWait()
+: mImpl( new ConditionalWaitImpl )
+{
+ pthread_mutex_init( &mImpl->mutex, NULL );
+ pthread_cond_init( &mImpl->condition, NULL );
+ mImpl->wait = false;
+}
+
+ConditionalWait::~ConditionalWait()
+{
+ pthread_cond_destroy( &mImpl->condition );
+ pthread_mutex_destroy( &mImpl->mutex );
+ delete mImpl;
+}
+
+void ConditionalWait::Notify()
+{
+ // pthread_cond_wait requires a lock to be held
+ pthread_mutex_lock( &mImpl->mutex );
+ bool wasWaiting = mImpl->wait;
+ mImpl->wait = false;
+ pthread_mutex_unlock( &mImpl->mutex );
+ // broadcast does nothing if the thread is not waiting but still has a system call overhead
+ // broadcast all threads to continue
+ if( wasWaiting )
+ {
+ pthread_cond_broadcast( &mImpl->condition );
+ }
+}
+
+void ConditionalWait::Wait()
+{
+ // pthread_cond_wait requires a lock to be held
+ pthread_mutex_lock( &mImpl->mutex );
+ mImpl->wait = true;
+ // pthread_cond_wait may wake up without anyone calling Notify
+ while( mImpl->wait )
+ {
+ // wait while condition changes
+ pthread_cond_wait( &mImpl->condition, &mImpl->mutex ); // releases the lock whilst waiting
+ }
+ // when condition returns the mutex is locked so release the lock
+ pthread_mutex_unlock( &mImpl->mutex );
+}
+
+bool ConditionalWait::IsWaiting() const
+{
+ bool isWaiting( false );
+ pthread_mutex_lock( &mImpl->mutex );
+ isWaiting = mImpl->wait;
+ pthread_mutex_unlock( &mImpl->mutex );
+ return isWaiting;
+}
+
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
--- /dev/null
+#ifndef __DALI_INTERNAL_CONDITIONAL_WAIT_H__
+#define __DALI_INTERNAL_CONDITIONAL_WAIT_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Helper class to allow conditional waiting and notifications between multiple threads
+ */
+class ConditionalWait
+{
+public:
+
+ /**
+ * @brief Constructor, creates the internal synchronization objects
+ */
+ ConditionalWait();
+
+ /**
+ * @brief Destructor, non-virtual as this is not a base class
+ */
+ ~ConditionalWait();
+
+ /**
+ * @brief Notifies another thread to continue if it is blocked on a wait.
+ *
+ * Can be called from any thread.
+ * Does not block the current thread but may cause a rescheduling of threads.
+ */
+ void Notify();
+
+ /**
+ * @brief Wait for another thread to notify us when the condition is true and we can continue
+ *
+ * Will always block current thread until Notify is called
+ */
+ void Wait();
+
+ /**
+ * @brief Return true if the wait is locked, i.e. someone is waiting for it
+ * @return true if this object is waiting on a thread
+ */
+ bool IsWaiting() const;
+
+private:
+
+ /// Not implemented as ConditionalWait is not copyable
+ ConditionalWait( const ConditionalWait& );
+ const ConditionalWait& operator= ( const ConditionalWait& );
+
+ struct ConditionalWaitImpl;
+ ConditionalWaitImpl* mImpl;
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_CONDITIONAL_WAIT_H__
# Add local source files here
base_adaptor_src_files = \
+ $(base_adaptor_src_dir)/conditional-wait.cpp \
$(base_adaptor_src_dir)/frame-time.cpp \
$(base_adaptor_src_dir)/display-connection.cpp \
$(base_adaptor_src_dir)/render-thread.cpp \
SET(CAPI_LIB "dali-adaptor-internal")
SET(TC_SOURCES
- utc-Dali-GifLoader.cpp
- utc-Dali-TiltSensor.cpp
+ utc-ConditionalWait.cpp
utc-Dali-CommandLineOptions.cpp
- utc-Dali-Lifecycle-Controller.cpp
+ utc-Dali-GifLoader.cpp
utc-Dali-ImageOperations.cpp
+ utc-Dali-Lifecycle-Controller.cpp
+ utc-Dali-TiltSensor.cpp
)
LIST(APPEND TC_SOURCES
ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
TARGET_LINK_LIBRARIES(${EXEC_NAME}
${${CAPI_LIB}_LIBRARIES}
+ -lpthread
)
INSTALL(PROGRAMS ${EXEC_NAME}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dali-test-suite-utils.h>
+#include "conditional-wait.h"
+
+using Dali::Internal::Adaptor::ConditionalWait;
+
+namespace // for local variables to avoid name clashes
+{
+volatile int gGlobalValue = 0;
+volatile bool gWorkerThreadWait = true;
+enum ThreadState { INIT, RUN, TERMINATE } volatile gWorkerThreadState = INIT;
+ConditionalWait* volatile gConditionalWait; // volatile pointer to a ConditionalWait object
+}
+
+void* WorkerThreadNotify( void* ptr )
+{
+ gGlobalValue = -1;
+ while( gWorkerThreadWait ) // wait till we can exit
+ {
+ gWorkerThreadState = RUN;
+ usleep( 1 ); // 1 microseconds
+ }
+ usleep( 1000 ); // 1000 microseconds to give other thread time to do its thing
+ gConditionalWait->Notify();
+ gWorkerThreadState = TERMINATE;
+ return NULL;
+}
+
+int UtcConditionalWait1P(void)
+{
+ tet_infoline("Testing ConditionalWait - scenario 1: wait - notify from separate thread");
+
+ pthread_t thread1;
+ // initialize values
+ gConditionalWait = new ConditionalWait();
+ gWorkerThreadWait = true;
+ DALI_TEST_EQUALS( INIT, gWorkerThreadState, TEST_LOCATION );
+ DALI_TEST_EQUALS( 0, gGlobalValue, TEST_LOCATION );
+
+ pthread_create( &thread1, NULL, &WorkerThreadNotify, NULL );
+ // wait till the thread is in run state
+ while( RUN != gWorkerThreadState )
+ {
+ usleep( 1 ); // 1 microsecond
+ }
+ // let worker continue and finish
+ gWorkerThreadWait = false;
+ gConditionalWait->Wait();
+
+ // wait till the thread is terminated state
+ while( TERMINATE != gWorkerThreadState )
+ {
+ usleep( 1 ); // 1 microsecond
+ }
+
+ void* exitValue;
+ pthread_join( thread1, &exitValue );
+
+ delete gConditionalWait;
+ END_TEST;
+}
+
+int UtcConditionalWait2P(void)
+{
+ tet_infoline("Testing ConditionalWait - scenario 2: notify without wait");
+
+ ConditionalWait wait;
+ DALI_TEST_EQUALS( false, wait.IsWaiting(), TEST_LOCATION );
+ wait.Notify();
+ DALI_TEST_EQUALS( false, wait.IsWaiting(), TEST_LOCATION );
+
+ END_TEST;
+}
+
+volatile unsigned int gNotifyCount = 0;
+void* WorkerThreadNotifyN( void* ptr )
+{
+ while( gNotifyCount )
+ {
+ gConditionalWait->Notify();
+ usleep( 10 ); // 10 microseconds between each notify
+ }
+ return NULL;
+}
+
+int UtcConditionalWait3P(void)
+{
+ tet_infoline("Testing ConditionalWait - scenario 1: wait - notify N times");
+
+ // initialize values
+ gConditionalWait = new ConditionalWait();
+ gNotifyCount = 100;
+
+ pthread_t thread1;
+ pthread_create( &thread1, NULL, &WorkerThreadNotifyN, NULL );
+
+ while( gNotifyCount )
+ {
+ gConditionalWait->Wait();
+ --gNotifyCount;
+ DALI_TEST_EQUALS( false, gConditionalWait->IsWaiting(), TEST_LOCATION );
+ usleep( 10 ); // 10 microseconds between each notify
+ }
+ DALI_TEST_EQUALS( false, gConditionalWait->IsWaiting(), TEST_LOCATION );
+
+ void* exitValue;
+ pthread_join( thread1, &exitValue );
+
+ delete gConditionalWait;
+ END_TEST;
+}
+
+int UtcConditionalWait4P(void)
+{
+ tet_infoline("Testing ConditionalWait - scenario 1: wait - notify N times from multiple threads");
+
+ // initialize values
+ gConditionalWait = new ConditionalWait();
+ gNotifyCount = 100;
+
+ pthread_t thread1;
+ pthread_create( &thread1, NULL, &WorkerThreadNotifyN, NULL );
+
+ pthread_t thread2;
+ pthread_create( &thread2, NULL, &WorkerThreadNotifyN, NULL );
+
+ pthread_t thread3;
+ pthread_create( &thread3, NULL, &WorkerThreadNotifyN, NULL );
+
+ while( gNotifyCount )
+ {
+ gConditionalWait->Wait();
+ --gNotifyCount;
+ DALI_TEST_EQUALS( false, gConditionalWait->IsWaiting(), TEST_LOCATION );
+ usleep( 10 ); // 10 microseconds between each notify
+ }
+
+ void* exitValue;
+ pthread_join( thread1, &exitValue );
+ pthread_join( thread2, &exitValue );
+ pthread_join( thread3, &exitValue );
+
+ delete gConditionalWait;
+ END_TEST;
+}
+
+
+int UtcConditionalWaitNonCopyable(void)
+{
+ // we want to make sure that ConditionalWait is not copyable (its copy constructor is not defined)
+ // this test will stop compiling if ConditionalWait has compiler generated copy constructor
+ DALI_COMPILE_TIME_ASSERT( !__has_trivial_copy( ConditionalWait ) );
+
+ DALI_TEST_CHECK( true );
+ END_TEST;
+}
+
+
#include "dali-test-suite-utils.h"
// EXTERNAL INCLUDES
-#include <ostream>
#include <cstdio>
#include <cstdarg>
for (int i=0;i<9;++i)
{
- equivalent &= (m1[i] != m2[i]);
+ equivalent &= (fabsf(m1[i] - m2[i])< GetRangedEpsilon(m1[i], m2[i]));
}
if (!equivalent)
DALI_TEST_EQUALS(str1, str2.c_str(), location);
}
-
-/**
- * Test whether one unsigned integer value is greater than another.
- * Test succeeds if value1 > value2
- * @param[in] value1 The first value
- * @param[in] value2 The second value
- * @param[in] location The TEST_LOCATION macro should be used here
- */
-void DALI_TEST_GREATER(unsigned int value1, unsigned int value2, const char* location)
-{
- if (!(value1 > value2))
- {
- fprintf(stderr, "%s, checking %d > %d\n", location, value1, value2);
- tet_result(TET_FAIL);
- }
- else
- {
- tet_result(TET_PASS);
- }
-}
-
-/**
- * Test whether one float value is greater than another.
- * Test succeeds if value1 > value2
- * @param[in] value1 The first value
- * @param[in] value2 The second value
- * @param[in] location The TEST_LOCATION macro should be used here
- */
-void DALI_TEST_GREATER( float value1, float value2, const char* location)
-{
- if (!(value1 > value2))
- {
- fprintf(stderr, "%s, checking %f > %f\n", location, value1, value2);
- tet_result(TET_FAIL);
- }
- else
- {
- tet_result(TET_PASS);
- }
-}
-
void DALI_TEST_ASSERT( DaliException& e, std::string conditionSubString, const char* location )
{
if( NULL == strstr( e.condition, conditionSubString.c_str() ) )
// EXTERNAL INCLUDES
#include <cstdarg>
-#include <iosfwd>
+#include <iostream>
// INTERNAL INCLUDES
#include <dali/public-api/dali-core.h>
* @param[in] value2 The second value
* @param[in] location The TEST_LOCATION macro should be used here
*/
-void DALI_TEST_GREATER(unsigned int value1, unsigned int value2, const char* location);
-
-/**
- * Test whether one float value is greater than another.
- * Test succeeds if value1 > value2
- * @param[in] value1 The first value
- * @param[in] value2 The second value
- * @param[in] location The TEST_LOCATION macro should be used here
- */
-void DALI_TEST_GREATER( float value1, float value2, const char* location);
+template< typename T >
+void DALI_TEST_GREATER(unsigned int value1, unsigned int value2, const char* location)
+{
+ if (!(value1 > value2))
+ {
+ std::cerr << location << ", checking " << value1 <<" > " << value2 << "\n";
+ tet_result(TET_FAIL);
+ }
+ else
+ {
+ tet_result(TET_PASS);
+ }
+}
/**
* Test whether the assertion condition that failed and thus triggered the
{
int result = EXIT_STATUS_TESTCASE_FAILED;
- try
+// dont want to catch exception as we want to be able to get
+// gdb stack trace from the first error
+// by default tests should all always pass with no exceptions
+ if( testCase.startup )
{
- if( testCase.startup )
- {
- testCase.startup();
- }
- result = testCase.function();
- if( testCase.cleanup )
- {
- testCase.cleanup();
- }
+ testCase.startup();
}
- catch (...)
+ result = testCase.function();
+ if( testCase.cleanup )
{
- printf("Caught exception in test case.\n");
- result = EXIT_STATUS_TESTCASE_ABORTED;
+ testCase.cleanup();
}
return result;
}
+
int RunTestCaseInChildProcess( struct ::testcase_s& testCase, bool suppressOutput )
{
int testResult = EXIT_STATUS_TESTCASE_FAILED;
$(CAPI_SYSTEM_INFO_LIBS) \
$(ELDBUS_LIBS) \
-lgif \
+ -lpthread \
-lboost_thread \
-lturbojpeg