This is the mail archive of the ecos-patches@sourceware.org mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Is timeslicing broken?


Gary Thomas <gary@mlbassoc.com> writes:

> It seems that timeslicing of equal priority threads is broken
> in the presence of any other higher priority threads that may
> cause preemption.
> 
> I have modified the timeslice test to have an additional thread.
> This thread is higher priority than the "worker" threads and
> all it does is wake up at a modest frequency (every 2 ticks).
> What this does is to preempt one of the worker threads before
> it has a chance to run the timeslice timer down to zero.  When
> the worker thread is resumed, the timeslice timer is reset and
> the same worker thread continues running forever, never being
> rescheduled and letting the other worker threads run.
> 

As it happens, I also fixed this bug myself a few weeks ago. It has
been running in our test farm for a while. I think my patch is a
little more complete since it also deals with the bitmap scheduler and
kapidata.h. I also think it leaves the scheduler code a little tidier.

Anyway here it is:


Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/kernel/current/ChangeLog,v
retrieving revision 1.140
diff -u -5 -r1.140 ChangeLog
--- ChangeLog	7 Jan 2007 17:08:53 -0000	1.140
+++ ChangeLog	8 Jan 2007 13:53:19 -0000
@@ -1,10 +1,30 @@
 2007-01-07  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* src/sync/mbox.cxx (Cyg_Mbox::get): Fix compiler warning with gcc
 	version 4.1.2.
 
+2006-12-08  Nick Garnett  <nickg@ecoscentric.com>
+	
+        * src/sched/mlqueue.cxx (add_thread, yield): 
+	* src/sched/sched.cxx (unlock_inner, thread_entry): 
+	* include/mlqueue.hxx (class Cyg_SchedThread_Implementation):
+	* include/kapidata.h (CYG_SCHEDTHREAD_TIMESLICE_MEMBER): 
+	* include/bitmap.hxx (class Cyg_SchedThread_Implementation):
+	Reimplement timeslicing code. There is now a timeslice_count field
+	in each thread which is moved to and from the per-CPU counter
+	during thread dispatch. This approach has been taken to minimize
+	the changes needed to SMP code. Scheduler specific thread
+	functions handle counter save, restore and reset. These functions
+	are defined (as empty inlines) even when timeslicing is disabled,
+	or in non-timeslicing schedulers, to avoid adding ifdefs to the
+	code (this change actually removes some).
+
+	* tests/timeslice2.c: 
+	* cdl/kernel.cdl: Added timeslice2 test to test behaviour of
+	timeslicing while being preempted.
+
 2006-10-12  Nick Garnett  <nickg@ecoscentric.com>
 
 	* cdl/synch.cdl: Added CYGIMP_MBOX_USE_MBOXT_PLAIN option. This is
 	tested in various places but was not actually defined. It now is
 	and defaults to 1 so that the plain version of mail boxes is
Index: cdl/kernel.cdl
===================================================================
RCS file: /cvs/ecos/ecos/packages/kernel/current/cdl/kernel.cdl,v
retrieving revision 1.20
diff -u -5 -r1.20 kernel.cdl
--- cdl/kernel.cdl	1 Jul 2003 17:34:53 -0000	1.20
+++ cdl/kernel.cdl	8 Jan 2007 13:53:20 -0000
@@ -321,11 +321,11 @@
             display "Kernel tests"
             flavor  data
             no_define
             calculated { 
                 "tests/bin_sem0 tests/bin_sem1 tests/bin_sem2 tests/bin_sem3 tests/clock0 tests/clock1 tests/clockcnv tests/clocktruth tests/cnt_sem0 tests/cnt_sem1 tests/except1 tests/flag0 tests/flag1 tests/intr0 tests/kill tests/mbox1 tests/mqueue1 tests/mutex0 tests/mutex1 tests/mutex2 tests/mutex3 tests/release tests/sched1 tests/sync2 tests/sync3 tests/thread0 tests/thread1 tests/thread2" 
-                . ((CYGFUN_KERNEL_API_C) ? " tests/kclock0 tests/kclock1 tests/kexcept1 tests/kflag0 tests/kflag1 tests/kintr0 tests/klock tests/kmbox1 tests/kmutex0 tests/kmutex1 tests/kmutex3 tests/kmutex4 tests/ksched1 tests/ksem0 tests/ksem1 tests/kthread0 tests/kthread1 tests/stress_threads tests/thread_gdb tests/timeslice tests/tm_basic tests/fptest tests/kalarm0" : "")
+                . ((CYGFUN_KERNEL_API_C) ? " tests/kclock0 tests/kclock1 tests/kexcept1 tests/kflag0 tests/kflag1 tests/kintr0 tests/klock tests/kmbox1 tests/kmutex0 tests/kmutex1 tests/kmutex3 tests/kmutex4 tests/ksched1 tests/ksem0 tests/ksem1 tests/kthread0 tests/kthread1 tests/stress_threads tests/thread_gdb tests/timeslice tests/timeslice2 tests/tm_basic tests/fptest tests/kalarm0" : "")
                 . ((!CYGPKG_INFRA_DEBUG && !CYGPKG_KERNEL_INSTRUMENT && CYGFUN_KERNEL_API_C) ? " tests/dhrystone" : "")
                 . ((CYGPKG_KERNEL_SMP_SUPPORT && CYGFUN_KERNEL_API_C) ? " tests/smp" : "")
                 . ((!CYGINT_HAL_TESTS_NO_CACHES && CYGFUN_KERNEL_API_C) ? " tests/kcache1 tests/kcache2" : "")
             }
             description   "
