This is the mail archive of the
ecos-patches@sourceware.org
mailing list for the eCos project.
Re: Is timeslicing broken?
- From: Nick Garnett <nickg at ecoscentric dot com>
- To: Gary Thomas <gary at mlbassoc dot com>
- Cc: eCos patches <ecos-patches at ecos dot sourceware dot org>
- Date: 08 Jan 2007 13:58:01 +0000
- Subject: Re: Is timeslicing broken?
- References: <45A0F41B.6070403@mlbassoc.com>
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( ¤t->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