Index: packages/kernel/current/tests/bin_sem1.cxx =================================================================== RCS file: /cvs/ecos/ecos/packages/kernel/current/tests/bin_sem1.cxx,v retrieving revision 1.7 diff -u -5 -p -r1.7 bin_sem1.cxx --- packages/kernel/current/tests/bin_sem1.cxx 23 May 2002 23:06:56 -0000 1.7 +++ packages/kernel/current/tests/bin_sem1.cxx 23 Sep 2004 16:00:03 -0000 @@ -85,11 +85,20 @@ static void entry0( CYG_ADDRWORD data ) CYG_TEST_PASS_FINISH("Binary Semaphore 1 OK"); } static void entry1( CYG_ADDRWORD data ) { +#if !defined(CYGPKG_KERNEL_SMP_SUPPORT) +// In SMP scenario this CHECK is likely to fail because of race between +// executions of entry0 and entry1 on two separate processors. +// +// "s1" is initialised with "false" and entry0 will take some time to finish +// with first "s1.post()" in it's execution, but this thread (entry1) CHECKs +// for "s1.posted()" in the very beginning of it's execution. + CHECK( s1.posted() ); +#endif // CYGPKG_KERNEL_SMP_SUPPORT s1.wait(); CHECK( 1 == q++ ); CHECK( ! s0.posted() ); s0.post(); s1.wait(); Index: packages/kernel/current/tests/bin_sem3.cxx =================================================================== RCS file: /cvs/ecos/ecos/packages/kernel/current/tests/bin_sem3.cxx,v retrieving revision 1.1 diff -u -5 -p -r1.1 bin_sem3.cxx --- packages/kernel/current/tests/bin_sem3.cxx 23 Jun 2003 18:10:01 -0000 1.1 +++ packages/kernel/current/tests/bin_sem3.cxx 23 Sep 2004 16:00:03 -0000 @@ -89,11 +89,20 @@ static void entry0( CYG_ADDRWORD data ) CYG_TEST_PASS_FINISH("Binary Semaphore 3 OK"); } static void entry1( CYG_ADDRWORD data ) { +#if !defined(CYGPKG_KERNEL_SMP_SUPPORT) +// In SMP scenario this CHECK is likely to fail because of race between +// executions of entry0 and entry1 on two separate processors. +// +// "s1" is initialised with "false" and entry0 will take some time to finish +// with first "s1.post()" in it's execution, but this thread (entry1) CHECKs +// for "s1.posted()" in the very beginning of it's execution. + CHECK( s1.posted() ); +#endif // CYGPKG_KERNEL_SMP_SUPPORT s1.wait(); CHECK( 1 == q++ ); CHECK( ! s0.posted() ); s0.post(); s1.wait(); Index: packages/kernel/current/tests/mqueue1.cxx =================================================================== RCS file: /cvs/ecos/ecos/packages/kernel/current/tests/mqueue1.cxx,v retrieving revision 1.5 diff -u -5 -p -r1.5 mqueue1.cxx --- packages/kernel/current/tests/mqueue1.cxx 23 May 2002 23:07:01 -0000 1.5 +++ packages/kernel/current/tests/mqueue1.cxx 23 Sep 2004 16:00:05 -0000 @@ -78,10 +78,26 @@ static char mempool[500]; static size_t storedmempoollen; Cyg_Mqueue *mq; static Cyg_Binary_Semaphore t0sem, t1sem; static int calledback; +#if defined(CYGPKG_KERNEL_SMP_SUPPORT) +// In SMP scenario, threads t0 and t1 will execute on separate processors +// simultaneously (when both are RUNNABLE). This brings in a race condition +// between "t1 checking for (mq == NULL)" and "the execution of my_free (called +// from inside Cyg_Mqueue destructor for the object 'the_mq' in thread t0) +// setting 'mq' to NULL". +// +// Introduction of "t0done" takes care of this race between t0 and t1. +// +// NOTE : Current solution will work as long as the size of mempool is kept +// lesser than whatever you are passing to huge_mq(99999, 99999, ...) object +// creation in thread t1, so that my_free gets called only once (as intended +// in this test). + +volatile int t0done = 0; +#endif // CYGPKG_KERNEL_SMP_SUPPORT /* FUNCTIONS */ static int my_memcmp(const void *m1, const void *m2, size_t n) @@ -112,10 +128,14 @@ static void my_free( void *ptr, size_t len ) { CYG_TEST_PASS_FAIL( (ptr == &mempool[0]) && (len == storedmempoollen), "Freed pool correctly"); mq = NULL; // invalidate + +#if defined(CYGPKG_KERNEL_SMP_SUPPORT) + t0done = 1; // t1 can proceed with "mq == NULL" check now +#endif // CYGPKG_KERNEL_SMP_SUPPORT } static void callback(Cyg_Mqueue &mq, CYG_ADDRWORD data) { @@ -374,10 +394,14 @@ t1( CYG_ADDRWORD data ) //------------------------------------------------------------------------ t0sem.post(); // t0 should run straight away Cyg_Thread::yield(); // but just in case we have a funny sched +#if defined(CYGPKG_KERNEL_SMP_SUPPORT) + while (0 == t0done) /* do nothing */ ; +#endif // CYGPKG_KERNEL_SMP_SUPPORT + // check that mq was destroyed when t0 dropped off the end CYG_TEST_PASS_FAIL( NULL == mq, "queue destroyed correctly" ); CYG_TEST_EXIT("kernel mqueue test 1"); Index: packages/kernel/current/tests/sched1.cxx =================================================================== RCS file: /cvs/ecos/ecos/packages/kernel/current/tests/sched1.cxx,v retrieving revision 1.7 diff -u -5 -p -r1.7 sched1.cxx --- packages/kernel/current/tests/sched1.cxx 23 May 2002 23:07:02 -0000 1.7 +++ packages/kernel/current/tests/sched1.cxx 23 Sep 2004 16:00:05 -0000 @@ -66,11 +66,17 @@ #include "testaux.hxx" static void entry0( CYG_ADDRWORD data ) { +#if !defined(CYGPKG_KERNEL_SMP_SUPPORT) + // This check is likely to fail in SMP configuration because of race + // conditions b/w entry0 and entry1, as get_sched_lock just returns the + // value of current schedlock count irrespective of which processor owns + // the schedlock currently. CHECK( 0 == Cyg_Scheduler::get_sched_lock() ); +#endif // CYGPKG_KERNEL_SMP_SUPPORT Cyg_Scheduler::lock(); { CHECK( 1 == Cyg_Scheduler::get_sched_lock() ); Cyg_Scheduler::lock(); { CHECK( 2 == Cyg_Scheduler::get_sched_lock() ); } Cyg_Scheduler::unlock(); Index: packages/net/common/current/tests/multi_lo_select.c =================================================================== RCS file: /cvs/ecos/ecos-opt/net/net/common/current/tests/multi_lo_select.c,v retrieving revision 1.2 diff -u -5 -p -r1.2 multi_lo_select.c --- packages/net/common/current/tests/multi_lo_select.c 6 Oct 2002 13:07:53 -0000 1.2 +++ packages/net/common/current/tests/multi_lo_select.c 23 Sep 2004 16:00:07 -0000 @@ -134,10 +134,17 @@ static cyg_sem_t recv_sema; static cyg_thread_entry_t master; static cyg_thread_entry_t listener; static cyg_thread_entry_t sender; +static cyg_sem_t dummy_sema; + +#if defined(CYGPKG_KERNEL_SMP_SUPPORT) +volatile cyg_int32 liscnt = 0; +cyg_mutex_t m0; +#endif // CYGPKG_KERNEL_SMP_SUPPORT + // ------------------------------------------------------------------------ void pexit(char *s) { @@ -164,10 +171,13 @@ void dummy( cyg_addrword_t which ) CYG_TEST_CHECK( 0 <= which, "which under" ); CYG_TEST_CHECK( NDUMMIES > which, "which over" ); diag_printf( "Dummy %d alive\n", which ); + // Ensure that only one dummy allocates a socket and binds (as intended) + cyg_semaphore_wait( &dummy_sema ); + if ( s_s1 < 0 ) { s_s1 = socket(AF_INET, SOCK_STREAM, 0); if (s_s1 < 0) { pexit("stream socket 1"); } @@ -180,10 +190,12 @@ void dummy( cyg_addrword_t which ) pexit("dummy bind /source_1/ error"); } listen(s_s1, SOMAXCONN); } + cyg_semaphore_post( &dummy_sema); + while (true) { FD_ZERO(&in_fds); FD_SET(s_s1, &in_fds); num = select( s_s1+1, &in_fds,0,0,0); @@ -240,10 +252,17 @@ void listener( cyg_addrword_t which ) pexit("bind /source_2/ error"); } listen(s_s2, SOMAXCONN); } +#if defined(CYGPKG_KERNEL_SMP_SUPPORT) + // let master know this listener is ready to listen now + cyg_mutex_lock(&m0); + liscnt++; + cyg_mutex_unlock(&m0); +#endif // CYGPKG_KERNEL_SMP_SUPPORT + while (true) { FD_ZERO(&in_fds); FD_SET(s_s1, &in_fds); if ( dual ) FD_SET(s_s2, &in_fds); @@ -290,10 +309,17 @@ void listener( cyg_addrword_t which ) close ( e_s2 ); cyg_semaphore_post( &listen_sema[which] ); // Verify that I was here cyg_semaphore_post( &recv_sema ); // Count receptions +#if defined(CYGPKG_KERNEL_SMP_SUPPORT) + // let master know this listener is done. + cyg_mutex_lock(&m0); + liscnt++; + cyg_mutex_unlock(&m0); +#endif // CYGPKG_KERNEL_SMP_SUPPORT + cyg_thread_exit(); // explicitly } // ------------------------------------------------------------------------ static void sender( cyg_addrword_t which ) // which means which set (odd/even) here... @@ -338,10 +364,15 @@ master(cyg_addrword_t param) int i; cyg_handle_t self = cyg_thread_self(); cyg_semaphore_init( &send_sema, 0 ); cyg_semaphore_init( &recv_sema, 0 ); +#if defined(CYGPKG_KERNEL_SMP_SUPPORT) + cyg_semaphore_init( &dummy_sema, 1 ); + + cyg_mutex_init(&m0); +#endif // CYGPKG_KERNEL_SMP_SUPPORT for ( i = 0 ; i < NLISTENERS; i++ ) cyg_semaphore_init( &listen_sema[i], 0 ); init_all_network_interfaces(); @@ -391,13 +422,29 @@ master(cyg_addrword_t param) for ( i = 0; i < NDUMMIES; i++ ) cyg_thread_resume( dummy_thread_handle[i]); // and let them start up and start listening... cyg_thread_set_priority( self, PRIO_MASTERLOW ); + +#if defined(CYGPKG_KERNEL_SMP_SUPPORT) + // master doesn't fire senders before all listeners are ready to listen + + while (NLISTENERS != liscnt) /* do nothing but wait. */ ; +#endif // CYGPKG_KERNEL_SMP_SUPPORT + CYG_TEST_INFO("All listeners should be go now"); cyg_thread_set_priority( self, PRIO_MASTERHIGH ); +#if defined(CYGPKG_KERNEL_SMP_SUPPORT) + // reset liscnt before resuming any sender. liscnt is used for - + // - ensuring that all the listeners are up and listening, before master + // thread fires the senders. + // - later on, to ensure that master proceeds only after all the listeners + // have finished. + liscnt = 0; +#endif // CYGPKG_KERNEL_SMP_SUPPORT + for ( i = 0; i < NSENDERS; i++ ) { cyg_thread_create( (0 == i) ?PRIO_SENDER_MID : PRIO_SENDER_LOW, // Priority sender, // entry @@ -414,10 +461,16 @@ master(cyg_addrword_t param) // Now we are still higher priority; so go low and let everyone else // have their head. When we next run after this, it should all be // over. cyg_thread_set_priority( self, PRIO_MASTERLOW ); +#if defined(CYGPKG_KERNEL_SMP_SUPPORT) + // master doesn't continue before all listeners have finished + + while (NLISTENERS != liscnt) /* do nothing but wait. */ ; +#endif // CYGPKG_KERNEL_SMP_SUPPORT + cyg_semaphore_peek( &recv_sema, &i ); CYG_TEST_CHECK( NLISTENERS == i, "Not enough recvs occurred!" ); cyg_semaphore_peek( &send_sema, &i ); CYG_TEST_CHECK( NLISTENERS == i, "Not enough sends occurred!" );