Index: include/bitmap.hxx
===================================================================
RCS file: /cvs/ecos/ecos/packages/kernel/current/include/bitmap.hxx,v
retrieving revision 1.8
diff -u -5 -r1.8 bitmap.hxx
--- include/bitmap.hxx	23 May 2002 23:06:46 -0000	1.8
+++ include/bitmap.hxx	8 Jan 2007 13:53:20 -0000
@@ -10,10 +10,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2006 eCosCentric Limited
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -154,10 +155,15 @@
     void yield();                       // Yield CPU to next thread
 
     // These are not applicable in a bitmap scheduler; placeholders:
     inline void rotate_queue( cyg_priority pri ) { };
     inline void to_queue_head( void ) { };
+
+    inline void timeslice_save() {};
+    inline void timeslice_restore() {};
+    inline void timeslice_reset() {};
+    
 };
 
 // -------------------------------------------------------------------------
 // Thread queue implementation.
 // This class provides the (scheduler specific) implementation of the
Index: include/kapidata.h
===================================================================
RCS file: /cvs/ecos/ecos/packages/kernel/current/include/kapidata.h,v
retrieving revision 1.13
diff -u -5 -r1.13 kapidata.h
--- include/kapidata.h	27 Feb 2003 06:14:32 -0000	1.13
+++ include/kapidata.h	8 Jan 2007 13:53:20 -0000
@@ -275,10 +275,17 @@
     cyg_uint32          cpu;            // CPU id of cpu currently running
 #else
 # define CYG_SCHEDTHREAD_CPU_MEMBER
 #endif
 
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+# define CYG_SCHEDTHREAD_TIMESLICE_MEMBER \
+    cyg_ucount32         timeslice_count; /* per-thread timeslice counter */
+#else
+# define CYG_SCHEDTHREAD_TIMESLICE_MEMBER
+#endif
+
 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
 # define CYG_SCHEDTHREAD_TIMESLICE_ENABLED_MEMBER \
     cyg_bool            timeslice_enabled; /* per-thread timeslice enable */
 #else
 # define CYG_SCHEDTHREAD_TIMESLICE_ENABLED_MEMBER
@@ -291,10 +298,11 @@
 # define CYG_SCHEDTHREAD_SCHEDIMP_MEMBERS                                    \
     cyg_thread *next;                                                        \
     cyg_thread *prev;                                                        \
     cyg_priority_t      priority;             /* current thread priority */  \
     CYG_SCHEDTHREAD_CPU_MEMBER                                               \
+    CYG_SCHEDTHREAD_TIMESLICE_MEMBER                                         \
     CYG_SCHEDTHREAD_TIMESLICE_ENABLED_MEMBER
 #elif defined(CYGSEM_KERNEL_SCHED_LOTTERY)
 # define CYG_SCHEDTHREAD_SCHEDIMP_MEMBERS                                    \
     cyg_thread *next;                                                        \
     cyg_thread *prev;                                                        \
Index: include/mlqueue.hxx
===================================================================
RCS file: /cvs/ecos/ecos/packages/kernel/current/include/mlqueue.hxx,v
retrieving revision 1.12
diff -u -5 -r1.12 mlqueue.hxx
--- include/mlqueue.hxx	23 May 2002 23:06:48 -0000	1.12
+++ include/mlqueue.hxx	8 Jan 2007 13:53:21 -0000
@@ -178,12 +178,10 @@
     // time it zeroes.
     
     static cyg_ucount32 timeslice_count[CYGNUM_KERNEL_CPU_MAX]
                                         CYGBLD_ANNOTATE_VARIABLE_SCHED;
 
-    static void reset_timeslice_count();
-
 #endif
 
     Cyg_Scheduler_Implementation();     // Constructor
     
     // The following functions provide the scheduler implementation
@@ -235,18 +233,10 @@
 inline void Cyg_Scheduler_Implementation::set_need_reschedule()
 {
     need_reschedule[CYG_KERNEL_CPU_THIS()] = true;
 }
 
-#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
-
-inline void Cyg_Scheduler_Implementation::reset_timeslice_count()
-{
-    timeslice_count[CYG_KERNEL_CPU_THIS()] = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
-}
-
-#endif
 
 // -------------------------------------------------------------------------
 // Scheduler thread implementation.
 // This class provides the implementation of the scheduler specific parts
 // of each thread.
@@ -276,10 +266,20 @@
 
     void to_queue_head( void );         // Move this thread to the head
                                         // of its queue (not necessarily
                                         // a scheduler queue)
 
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+    cyg_ucount32 timeslice_count;
+        
+    void timeslice_save();
+
+    void timeslice_restore();
+    
+    void timeslice_reset();
+
 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
 
     // This defines whether this thread is subject to timeslicing.
     // If false, timeslice expiry has no effect on the thread.
     
@@ -289,17 +289,44 @@
     
     void timeslice_enable();
 
     void timeslice_disable();
     
+#endif
+
+#else
+
+    inline void timeslice_save() {};
+    inline void timeslice_restore() {};
+    inline void timeslice_reset() {};
+    
 #endif    
        
 };
 
 // -------------------------------------------------------------------------
 // Cyg_SchedThread_Implementation inlines.
 
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+inline void Cyg_SchedThread_Implementation::timeslice_save()
+{
+    timeslice_count = Cyg_Scheduler_Implementation::timeslice_count[CYG_KERNEL_CPU_THIS()];
+}
+
+inline void Cyg_SchedThread_Implementation::timeslice_restore()
+{
+    Cyg_Scheduler_Implementation::timeslice_count[CYG_KERNEL_CPU_THIS()] = timeslice_count;
+}
+
+inline void Cyg_SchedThread_Implementation::timeslice_reset()
+{
+    timeslice_count = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
+//    if( this == Cyg_Scheduler::get_current_thread() )
+//        Cyg_Scheduler_Implementation::timeslice_count[CYG_KERNEL_CPU_THIS()] = timeslice_count;
+}
+
 #ifdef CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
 
 inline void Cyg_SchedThread_Implementation::timeslice_enable()
 {
     timeslice_enabled = true;
@@ -310,9 +337,11 @@
     timeslice_enabled = false;
 }
 
 #endif
 
+#endif
+
 
 // -------------------------------------------------------------------------
 #endif // ifndef CYGONCE_KERNEL_MLQUEUE_HXX
 // EOF mlqueue.hxx
Index: src/sched/mlqueue.cxx
===================================================================
RCS file: /cvs/ecos/ecos/packages/kernel/current/src/sched/mlqueue.cxx,v
retrieving revision 1.19
diff -u -5 -r1.19 mlqueue.cxx
--- src/sched/mlqueue.cxx	24 Sep 2004 16:57:12 -0000	1.19
+++ src/sched/mlqueue.cxx	8 Jan 2007 13:53:21 -0000
@@ -234,10 +234,15 @@
 
     // If the new thread is higher priority than any
     // current thread, request a reschedule.
 
     set_need_reschedule(thread);
+
+    // Also reset the timeslice_count so that this thread gets a full
+    // timeslice once it begins to run.
+    
+    thread->timeslice_reset();
     
 #ifdef CYGPKG_KERNEL_SMP_SUPPORT
 
     // If the thread is not currently running, increment the pending
     // count for the priority, and if necessary set the bit in the
@@ -638,16 +643,18 @@
             queue->rotate();
 #endif
         
         if( queue->get_head() != thread )
             sched->set_need_reschedule();
+        else
+        {
+            // Reset the timeslice counter so that this thread gets a
+            // full quantum as a reward for yielding when it is
+            // eventually rescheduled.
+            thread->timeslice_reset();
+        }
 
-#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
-            // Reset the timeslice counter so that this thread gets a full
-            // quantum. 
-        else Cyg_Scheduler::reset_timeslice_count();
-#endif
     }
     
     // Unlock the scheduler and switch threads
 #ifdef CYGDBG_USE_ASSERTS
     // This test keeps the assertions in unlock_inner() happy if
Index: src/sched/sched.cxx
===================================================================
RCS file: /cvs/ecos/ecos/packages/kernel/current/src/sched/sched.cxx,v
retrieving revision 1.18
diff -u -5 -r1.18 sched.cxx
--- src/sched/sched.cxx	19 Jan 2006 17:53:58 -0000	1.18
+++ src/sched/sched.cxx	8 Jan 2007 13:53:22 -0000
@@ -196,11 +196,12 @@
                 thread_switches[CYG_KERNEL_CPU_THIS()]++;
 
 #ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
                 next->check_stack(); // before running it
 #endif
-
+                current->timeslice_save();
+                
                 // Switch contexts
                 HAL_THREAD_SWITCH_CONTEXT( &current->stack_ptr,
                                            &next->stack_ptr );
 
                 // Worry here about possible compiler
@@ -219,17 +220,13 @@
 
                 CYG_CHECK_DATA_PTR( current, "Invalid current thread pointer");
                 CYG_ASSERTCLASS( current, "Bad current thread" );
 
                 current_thread[CYG_KERNEL_CPU_THIS()] = current;   // restore current thread pointer
-            }
 
-#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
-            // Reset the timeslice counter so that this thread gets a full
-            // quantum. 
-            reset_timeslice_count();
-#endif
+                current->timeslice_restore();
+            }
 
             clear_need_reschedule();    // finished rescheduling
         }
 
         if( new_lock == 0 )
@@ -316,16 +313,13 @@
 {
     clear_need_reschedule();            // finished rescheduling
     set_current_thread(thread);         // restore current thread pointer
 
     CYG_INSTRUMENT_THREAD(ENTER,thread,0);
-    
-#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
-    // Reset the timeslice counter so that this thread gets a full
-    // quantum. 
-    reset_timeslice_count();
-#endif
+
+    thread->timeslice_reset();
+    thread->timeslice_restore();
     
     // Finally unlock the scheduler. As well as clearing the scheduler
     // lock this allows any pending DSRs to execute. The new thread
     // must start with a lock of zero, so we keep unlocking until the
     // lock reaches zero.
Index: tests/timeslice.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/kernel/current/tests/timeslice.c,v
retrieving revision 1.5
diff -u -5 -r1.5 timeslice.c
--- tests/timeslice.c	14 Feb 2006 19:10:06 -0000	1.5
+++ tests/timeslice.c	8 Jan 2007 13:53:22 -0000
@@ -7,10 +7,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2006 eCosCentric Limited
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -262,20 +263,18 @@
 
 externC void
 cyg_start( void )
 {
     CYG_TEST_INIT();
-    CYG_TEST_INFO("SMP test requires:\n"
+    CYG_TEST_INFO("Timeslice test requires:\n"
                 "CYGSEM_KERNEL_SCHED_TIMESLICE &&\n"
-                "CYGPKG_KERNEL_SMP_SUPPORT &&\n"
                 "CYGFUN_KERNEL_API_C && \n"
                 "CYGSEM_KERNEL_SCHED_MLQUEUE &&\n"
                 "CYGVAR_KERNEL_COUNTERS_CLOCK &&\n"
-                "!CYGPKG_HAL_I386_LINUX &&\n"
                 "!CYGDBG_INFRA_DIAG_USE_DEVICE &&\n"
                 "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n");
-    CYG_TEST_NA("SMP test requirements");
+    CYG_TEST_NA("Timeslice test requirements");
 }
 
 #endif // CYGSEM_KERNEL_SCHED_TIMESLICE etc.
 
 //==========================================================================
Index: tests/timeslice2.c
===================================================================
RCS file: tests/timeslice2.c
diff -N tests/timeslice2.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/timeslice2.c	8 Jan 2007 13:53:22 -0000
@@ -0,0 +1,307 @@
+//==========================================================================
+//
+//        timeslice2.c
+//
+//        Timeslice 2 test
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2006 eCosCentric Limited
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     nickg
+// Contributors:  nickg
+// Date:          2001-06-18
+// Description:   An additional timeslicing test.
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/hal.h>
+
+#include <cyg/hal/hal_arch.h>
+
+#include <cyg/kernel/smp.hxx>
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+
+//==========================================================================
+
+#if defined(CYGSEM_KERNEL_SCHED_TIMESLICE) &&   \
+    defined(CYGFUN_KERNEL_API_C) &&             \
+    defined(CYGSEM_KERNEL_SCHED_MLQUEUE) &&     \
+    defined(CYGVAR_KERNEL_COUNTERS_CLOCK) &&    \
+    !defined(CYGDBG_INFRA_DIAG_USE_DEVICE) &&   \
+    (CYGNUM_KERNEL_SCHED_PRIORITIES > 12)
+
+//==========================================================================
+
+#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#define NTHREADS_MAX (CYGNUM_KERNEL_CPU_MAX*6)
+
+static int ncpus = CYGNUM_KERNEL_CPU_MAX;
+
+static char test_stack[STACK_SIZE];
+static cyg_thread test_thread;
+static cyg_handle_t main_thread;
+
+static char hipri_stack[STACK_SIZE];
+static cyg_thread hipri_thread_obj;
+static cyg_handle_t hipri_thread;
+
+static char stacks[NTHREADS_MAX][STACK_SIZE];
+static cyg_thread test_threads[NTHREADS_MAX];
+static cyg_handle_t threads[NTHREADS_MAX];
+
+static volatile int failed = false;
+
+static volatile cyg_uint32 slicerun[NTHREADS_MAX][CYGNUM_KERNEL_CPU_MAX];
+
+//==========================================================================
+
+void 
+test_thread_timeslice(CYG_ADDRESS id)
+{
+    for(;;)
+        slicerun[id][CYG_KERNEL_CPU_THIS()]++;
+}
+
+//==========================================================================
+
+void run_test_timeslice(int nthread)
+{
+    int i,j;
+    cyg_uint32 cpu_total[CYGNUM_KERNEL_CPU_MAX];
+    cyg_uint32 cpu_threads[CYGNUM_KERNEL_CPU_MAX];
+    cyg_uint32 thread_total[NTHREADS_MAX];
+
+    CYG_TEST_INFO( "Timeslice2 Test: Check timeslicing works under preemption");
+    
+    // Init flags.
+    for (i = 0;  i < nthread;  i++)
+        for( j = 0; j < ncpus; j++ )
+            slicerun[i][j] = 0;
+    
+    // Set my priority higher than any I plan to create
+    cyg_thread_set_priority(cyg_thread_self(), 2);
+
+    for (i = 0;  i < nthread;  i++) {
+        cyg_thread_create(10,              // Priority - just a number
+                          test_thread_timeslice, // entry
+                          i,               // index
+                          "test_thread",     // Name
+                          &stacks[i][0],   // Stack
+                          STACK_SIZE,      // Size
+                          &threads[i],     // Handle
+                          &test_threads[i] // Thread data structure
+            );
+        cyg_thread_resume( threads[i]);
+    }
+
+    // Just wait a while, until the threads have all run for a bit.
+    cyg_thread_delay( CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS*100 );
+
+    // Suspend all the threads
+    for (i = 0;  i < nthread;  i++) {
+        cyg_thread_suspend(threads[i]);
+    }
+
+    
+    // And check that a thread ran on each CPU, and that each thread
+    // ran.
+    
+    
+    diag_printf(" Thread ");
+    for( j = 0; j < ncpus; j++ )
+    {
+        cpu_total[j] = 0;
+        cpu_threads[j] = 0;
+        // "  %11d"  __123456789ab"
+        diag_printf("       CPU %2d",j);
+    }
+    // "  %11d"  __123456789ab"
+    diag_printf("        Total\n");
+    for (i = 0;  i < nthread;  i++)
+    {
+        thread_total[i] = 0;
+        diag_printf("     %2d ",i);
+        for( j = 0; j < ncpus; j++ )
+        {
+            thread_total[i] += slicerun[i][j];
+            cpu_total[j] += slicerun[i][j];
+            if( slicerun[i][j] > 0 )
+                cpu_threads[j]++;
+            diag_printf("  %11d",slicerun[i][j]);
+        }
+        diag_printf("  %11d\n",thread_total[i]);
+        if( thread_total[i] == 0 )
+            failed++;
+    }
+    
+    diag_printf(" Total  ");
+    for( j = 0; j < ncpus; j++ )
+        diag_printf("  %11d",cpu_total[j]);
+    diag_printf("\n");
+    diag_printf("Threads ");
+    for( j = 0; j < ncpus; j++ )
+    {
+        diag_printf("  %11d",cpu_threads[j]);
+        if( cpu_threads[j] < 2 )
+            failed++;
+    }
+    diag_printf("\n");
+
+    // Delete all the threads
+    for (i = 0;  i < nthread;  i++) {
+        cyg_thread_delete(threads[i]);
+    }
+
+    CYG_TEST_INFO( "Timeslice2 Test: done");
+}
+
+
+//==========================================================================
+
+void 
+hipri_test(CYG_ADDRESS id)
+{
+    while( 1 )
+    {
+        cyg_thread_delay( CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS/2 );
+    }
+}
+
+//==========================================================================
+
+void 
+run_tests(CYG_ADDRESS id)
+{
+    int step;
+    int nthread;
+    
+    // Try to run about 10 times in total, with varying numbers of threads
+    // from only one extra up to the full set:
+
+    step = (NTHREADS_MAX - (1 + CYG_KERNEL_CPU_COUNT()))/10;
+    if( step == 0 ) step = 1;
+    
+    for( nthread = 1 + CYG_KERNEL_CPU_COUNT() ;
+         nthread <= NTHREADS_MAX ;
+         nthread += step )
+            run_test_timeslice(nthread);
+
+    if( failed )
+        CYG_TEST_FAIL_FINISH("Timeslice2 test failed\n");
+    
+    CYG_TEST_PASS_FINISH("Timeslice2 test OK");    
+}
+
+//==========================================================================
+
+void timeslice_main( void )
+{
+    CYG_TEST_INIT();
+
+    // Work out how many CPUs we actually have.
+    ncpus = CYG_KERNEL_CPU_COUNT();
+
+    cyg_thread_create(0,              // Priority - just a number
+                      run_tests, // entry
+                      0,               // index
+                      "run_tests",     // Name
+                      test_stack,   // Stack
+                      STACK_SIZE,      // Size
+                      &main_thread,     // Handle
+                      &test_thread // Thread data structure
+        );
+    cyg_thread_resume( main_thread);
+
+    cyg_thread_create(5,               // Priority - just a number
+                      hipri_test,      // entry
+                      0,               // index
+                      "hipri_run",     // Name
+                      hipri_stack,   // Stack
+                      STACK_SIZE,      // Size
+                      &hipri_thread,     // Handle
+                      &hipri_thread_obj // Thread data structure
+        );
+    cyg_thread_resume( hipri_thread);
+    
+    cyg_scheduler_start();
+}
+
+//==========================================================================
+
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+externC void
+cyg_hal_invoke_constructors();
+#endif
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+    cyg_hal_invoke_constructors();
+#endif
+    timeslice_main();
+}   
+
+//==========================================================================
+
+#else // CYGSEM_KERNEL_SCHED_TIMESLICE etc
+
+externC void
+cyg_start( void )
+{
+    CYG_TEST_INIT();
+    CYG_TEST_INFO("Timeslice test requires:\n"
+                "CYGSEM_KERNEL_SCHED_TIMESLICE &&\n"
+                "CYGFUN_KERNEL_API_C && \n"
+                "CYGSEM_KERNEL_SCHED_MLQUEUE &&\n"
+                "CYGVAR_KERNEL_COUNTERS_CLOCK &&\n"
+                "!CYGDBG_INFRA_DIAG_USE_DEVICE &&\n"
+                "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n");
+    CYG_TEST_NA("Timeslice test requirements");
+}
+
+#endif // CYGSEM_KERNEL_SCHED_TIMESLICE etc.
+
+//==========================================================================
+// EOF timeslice2.c


-- 
Nick Garnett                                     eCos Kernel Architect
http://www.ecoscentric.com                The eCos and RedBoot experts
http://www.ecoscentric.com/legal        Legal info, address and number


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]