summaryrefslogtreecommitdiff
path: root/ecos/packages/kernel
diff options
context:
space:
mode:
authorschodet2007-02-23 12:33:47 +0000
committerschodet2007-02-23 12:33:47 +0000
commit22e4b1be3fe83053543994c325cb0d44e4587723 (patch)
tree6a4ef5b3c8ed45de299c185e5dd3391c934c6e1b /ecos/packages/kernel
parent16697c575dfa90feb62c8db019d62682dfe026ca (diff)
Added ecos and build system.
git-svn-id: svn+ssh://pessac/svn/cesar/trunk@4 017c9cb6-072f-447c-8318-d5b54f68fe89
Diffstat (limited to 'ecos/packages/kernel')
-rw-r--r--ecos/packages/kernel/current/ChangeLog4606
-rw-r--r--ecos/packages/kernel/current/cdl/counters.cdl190
-rw-r--r--ecos/packages/kernel/current/cdl/instrument.cdl312
-rw-r--r--ecos/packages/kernel/current/cdl/interrupts.cdl129
-rw-r--r--ecos/packages/kernel/current/cdl/kernel.cdl345
-rw-r--r--ecos/packages/kernel/current/cdl/scheduler.cdl256
-rw-r--r--ecos/packages/kernel/current/cdl/synch.cdl213
-rw-r--r--ecos/packages/kernel/current/cdl/thread.cdl332
-rw-r--r--ecos/packages/kernel/current/doc/SMP.txt544
-rw-r--r--ecos/packages/kernel/current/doc/kernel.sgml5456
-rw-r--r--ecos/packages/kernel/current/host/instr/dump_instr.c106
-rwxr-xr-xecos/packages/kernel/current/host/instr/instrument.sh23
-rw-r--r--ecos/packages/kernel/current/host/instr/readme.txt80
-rw-r--r--ecos/packages/kernel/current/include/bitmap.hxx201
-rw-r--r--ecos/packages/kernel/current/include/clock.hxx261
-rw-r--r--ecos/packages/kernel/current/include/clock.inl125
-rw-r--r--ecos/packages/kernel/current/include/diag.h66
-rw-r--r--ecos/packages/kernel/current/include/errors.h83
-rw-r--r--ecos/packages/kernel/current/include/except.hxx128
-rw-r--r--ecos/packages/kernel/current/include/flag.hxx166
-rw-r--r--ecos/packages/kernel/current/include/instrmnt.h465
-rw-r--r--ecos/packages/kernel/current/include/instrument_desc.h143
-rw-r--r--ecos/packages/kernel/current/include/intr.hxx371
-rw-r--r--ecos/packages/kernel/current/include/kapi.h681
-rw-r--r--ecos/packages/kernel/current/include/kapidata.h554
-rw-r--r--ecos/packages/kernel/current/include/kernel.hxx86
-rw-r--r--ecos/packages/kernel/current/include/ktypes.h129
-rw-r--r--ecos/packages/kernel/current/include/llistt.hxx171
-rw-r--r--ecos/packages/kernel/current/include/lottery.hxx223
-rw-r--r--ecos/packages/kernel/current/include/mbox.hxx136
-rw-r--r--ecos/packages/kernel/current/include/mboxt.hxx138
-rw-r--r--ecos/packages/kernel/current/include/mboxt.inl634
-rw-r--r--ecos/packages/kernel/current/include/mboxt2.hxx142
-rw-r--r--ecos/packages/kernel/current/include/mboxt2.inl683
-rw-r--r--ecos/packages/kernel/current/include/mlqueue.hxx318
-rw-r--r--ecos/packages/kernel/current/include/mqueue.hxx163
-rw-r--r--ecos/packages/kernel/current/include/mqueue.inl543
-rw-r--r--ecos/packages/kernel/current/include/mutex.hxx217
-rw-r--r--ecos/packages/kernel/current/include/sched.hxx412
-rw-r--r--ecos/packages/kernel/current/include/sched.inl168
-rw-r--r--ecos/packages/kernel/current/include/sema.hxx137
-rw-r--r--ecos/packages/kernel/current/include/sema2.hxx137
-rw-r--r--ecos/packages/kernel/current/include/smp.hxx468
-rw-r--r--ecos/packages/kernel/current/include/test/stackmon.h239
-rw-r--r--ecos/packages/kernel/current/include/thread.hxx590
-rw-r--r--ecos/packages/kernel/current/include/thread.inl693
-rw-r--r--ecos/packages/kernel/current/include/timer.hxx127
-rw-r--r--ecos/packages/kernel/current/src/common/clock.cxx946
-rw-r--r--ecos/packages/kernel/current/src/common/except.cxx268
-rw-r--r--ecos/packages/kernel/current/src/common/kapi.cxx1264
-rw-r--r--ecos/packages/kernel/current/src/common/thread.cxx1299
-rw-r--r--ecos/packages/kernel/current/src/common/timer.cxx129
-rw-r--r--ecos/packages/kernel/current/src/debug/dbg-thread-demux.c181
-rw-r--r--ecos/packages/kernel/current/src/debug/dbg_gdb.cxx469
-rw-r--r--ecos/packages/kernel/current/src/instrmnt/meminst.cxx261
-rw-r--r--ecos/packages/kernel/current/src/intr/intr.cxx784
-rw-r--r--ecos/packages/kernel/current/src/sched/bitmap.cxx323
-rw-r--r--ecos/packages/kernel/current/src/sched/lottery.cxx456
-rw-r--r--ecos/packages/kernel/current/src/sched/mlqueue.cxx885
-rw-r--r--ecos/packages/kernel/current/src/sched/sched.cxx741
-rw-r--r--ecos/packages/kernel/current/src/sync/bin_sem.cxx276
-rw-r--r--ecos/packages/kernel/current/src/sync/cnt_sem.cxx283
-rw-r--r--ecos/packages/kernel/current/src/sync/cnt_sem2.cxx295
-rw-r--r--ecos/packages/kernel/current/src/sync/flag.cxx418
-rw-r--r--ecos/packages/kernel/current/src/sync/mbox.cxx170
-rw-r--r--ecos/packages/kernel/current/src/sync/mqueue.cxx65
-rw-r--r--ecos/packages/kernel/current/src/sync/mutex.cxx863
-rw-r--r--ecos/packages/kernel/current/tests/bin_sem0.cxx89
-rw-r--r--ecos/packages/kernel/current/tests/bin_sem1.cxx130
-rw-r--r--ecos/packages/kernel/current/tests/bin_sem2.cxx224
-rw-r--r--ecos/packages/kernel/current/tests/bin_sem3.cxx138
-rw-r--r--ecos/packages/kernel/current/tests/clock0.cxx286
-rw-r--r--ecos/packages/kernel/current/tests/clock1.cxx132
-rw-r--r--ecos/packages/kernel/current/tests/clockcnv.cxx287
-rw-r--r--ecos/packages/kernel/current/tests/clocktruth.cxx155
-rw-r--r--ecos/packages/kernel/current/tests/cnt_sem0.cxx89
-rw-r--r--ecos/packages/kernel/current/tests/cnt_sem1.cxx135
-rw-r--r--ecos/packages/kernel/current/tests/dhrystone.c1176
-rw-r--r--ecos/packages/kernel/current/tests/except1.cxx271
-rw-r--r--ecos/packages/kernel/current/tests/flag0.cxx88
-rw-r--r--ecos/packages/kernel/current/tests/flag1.cxx219
-rw-r--r--ecos/packages/kernel/current/tests/fptest.c364
-rw-r--r--ecos/packages/kernel/current/tests/intr0.cxx209
-rw-r--r--ecos/packages/kernel/current/tests/kalarm0.c191
-rw-r--r--ecos/packages/kernel/current/tests/kcache1.c422
-rw-r--r--ecos/packages/kernel/current/tests/kcache2.c920
-rw-r--r--ecos/packages/kernel/current/tests/kclock0.c274
-rw-r--r--ecos/packages/kernel/current/tests/kclock1.c153
-rw-r--r--ecos/packages/kernel/current/tests/kexcept1.c288
-rw-r--r--ecos/packages/kernel/current/tests/kflag0.c99
-rw-r--r--ecos/packages/kernel/current/tests/kflag1.c244
-rw-r--r--ecos/packages/kernel/current/tests/kill.cxx199
-rw-r--r--ecos/packages/kernel/current/tests/kintr0.c230
-rw-r--r--ecos/packages/kernel/current/tests/klock.c318
-rw-r--r--ecos/packages/kernel/current/tests/kmbox1.c217
-rw-r--r--ecos/packages/kernel/current/tests/kmutex0.c98
-rw-r--r--ecos/packages/kernel/current/tests/kmutex1.c188
-rw-r--r--ecos/packages/kernel/current/tests/kmutex3.c639
-rw-r--r--ecos/packages/kernel/current/tests/kmutex4.c526
-rw-r--r--ecos/packages/kernel/current/tests/kphilo.c236
-rw-r--r--ecos/packages/kernel/current/tests/ksched1.c103
-rw-r--r--ecos/packages/kernel/current/tests/ksem0.c100
-rw-r--r--ecos/packages/kernel/current/tests/ksem1.c169
-rw-r--r--ecos/packages/kernel/current/tests/kthread0.c120
-rw-r--r--ecos/packages/kernel/current/tests/kthread1.c136
-rw-r--r--ecos/packages/kernel/current/tests/mbox1.cxx201
-rw-r--r--ecos/packages/kernel/current/tests/mqueue1.cxx411
-rw-r--r--ecos/packages/kernel/current/tests/mutex0.cxx96
-rw-r--r--ecos/packages/kernel/current/tests/mutex1.cxx162
-rw-r--r--ecos/packages/kernel/current/tests/mutex2.cxx272
-rw-r--r--ecos/packages/kernel/current/tests/mutex3.cxx631
-rw-r--r--ecos/packages/kernel/current/tests/philo.cxx241
-rw-r--r--ecos/packages/kernel/current/tests/release.cxx129
-rw-r--r--ecos/packages/kernel/current/tests/sched1.cxx111
-rw-r--r--ecos/packages/kernel/current/tests/smp.cxx474
-rw-r--r--ecos/packages/kernel/current/tests/stress_threads.c859
-rw-r--r--ecos/packages/kernel/current/tests/sync2.cxx201
-rw-r--r--ecos/packages/kernel/current/tests/sync3.cxx232
-rw-r--r--ecos/packages/kernel/current/tests/tcdiag.cxx97
-rw-r--r--ecos/packages/kernel/current/tests/testaux.h62
-rw-r--r--ecos/packages/kernel/current/tests/testaux.hxx110
-rw-r--r--ecos/packages/kernel/current/tests/thread0.cxx114
-rw-r--r--ecos/packages/kernel/current/tests/thread1.cxx172
-rw-r--r--ecos/packages/kernel/current/tests/thread2.cxx236
-rw-r--r--ecos/packages/kernel/current/tests/thread_gdb.c413
-rw-r--r--ecos/packages/kernel/current/tests/timeslice.c282
-rw-r--r--ecos/packages/kernel/current/tests/tm_basic.cxx1880
-rw-r--r--ecos/packages/kernel/current/tests_smp/README.SPLASH2349
-rw-r--r--ecos/packages/kernel/current/tests_smp/README.fft62
-rw-r--r--ecos/packages/kernel/current/tests_smp/README.lu55
-rw-r--r--ecos/packages/kernel/current/tests_smp/README.radix44
-rw-r--r--ecos/packages/kernel/current/tests_smp/SPLASH2.POSTING124
-rw-r--r--ecos/packages/kernel/current/tests_smp/c.m4.ecos290
-rw-r--r--ecos/packages/kernel/current/tests_smp/fft.C1057
-rw-r--r--ecos/packages/kernel/current/tests_smp/fft.c1460
-rw-r--r--ecos/packages/kernel/current/tests_smp/fft_arg.c18
-rw-r--r--ecos/packages/kernel/current/tests_smp/getopt.c654
-rw-r--r--ecos/packages/kernel/current/tests_smp/getopt.h129
-rw-r--r--ecos/packages/kernel/current/tests_smp/lu.C788
-rw-r--r--ecos/packages/kernel/current/tests_smp/lu.c1118
-rw-r--r--ecos/packages/kernel/current/tests_smp/lu_arg.c12
-rw-r--r--ecos/packages/kernel/current/tests_smp/makefile13
-rw-r--r--ecos/packages/kernel/current/tests_smp/radix.C909
-rw-r--r--ecos/packages/kernel/current/tests_smp/radix.c1346
-rw-r--r--ecos/packages/kernel/current/tests_smp/radix_arg.c12
145 files changed, 58454 insertions, 0 deletions
diff --git a/ecos/packages/kernel/current/ChangeLog b/ecos/packages/kernel/current/ChangeLog
new file mode 100644
index 0000000000..84ccce3861
--- /dev/null
+++ b/ecos/packages/kernel/current/ChangeLog
@@ -0,0 +1,4606 @@
+2005-08-03 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * tests/ksem1.c: Type fix to fix a compiler warning.
+ * tests/mutex3.cxx: new cannot be both static and global.
+ * tests/testaux.hxx: Ditto
+
+2005-07-30 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/sync/mbox.cxx (tryget,peak_item): initialize local variable
+ to avoid compiler warning.
+
+2005-06-21 Peter Korsgaard <jacmet@sunsite.dk>
+
+ * tests/kcache2.c (test_dcache_operation): Fixed compiler warnings
+ about formats strings for diag_printf.
+
+2005-03-27 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * tests/tm_basic.cxx (_run_all_tests): Fixed compiler warning.
+
+2004-12-15 Sergei Organov <osv@topconrd.ru>
+
+ * cdl/scheduler.cdl: Correct the description of
+ CYGIMP_KERNEL_SCHED_SORTED_QUEUES
+
+2004-09-24 Nick Garnett <nickg@ecoscentric.com>
+
+ * src/sched/mlqueue.cxx (enqueue): Fix bug in sorted queue
+ insertion: priority test was inverted. Spotted by TomChen.
+
+2004-08-08 Bart Veer <bartv@ecoscentric.com>
+
+ * cdl/counters.cdl: add new option for the clock interrupt
+ priority.
+
+ * src/common/clock.cxx (Cyg_RealTimeClock): use this option.
+
+2004-04-15 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * tests/fptest.c (do_test): Silence aliasing warning when breaking
+ doubles into two ints.
+
+2004-04-11 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * doc/kernel.sgml: Expanded the documentation about the use of
+ CYG_FLAG_WAITMODE_CLR.
+
+2004-03-27 Sebastien Couret <sebastien.couret@elios-informatique.fr>
+
+ * src/debug/dbg-thread-demux.c (dbg_thread_syscall_rmt): Only
+ needed if CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT is enabled.
+
+2004-03-12 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * include/kapi.h: Add throw specifications throughout.
+ * src/kapi.cxx: Ditto.
+ * include/sched.inl: Move include of thread.inl further down to
+ allow Cyg_Scheduler inlines to be defined first.
+ * include/thread.inl: Reorder destructors section and include
+ sched.inl right before it to solve mutual header dependency
+ problems.
+
+2004-03-04 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * doc/kernel.sgml: Document cyg_thread_delete return value.
+
+2004-02-19 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * tests/kmutex3.c (cyg_start): Use CYG_TEST_NA.
+ * tests/kmutex4.c (cyg_start): Ditto.
+ * tests/mutex2.cxx (cyg_start): Ditto.
+ * tests/mutex3.cxx (cyg_start): Ditto.
+ * tests/sync3.cxx (cyg_start): Ditto.
+ * tests/thread2.cxx (cyg_start): Ditto.
+
+ * tests/fptest.c (cyg_start): Use one line NA msg.
+ * tests/smp.cxx (cyg_start): Ditto.
+ * tests/timeslice.c (cyg_start): Ditto.
+ * tests/tm_basic.cxx (cyg_start): Ditto.
+
+2003-12-08 Dan Jakubiec <djakubiec@yahoo.com>
+
+ * src/common/kapi.cxx: Added new function cyg_thread_get_id().
+ This function returns the unique thread ID for a given thread
+ handle.
+
+ * include/kapi.h: Added function prototype for cyg_thread_get_id().
+
+ * doc/kernel.sgml: Added documentation for cyg_thread_get_id().
+
+2003-10-13 Nick Garnett <nickg@balti.calivar.com>
+
+ * src/common/clock.cxx (Cyg_Counter::tick): Changed code to deal
+ with manipulation of unsorted lists (see ChangeLogs passim). There
+ are several corner cases where the current code does not
+ work. Replaced with a more straightforward, but slightly more
+ expensive, implementation.
+
+2003-09-22 Reinhard Jessich <Reinhard.Jessich@frequentis.com>
+
+ * src/common/clock.cxx: Removed label/goto
+ add_alarm_unlock_return to get rid of compiler error when
+ CYGIMP_KERNEL_COUNTERS_SORT_LIST is enabled.
+
+2003-09-01 Bart Veer <bartv@ecoscentric.com>
+
+ * doc/kernel.sgml: fix typo, cyg_thread vs. cyg_thread_t
+
+2003-07-18 Nick Garnett <nickg@balti.calivar.com>
+
+ * cdl/counters.cdl: Removed the counters override CDL
+ options. These are no longer very useful, since too much
+ non-kernel code now uses the HAL options to get these values.
+
+2003-07-10 Nick Garnett <nickg@balti.calivar.com>
+
+ * src/common/clock.cxx (Cyg_Counter::tick): In unsorted list case:
+ moved saving of next node details to before re-insertion of alarms
+ with intervals. The call to add_alarm() can make enough of a
+ difference to the list to need to force a rescan.
+
+2003-07-06 Bart Veer <bartv@ecoscentric.com>
+
+ * include/test/stackmon.h (cyg_test_size_a_stack):
+ If stack checking is enabled, look for 0xdeadbeef rather than 0x0
+ to determine usage. Also reset the interrupt stack to that value.
+
+2003-07-02 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * doc/kernel.sgml: Document that timeouts for timed functions are
+ absolute, not relative. Also document new semantics for
+ cyg_semaphore_timed_wait() for timeouts in the past.
+
+2003-07-01 Nick Garnett <nickg@balti.calivar.com>
+
+ * include/clock.hxx: Made Cyg_Counter::add_alarm() and
+ Cyg_Counter::rem_alarm() private functions. They no longer lock
+ the scheduler, so should not be called directly, only via the
+ Cyg_Alarm functions.
+
+ * include/clock.inl: Removed inline version of
+ Cyg_Alarm::disable(). It's no longer a one-liner and is thus
+ better as a proper function.
+
+ * src/common/clock.cxx (Cyg_Counter::tick): Rewrote the unsorted
+ list option. If the function of one alarm adds or removes other
+ alarms, then is was possible for the list to become corrupted. The
+ new implementation attempts to avoid this problem.
+ (Cyg_Alarm::initialize): Added scheduler locking to protect the
+ enabled flag.
+ (Cyg_Alarm::enable): Ditto.
+ (Cyg_Alarm::disable): Ditto. Moved here from clock.inl.
+ (Cyg_Alarm::add_alarm): Removed scheduler locking, it is now
+ always called from functions that have already locked it. Added an
+ assertion to double-check this.
+ (Cyg_Alarm::rem_alarm): Ditto.
+
+ * cdl/kernel.cdl:
+ * tests/kalarm0.c:
+ Added new test to test that alarms can be added and removed in
+ alarm functions safely.
+
+2003-06-25 Thomas Binder <Thomas.Binder@frequentis.com>
+
+ * src/common/clock.cxx (Cyg_Counter::rem_alarm): Bugfix: call
+ Cyg_Scheduler::lock() before calculation of index into alarm_list
+ array to avoid race condition with multi list counters.
+
+2003-06-06 David Brennan <eCos@brennanhome.com>
+2003-06-23 Nick Garnett <nickg@balti.calivar.com>
+
+ * cdl/kernel.cdl: Added tests/bin_sem3 to list of kernel tests.
+
+ * include/sema.hxx: Added declaration for wait with timeout for
+ Cyg_Binary_Semaphore.
+
+ * include/instrmnt.h: Added instrumentation point for binary semaphore
+ timeout.
+
+ * src/sync/bin_sem.cxx: Added wait with time-out function to
+ Cyg_Binary_Semaphore class.
+
+ * src/sync/cnt_sem.cxx: Modified semantics slightly to claim an
+ available semaphore even with a timeout in the past. This is in
+ line with the new timed wait in bin_sem.cxx.
+
+ * tests/bin_sem3.cxx: Created new test for timed wait binary
+ semaphore.
+
+2003-05-20 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/common/kapi.cxx (cyg_thread_get_next): Passing a *current
+ pointer as NULL if how you start the walk of the linked list. So
+ don't assert on NULL. Reported by Daniel Lidsten.
+
+2003-05-05 Gary Thomas <gary@mlbassoc.com>
+
+ * tests/tm_basic.cxx: Support new option controlling number of times
+ this test runs. This is useful for long-term stress and performance
+ analysis.
+
+2003-05-03 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * include/mqueue.inl (Cyg_Mqueue::get): Fix invalid loop termination
+ cheque for whether busy or not.
+ (Cyg_Mqueue::put): Ditto.
+
+2003-03-03 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * tests/fptest.c: Make all variables static to avoid any risk
+ of collisions with symbols defined elsewhere in eCos.
+
+2003-02-27 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * include/kapidata.h: Revert change of 2001-08-23 and instead make
+ it conditional on the GCC version. Also add comments explaining why
+ this file has been apparently obfuscated.
+
+2003-02-25 Nick Garnett <nickg@calivar.com>
+
+ * tests/fptest.c (alarm_fn): Added CYG_TEST_PASS() call to keep
+ configtool happy.
+
+2003-02-24 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * cdl/kernel.cdl: Update doc links.
+ * cdl/synch.cdl: Ditto.
+ * cdl/thread.cdl: Ditto.
+
+2003-02-19 Nick Garnett <nickg@calivar.com>
+
+ * tests/fptest.c: Changed to run for a constant time rather than a
+ constant number of iterations, with a shorter run time for
+ simulated targets.
+
+2003-02-10 Gary Thomas <gary@mlbassoc.com>
+
+ * include/thread.inl: Add more debug info to thread stack checking.
+
+ * tests/clocktruth.cxx:
+ * tests/clockcnv.cxx: Use <cyg/infra/diag.h> for diag_printf()
+ prototype, rather than hard coding (because it was inconsistent).
+
+2003-02-05 Gary Thomas <gary@mlbassoc.com>
+
+ * tests/kcache2.c (test_dcache_operation): New test to verify
+ that the DATA cache syncs properly.
+
+2003-01-31 Nick Garnett <nickg@calivar.com>
+
+ * cdl/kernel.cdl:
+ * tests/fptest.c: Added this program to test interaction of FPU
+ with multiple threads.
+
+2003-01-30 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * src/common/thread.cxx: Fix potential warning and overflow with
+ CYGNUM_KERNEL_THREADS_DATA_MAX == 32.
+
+2003-01-28 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * src/common/kapi.cxx (cyg_thread_get_next): Be quite zealous about
+ checking the validity of passed in threads in debug mode.
+ (cyg_thread_get_info): Ditto.
+
+ * cdl/thread.cdl: Correct max legal value for
+ CYGNUM_KERNEL_THREADS_DATA_MAX.
+
+2003-01-22 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * doc/kernel.sgml: Document cyg_thread_info type.
+
+2003-01-13 Dmitriy Korovkin <dkorovkin@rambler.ru>
+2003-01-13 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * include/mqueue.hxx: Allow get/put to return time out.
+ * include mqueue.inl: Ditto.
+
+2003-01-02 Gary Thomas <gary@mlbassoc.com>
+
+ * tests/kcache2.c: New subtest for raw data cache operations.
+
+2002-12-12 Nick Garnett <nickg@ecoscentric.com>
+
+ * src/common/kapi.cxx:
+ * include/kapi.h:
+ Added function cyg_thread_get_next(), cyg_thread_find() and
+ cyg_thread_get_info() to allow the current set of threads to be
+ enumerated, and per-thread information to be retrieved safely.
+
+ * doc/kernel.sgml: Documented new KAPI calls.
+
+ * src/common/thread.cxx: Zero unique_id in thread destructor so
+ that a stale thread pointer can be checked for validity.
+
+ * include/instrmnt.h:
+ Added cyg_instrument_state() to report the current state of an
+ instrumentation flag.
+ Moved ifdef for CYGDBG_KERNEL_INSTRUMENT_MSGS out of within FLAGS
+ ifdef. We can have messages without flags.
+
+ * src/instrmnt/meminst.cxx:
+ Added cyg_instrument_state() to report the current state of an
+ instrumentation flag.
+ Modified cyg_instrument_msg() in line with header and table
+ changes.
+
+ * host/instr/dump_instr.c:
+ * host/instr/instrument.sh:
+ * include/instrument_desc.h:
+ Added a final NULL element to the generated table in
+ instrument_desc.h to mark its end. Otherwise code that does not
+ have access to the table definition cannot find its end. Also
+ added ifdefs to allow instrument_desc.h to be used to acquire the
+ structure definition and table pointer.
+
+2002-12-03 Gary Thomas <gthomas@ecoscentric.com>
+
+ * tests/tm_basic.cxx: Add tests of 'flag' synchronizers.
+
+2002-10-28 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * tests/tm_basic.cxx: Include infra/diag.h and removed the
+ incorrect prototype for diag_printf
+
+2002-10-16 Gary Thomas <gthomas@ecoscentric.com>
+
+ * include/test/stackmon.h (STACKMON_PRINTF): Use #include to get
+ prototype for 'diag_printf()'.
+
+2002-10-01 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * src/common/clock.cxx (add_alarm): Tweak last change to allow
+ alarm order for identical alarms to be the same as it used to be.
+
+2002-09-30 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * src/common/clock.cxx (add_alarm): Fix bug resulting in alarms
+ not being added at all if a lower triggered alarm already exists.
+ Reported by Christoph Csebits.
+ Also fix bug when alarm is entered for the same time as tail.
+ These bugs only apply for CYGIMP_KERNEL_COUNTERS_SORT_LIST enabled.
+
+ * doc/kernel.sgml: document that order of callback for alarms at
+ identical times is unspecified.
+
+2002-08-08 Nick Garnett <nickg@calivar.demon.co.uk>
+
+ * src/sched/sched.cxx (unlock_inner): Removed initial
+ assertion. This has served its purpose and with the introduction
+ of routines such as unlock_reschedule() is prone to firing in
+ otherwise benign circumstances.
+
+2002-08-05 Bart Veer <bartv@tymora.demon.co.uk>
+
+ * cdl/kernel.cdl, include/kapidata.h, include/kapi.h:
+ Allow configurations with the kernel but no malloc
+
+2002-06-05 Gary Thomas <gary@chez-thomas.org>
+
+ * include/kapi.h: Fix prototype (to allow builds with net stack).
+
+2002-05-24 Jesper Skov <jskov@redhat.com>
+
+ * cdl/kernel.cdl: Fix typo.
+
+2002-05-23 Jonathan Larmour <jlarmour@redhat.com>
+
+ * include/kapi.h: Expose new cyg_thread_add_destructor and
+ cyg_thread_rem_destructor APIs.
+
+ * include/kapidata.h (struct Cyg_Destructor_Entry):
+ Change CYG_ADDRWORD to more correct cyg_addrword_t.
+
+ * include/thread.hxx (class Cyg_Thread): add_destructor and
+ rem_destructor are onyl static when not per-thread.
+
+ * include/thread.inl (add_destructor): Don't need to lock and unlock
+ scheduler when destructors are per-thread.
+ (rem_destructor): Ditto.
+
+ * src/common/thread.cxx (exit): No need to lock scheduler when
+ calling destructors.
+
+ * doc/kernel.sgml: Document thread destructor API.
+
+2002-05-23 Nick Garnett <nickg@redhat.com>
+
+ * doc/kernel.sgml: Some more edits to the kernel documentation:
+ changed all references to message boxes to mail boxes, clarified
+ some thing in various places, fixed a few typos.
+
+2002-05-23 Jesper Skov <jskov@redhat.com>
+
+ * cdl/kernel.cdl: Cleaned up kernel tests rule. Also remove tests
+ depending on the C API when its not present. And skip dhrystone
+ test when debug or instrumentation is enabled.
+
+ * tests/tm_basic.cxx: Fixed warning.
+
+2002-05-22 Nick Garnett <nickg@redhat.com>
+
+ * doc/kernel.sgml:
+ Fixed up SMP documentation.
+ Rewrote condtion variable documentation to make its relationship
+ to mutexes more apparent.
+
+2002-05-22 Jesper Skov <jskov@redhat.com>
+
+ * tests/smp.cxx: Move inclusion of testaux.hxx to below NA
+ checks.
+
+2002-05-21 Bart Veer <bartv@redhat.com>
+
+ * doc/kernel.sgml:
+ Major update to the kernel documentation.
+
+2002-05-21 Jesper Skov <jskov@redhat.com>
+
+ * src/common/clock.cxx (dsr): Fix latency ifdef guards.
+ * tests/tm_basic.cxx: Same.
+
+2002-05-20 Jonathan Larmour <jlarmour@redhat.com>
+
+ * src/sched/mlqueue.cxx: Don't force timeslice tracing on by default
+ against the user's wishes.
+ * cdl/scheduler.cdl: Instead provide an option controlling it.
+
+2002-05-09 Jonathan Larmour <jlarmour@redhat.com>
+
+ * include/kapidata.h (CYG_HARDWARETHREAD_MEMBERS): entry_point
+ should be a pointer to function not an addrword (which may be
+ different).
+ (cyg_reason_t): Define cyg_reason_t as an enum not an int.
+ (struct cyg_mutex_t): Define mutex protocol as an enum not a cyg_uint32.
+ Define locked member as a cyg_atomic, not a cyg_bool.
+
+2002-05-09 Nick Garnett <nickg@redhat.com>
+
+ * tests/timeslice.c: Modified test thread to accumulate run time
+ by reading HAL clock, and to detect and record changes of CPU. The
+ previous version of this code reported varying results - probably
+ as a consequence of cache effects.
+
+ * include/instrmnt.h: Fixed left-over debug edit to MLQ
+ instrumentation enable code.
+
+2002-04-29 Jesper Skov <jskov@redhat.com>
+
+ * include/kapi.h: Added cyg_alarm_get_times and
+ cyg_counter_multi_tick.
+ * src/common/kapi.cxx: Same. Er, fix oversight.
+ * doc/kernel.sgml: Doc update.
+
+2002-04-24 Yoshinori Sato <qzb04471@nifty.ne.jp>
+
+ * src/sync/flag.cxx: Don't set default args in func definitions.
+
+2002-04-24 Jesper Skov <jskov@redhat.com>
+
+ * tests/dhrystone.c: Moved platform max number of passes to CDL in
+ HALs.
+
+2002-04-23 Jesper Skov <jskov@redhat.com>
+
+ * tests/dhrystone.c: Allow platform to define max number of passes
+ via CYGPRI_KERNEL_TESTS_DHRYSTONE_PASSES.
+
+2002-04-09 Jonathan Larmour <jlarmour@redhat.com>
+
+ * include/kapi.h: Use NORET attributes from cyg_type.h.
+ * include/sched.hxx (class Cyg_Scheduler): Ditto.
+
+2002-04-08 Nick Garnett <nickg@redhat.com>
+
+ * src/sync/mutex.cxx: Added IF_PROTOCOL_ACTIVE macro to condition
+ use of the mutex counter. This means that a mutex that is not
+ configured to participate in a priority inversion protocol does not
+ count for operation of that protocol.
+
+2002-03-04 Lars Viklund <lars.viklund@axis.com>
+
+ * include/kapidata.h (CYG_SCHEDTHREAD_ASR_MEMBER):
+ asr_inhibit is cyg_ucount32 - must match
+
+2002-02-13 Hugo Tyson <hmt@redhat.com>
+
+ * doc/kernel.sgml: NEW FILE: Correct reference to uITRON doc.
+
+2002-01-28 Jesper Skov <jskov@redhat.com>
+
+ * tests/kexcept1.c: Fix warning.
+
+2002-01-24 Jesper Skov <jskov@redhat.com>
+
+ * tests/kcache1.c (time0DI): Disable interrupts around the
+ sync+invalidate process.
+ * tests/kcache2.c: Same.
+
+2002-01-23 Jonathan Larmour <jlarmour@redhat.com>
+
+ * src/intr/intr.cxx (mask_interrupt): Disable interrupts.
+ (unmask_interrupt): Ditto.
+ (mask_interrupt_intunsafe): New function to avoid disabled interrupts.
+ (unmask_interrupt_intunsafe): Ditto.
+ * include/intr.hxx (class Cyg_Interrupt): Declare above new funcs.
+ * src/common/kapi.cxx (cyg_interrupt_unmask_intunsafe): Above
+ replicated to KAPI.
+ (cyg_interrupt_mask_intunsafe): Ditto.
+ * include/kapi.h: Ditto.
+
+2002-01-07 Nick Garnett <nickg@redhat.com>
+
+ * tests/except1.cxx:
+ * tests/kexcept1.cxx:
+ Added ifdef to disable these tests in ARM PID platform. This
+ platform cannot generate any of the exceptions that this test
+ needs to work.
+
+2001-12-12 Jesper Skov <jskov@redhat.com>
+
+ * tests/kcache2.c (time_ilock): Put some dummy goto statements in
+ to prevent compiler from moving labels around.
+
+2001-11-29 Jonathan Larmour <jlarmour@redhat.com>
+
+ * src/sched/mlqueue.cxx (timeslice_cpu): Reset timeslice_count on
+ a timeslice.
+ Noticed by Tony Kho.
+
+2001-11-23 Jonathan Larmour <jlarmour@redhat.com>
+
+ * tests/klock.c (entry1): Support running with
+ CYGFUN_KERNEL_THREADS_TIMER disabled.
+
+2001-10-30 Nick Garnett <nickg@redhat.com>
+
+ * tests/kcache2.c (test_dsync):
+ Added call to HAL_ICACHE_INVALIDATE_ALL() just before DCACHE
+ disable. In platforms where both caches are controlled together,
+ such as the VR4300, not doing this can result in strange behaviour
+ as the ICACHE gets turned off under the program's feet, when it is
+ not ready for it.
+
+2001-10-17 Jesper Skov <jskov@redhat.com>
+
+ * tests/dhrystone.c: CYGINT_ISO_STRING_STRFUNCS check changed to
+ ifdef.
+
+2001-10-12 Jonathan Larmour <jlarmour@redhat.com>
+
+ * cdl/synch.cdl (CYGIMP_KERNEL_SYNCH_MQUEUE_NOT_INLINE): New option
+ to avoid inlining mqueue implementation.
+
+ * src/sync/mqueue.cxx: New file to provide non-inline version of
+ mqueue functions.
+
+ * include/mqueue.hxx: Don't include .inl if user doesn't want inlining.
+
+ * include/mqueue.inl: Allow choice of inlining or not to be
+ overridden by macro.
+
+ * tests/mqueue1.cxx: Never use inline version.
+
+2001-10-11 Jesper Skov <jskov@redhat.com>
+
+ * tests/kmutex3.c (new_thread): Fixed allocation: increase counter
+ before starting threads which have been allocated resources.
+ * tests/kmutex4.c (new_thread): Same.
+ * tests/mutex3.cxx (new_thread): Same.
+ * tests/testaux.hxx (new_thread): Same.
+
+ * tests/kcache2.c: Fixed warning.
+ * tests/stress_threads.c: Same.
+
+2001-09-20 Jonathan Larmour <jlarmour@redhat.com>
+
+ * host/instr/dump_instr.c (main): Fix argc check.
+
+2001-09-07 Jonathan Larmour <jlarmour@redhat.com>
+
+ * include/thread.inl (measure_stack_usage): Deal with stack limits.
+
+2001-09-07 Nick Garnett <nickg@redhat.com>
+
+ * src/common/thread.cxx (set_priority): Change argument to
+ instrumentation call to new_priority rather than current
+ priority. (Suggested by Andrew Lunn).
+
+2001-09-05 Jesper Skov <jskov@redhat.com>
+
+ * include/mqueue.inl (Cyg_Mqueue): Initialize busy flag of last
+ entry in the list.
+
+2001-09-04 Jonathan Larmour <jlarmour@redhat.com>
+
+ * cdl/instrument.cdl (CYGDBG_KERNEL_INSTRUMENT_BUILD_HOST_DUMP):
+ Remove redundant requires, and adjust make rule to be more portable
+ across hosts.
+ (CYGDBG_KERNEL_INSTRUMENT_MSGS_BUILD_HEADERFILE):
+ Invoke script with sh directly rather than rely on executable attribute.
+
+ * host/instr/readme.txt: Update build of host dump as per the changed
+ CDL.
+
+ * cdl/kernel.cdl: Don't build nullinst.cxx any more.
+ Build meminst.cxx only in CYGPKG_KERNEL_INSTRUMENT.
+ * src/instrmnt/nullinst.cxx: Delete. It causes confusion in the
+ library as it declares cyg_instrument like meminst.cxx does.
+
+2001-08-31 Nick Garnett <nickg@redhat.com>
+
+ * src/intr/intr.cxx: Clean up typo in DSR table
+ case. dsr_table_tail and dsr_table_head were not being subscripted
+ in a couple of places.
+
+2001-08-23 Hugo Tyson <hmt@redhat.com>
+2001-08-20 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * include/instrument_desc.h: New file. This contains the table of
+ events used to print the nice information. It should be
+ regenerated when the instrumentation numbers change.
+
+ * src/instrmnt/meminst.cxx (cyg_instrument_msg):
+ returns an ASCII string describing the type of event the
+ instrumentation code logged.
+
+ * include/instrmnt.h: Added function prototype.
+
+ * cdl/instrument.cdl: Configury for enabling the new function, and
+ optionally rebuilding its header file and building a host tool.
+
+ * host/instr/dump_instr.c: New file. A host program to print the
+ instrumentation information in a human readable form.
+
+ * host/instr/instrument.sh: New file. Script to generate table of
+ events with textual representation.
+
+ * host/instr/readme.txt: New file. Helpful information.
+
+2001-08-23 Nick Garnett <nickg@redhat.com>
+
+ * include/kapidata.h (CYG_THREADTIMER_MEMBERS):
+ Substituted an expicit cyg_alarm object for CYG_ALARM_MEMBERS in
+ this definition. In some architectures (MIPS in particular) the
+ structures need to be padded to a multiple of 64 bits. This was
+ not happening with the macro substituted versions.
+ This is just a temporary fix, I'll leave it to Jifl to sort out a
+ real patch when he returns.
+
+2001-08-23 Hugo Tyson <hmt@redhat.com>
+
+ * src/common/thread.cxx: Properly qualify Cyg_Thread::destructors
+ array so that it builds when destructors are not used.
+
+2001-08-23 Nick Garnett <nickg@redhat.com>
+
+ * src/sched/mlqueue.cxx: Added code to
+ Cyg_SchedThread_Implementation::to_queue_head() to handle a NULL
+ thread queue pointer. This compensates for a minor change in
+ behaviour of the scheduler.
+
+2001-08-22 Jonathan Larmour <jlarmour@redhat.com>
+
+ * cdl/thread.cdl: Add kernel thread destructor options.
+ * include/kapidata.h: Add thread destructor entries to cyg_thread
+ * include/thread.hxx (Cyg_Thread): Give per-thread data indexes
+ their own type, cyg_data_index.
+ Include new thread destructor data members, and new add_destructor
+ and rem_destructor member functions.
+ * include/thread.inl: Use a cyg_data_index for per-thread data handle.
+ (add_destructor): New Cyg_Thread member function.
+ (rem_destructor): Ditto.
+ * src/common/kapi.cxx: Use cyg_data_index type for per-thread data
+ functions.
+ * src/common/thread.cxx (Cyg_Thread): initialise per-thread
+ destructors if needed.
+ Define static destructors if needed.
+ (exit): Call destructors.
+ (new_data_index): Use cyg_data_index type.
+ (free_data_index): Ditto.
+
+2001-08-22 Hugo Tyson <hmt@redhat.com>
+
+ * src/sync/mutex.cxx (Cyg_Mutex): Add initialization of the
+ priority ceiling value in the non-dynamic protocol case.
+
+2001-08-22 Nick Garnett <nickg@redhat.com>
+
+ * tests/intr0.c:
+ * tests/kintr0.c:
+ Swapped order of interrupt enable/disable calls to keep kernel
+ happy when assertions are enabled. Otherwise the enable call
+ complains that interrupts have not been disabled.
+
+ * src/sched/mlqueue.cxx:
+ Simplified algorithm in set_need_reschedule().
+
+ * include/smp.hxx:
+ * include/kapidata.h: Change spinlock to be a cyg_uint32, rather
+ than a cyg_atomic.
+
+ * src/intr/intr.cxx:
+ * include/intr.hxx:
+ Now arrange for DSRs to be called on the same CPU as the ISR. This
+ is necessary if the DSR needs to access per-CPU hardware (such as
+ interrupt controllers). This is achieved by keeping a separate DSR
+ list/table for each CPU.
+
+ * tests/smp.cxx: Some modifications to make this test work in a
+ real SMP environment.
+
+ * tests/timeslice.c:
+ * cdl/kernel.cdl: Added timeslice test.
+
+2001-08-21 Hugo Tyson <hmt@redhat.com>
+
+ * src/sync/mutex.cxx (lock): Bugfix: a ceiling priority mutex
+ wasn't elevated until after it had acquired the mutex. This meant
+ it slept with a low priority, and so did not run when awakened by
+ the release of the mutex. The fix is to elevate the potential
+ claimant before it sleeps in contention.
+
+ * tests/kmutex4.c: New testcase - very similar to kmutex3 but it
+ loops a load more times using different mutex priority protocols.
+ This checks that dynamically set protos do in fact behave
+ differently from one another and as they are each intended to.
+
+ * tests/kmutex3.c: Remove FIXME comments - we now test dynamic
+ protocol.
+
+ * cdl/kernel.cdl: Build the new test.
+
+2001-08-20 Jonathan Larmour <jlarmour@redhat.com>
+
+ * include/kapidata.h: Reorganize most struct type definitions into
+ macros to allow compatible layout with all G++ implementations that
+ align non-POD types differently from included C structures.
+ * include/kapi.h: Similarly for cyg_resolution_t.
+
+2001-08-17 Nick Garnett <nickg@redhat.com>
+
+ * src/sched/mlqueue.cxx (timeslice): Fix timeslice_count comparison.
+
+2001-08-16 Hugo Tyson <hmt@redhat.com>
+
+ * include/kapi.h (cyg_mutex_protocol): Tidy up names of mutex
+ protocol type and values. These polluted rather in 'C'.
+
+ * src/common/kapi.cxx (cyg_mutex_set_protocol): ditto.
+
+2001-08-15 Hugo Tyson <hmt@redhat.com>
+2001-08-15 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/common/kapi.c (cyg_thread_get_current_priority): Export
+ this function into the C api.
+ * include/kapi.h: Declaration of new function.
+
+2001-08-14 Jonathan Larmour <jlarmour@redhat.com>
+
+ * src/common/kapi.cxx (cyg_spinlock_spin_intsave): Cast to istate
+ to CYG_INTERRUPT_STATE * since that's what is needed.
+ (cyg_spinlock_clear_intsave): Similarly.
+
+2001-08-10 Hugo Tyson <hmt@redhat.com>
+
+ * cdl/synch.cdl: Re-organize the options for mutexes so they are
+ active a bit more sensibly; place the default ceiling within
+ selection of ceiling protocol, and only have a default protocol if
+ there is more than one protocol active.
+
+ * tests/mutex3.cxx: More detailed handling of the possibility of
+ ceiling protocol instead of the inherit or none cases; we can run
+ the test ok and treat as inherit if the ceiling prio is higher
+ than 5, treat as none if lower than 15, and don't check anything
+ if in between - the test runs happily.
+
+ * tests/kmutex3.c (cyg_start): New test, a KAPI translation of the
+ now-classic mutex3.cxx.
+
+ * cdl/kernel.cdl: Build tests/kmutex3.c
+
+2001-08-06 Hugo Tyson <hmt@redhat.com>
+
+ * src/sched/sched.cxx (unlock_inner): Fix assignment to current,
+ wouldn't build if stack checking after merger from SMP branch.
+
+2001-08-06 Andrew Lunn <andrew.lunn@ascom.ch>
+2001-08-06 Hugo Tyson <hmt@redhat.com>
+
+ * src/sync/mutex.cxx: (set_protocol) Added a function to set the
+ priority inversion protocol for a mutex.
+
+ * src/common/kapi.cxx: Export the new function above and
+ set_ceiling into the C API.
+
+ * include/mutex.hxx (class Cyg_Mutex): New member function
+ set_protocol().
+
+ * include/kapi.h (cyg_protcol): Define new emumeration for mutex
+ priority protocol setting, and headers for the new function to set
+ it.
+
+2001-08-03 Nick Garnett <nickg@redhat.com>
+
+ Imported from a development branch:
+
+ 2001-07-11 Nick Garnett <nickg@redhat.com>
+
+ * src/sched/mlqueue.cxx: Changed behaviour of
+ set_need_reschedule() to a better implementation of the intended
+ algorithm.
+
+ * include/kapi.h:
+ * src/common/kapi.cxx:
+ Added API for controlling routing of interrupts to CPUs in SMP
+ configurations.
+
+ 2001-07-03 Nick Garnett <nickg@cygnus.co.uk>
+
+ * cdl/scheduler.cdl:
+ * include/bitmap.hxx:
+ * src/sched/bitmap.cxx:
+ Fixed up bitmap scheduler so it still works within the
+ SMP-modified scheduling infrastructure. The bitmap scheduler
+ is not currently SMP-enabled, only single CPU configurations are
+ supported - hence the CDL change to require this.
+
+ 2001-06-29 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/sched/sched.cxx:
+ Removed the call to Cyg_Interrupt::enable_interrupts() in
+ Cyg_Scheduler::start_cpu(). This was a relic from the days when
+ the interrupt enable state was not part of the thread state. Now
+ it is, and loading the first thread will cause interrupts to be
+ enabled.
+
+ * src/intr/intr.cxx:
+ Changed initial values of Cyg_Interrupt::disable_counter[]s to
+ zero as a result of the change in Cyg_Scheduler::start_cpu().
+
+ * include/kapi.h:
+ * include/kapidata.h:
+ * src/common/kapi.cxx:
+ Added API for using spinlocks. Largely so that it may be extended
+ to the driver API.
+
+ * include/mlqueue.hxx:
+ * include/intr.hxx:
+ * include/sched.hxx:
+ Added annotations to various static variables.
+
+ 2001-06-28 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/intr.hxx:
+ * src/intr/intr.cxx:
+ Changed behaviour of Cyg_Interrupt::disable_interrupts() and
+ Cyg_Interrupt::enable_interrupts(). These now claim and release a
+ spinlock in addition to disabling and enabling interrupts. The
+ original interrupt state is also preserved and restored. This is
+ necessary in SMP systems to allow drivers etc. to correctly
+ synchronize with threads and DSRs that may be running on different
+ CPUs. In the single CPU case this mechanism reduces to the
+ original simple interrupt disable code.
+ [Later change] Backed off addition of volatile modifier to
+ interrupt_disable_state.
+
+ * include/smp.hxx: Some minor tidies.
+
+ 2001-06-27 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/release.cxx: Added spin loop in thread1 to allow thread0
+ to execute its wait. This is necessary in SMP systems where the
+ threads will execute in parallel, but is also benign in single CPU
+ systems.
+
+ * tests/mutex2.cxx:
+ * tests/mutex3.cxx:
+ * tests/sync3.cxx:
+ * tests/thread2.cxx:
+ These tests depend on predicting the behaviour of threads at
+ different priorities to pass. In an SMP system, several threads
+ will run in parallel, and the execution order will not be as
+ expected. These tests are therefore disabled in SMP
+ configurations.
+
+ * src/sched/mlqueue.cxx (add_thread): Moved call to
+ set_need_reschedule() out of test for empty queue. In SMP systems,
+ any addition to a queue may require a reschedule on another CPU.
+
+ 2001-06-22 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/mlqueue.hxx:
+ * src/sched/mlqueue.cxx:
+ A major change to the way in which this scheduler works in SMP
+ systems. The previous version removed all runnable threads from
+ the run queues when they were executing. This resulted in serious
+ complications and messy code, particularly when dealing with
+ priority changes and timeslicing. The new version keeps running
+ threads in the run queues, just like the single-CPU version. The
+ main disadvantage of this is that we may have to search past
+ threads running on other CPUs before we find one available to run
+ on this CPU. However, the pending count array and map mean that we
+ only need search one run queue, and in any case the search remains
+ bounded by the number of CPUs available.
+ Another change is in the way that timeslicing is handled. Now, the
+ CPU that takes the clock interrupt decrements the timeslice counts
+ for all CPUs and if any go zero, sends a TIMESLICE message to
+ that CPU.
+
+ * src/sched/sched.cxx (unlock_inner):
+ Removed call to requeue(), no longer needed as a result of
+ scheduler reorganization.
+
+ * src/common/thread.cxx:
+ Added test in Cyg_Thread::exit() to check that the thread has not
+ already been killed. This is only an issue if the thread is
+ calling exit() when it is kill()ed from another CPU. The test is
+ redundant in single-CPU systems, but it does no harm having it.
+ Added code to Cyg_Thread::set_priority() to check for reschedule
+ when another thread is being changed in priority.
+ Added call in idle thread constructor to scheduler to install the
+ idle thread as the default current thread for a CPU.
+
+ * include/smp.hxx:
+ Added CYG_KERNEL_CPU_TIMESLICE_INTERRUPT(), did some miscellaneous
+ tidying.
+
+ * include/instrmnt.h: Added SMP_RESCHED_SEND and SMP_RESCHED_RECV
+ events.
+
+ * cdl/kernel.cdl: Added smp test program.
+
+ * tests/smp.cxx: Added this program to test SMP functionality.
+
+ 2001-06-13 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/sched/sched.cxx:
+ Removed code to set up initial current thread, this is now done
+ in the idle thread constructor.
+ Added code here to set up interrupts for SMP inter-processor
+ interrupts. This is not very tidy and may need to be
+ changed in the future.
+
+ * src/sched/mlqueue.cxx:
+ Added local set_need_reschedule() function to set the
+ need_reschedule flag on a suitable CPU.
+ Many more changes to cope with SMP systems.
+ NOTE: This code has all become somthing of a mess, it need to be
+ tidied up and the SMP-specific changes integrated better into the
+ code. Also, timesliceing currently only works on the CPU that
+ takes clock interrupts - this needs fixing.
+
+ * src/common/thread.cxx:
+ Moved assignment of initial current thread to here from sched.cxx.
+
+ * include/smp.hxx:
+ Changed CYG_KERNEL_CPU_INTERRUPT()
+ CYG_KERNEL_CPU_RESCHEDULE_INTERRUPT() since there may be other
+ interrupt types to worry about.
+ Added annotations to scheduler data items.
+
+ * include/sched.hxx:
+ Split set_current_thread() into two functions, the original works
+ only on the current CPU, the new one sets another CPU's current
+ thread. This latter function is only used to prime the current
+ threads during initialization.
+ Added second need_reschedule() function that takes a thread
+ argument. This is intended to be overridden by a scheduler
+ specific function that sets the need_reschedule flag if the
+ supplied thread is more deserving of CPU time that any current
+ thread.
+
+ * include/mlqueue.hxx:
+ Made cyg_scheduler_set_need_reschedule() a friend of
+ Cyg_Scheduler_Implementation class.
+ Added override set_need_reschedule() functions.
+
+ * include/kapidata.h: Added cpu field to cyg_thread structure when
+ in SMP systems.
+
+ * include/intr.hxx:
+ * src/intr/intr.cxx:
+ Added Cyg_Interrupt::set_cpu() and Cyg_Interrupt::get_cpu() for
+ SMP systems.
+
+ * include/instrmnt.h: Added events for INTR_GET_CPU and
+ INTR_SET_CPU.
+
+ 2001-05-29 Nick Garnett <nickg@cygnus.co.uk>
+
+ The following changes were all imported from the SMP branch:
+
+ * tests/tm_basic.cxx:
+ Modified to work in SMP configuration - mostly at present by
+ ifdeffing out code I didn't want to fix.
+
+ * include/sched.hxx:
+ Moved scheduler lock operation into Cyg_Scheduler_SchedLock class.
+ Converted current_thread, need_reschedule, and thread_switches
+ into CPU indexed arrays. Added member functions to get and set
+ these indirectly.
+ Added start_cpu() to do per-CPU scheduler startup.
+
+ * include/sched.inl:
+ Converted scheduler lock/unlock functions to use new schedlock
+ class.
+
+ * src/sched/sched.cxx:
+ Changed in line with sched.hxx.
+ Added call to requeue() in unlock_inner() to restore current
+ thread to run queue if necessary.
+ Moved most of scheduler startup to Cyg_Scheduler::start_cpu().
+ Cyg_Scheduler::start() now also starts secondary CPUs in SMP
+ systems.
+ Added cyg_kernel_smp_startup() as entry point from HAL into kernel
+ for secondary CPUs.
+
+ * include/mlqueue.hxx:
+ Added Cyg_RunQueue type and removed
+ Cyg_SchedulerThreadQueue_Implementation type.
+ Converted timeslice_count to CPU indexed array.
+ Added requeue() member function to scheduler class.
+ Added cpu member to thread implementation class, to record
+ thread's current CPU.
+
+ * src/sched/mlqueue.cxx:
+ Changed behaviour when in SMP system to remove scheduled thread
+ from run queue and replace it when preempted.
+ Added some extra asserts, and removed some that are no longer true
+ in an SMP system.
+
+ * src/instrmnt/meminst.cxx: In SMP systems: added spinlock to
+ protect instrument buffer, added CPU Id in top 4 bits of thread Id
+ field.
+
+ * src/common/thread.cxx:
+ Converted to use accessor functions for need_reschedule and
+ current_thread.
+ Rearranged idle thread creation to create one for each CPU.
+
+ * include/test/stackmon.h: Extended to handle stack usage for
+ multiple idle threads.
+
+ * include/thread.inl:
+ Added some extra instrumentation.
+
+ * include/smp.hxx:
+ Added this file to contain all kernel SMP support. The main
+ definitions exported by this file are spin lock and scheduler lock
+ implementation classes, for both SMP and uniprocessor
+ configurations.
+
+ * src/intr/intr.cxx:
+ * include/intr.hxx:
+ Converted interrupt disable counter to CPU indexed array. In
+ intr.cxx: added lock of scheduler lock in interrupt_end() rather
+ than in default interrupt VSR.
+
+ * cdl/kernel.cdl: Added option to enable SMP support.
+
+ * include/instrmnt.h:
+ * cdl/instrument.cdl: Added SMP instrumentation.
+
+ 2001-05-25 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/intr.hxx:
+ * src/intr/intr.cxx:
+ Added default definition of CYGNUM_HAL_ISR_TABLE_SIZE. This is now
+ used to declare the chain table so that architectures which have
+ different sizes for the interrupt table and vector count will work
+ correctly.
+
+ 2001-05-22 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/sched.hxx (class Cyg_Scheduler_Base):
+ Added annotation to sched_lock.
+
+ * cdl/instrument.cdl:
+ Rename CYGNUM_KERNEL_INSTRUMENT_BUFFER_WRAP to
+ CYGDBG_KERNEL_INSTRUMENT_BUFFER_WRAP as it appears in the code.
+
+2001-07-27 Jesper Skov <jskov@redhat.com>
+
+ * src/intr/intr.cxx (chain_isr): Return isr_ret so caller (which
+ may be an arbiter) can tell if the interrupt was handled.
+
+2001-07-26 Gary Thomas <gthomas@redhat.com>
+
+ * src/common/clock.cxx (dsr): Fix problems mixing signed and
+ unsigned values. Normally only generated warnings, but...
+
+2001-07-09 Jonathan Larmour <jlarmour@redhat.com>
+
+ * include/sched.inl (unlock_reschedule): Fix commenting.
+ * src/sched/sched.cxx: Improve description of unlock_inner().
+
+2001-06-21 Jonathan Larmour <jlarmour@redhat.com>
+
+ * src/common/thread.cxx (Cyg_Thread::Cyg_Thread): Initialize
+ wakeup_count
+
+2001-06-06 Hugo Tyson <hmt@redhat.com>
+
+ * tests/clocktruth.cxx: New file. A test to get a sanity check on
+ whether the clock is accurate to wallclock time, only useful for
+ humans to watch really. But important!
+
+2001-05-31 Jonathan Larmour <jlarmour@redhat.com>
+
+ * include/thread.hxx (class Cyg_HardwareThread): Remove unused
+ load_context() method.
+ * include/thread.inl: Ditto.
+
+2001-05-29 Jonathan Larmour <jlarmour@redhat.com>
+
+ * src/sched/bitmap.cxx (rem_thread): No need to set need_reschedule...
+ rescheduling will happen automatically when the state changes.
+
+ * src/sched/mlqueue.cxx (add_thread): No need to explicitly clear
+ thread->queue.
+
+2001-04-26 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/intr0.cxx:
+ * tests/kintr0.c:
+ Fixed these two tests so that they work properly on architectures
+ where CYGNUM_HAL_ISR_MIN is not zero. These include the x86 and
+ V850.
+
+2001-04-18 Bart Veer <bartv@redhat.com>
+
+ * tests/dhrystone.c:
+ Fix the conditional for STDIO_FORMATTED_IO
+
+2001-04-17 Bart Veer <bartv@redhat.com>
+
+ * tests/stress_threads.c (setup_death_alarm):
+ Cope with synthetic target reorg
+
+ * tests/except1.cxx, tests/kexcept1.c:
+ Reenable for the synthetic target
+
+ * tests/tm_basic.cxx:
+ Reenable for the synthetic target
+
+2001-04-17 Jesper Skov <jskov@redhat.com>
+
+ * cdl/kernel.cdl: Do cache tests on E7T.
+
+2001-04-05 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/flag1.cxx: Apply same changes here as were applied to
+ kflag1 on 2000-07-17. This allows this test to run to completion
+ in slow targets, especially simulators.
+
+ * tests/stress_threads.c: Reduce run time even further in
+ simulator runs where instrumentation is enabled.
+
+2001-04-03 Jesper Skov <jskov@redhat.com>
+
+ * tests/dhrystone.c: Fix feature check.
+
+2001-03-28 Jonathan Larmour <jlarmour@redhat.com>
+
+ * cdl/kernel.cdl: Only need to compile dbg_gdb.cxx with
+ CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+
+ * src/debug/dbg_gdb.cxx: Add new dbg_thread_id() function.
+
+2001-02-23 Jonathan Larmour <jlarmour@redhat.com>
+
+ * include/thread.inl (attach_stack): Check for non-NULL stack base.
+
+2001-02-11 Jonathan Larmour <jlarmour@redhat.com>
+
+ * tests/stress_threads.c: CYGINT_ISO_STDIO_FORMATTED_IO needs a
+ #ifdef not an #if.
+ * tests/dhrystone.c: Ditto.
+
+2001-02-04 Jonathan Larmour <jlarmour@redhat.com>
+
+ * tests/kill.cxx: Increase delay for all targets, just in case some
+ are slow.
+
+2001-01-30 Hugo Tyson <hmt@redhat.com>
+
+ * src/common/clock.cxx (rem_alarm): Must clear the enabled flag;
+ this disappeared in the changes to using clists of 2001-01-09.
+ Symptom was that an alarm, once disabled, could never be
+ re-attached to its counter because it claimed it already was.
+ Plus asserts with multiple disables - "bad counter object".
+
+2001-01-30 Hugo Tyson <hmt@redhat.com>
+
+ * src/common/thread.cxx (reinitialize): Following change of
+ 2000-12-05, if CYGFUN_KERNEL_THREADS_STACK_CHECKING, this was
+ using the stack_base/stack_size variables directly to reinitialize
+ the stack area. This was wrong, and leaked store off the top and
+ bottom of the stacks because the "buffer zone" was carved off
+ repeatedly. Fix is to use the published APIs which compensate.
+
+2001-01-26 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/mlqueue.hxx:
+ * src/sched/mlqueue.cxx:
+ Restored Cyg_ThreadQueue_Implementation::remove() since it must
+ clear the thread's queue pointer, which the base clist class
+ remove() does not.
+
+2001-01-24 Jesper Skov <jskov@redhat.com>
+
+ * src/sched/mlqueue.cxx (highpri): Fix trace call.
+
+2001-01-09 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/mlqueue.hxx:
+ * src/sched/mlqueue.cxx:
+ Converted to use clist.hxx list implementation. The main effect of
+ this is to clean up the code and class definitions since much of
+ what was part of the thread queue and thread classes now moves to
+ the DNode and CList classes.
+
+ * include/clock.hxx:
+ * src/common/clock.cxx:
+ Converted to use clist.hxx list implementation. This removes all
+ the explicit list manipulation code from the counter and alarm
+ classes, resulting in cleaner, easier to understand code.
+
+ * include/kapidata.h: Adjusted cyg_alarm struct to match Cyg_Alarm
+ using Cyg_DNode.
+
+2000-12-22 Jonathan Larmour <jlarmour@redhat.com>
+
+ * include/thread.inl (check_stack): check word alignment with CYG_WORD
+ not cyg_uint32
+ Add extra stack checking for when stack limits are used.
+ (measure_stack_usage): New function to measure stack usage of the thread
+ (attach_stack): check word alignment with CYG_WORD not cyg_uint32
+ Initialize stack to preset value when measuring stack usage
+ (increment_stack_limit): Conditionalize here wrt
+ CYGFUN_KERNEL_THREADS_STACK_CHECKING and use the version in thread.cxx
+ instead if CYGFUN_KERNEL_THREADS_STACK_CHECKING is defined.
+
+ * src/common/thread.cxx (exit): If verbose stack measurement enabled,
+ output stack usage
+ (increment_stack_limit): Add version of this method when
+ CYGFUN_KERNEL_THREADS_STACK_CHECKING *is* defined. This will add
+ padding above the stack limit as necessary.
+
+ * include/thread.hxx (class Cyg_HardwareThread): Add
+ measure_stack_usage() member
+
+ * cdl/thread.cdl (CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT):
+ Add to implement stack usage measurement.
+
+ * include/kapi.h (cyg_thread_measure_stack_usage): New function
+ * src/common/kapi.cxx (cyg_thread_measure_stack_usage): New function
+
+2000-12-08 Jonathan Larmour <jlarmour@redhat.com>
+
+ * cdl/thread.cdl (CYGFUN_KERNEL_ALL_THREADS_STACK_CHECKING):
+ Requires threads list, rather than active_if them so that
+ inference engine can do its thang.
+
+2000-12-07 Jesper Skov <jskov@redhat.com>
+
+ * src/debug/dbg-thread-demux.c: Add comment about the use of
+ DBG_SYSCALL_THREAD_VEC_NUM vs CYGNUM_CALL_IF_DBG_SYSCALL.
+
+2000-12-06 Hugo Tyson <hmt@redhat.com>
+
+ * include/thread.inl (attach_stack): Additional assert check for
+ unsigned wrap of the stack size in subtracting the signature
+ areas' size. Also round to whole words better.
+
+2000-12-05 Hugo Tyson <hmt@redhat.com>
+
+ * cdl/thread.cdl (CYGFUN_KERNEL_THREADS_STACK_CHECKING): New
+ option, to control new stack check features. Enabled by default,
+ but only active if CYGPKG_INFRA_DEBUG and CYGDBG_USE_ASSERTS
+ anyway, plus checking *all* threads is possible, but default off,
+ iff CYGVAR_KERNEL_THREADS_LIST.
+
+ * include/thread.hxx (class Cyg_HardwareThread): Define
+ check_stack() function.
+
+ * include/thread.inl (attach_stack): Add initialization of a
+ signature in the top and base of the stack, if so configured.
+ (check_stack): New function to check that signature for
+ correctness; minor re-ordering to permit more inlining.
+
+ * src/sched/sched.cxx (unlock_inner): Check departing and incoming
+ thread stacks if CYGFUN_KERNEL_THREADS_STACK_CHECKING. Also, if
+ CYGFUN_KERNEL_ALL_THREADS_STACK_CHECKING, check all registered
+ thread stacks. This is placed here to get executed every
+ clocktick and other interrupts that call DSRs, rather than messing
+ with interrupt_end() or the idle thread.
+
+2000-12-04 Hugo Tyson <hmt@redhat.com>
+
+ * tests/kcache2.c (entry0): Make this more robust against a
+ complete absence of useful caches. Previous change was not
+ careful enough.
+
+2000-12-01 Hugo Tyson <hmt@redhat.com>
+
+ * cdl/kernel.cdl: Build the kcache tests for SA11x0 family; they
+ were being omitted by default as part of ARM family. They work on
+ SA1110, so this should be OK. They're OK on EBSAs too. See
+ associated fix to cache macros in SA11x0 and EBSSA HALs.
+
+ * tests/kcache2.c (entry0): Fix the test; the problem was it
+ assumed that a write to a previously unseen location would end up
+ in the cache. It ain't so on StrongARMs. Also make tests safe
+ wrt interrupts possibly perturbing the cache, add explicit tests
+ for HAL_DCACHE_INVALIDATE_ALL(), ...DISABLE() and ...SYNC(), and
+ improve the tests for cache line invalidate and store.
+
+2000-10-30 Jesper Skov <jskov@redhat.com>
+
+ * cdl/synch.cdl: Replaced CYGINT_KERNEL_SCHEDULER_CAN_YIELD with
+ CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES.
+ * cdl/scheduler.cdl:
+ CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL requires
+ CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES.
+
+ * tests/thread2.cxx: Use new option.
+ * tests/klock.c: Same.
+ * src/common/thread.cxx: Same.
+ * src/common/clock.cxx: Same.
+
+ * include/bitmap.hxx: Leave unique priority setting to CDL.
+ * include/mlqueue.hxx: Same.
+ * include/sched.hxx: Let CDL do sanity check of config.
+
+2000-10-27 Jesper Skov <jskov@redhat.com>
+
+ * cdl/scheduler.cdl: Added CYGINT_KERNEL_SCHEDULER_CAN_YIELD
+
+ * tests/klock.c: Avoid use of disabled features. Require scheduler
+ that can yield.
+
+2000-10-20 Jonathan Larmour <jlarmour@redhat.com>
+
+ * tests/bin_sem0.cxx:
+ * tests/bin_sem1.cxx:
+ * tests/bin_sem2.cxx:
+ * tests/clock0.cxx:
+ * tests/clock1.cxx:
+ * tests/clockcnv.cxx:
+ * tests/cnt_sem0.cxx:
+ * tests/cnt_sem1.cxx:
+ * tests/except1.cxx:
+ * tests/flag0.cxx:
+ * tests/flag1.cxx:
+ * tests/intr0.cxx:
+ * tests/kill.cxx:
+ * tests/mbox1.cxx:
+ * tests/mqueue1.cxx:
+ * tests/mutex0.cxx:
+ * tests/mutex1.cxx:
+ * tests/mutex2.cxx:
+ * tests/mutex3.cxx:
+ * tests/philo.cxx:
+ * tests/release.cxx:
+ * tests/sched1.cxx:
+ * tests/sync2.cxx:
+ * tests/sync3.cxx:
+ * tests/testaux.hxx:
+ * tests/thread0.cxx:
+ * tests/thread1.cxx:
+ * tests/thread2.cxx:
+ * tests/tm_basic.cxx:
+ Make sure default priority constructors have been invoked.
+
+ * include/intr.hxx (class Cyg_Interrupt): Make dsr_count volatile
+ to prevent a potential race condition with overzealous C
+ compilers.
+
+2000-10-13 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/sched/sched.cxx (unlock_inner): Added condition to test for
+ DSRs to only call DSRs when the scheduler lock is making a 0->1
+ transition. Otherwise there is the danger of calling DSRs when the
+ scheduler lock is > 1. This violates our original assumptions
+ about how the scheduler lock worked with respect to DSR.
+
+ * src/intr/intr.cxx (call_pending_DSRs): Added assert to check
+ that DSRs are only called when the scheduler lock is exactly 1.
+
+2000-10-13 Jesper Skov <jskov@redhat.com>
+
+ * include/intr.hxx: Fixing syntax mistake; volatile keyword must
+ appear after the type for it to affect the pointer variable.
+ * src/intr/intr.cxx: Same. Remove volatile from local block.
+
+2000-10-05 Jesper Skov <jskov@redhat.co.uk>
+
+ * src/intr/intr.cxx: Made dsr_table_tail volatile as well.
+ * include/intr.hxx: Ditto.
+
+2000-10-05 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/sched/sched.cxx:
+ * include/sched.hxx: Converted asr_inhibit from a bool to a
+ counter. This is necessary to permit nesting of ASR inhibiting
+ functions.
+
+2000-10-04 Jesper Skov <jskov@redhat.co.uk>
+
+ * include/intr.hxx: Made dsr_list volatile.
+ * src/intr/intr.cxx: Same. Also fix compiler warning.
+
+2000-09-25 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/sched/mlqueue.cxx:
+ Added test for current thread not runnable in
+ Cyg_Scheduler_Implementation::timeslice(). This is possible if a
+ prior DSR has caused the current thread to be descheduled. Added
+ an assert to Cyg_ThreadQueue_Implementation::rotate() for
+ additional paranoia. (This problem was originally identified and
+ fixed (differently) by Andrew Lunn <andrew.lunn@ascom.ch>.)
+
+2000-09-13 Jesper Skov <jskov@redhat.com>
+
+ * tests/kexcept1.c (cause_exception): Use separate cause_fpe function.
+ * tests/except1.cxx (cause_exception): Same.
+
+ * tests/kexcept1.c (cause_exception): Do not use division at all.
+ * tests/except1.cxx (cause_exception): Same.
+
+ * tests/kexcept1.c (cause_exception): Do not cause div-by-zero.
+ * tests/except1.cxx (cause_exception): Same.
+
+2000-09-11 Jonathan Larmour <jlarmour@redhat.com>
+
+ * cdl/instrument.cdl (CYGVAR_KERNEL_INSTRUMENT_EXTERNAL_BUFFER):
+ Bring this option back from the dead
+
+2000-09-08 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/sched.hxx:
+ * include/sched.inl:
+ Added Cyg_Scheduler::unlock_reschedule() function. This decrements
+ the scheduler lock by one but also permits the current thread to
+ be rescheduled if it ready to sleep, or there is a higher priority
+ thread ready to run. This is to support use of various
+ synchronization objects while the scheduler lock is claimed.
+
+ * src/sched/sched.cxx (unlock_inner): Modified precondition to
+ allow for functionality of unlock_reschedule().
+
+ * src/sched/mlqueue.cxx:
+ Now uses Cyg_SchedulerThreadQueue_Implementation for all runqueue
+ pointers. It was using Cyg_ThreadQueue_Implementation in some
+ places which meant we were trying to sort the run queues!
+ Changed yield() so it can be called with the scheduler lock
+ claimed.
+ Changed Cyg_Scheduler_Implementation::timeslice() to rotate the
+ queue itself rather than call yield(). The changes to yield() make
+ it unsafe to call here any more.
+
+ * include/mlqueue.hxx (class Cyg_SchedulerThreadQueue_Implementation):
+ Made enqueue() member public.
+
+ * include/mboxt2.inl:
+ * src/common/thread.cxx:
+ * src/sync/mutex.cxx:
+ * src/sync/cnt_sem2.cxx:
+ Removed assertions for zero scheduler lock and replaced some
+ invocations of Cyg_Scheduler::unlock() with
+ Cyg_Scheduler::unlock_reschedule() or Cyg_Scheduler::reschedule()
+ where appropriate.
+
+ * tests/klock.c:
+ * cdl/kernel.cdl:
+ Added klock.c to test functionality while scheduler lock is claimed.
+
+2000-08-17 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/sched/sched.cxx (unlock_inner): Move an assert to some place
+ where it's true *all* the time! There was a narrow margin where a
+ DSR could confuse unlock_inner() by reanimating the current thread
+ before it had a chance to sleep - hence the call appears to be
+ pointless. Putting the assert before the DSR calls makes sense.
+
+ * include/mboxt.inl:
+ * src/sync/bin_sem.cxx:
+ * src/sync/cnt_sem.cxx:
+ * src/sync/flag.cxx:
+ * src/sync/mutex.cxx:
+ All of these now use Cyg_Scheduler::reschedule() rather than an
+ unlock/lock pair to yield in their functions which can sleep.
+ They therefore can be called safely and atomically with the
+ scheduler already locked. This is a Good Thing[tm]. Since the
+ network stack synch primitives now use this feature, the asserts
+ that the scheduler was not locked must disappear: this change.
+
+
+2000-08-07 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * include/mutex.hxx (class Cyg_Mutex): Add comment explaining
+ presence of locked.
+
+2000-08-04 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * tests/stress_threads.c (STACK_SIZE_HANDLER): Increase stack sizes
+ otherwise it crashes!
+
+2000-07-31 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * include/mempolt2.hxx: As per change of 2000-07-04, also delete - left
+ behind accidentally
+
+2000-07-20 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/mutex.hxx (class Cyg_Mutex): Added get_ceiling()
+ accessor function.
+
+ * src/sched/mlqueue.cxx: Fixed bug in sorted queue code that
+ resulted in an infinite loop if the thread being inserted is of
+ lower priority than all threads in the queue. This case is now
+ detected early.
+
+2000-07-17 Gary Thomas <gthomas@redhat.com>
+
+ * tests/kflag1.c (FIRST_THREAD_WAIT_TIME): Parameterize thread
+ synchronization wait times (for understanding) and adjust for
+ incredibly slow platforms. [Previous value allowed for the test
+ to get out of sync because the code ran so slowly]
+
+2000-07-04 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * cdl/kernel.cdl: Remove all configury related to memory allocators,
+ including tests. Make CYGFUN_KERNEL_API_C require CYGFUN_MEMALLOC_KAPI
+
+ * include/memfixed.hxx, include/mempolt2.inl, include/mempoolt.hxx,
+ include/mempoolt.inl, include/memvar.hxx, include/mfiximpl.hxx,
+ include/mfiximpl.inl, include/mvarimpl.hxx, include/mvarimpl.inl,
+ src/mem/memfixed.cxx, src/mem/memvar.cxx, tests/kmemfix1.c,
+ tests/kmemvar1.c, tests/memfix1.cxx, tests/memfix2.cxx,
+ tests/memvar1.cxx, tests/memvar2.cxx:
+ Move to separate memory allocator package CYGPKG_MEMALLOC
+
+ * include/kapi.h, include/kapidata.h, src/common/kapi.cxx:
+ Remove memory allocator functionality - now implemented in
+ CYGPKG_MEMALLOC
+
+ * tests/dhrystone.c:
+ Update configuration dependencies for new isoinfra design
+ * tests/stress_threads.c:
+ Likewise.
+ Also fix early termination after DEATH_TIME_LIMIT so that
+ allocated resources are freed, and so more appropriate
+ statistics are reported
+ Also update to use mallinfo() interface to memory allocator
+
+2000-06-23 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/kapi.h (cyg_scheduler_read_lock): New function, to
+ return the value of the scheduler lock; this for implementing SPLX
+ in the network stack.
+
+ * src/common/kapi.cxx (cyg_scheduler_read_lock): New function.
+
+2000-06-20 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/sched/mlqueue.cxx (Cyg_ThreadQueue_Implementation::enqueue):
+ Rewrote code to insert threads into priority sorted queue. The
+ original code could not cope with a queue all of whose members
+ were lower priority than the new thread - it looped for ever. Also
+ provided fast paths for common and easily detected cases such as
+ adding to a single element queue and adding at the front. By
+ taking these cases out early, we can also simplify the code to
+ search the queue.
+
+2000-06-16 Gary Thomas <gthomas@redhat.com>
+
+ * cdl/kernel.cdl: Remove exception tests for CMA230 - not supported
+ by hardware.
+
+2000-06-16 Jesper Skov <jskov@redhat.com>
+
+ * src/intr/intr.cxx (chain_isr): Only call default_isr if no isrs
+ in the chain reacted to the interrupt.
+
+2000-06-15 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/mutex.hxx (class Cyg_Condition_Variable): Added an
+ inline function, get_queue(), to return a pointer to the
+ underlying thread queue. To be used mainly for comparing with a
+ thread's current queue to decide whether it is waiting for a
+ condition variable.
+
+ * include/kapi.h:
+ * src/common/kapi.cxx:
+ Changed return type of cyg_semaphore_wait() to match existing
+ behaviour of Cyg_Counting_Semaphore::wait().
+ Changed return type of cyg_cond_wait() to match new behaviour of
+ Cyg_Condition_Variable::wait().
+
+2000-06-09 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/mutex.hxx:
+ * src/sync/mutex.cxx:
+ Modified non-timeout condition variable wait() API to return
+ cyg_bool. A true result indicates that the wait() terminated
+ normally. A false result indicates that the wait() was terminated
+ as a result of a release() or destroy operation. For most uses
+ this distinction is irrelevant, but in some situations it is a
+ useful bit of information to have.
+ Also modified timeout condition variable wait to reacquire the
+ mutex under all circumstances. This is the correct and consistent
+ thing to do.
+
+2000-06-08 Jesper Skov <jskov@redhat.com>
+
+ * src/debug/dbg-thread-demux.c: Use generic HAL feature to allow
+ ROM/RAM intercalling.
+
+2000-06-06 Jesper Skov <jskov@redhat.com>
+
+ * tests/kcache1.c (entry0): Skip invalidate tests on TX49. Too slow.
+
+2000-05-30 Gary Thomas <gthomas@redhat.com>
+
+ * tests/dhrystone.c: Increase number of test loops for faster
+ StrongARM platforms.
+
+2000-05-22 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * cdl/scheduler.cdl (CYGIMP_KERNEL_SCHED_SORTED_QUEUES): Disable by
+ default
+
+ * src/sched/mlqueue.cxx (enqueue): Add to end of thread queue even
+ when not priority ordered
+
+2000-05-20 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * include/mqueue.hxx, include/mqueue.inl:
+ Add POSIX-style message queue implementation
+
+ * cdl/kernel.cdl: Add mqueue1 test
+ * cdl/scheduler.cdl: Add new CYGIMP_KERNEL_SCHED_SORTED_QUEUES option
+
+ * include/sema.hxx: Need thread.inl header, not just thread.hxx
+ Make Cyg_Counting_Semaphore::peek() const since it is
+
+ * src/sync/cnt_sem.cxx, src/sync/cnt_sem2.cxx, include/sema2.hxx:
+ Make Cyg_Counting_Semaphore{2}::peek() const since it is
+
+ * include/thread.hxx: don't want Cyg_Thread_queue::empty() to be marked
+ inline in the class def, otherwise we get warnings elsewhere
+
+ * include/mlqueue.hxx (Cyg_ThreadQueue_Implementation):
+ Add set_thread_queue private method
+ Add derived class Cyg_SchedulerThreadQueue_Implementation, and
+ make scheduler implementation use it instead of
+ Cyg_ThreadQueue_Implementation
+
+ * src/mlqueue.cxx: Fix typo
+ Support CYGIMP_KERNEL_SCHED_SORTED_QUEUES, i.e. allow insertion
+ into thread queue in order of thread priority, with oldest at the
+ front
+ (Cyg_ThreadQueue_Implementation::set_thread_queue): Add
+ (Cyg_SchedulerThreadQueue_Implementation::enqueue): Add, like old
+ one, except make it FIFO instead of LIFO by inserting at end of queue
+
+2000-05-16 Jesper Skov <jskov@redhat.com>
+
+ * tests/dhrystone.c: More loops on the TX49
+
+2000-05-15 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * cdl/counters.cdl (CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY):
+ Default to CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY
+
+2000-05-04 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * include/instrmnt.h: Remove all CYG_UNUSED_PARAMs as they could
+ cause problems when used with volatile arguments
+ * src/intr/intr.cxx: Use CYG_UNUSED_PARAM to silence warning that
+ appears because of the above change.
+
+2000-05-02 Gary Thomas <gthomas@redhat.com>
+
+ * tests/kintr0.c:
+ * tests/intr0.cxx: Correct test for cases when VSR_MIN or
+ ISR_MIN are not zero (bad assumption).
+
+2000-05-02 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * cdl/thread.cdl (CYGNUM_KERNEL_THREADS_DATA_LIBC): Don't need libc
+ slot. Replace with CYGNUM_KERNEL_THREADS_DATA_ERRNO slot instead.
+
+2000-04-28 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/sched/sched.cxx (unlock_inner):
+ A significant change to the behaviour of this function. The
+ new_lock argument contains the value that the scheduler lock
+ should have after this function has completed. If it is zero then
+ the lock is being released and some extra work (running ASRs,
+ checking for DSRs) is done before returning. If it is non-zero
+ then it must equal the current value of the lock, and is used to
+ indicate that we want to reacquire the scheduler lock before
+ returning. This latter option only makes any sense if the current
+ thread is no longer runnable, otherwise this function will do
+ nothing.
+
+ The result of this is that where we used to "blip" the scheduler
+ lock to force a sleep, we now call reschedule(), which calls
+ unlock_inner() with the current sched_lock value. The important
+ difference is that there is not now the brief window between the
+ calls where the lock is unclaimed. It also prevents ASRs being run
+ at inopportune moments. In future this will also allow us to force
+ threads to sleep even when they are deeply nested in the scheduler
+ lock.
+
+ * include/mutex.hxx:
+ Added Cyg_Mutex::get_owner() to return pointer to owning thread.
+
+ * include/sched.hxx:
+ * include/sched.inl:
+ Added new_lock argument to unlock_inner(), added reschedule().
+ Made set_asr_inhibit() and clear_asr_inhibit() available even when
+ ASRs are disabled.
+
+ * include/mboxt.inl:
+ * src/sync/bin_sem.cxx:
+ * src/sync/cnt_sem.cxx:
+ * src/sync/flag.cxx:
+ * src/sync/mutex.cxx:
+ Converted instances of "blipping" the scheduler lock into calls to
+ Cyg_Scheduler::reschedule(), which is better behaved. Some calls
+ to set_asr_inhibit() and clear_asr_inhibit() also added in various
+ places.
+
+2000-04-26 Jesper Skov <jskov@redhat.com>
+
+ * tests/kcache1.c: Also to flush testing with unified caches.
+
+2000-04-26 Jesper Skov <jskov@redhat.com>
+
+ * tests/clockcnv.cxx:
+ * tests/dhrystone.c:
+ Renamed 850 HAL package.
+
+2000-04-25 Jesper Skov <jskov@redhat.com>
+
+ * tests/kcache1.c: Fixed cache check to also look for unified
+ caches.
+
+2000-04-19 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/clockcnv.cxx:
+ * tests/dhrystone.c:
+ Only a few laps around the block on the v850...
+
+2000-04-13 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/clock.hxx:
+ * src/common/clock.cxx:
+ Added Cyg_Alarm::get_times() member function to allow reading of
+ trigger and interval values from an alarm.
+
+2000-04-12 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/sched.hxx:
+ * src/sched/sched.cxx:
+ Added ASR support.
+
+ * include/thread.hxx:
+ Made Cyg_ThreadQueue::empty() an inline in class definition.
+
+ * src/common/thread.cxx:
+ Added CYG_REPORT_FUNCTION() to Cyg_Thread::exit().
+
+ * include/kapidata.h:
+ Brought thread structures up to date with kernel objects.
+
+ * cdl/thread.cdl:
+ * cdl/scheduler.cdl:
+ Added ASR configuration, minor tidies.
+
+2000-04-12 Gary Thomas <gthomas@redhat.com>
+
+ * src/common/kapi.cxx (cyg_scheduler_safe_lock):
+ * include/kapi.h: Add 'cyg_scheduler_safe_lock()' function.
+
+2000-04-12 Jesper Skov <jskov@redhat.com>
+
+ * cdl/interrupts.cdl:
+ * cdl/scheduler.cdl:
+ * cdl/counters.cdl:
+ Don't let interfaces define anything.
+
+2000-04-07 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/sched.hxx:
+ * include/thread.inl:
+ * src/sync/mutex.cxx:
+ * src/sched/sched.cxx:
+ * src/common/thread.cxx:
+ General reorganization of priority inversion protocol support,
+ addition of priority ceiling protocol.
+
+ * include/mlqueue.hxx:
+ * src/sched/mlqueue.cxx:
+ Added timeslicing enable support.
+
+ * cdl/thread.cdl:
+ * cdl/synch.cdl:
+ Reorganized priority inversion protocol configuration to permit
+ different protocols and dynamic choice. Added configuration for
+ condition variables to use a user-specified mutex.
+
+ * cdl/scheduler.cdl:
+ Added dynamic timeslicing enable option.
+
+ * include/kapidata.h:
+ Adjusted to match changes in other header files.
+
+ * tests/mutex3.cxx:
+ * tests/sync3.cxx:
+ Modified these tests to match new priority inversion protocols
+ configuration options.
+
+2000-03-28 John Dallaway <jld@cygnus.co.uk>
+
+ * cdl/counters.cdl,
+ cdl/interrupts.cdl,
+ cdl/kernel.cdl,
+ cdl/scheduler.cdl,
+ cdl/synch.cdl,
+ cdl/thread.cdl:
+
+ Adjust documentation URLs.
+
+2000-03-27 Gary Thomas <gthomas@redhat.com>
+
+ * tests/except1.cxx:
+ * tests/kexcept1.c: Avoid trying to generate data access errors
+ on platforms that don't support them.
+
+ * tests/kcache1.c: Ignore test if no [data] caches defined.
+
+ * tests/stress_threads.c: Infer minimal configuration for platforms
+ with small amount of memory (as opposed to platform special cases).
+
+2000-03-27 Jesper Skov <jskov@redhat.com>
+
+ * src/sync/mutex.cxx:
+ * src/sched/sched.cxx:
+ * src/common/thread.cxx:
+ * src/common/clock.cxx:
+ Use cyg_bool instead of bool for check_this().
+
+ * tests/dhrystone.c: Requires CYGPKG_LIBC_MALLOC
+
+2000-03-07 Jesper Skov <jskov@redhat.com>
+
+ * tests/mutex3.cxx: Minor tweak from Hugo to allow reduced runtime
+ on sims.
+
+2000-02-29 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * src/debug/dbg-thread-demux.c:
+ CYG_HAL_SPARCLITE_SLEB -> CYGPKG_HAL_SPARCLITE_SLEB
+ Also fix a comment typo
+
+2000-02-29 Jesper Skov <jskov@redhat.com>
+
+ * tests/kcache1.c: Don't run last part of test on MIPS sim - it's
+ very slow.
+
+2000-02-25 Jesper Skov <jskov@redhat.com>
+
+ * tests/dhrystone.c:
+ * tests/tm_basic.cxx:
+ Don't allow use of devices for diag output when running performace
+ tests.
+
+2000-02-17 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * include/pkgconf/kernel.h: Make
+ CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE_SIMPLE a cdl_component
+ since it has children now
+
+2000-02-17 Jesper Skov <jskov@redhat.com>
+ CR101202, CR902078
+ * include/mvarimpl.inl: Avoid unlinking the list from the head
+ during coalescing.
+
+2000-02-11 Jesper Skov <jskov@redhat.com>
+
+ * tests/dhrystone.c (PASSES): Reduced for MPC8xx targets.
+
+2000-02-10 Jesper Skov <jskov@redhat.com>
+
+ * tests/except1.cxx (except0_main):
+ * tests/kexcept1.c (except0_main):
+ Also reclaim DATA_TLB_MISS vector if available.
+
+2000-02-03 Jesper Skov <jskov@redhat.com>
+
+ * src/sched/lottery.cxx (schedule): CYG_HAL_POWERPC_x->CYGPKG_...
+
+2000-02-01 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * tests/tm_basic.cxx (NTEST_THREADS): Reduce further to fit on small
+ targets
+ (NMBOXES): Likewise
+ (NCOUNTERS): Likewise
+
+ * src/common/clock.cxx: Rework last change - change types of
+ clock_dsr_read and delta to unsigned instead
+
+2000-01-31 Jonathan Larmour <jlarmour@redhat.co.uk>
+
+ * src/common/clock.cxx (isr): Use HAL_CLOCK_LATENCY, not HAL_CLOCK_READ
+ (dsr): Likewise
+
+ * cdl/counters.cdl (CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY):
+ Copy configury for this option here from include/pkgconf/kernel.h - it
+ was left behind by accident
+
+2000-01-31 Simon FitzMaurice <sdf@cygnus.co.uk>
+ * cdl/*.cdl:
+
+ Adjust help URLs in line with new doc layout.
+
+2000-01-31 Jesper Skov <jskov@redhat.com>
+
+ * tests/tm_basic.cxx: Use CYG_TEST_NA insetad of PASS when not
+ applicable.
+
+2000-01-28 Simon FitzMaurice <sdf@cygnus.co.uk>
+ * cdl/*.cdl:
+
+ Adjust help URLs in line with new doc layout.
+
+2000-01-26 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/clock.hxx (class Cyg_Clock): Add members to convert to
+ and from this clock resolution and others.
+
+ * include/clock.inl (convert): New Cyg_Clock member.
+
+ * src/common/clock.cxx (construct_converter): New routine to
+ factorize a rational (or very near neighbour) to help with clock
+ tick conversions for a particular clock.
+ (get_other_to_clock_converter):
+ (get_clock_to_other_converter): Cyg_Clock member functions to
+ construct converters to or from this clock, using above routine.
+
+ * tests/clockcnv.cxx: New file: test the clock converters.
+
+ * tests/PKGconf.mak (TESTS): Add clockcnv to the tests.
+
+ * cdl/kernel.cdl: Add clockcnv to the tests.
+
+2000-01-20 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * cdl/synch.cdl
+ (CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE_SIMPLE_RELAY):
+ Change this to an active_if on simple prio-inh. Was broken.
+
+2000-01-19 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * cdl/*.cdl: Add descriptions to a number of options &c which were
+ lacking same, also tidied up other typos as noticed en passant.
+ Also reorganized calculated opts about per-thread-data in
+ thread.cdl; these are really for info only.
+
+2000-01-19 Jesper Skov <jskov@cygnus.co.uk>
+ CR 902054
+ * tests/stress_threads.c: Don't assert requested priority =
+ allocated. Allow some flexibility of handler priorities.
+
+2000-01-13 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/mutex3.cxx (control_thread): Add a CYG_TEST_INIT();
+ Whoops!
+
+2000-01-11 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * cdl/kernel.cdl: Add new kernel test mutex3, put in to test
+ RELAY prio inheritance extension.
+
+ * tests/mutex3.cxx: New test case. It tests mutex prio
+ inheritance - or not - in a multiple thread manner, depending only
+ on delays and the clock, so it tests that scheduling does the
+ right thing, rather than simply checking reported priorities.
+
+ * tests/PKGconf.mak: Add new kernel test mutex3, put in to test
+ RELAY prio inheritance extension.
+
+2000-01-11 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * cdl/synch.cdl: New config option added,
+ (CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE_SIMPLE_RELAY).
+
+ * include/pkgconf/kernel.h: New config option added,
+ (CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INHERITANCE_SIMPLE_RELAY).
+ It is a child of ..._PRIORITY_INHERITANCE_SIMPLE and is really
+ only there to turn off if you really want the old implementation.
+
+ * src/sync/mutex.cxx (unlock): Add call to
+ Cyg_SchedThread::relay_priority() when relinquishing the mutex, in
+ order to relay any raised priority to the new owner. Also count
+ the mutex we are waiting for as well as those held for correct
+ recovery in the case of inheriting priority then being killed, for
+ example.
+
+ * include/sched.hxx (class Cyg_SchedThread::relay_priority): New
+ member function declared.
+
+ * src/sched/sched.cxx (Cyg_SchedThread::relay_priority): New
+ member function to implement pass-it-on or "discovered ceiling"
+ priority inheritance extension to the simple algorithm. Also use
+ get_current_priority() in Cyg_SchedThread::inherit_priority() to
+ let this work.
+
+2000-01-11 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/clock.hxx (class Cyg_Counter::counter): make the counter
+ volatile, otherwise a busy-wait loop for the real time clock to
+ change never completes.
+
+1999-12-23 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/sched/sched.cxx (inherit_priority): Fix bug; inheriting a
+ 2nd time would overwrite the saved initial_priority, so
+ disinheriting had no effect.
+
+1999-12-13 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/tm_basic.cxx (run_alarm_tests): Add new measurement of
+ latency between alarm firing and thread resume
+
+1999-12-13 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * cdl/kernel.cdl: Fix some minor mistakes in the lists of tests to
+ build conditionally
+
+1999-12-08 John Dallaway <jld@cygnus.co.uk>
+
+ * cdl/kernel.cdl:
+
+ Conditionally build the tests 'stress_threads', 'kcache1' and
+ 'kcache2'.
+
+1999-11-30 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/common/kapi.cxx (cyg_scheduler_lock, cyg_scheduler_unlock):
+ assert good range for sched lock, and be defensive anyway. This
+ is in response to a long time taken to track down a "unlocked too
+ many times" bug.
+
+1999-11-24 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Size tests based on available resources,
+ using MLT files. Fall back if not available.
+
+1999-11-22 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/sched/bitmap.cxx (Cyg_Scheduler_Implementation::add_thread):
+ Fixed typo in assertion, and moved it to a more useful place.
+
+1999-11-03 John Dallaway <jld@cygnus.co.uk>
+
+ * cdl/kernel.cdl: Define all tests.
+
+1999-10-29 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/PKGconf.mak: Enable cache tests for Cirrus Logic boards.
+
+1999-10-27 John Dallaway <jld@cygnus.co.uk>
+
+ * cdl/kernel.cdl:
+
+ Specify CYGPKG_KERNEL_TESTS in terms of testing
+ source files.
+
+1999-10-26 John Dallaway <jld@cygnus.co.uk>
+
+ * cdl/kernel.cdl:
+
+ Define initial version of CYGPKG_KERNEL_TESTS for
+ verification purposes.
+
+1999-10-19 John Dallaway <jld@cygnus.co.uk>
+
+ * cdl/kernel.cdl:
+
+ Define CDL options for package-specific CFLAGS.
+
+1999-10-08 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/kcache1.c: Fix array size.
+
+ * src/sched/bitmap.cxx (add_thread):
+ * src/sched/mlqueue.cxx (add_thread):
+ Check for valid thread priority.
+
+1999-10-07 John Dallaway <jld@cygnus.co.uk>
+
+ * cdl/counters.cdl,
+ cdl/interrupts.cdl,
+ cdl/scheduler.cdl:
+
+ Specify radio buttons using CDL interfaces.
+
+1999-10-06 Bart Veer <bartv@cygnus.co.uk>
+
+ * cdl/scheduler.cdl:
+ Make the schedulers mutually exclusive via a cdl_interface
+
+1999-10-05 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/kcache1.c: Reduced memory footprint.
+
+1999-09-25 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/stress_threads.c: Added date header and flush() calls.
+
+1999-09-16 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/tm_basic.cxx (run_mutex_tests): Must unlock mutices before
+ destroying, given the change below.
+
+ * src/common/kapi.cxx (cyg_cond_destroy): Call the correct
+ destructor. As it happens, it didn't matter because all these
+ destructors do is assert the queue is empty, and the queue is the
+ 2nd word in every case.
+ (cyg_mutex_destroy): Call the destructor at all, so that
+ assertions are made.
+
+1999-09-13 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * src/intr/intr.cxx (call_pending_DSRs_inner): Add assert to check
+ for valid DSR (before trying to use it).
+
+1999-09-13 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/stress_threads.c: Print out malloc system info.
+ (print_statistics): Fix buglet.
+
+1999-09-10 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/stress_threads.c: Print out more info. Reduce dump
+ frequency as test runs.
+
+1999-08-25 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h: Add missing close brace in
+ CYGIMP_KERNEL_COUNTERS_CLOCK_LATENCY CDL.
+
+1999-08-24 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/kcache1.c (entry0): Depending on architecture, set
+ cyg_test_is_simulator for last two tests. Otherwise they take far
+ too long and time out.
+
+1999-08-23 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/intr0.cxx (vsr0):
+ * tests/kintr0.c (vsr0):
+ Add a comment to the effect that vsr0() is NOT a valid VSR on any
+ known platform; VSRs must be writ in assembler. Customer
+ requested this, the examples are rather confusing otherwise.
+
+1999-08-23 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ * src/common/clock.cxx:
+ * tests/tm_basic.cxx:
+ Added CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY to enable recording
+ of DSR latency figures. Added code controlled by this option to
+ clock and tm_basic. Also made interrupt latency measurement
+ primarily dependent on CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY since
+ whether HAL_CLOCK_LATENCY is defined is not sufficient.
+
+1999-08-17 John Dallaway <jld@cygnus.co.uk>
+
+ * cdl/counters.cdl, cdl/interrupts.cdl, cdl/scheduler.cdl:
+
+ Implement radio buttons using "FIXME radio" hack in
+ description field for now.
+
+1999-08-16 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * src/sload/sload.c: Rename AM32 to AM31
+
+1999-08-12 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/dbg_gdb.cxx (dbg_make_threadref): Extended test for
+ uninitialized thread pointer.
+
+1999-07-29 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/sync/mutex.cxx (lock): Removed assertion again. Not possible
+ to determine if a violation wil cause a deadlock.
+
+1999-07-27 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/sync/mutex.cxx (lock): Added simple assertion check for
+ deadlocks.
+
+ * tests/stress_threads.c: Only allow printf from main thread to
+ prevent deadlocks.
+
+1999-07-14 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/kcache1.c (entry0): Also perform timing tests with
+ HAL_DCACHE_INVALIDATE_ALL and/or HAL_ICACHE_INVALIDATE_ALL in the
+ loop if provided by the HAL. Invalidating the Data cache can
+ spoil clock operation, so elapsed time appears to be 0.
+
+ * tests/kcache2.c (entry0): Replace the "if (0)" for having a
+ copy-back cache with a proper test on a HAL macro. Even though I
+ couldn't actually get those parts of the test to work on the
+ platform I'm currently working on.
+
+ * tests/PKGconf.mak (TESTS): Do build kcache1 and kcache2 for the
+ ARM_EBSA285; it seems kosher. kcache2 does absolutely nothing, of
+ course.
+
+1999-07-09 Jesper Skov <jskov@cygnus.co.uk>
+ PR 20210, 20142
+ * tests/stress_threads.c: Shifted thread priorities to make room
+ for main() at priority 0.
+
+ Fixed indentation.
+
+1999-07-08 Jesper Skov <jskov@cygnus.co.uk>
+ PR 20244
+ * tests/stress_threads.c: Changed cyg_user_start() to main()
+ ensuring a bigger stack (it calls sprintf).
+ Increased STACK_SIZE by 2kB for printf calls.
+
+1999-06-30 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/dhrystone.c: Also NA-quit if CYGPKG_INFRA_DEBUG or
+ CYGPKG_KERNEL_INSTRUMENT are enabled.
+
+1999-06-23 Jesper Skov <jskov@cygnus.co.uk>
+ PR 20209
+ * tests/dhrystone.c: Use fewer loops on ARM targets - they don't
+ have a cache.
+
+1999-06-22 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/intr/intr.cxx (Cyg_Interrupt::chain_isr): Was testing the wrong
+ macro for the default ISR. Fixed.
+
+ * src/common/clock.cxx (Cyg_RealTimeClock::isr): Add HANDLED bit
+ to returned value.
+
+1999-06-21 Jesper Skov <jskov@cygnus.co.uk>
+ PR 20209
+ * tests/dhrystone.c: Don't run test on sims or synthetic target.
+ Only run test when compiled with optimization.
+
+1999-06-18 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/dhrystone.c: Added unsupported header.
+
+1999-06-10 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/debug/dbg_gdb.cxx (dbg_threadinfo): Report counted sleep
+ correctly; both COUNTSLEEP and SLEEPING are set.
+
+1999-06-01 Hugo Tyson <hmt@masala.cygnus.co.uk>
+
+ * src/debug/dbg_gdb.cxx (dbg_threadinfo): Make the thread state
+ string a little more sensible when read as plain english.
+
+1999-05-31 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/dhrystone.c:
+ * tests/PKGconf.mak (TESTS):
+ Added dhrystone test.
+
+ Updated to 2.1 from ftp.nosc.mil
+
+1999-05-27 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/intr/intr.cxx (Cyg_Interrupt::chain_isr): Calls
+ HAL_DEFAULT_ISR if it is defined and no chained ISRs have
+ reported that they have handled the interrupt.
+
+ * src/debug/dbg_gdb.cxx (dbg_make_threadref): Fixed this routine
+ so that it copes with a NULL thread object.
+
+1999-05-27 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/stress_threads.c: Output stackmon status
+ occasionally. Output (simple) run time.
+
+1999-05-27 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/kcache1.c: Added handling of unified caches.
+
+1999-05-26 Jesper Skov <jskov@cygnus.co.uk>
+
+ * include/test/stackmon.h: Fixed some typos and thinkos.
+
+ * tests/tm_basic.cxx: Include new stackmon header.
+
+ * src/common/kapi.cxx:
+ * include/kapi.h:
+ Added kapi support for stackmon requirements.
+
+ * include/stackmon.hxx: [deleted]
+ * include/test/stackmon.h: [added]
+ Made stackmon safe to use from both C and C++.
+
+1999-05-25 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/stress_threads.c (setup_death_alarm): Only compile when
+ DEATH_TIME_LIMIT is defined.
+
+1999-05-25 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/except1.cxx:
+ * tests/intr0.cxx (intr0_main):
+ * tests/kexcept1.c:
+ * tests/kintr0.c (kintr0_main):
+ Change all mentions of CYG_HAL_TX39[_JMR3904] to
+ CYG_HAL_MIPS_TX39[_JMR3904]
+
+ * tests/kcache1.c: Use HAL_DCACHE_SYNC if possible
+
+1999-05-20 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/tm_basic.cxx (run_all_tests): Added some more stack stats
+ output using stackmon.hxx; also fixed a BUG associated with the
+ definition of stacks in testaux.hxx (within tests dir) that was
+ making the main stack usage bogus.
+
+ * include/stackmon.hxx: new file, to ease printing stuff about
+ stack usage, particularly of interrupt stacks and the idle
+ thread. It's not HAL specific, and it can apply to tests outside
+ of the kernel, which is why it's in a public include-place.
+ It just contains inline functions which define empty if there's no
+ handle on the symbols available, so should be safe enough.
+
+1999-05-18 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/stress_threads.c (main_program): Changed behavior of
+ cyg_thread_delete caller.
+
+1999-05-18 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/kapi.h (cyg_thread_delete): is now a boolean function to
+ indicate success. Failure is when the thread needs to run in
+ order to become killed.
+
+ * src/common/kapi.cxx (cyg_thread_delete): Try killing the thread
+ if necessary before deleting; only run the destructor if it was
+ killed, and tell the caller so.
+ (cyg_thread_kill): Back to the simpler version with no priority
+ diddling; it's up to the called to determine that it _has_ died.
+
+ * src/common/thread.cxx (kill): Only perform the state-changes
+ implied by kill if the thread has not already been killed;
+ otherwise two kill()'s will remove a thread unconditionally,
+ whether it's in the middle of a wait that needs tidying up or not.
+ In other words, ensure idempotency.
+
+1999-05-17 Hugo Tyson <hmt@masala.cygnus.co.uk>
+
+ * src/common/kapi.cxx (cyg_thread_kill): Up the priority of the
+ killee to make it terminate *now* if we have priorities and they
+ are not unique, otherwise asserts are likely with the bitmap
+ scheduler. Likewise in thread delete. Condition out the bodies
+ of the priority ops if the scheduler does not support priorities.
+
+1999-05-16 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * src/intr/intr.cxx (call_pending_DSRs):
+ * include/intr.hxx: Change mechanism for defining HAL function
+ to run DSRs. This was a "weak" symbol with override, but is now
+ a macro in <cyg/hal/hal_intr.h>.
+
+1999-05-13 Nick Garnett <nickg@cygnus.co.uk>
+
+ The following changes were all made in a branch and are now being
+ merged:
+
+ 1999-05-06 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/dbg-thread-demux.c:
+ Use dbg-thread-syscall.h from HAL rather than local version.
+ Made dbg_thread_syscall_rmt_1() generic to all MIPS targets.
+
+ * src/debug/dbg-thread-syscall.h:
+ Removed. Replaced by identical file in hal/common.
+
+ 1999-04-21 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Added CYGDBG_KERNEL_INSTRUMENT_BUFFER_WRAP option.
+ Changed CYGNUM_KERNEL_COUNTERS_RTC_PERIOD to the correct value for
+ VR4300.
+
+ * include/instrmnt.h: Added CYG_INSTRUMENT_EVENT_THREAD_ENTER
+ event.
+
+ * src/instrmnt/meminst.cxx (cyg_instrument): Added implementation
+ of CYGDBG_KERNEL_INSTRUMENT_BUFFER_WRAP option.
+
+ * src/common/thread.cxx: Added extra instrumentation point on
+ thread entry.
+
+1999-05-10 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/stress_threads.c (main_program): Added workaround for a
+ few PRs.
+
+1999-05-07 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/common/kapi.cxx (cyg_scheduler_unlock, cyg_scheduler_lock):
+ Make these simple calls to the scheduler.
+
+1999-05-07 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/stress_threads.c (setup_death_alarm): Reduce run time on
+ synthetic target.
+
+1999-05-06 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/stress_threads.c: Reversed priorities of agents.
+
+1999-05-06 Jesper Skov <jskov@cygnus.co.uk>
+ PRs 20040, (20027), 19991
+ * tests/stress_threads.c: Added main_thread handling resource
+ deallocation and printing.
+
+1999-04-27 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/stress_threads.c:
+ If there aren't enough priorities, output an N/A, rather than
+ stopping compilation with a #error
+
+1999-04-28 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19850
+ * tests/stress_threads.c: Don't print text from alarm handler.
+
+1999-04-28 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19945 workaround
+ * tests/kexcept1.c:
+ * tests/except1.cxx:
+ Made NA to PowerPC SIM.
+
+1999-04-27 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx:
+ Use/test 'cyg_thread_delete()' function.
+ Add ability to compute statistics with first datum removed which
+ can show up cache effects.
+ Show thread stack usage.
+
+ Fix merge screwup :-(
+
+1999-04-26 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/kapi.h: Add missing function cyg_thread_delete();
+ otherwise there is no way in the C API to re-use thread memory
+ safely. It just calls the destructor of the Cyg_Thread class.
+
+ * src/common/kapi.cxx (cyg_thread_delete): Implement it.
+
+1999-04-26 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/stress_threads.c: Commit a better version for Mark since I
+ happen to have it here; having addressed the main concern of my
+ approval process. It runs better in sims so long as the
+ constructor execution isn't messed with, nor timeslicing nor
+ priority inheritance.
+
+1999-04-23 Mark Galassi <rosalia@cygnus.com>
+
+ * tests/stress_threads.c (setup_death_alarm): shortened the
+ simulator time by another factor of 10, hoping that it will not
+ slow down nightly testing for simulator platforms too much.
+ (perform_stressful_tasks): added writing of a bit pattern to the
+ malloc()-ed spaces. Also reduced stack requirements for threads.
+
+1999-04-23 Hugo Tyson <hmt@masala.cygnus.co.uk>
+
+ * src/common/timer.cxx (Cyg_Timer::activate): we must also disable
+ the alarm when resetting it so as to remove it from its queue, so
+ that the enable afterwards places it on the right queue instead of
+ assuming that, being enabled, it's already there. (if not
+ enabling, the behaviour is unchanged and correct) This was
+ detected by uITRON tests[cx]4, with some random perms including
+ enable CYGIMP_KERNEL_COUNTERS_MULTI_LIST,
+ value CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE {8}.
+ The PR is 19475.
+
+1999-04-21 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/bin_sem1.cxx (bin_sem1_main): Doh! Use priorities 4 and 5
+ for the two threads so that they are unique (with a bitmap
+ scheduler, the threads had prios 0 and 1 resp, which causes an
+ assert in the attempt to set thread 0's prio to 1, "prios not
+ unique"). PR 19904.
+
+1999-04-20 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/kcache2.c:
+ Reduce iterations for time_ilock(), time_dlock(), and test_dzero()
+ if a simulated environment is detected
+ Fix for PR 19853
+
+1999-04-19 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/kill.cxx: Make delay ticks greater than 1 to prevent
+ scheduling problems if the clock rolls over immediately
+ Fix for PR 19516
+
+1999-04-20 Mark Galassi <rosalia@cygnus.com>
+
+ * tests/stress_threads.c: applied Hugo's patch to fix stack sizes.
+
+1999-04-19 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/bin_sem1.cxx (bin_sem1_main): Add priorities to the
+ threads so that they run sequentially like the tester expected.
+ Otherwise simple timing, and shorter timeslicing, causes failure
+ to be reported; likewise if the kernel happens not to run entry0
+ first!
+ (another checkin)
+ (bin_sem1_main): Add conditional use of set_priority on
+ CYGIMP_THREAD_PRIORITY as it should be.
+
+1999-04-14 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/debug/dbg_gdb.cxx: Fixed compiler warnings, cleaned up stub
+ requirements (removed FIX ME).
+
+1999-04-14 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * include/intr.hxx:
+ * src/intr/intr.cxx (call_pending_DSRs_inner): Rework calling of
+ DSRs to allow calls from HAL code. This will allow for proper
+ use of a separate interrupt stack.
+
+1999-04-14 Mark Galassi <rosalia@cygnus.com>
+
+ * tests/PKGconf.mak: added an ifndef for the AEB-1 board so that
+ stress_threads is only built conditionally.
+
+ * tests/stress_threads.c: added more config smarts suggested by
+ Jesper for his configurations.
+
+1999-04-13 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19822
+ * src/debug/dbg_gdb.cxx: Current thread's registers live in
+ registers, not _registers.
+
+1999-04-13 Mark Galassi <rosalia@cygnus.com>
+
+ * tests/stress_threads.c: simple stressing of thread
+ creation/deletion with some memory-intensive and alarm-based
+ tasks. This version is set so that it dies after DEATH_TIME_LIMIT
+ seconds, currently set to 120. #undef-ing DEATH_TIME_LIMIT makes
+ the test run forever. This is currently not working with the
+ bitmap scheduler, probably for some simple reason, but I have not
+ yet broken it down to see why.
+
+1999-04-12 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/except1.cxx:
+ * tests/kexcept1.cxx:
+ Remove now unnecessary tx39-specific setting of
+ CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS VSR
+ Part of cleanup for PR 19731
+
+1999-04-09 Hugo Tyson <hmt@cygnus.co.uk>
+
+ Generally: thread->to_queue_head() moves a thread to the head of
+ whatever queue it is on, if relevant. This is so that a thread
+ can change priority and then put itself at the front of its new
+ run queue instead of the end; otherwise it yields too, which may
+ be undesirable. Particularly for internal use of priorities in
+ the uITRON compatibility layer.
+
+ * include/thread.hxx (class Cyg_Thread): to_queue_head(): new
+ function. Define Cyg_Thread::rotate_queue() for all schedulers.
+ Public inheritance of Cyg_ThreadQueue_Implementation.
+
+ * include/thread.inl (class Cyg_Thread): to_queue_head(): new
+ function. Define Cyg_Thread::rotate_queue() for all schedulers.
+
+ * include/mlqueue.hxx (class Cyg_SchedThread_Implementation):
+ to_queue_head(), ...ThreadQueue...::to_head(): new functions.
+
+ * src/sched/mlqueue.cxx (class Cyg_SchedThread_Implementation):
+ to_queue_head(), ...ThreadQueue...::to_head(): new functions.
+
+ * include/bitmap.hxx (class Cyg_SchedThread_Implementation):
+ Add empty placeholders for rotate_queue() and to_queue_head() to
+ maintain commonality of interface.
+
+1999-04-08 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19667
+ * kernel/current/src/common/thread.cxx:
+ Removed obsolete Cyg_Thread constructor.
+
+ * kernel/current/tests/testaux.hxx:
+ * kernel/current/tests/thread0.cxx:
+ * kernel/current/tests/thread1.cxx:
+ Changed to use the new Cyg_Thread constructor.
+
+1999-04-08 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/common/kapi.cxx: Minor indentation fixes.
+
+1999-04-07 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19743
+ * include/mfiximpl.inl (Cyg_Mempool_Fixed_Implementation): Moved
+ argument assertions before the first use of the arguments.
+
+1999-04-07 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/kexcept1.c (except0_main):
+ * tests/except1.cxx (except0_main):
+ Use macro HAL_VSR_SET_TO_ECOS_HANDLER() if defined, to reset
+ likely exception handler VSRs to eCos' default handlers - the
+ target side equivalent to CYG_TEST_GDBCMD("handle SIGBUS nostop");
+ The VSR may not be the eCos standard one in some implementations
+ of cooperation with CygMon.
+
+1999-03-31 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h (CYGNUM_KERNEL_COUNTERS_RTC_PERIOD):
+ Fixed value of this option for TX39 66MHz to correct number.
+
+1999-03-25 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: More adjustments to get clock latency correct.
+ Some fine tuning of messages and layout to fit well within 80 columns.
+
+1999-03-24 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h: Fixed an ifdef error.
+
+1999-03-24 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx (NTEST_THREADS): Reduce # threads so test can
+ build on smaller machines. Also, only adjust timings by single
+ "overhead" value instead of the more generous 2*overhead.
+
+ * src/common/clock.cxx: Clock latency measurement defaults to 'off'.
+
+1999-03-23 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/kcache2.c: Reduced number of loops in time_ilock(). On the
+ MN10300 and TX39 this caused the test to timeout in the testing
+ farm.
+
+1999-03-23 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx:
+ * src/common/clock.cxx: Add 'measure_clock_latency' boolean which
+ is used to turn clock latency measurements on/off.
+
+1999-03-23 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/tm_basic.cxx (run_all_tests): Changed initial delay from
+ 100 ticks to 2. This is adequate for the purpose of letting the
+ clock get going, while 100 ticks was too long on simulators.
+
+1999-03-23 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/kcache1.c:
+ * tests/kcache2.c:
+ * tests/kclock1.c:
+ * tests/kexcept1.c:
+ * tests/kflag1.c:
+ * tests/kmbox1.c:
+ * tests/kmemfix1.c:
+ * tests/kmemvar1.c:
+ * tests/kmutex1.c:
+ * tests/ksched1.c:
+ * tests/ksem1.c:
+ * tests/kthread0.c:
+ * tests/thread0.cxx:
+ Use CYGNUM_HAL_STACK_SIZE_TYPICAL instead of "4096" and include
+ hal_arch.h where necessary to get it.
+
+1999-03-22 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/thread.inl (attach_stack):
+ Fix typo in assert; missing comma.
+
+1999-03-22 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * src/debug/dbg-thread-syscall.h: Update copyright
+
+1999-03-22 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/thread.inl:
+ * src/common/thread.cxx:
+ * tests/kthread1.c:
+ * tests/testaux.hxx:
+ * tests/thread1.cxx:
+ * tests/thread_gdb.c:
+ * tests/tm_basic.cxx:
+ Use CYGNUM_HAL_STACK_SIZE_TYPICAL for the stack size instead of
+ CYGNUM_HAL_MINIMUM_STACK_SIZE.
+ Except for stack checking and the idle thread stack which uses
+ CYGNUM_HAL_STACK_SIZE_MINIMUM.
+
+1999-03-19 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/kcache1.c:
+ * tests/kcache2.c:
+ Made all CYG_INTERRUPT_STATE variables register variables. The
+ value of this variable has to survive cache invalidation and does
+ not in some testing permutations that are unoptimized.
+ Fixes PR 19165.
+
+ * include/kapi.h: Type of cyg_tick_count_t changed to cyg_uint64.
+ Response to PR 19320.
+
+1999-03-19 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Much better analysis of clock interrupt times.
+ Print average deviation instead of variance. Also print "confidence"
+ numbers which are a measure of "how likely" a particular number would
+ be relative to the mean and min of the sample set.
+
+1999-03-17 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Improve messages and layout.
+ Better message for 'hardware clock tick' value.
+
+ * src/common/clock.cxx: Be more careful about clock latency delta
+ values that are used/kept - some hardware can yield incorrect values.
+
+ * tests/testaux.hxx: Use HAL recommended stack size for default.
+
+1999-03-16 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/common/thread.cxx:
+ Removed MIPS specific definition of idle_thread_stack[]. This is
+ so it gets the benefit of the redefinition of
+ CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE. This definition has also
+ been made static, since the MIPS compiler would otherwise put it
+ in the .data section.
+
+ * include/intr.hxx (class Cyg_Interrupt):
+ Changed implementation of Cyg_Interrupt::interrupts_enabled() to
+ test the value of disable_counter, rather than the hardware.
+
+1999-03-15 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/kcache1.c:
+ * tests/kcache2.c:
+ Added interrupt disables around cache operations. If these take
+ too long, an inopportune interrupt can disrupt the cache contents,
+ or result in the interrupt seeing an inconsistent world.
+
+1999-03-15 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Improved and cleaned up messages overall.
+
+1999-03-15 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19504
+ * tests/tm_basic.cxx: Kill created threads after mutex, mbox and
+ semaphore tests.
+
+1999-03-12 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/debug/dbg-thread-demux.c:
+ Only try handling the SPARClite-SLEB vector correctly if
+ CYG_HAL_USE_ROM_MONITOR_CYGMON ie. we are talking with CygMon.
+ Otherwise the code is wrong, but also not used. No matter.
+
+1999-03-12 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/kthread1.c:
+ * tests/thread1.cxx:
+ * tests/thread_gdb.c:
+ Deal with CYGNUM_HAL_MINIMUM_STACK_SIZE requirement.
+
+1999-03-12 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * include/thread.inl (attach_stack): Add check/assert for minimum
+ stack size (HAL defined)
+
+1999-03-11 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/debug/dbg-thread-demux.c (patch_dbg_syscalls):
+ Use the correct vector table slot for SPARClite-SLEB; it's not 15
+ on here, it's BSP_VEC_MT_DEBUG from the hal's hal_cygm.h
+
+1999-03-11 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/testaux.hxx:
+ Move definition of inline placement operator new outside of ifdef
+ for NTHREADS so that it can be used by other code.
+
+ * tests/intr0.cxx:
+ * tests/thread1.cxx:
+ Make use of placement operator new rather than dynamic one in
+ intr0. Removed duplicate definition from thread1.
+
+1999-03-11 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19472
+ * tests/kill.cxx: Increased delays for the synthetic target.
+
+1999-03-11 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19468
+ * tests/intr0.cxx (intr0_main):
+ * tests/kintr0.c (kintr0_main):
+ Only attach interrupt handlers to vectors not in use.
+
+1999-03-10 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19368
+ * src/sched/sched.cxx (start): Change the dependency for
+ referencing the RTC to make its inclusion independent of scheduler
+ choice.
+
+1999-03-10 Jesper Skov <jskov@cygnus.co.uk>
+ PR 17357
+ * src/intr/intr.cxx (attach): Assert that interrupt vector attach
+ will succeed.
+
+1999-03-10 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Changed names used to control clock frequency on TX39 target.
+
+1999-03-08 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * src/sync/mutex.cxx: Allow 'Cyg_Condition_Variable::wait()'
+ to be entered with the scheduler locked (and thsu exit in
+ the same state). This will allow for fully thread-safe use
+ of 'Cyg_Condition_Variable::wait()'.
+
+1999-02-26 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/except1.cxx (except0_main):
+ * tests/kexcept1.c (except0_main):
+ Move CYG_TEST_GDBCMD back to being before CYG_TEST_INIT
+
+1999-02-26 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19283
+
+ * src/common/kapi.cxx: Changed cyg_exception_call_handler
+ definition to be consistent with declaration.
+
+ * include/kapi.h: Change cyg_code_t to signed type.
+
+ * tests/except1.cxx (except0_main):
+ * tests/kexcept1.c (except0_main):
+ Init diag before making first output.
+
+1999-02-26 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19284
+ * tests/mutex2.cxx (mutex2_main): Set priorities in a different
+ order.
+
+1999-02-25 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/sched.hxx (class Cyg_Scheduler_Base):
+ Added CYGBLD_ATTRIB_ASM_ALIAS(cyg_scheduler_sched_lock) to
+ declaration of sched_lock member. This makes it have the given
+ name in the object and assembler files. This in turn eliminates
+ the need to have a C++ mangled name in the HAL.
+
+ * src/intr/intr.cxx:
+ Cyg_Interrupt::detach() was not translating the vector to a table
+ index correctly in the chained case. Fixed.
+
+1999-02-24 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/intr.hxx:
+ * src/intr/intr.cxx:
+ Added an interrupt disable counter to
+ Cyg_Interrupt::disable_interrupts() and
+ Cyg_Interrupt::enable_interrupts().
+
+1999-02-23 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Added support for 66MHz part.
+
+ * include/instrmnt.h:
+ Added CYG_INSTRUMENT_EVENT_MUTEX_RELEASE and
+ CYG_INSTRUMENT_EVENT_MUTEX_RELEASED. This should have been part of
+ the 1999-02-22 checkin.
+
+1999-02-23 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/clock0.cxx, tests/clock1.cxx, tests/except1.cxx,
+ tests/kcache1.c, tests/kcache2.c, tests/kclock0.c, tests/kclock1.c,
+ tests/kexcept1.c, tests/kflag0.c, tests/kflag1.c, tests/kill.cxx,
+ tests/kintr0.c, tests/kmbox1.c, tests/kmemfix1.c, tests/kmemvar1.c,
+ tests/kmutex0.c, tests/kmutex1.c, tests/ksched1.c, tests/ksem0.c,
+ tests/ksem1.c, tests/kthread0.c, tests/kthread1.c, tests/thread1.cxx:
+ Use CYG_TEST_NA() rather than CYG_TEST_PASS_FINISH() for tests that
+ are not applicable for this configuration
+
+1999-02-22 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/kapi.h:
+ * include/mutex.hxx:
+ * src/sync/mutex.cxx:
+ * src/common/kapi.cxx:
+ * tests/mutex2.cxx:
+ * tests/PKGconf.mak:
+ Added Kernel API support for thread release, which allows a thread
+ to be broken out of any wait. Also added support for releasing all
+ threads waiting to lock a mutex, both at C++ and Kernel API
+ levels. Added a test program, mutex2, to test this fuctionality
+ out.
+
+1999-02-20 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/except.hxx:
+ * include/kapidata.h
+ Rename CYG_EXCEPTION_COUNT -> CYGNUM_HAL_EXCEPTION_COUNT in line
+ with HAL changes
+ Rename deliver_exception() -> cyg_hal_deliver_exception()
+ QA improvements
+
+ * src/common/clock.cxx:
+ Rename CYG_VECTOR_RTC -> CYGNUM_HAL_INTERRUPT_RTC in line with
+ HAL changes
+
+ * src/common/except.cxx:
+ Rename CYG_EXCEPTION_* -> CYGNUM_HAL_EXCEPTION_* in line
+ with HAL changes
+ Allow for CYGNUM_HAL_EXCEPTION_MIN != 0
+ Rename deliver_exception() -> cyg_hal_deliver_exception()
+ Add more tracing, and fix some existing
+ QA improvements
+
+ * src/intr/intr.cxx:
+ Rename CYG_ISR_* -> CYGNUM_HAL_ISR_* in line with HAL changes
+ Add more tracing, and fix some existing
+ QA improvements
+
+ * src/sched/bitmap.cxx:
+ * src/sched/mlqueue.cxx:
+ * src/sync/mutex.cxx:
+ Add more tracing and fix some existing
+ QA improvements
+
+ * tests/except1.cxx:
+ * tests/kexcept1.c
+ Rename CYG_EXCEPTION_* -> CYGNUM_HAL_EXCEPTION_* in line
+ with HAL changes
+ QA improvements
+ Use new CYG_TEST_GDBCMD to tell GDB not to stop
+ Remove special simulator case as it should now work
+
+ * tests/intr0.cxx:
+ * tests/kintr0.c:
+ Rename CYG_ISR/VSR_* -> CYGNUM_HAL_ISR/VSR_* in line
+ with HAL changes
+ QA improvements
+
+1999-02-16 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/kexcept1.c (except0_main): Tell GDB to not stop on
+ SIGBUS or SIGSEGV since we know we're going to cause an exception
+
+1999-02-12 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/common/thread.cxx (idle_thread_stack):
+ Override CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE if
+ CYGNUM_HAL_MINIMUM_STACK_SIZE demands it.
+
+ * include/pkgconf/kernel.h (CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE):
+ Document that this option can be overridden by HALs demands.
+
+1999-02-11 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/debug/dbg-thread-syscall.h:
+ * src/debug/dbg-thread-demux.c:
+ Added handling of dbg_scheduler_func calls.
+
+1999-02-11 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/kapi.h:
+ * src/common/kapi.cxx:
+ Added API support for per-thread data.
+
+ * include/kapi.h:
+ * src/common/kapi.cxx:
+ * tests/ksem1.c:
+ * tests/tm_basic.cxx:
+ Changed arguments to Kernel C API semaphore functions to take
+ cyg_count32 rather than cyg_ucount32. This makes them consistent
+ with the underlying implementation and allows for negative counts
+ in the future. Changed some tests to match.
+ Fixes PR 17877.
+
+1999-02-08 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/kexcept1.c (entry0):
+ * tests/except1.cxx (entry0):
+ Don't call cause_exception on SIMs.
+
+1999-02-05 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/common/clock.cxx (isr): Ignore a latency of 0 when finding
+ min_clock_latency.
+
+1999-02-04 Jesper Skov <jskov@cygnus.co.uk>
+ PR 19075
+ * include/instrmnt.h: Slightly overdid the use of CYG_UNUSED_PARAM
+ macros.
+
+1999-02-04 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/intr/intr.cxx:
+ Make instrumentation macros always use the parameters to avoid
+ compiler warnings.
+
+1999-02-03 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18075
+ * tests/memfix1.cxx:
+ * tests/kmemfix1.c:
+ Make timing less sensitive.
+
+1999-02-02 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/bin_sem2.cxx: Fixed compiler warning.
+
+1999-02-02 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18971
+ * tests/bin_sem2.cxx (bin_sem2_main): Reduce run time in SIM.
+
+1999-02-01 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/kcache2.c: Added calls to HAL_DCACHE_SYNC() before all
+ relevant calls to HAL_DCACHE_DISABLE(). This should have been done
+ on 1999-01-25 where is was only done to one instance.
+
+1999-02-01 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Adjust stack sizes for platforms with
+ limited memory.
+
+1999-01-28 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/intr/intr.cxx: When using chained interrupts,
+ interrupt_end() is passed NULL as the intr argument. If
+ instrumentation is also enabled, the CYG_INSTRUMENT_INTR() calls
+ will try to indirect through zero. Added ifdefs to avoid
+ this. Also test intr for NULL before trying to post the DSR.
+ Fixes PR 18771.
+
+1999-01-28 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Fixed strings.
+
+1999-01-26 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/kcache1.c (time0): Waste much less time if running in a
+ simulator. Do only 40 loops instead of 4000.
+ In consequence the nasty meddling with MAX_STRIDE depending on
+ HAL_xxx_SIM package definitions can go.
+
+1999-01-26 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18902
+ * src/debug/dbg-thread-demux.c: Oops. Undid my change of 1999-01-21.
+
+1999-01-25 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * src/common/except.cxx: Make global exception initialisation object
+ be constructed at INTERRUPT priority
+
+1999-01-25 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18002
+ * tests/thread_gdb.c: Ensure that there are enough priorities.
+
+1999-01-25 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18875
+ * tests/tm_basic.cxx: Ensure that there are enough priorities.
+
+1999-01-25 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/kcache2.c (test_dstore): Added call to HAL_DCACHE_SYNC()
+ before disabling cache. On some architectures disabling the cache
+ would cause the following call to do nothing.
+ Fixes PR 18849.
+
+1999-01-22 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Don't run on Linux target.
+
+1999-01-21 Hugo Tyson <hmt@cygnus.co.uk>
+ These changes are to get tests working with the SPARClite port; it
+ doesn't do 8-byte register access unless it's properly aligned.
+
+ * tests/philo.cxx (cyg_start):
+ Use tests/testaux.hxx to get new threads, to get the alignment
+ required; see below.
+
+ * tests/thread2.cxx (thread2_main):
+ Use tests/testaux.hxx to get new threads, to get the alignment
+ required; see below.
+
+ * tests/tm_basic.cxx:
+ Larger stack for greedy processor.
+
+ * tests/testaux.hxx:
+ thread_obj[][] and stack[][] are now 8-byte aligned like certain
+ processors require; Cyg_Thread contains cyg_tick_count which is
+ 64-bit so any "standalone" C++ object would be so aligned. These
+ dynamically allocated ones should be too.
+
+1999-01-21 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18747
+ * tests/flag1.cxx: Increase delays/timeouts to prevent failure
+ when configured with full trace logging.
+
+1999-01-21 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/debug/dbg-thread-demux.c: Removed PR 17327 workarounds.
+
+1999-01-19 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * src/sched/sched.cxx (start):
+ CYG_REFERENCE_SYMBOL -> CYG_REFERENCE_OBJECT in line with
+ cyg_type.h change
+
+1999-01-19 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18824
+ * src/sync/mutex.cxx:
+ * include/pkgconf/kernel.h: Let
+ CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT require
+ CYGFUN_KERNEL_THREADS_TIMER.
+
+1999-01-18 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/dbg-thread-demux.c (patch_dbg_syscalls): Added test
+ for CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT in patch_dbg_syscalls().
+
+1999-01-15 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * include/mvarimpl.inl (free): Memory list sort was incorrect.
+
+ * tests/PKGconf.mak (TESTS): Don't build cache tests on
+ some platforms.
+
+1999-01-15 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18768
+
+ * tests/kmbox1.c:
+ * tests/mbox1.cxx:
+ Increase delays used so the overhead of GDB packets doesn't make
+ the tests fail.
+
+1999-01-14 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/sched/sched.cxx (start): Use new CYG_REFERENCE_SYMBOL macro.
+
+1999-01-14 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/dbg_gdb.cxx: Extended return types to include success,
+ fail and caller-do-it as required by msnyder.
+
+ * src/debug/dbg-thread-demux.c: Moved prototype of dbg_scheduler()
+ to dbg-threads-api.h.
+
+1999-01-13 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/sched/sched.cxx (start): Better implementation of the
+ real_time_clock reference.
+
+1999-01-13 Jesper Skov <jskov@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h: Disable CYGSEM_KERNEL_SCHED_TIMESLICE
+ in CYG_HAL_ROM_MONITOR magic.
+
+1999-01-07 Jesper Skov <jskov@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h: Added RTC values for i386/Linux.
+
+
+1999-01-12 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/dbg-thread-demux.c:
+ Changed API of patch_dbg_syscalls() to take a pointer to the start
+ of the vector and insert several vectors.
+
+ * src/debug/dbg_gdb.cxx:
+ Added dbg_scheduler() function to allow debuggers to lock and
+ unlock the scheduler. This helps when stepping multithreaded code.
+
+ * include/sched.hxx:
+ * include/sched.inl:
+ Added Cyg_Scheduler::unlock_simple() to decrement the lock without
+ rescheduling.
+
+1999-01-05 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18574
+
+ * src/sched/sched.cxx (start): Reference the real time clock to
+ ensure it is included when linking.
+
+1999-01-04 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/thread1.cxx:
+ * tests/mbox1.cxx:
+ * tests/kmbox1.c:
+ * tests/kill.cxx:
+ * tests/kflag1.c:
+ * tests/kclock1.c:
+ * tests/flag1.cxx:
+ * src/common/thread.cxx:
+ CYGFUN_KERNEL_THREADS_TIMER requires CYGVAR_KERNEL_COUNTERS_CLOCK
+ so don't check for the latter explicitly.
+
+1999-01-04 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18573
+
+ * tests/thread1.cxx:
+ * tests/mbox1.cxx:
+ * tests/kmbox1.c:
+ * tests/kflag1.c:
+ * tests/flag1.cxx:
+ Don't run tests that rely on delay() when delay() is only defined
+ as an empty function.
+
+1998-12-24 Bart Veer <bartv@cygnus.co.uk>
+
+ * src/sync/mutex.cxx:
+ * src/sync/mbox.cxx:
+ * src/sync/flag.cxx:
+ * src/sched/sched.cxx:
+ * src/mem/memvar.cxx:
+ * src/mem/memfixed.cxx:
+ * src/common/thread.cxx:
+ * src/common/clock.cxx:
+ * include/mempoolt.inl:
+ * include/mempolt2.inl:
+ * include/mboxt2.inl:
+ * include/mboxt.inl:
+ check_this() member functions should now be const
+
+1998-12-22 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/instrmnt.h: Fixed casts for arguments to
+ cyg_instrument() to work in C. Fixes PR 18413.
+
+1998-12-21 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h: Change AEB-1 clock scale.
+
+1998-12-17 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Calculate system clock resolution
+ based on 'CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION'
+
+1998-12-16 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h (CYGNUM_KERNEL_COUNTERS_RTC_PERIOD):
+ Add support for new ARM AEB-1.
+
+1998-12-16 Hugo Tyson <hmt@masala.cygnus.co.uk>
+
+ * tests/intr0.cxx (intr0_main):
+ * tests/kintr0.c (kintr0_main):
+ Conditionally use a different interrupt vector number on tx39 when
+ in the simulator (according to cyg_test_is_simulator) so that
+ these tests execute correctly in simulators.
+
+1998-12-16 Jesper Skov <jskov@cygnus.co.uk>
+ PR 18546
+
+ * tests/kill.cxx (cyg_start): Do NOP test if required kernel
+ functionality is disabled.
+
+1998-12-15 Jesper Skov <jskov@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h: Changed
+ CYGDBG_KERNEL_DEBUG_GDB_INCLUDE_STUBS to
+ CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS.
+
+1998-12-14 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Made use of cyg_mbox_get() conditional on
+ CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT.
+
+1998-12-14 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Added requirement for kernel RTC.
+
+1998-12-11 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/kcache2.c: Added tests of three more macros.
+
+1998-12-10 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/kcache2.c: Added tests of three more macros.
+
+1998-12-10 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/PKGconf.mak:
+ * tests/kcache2.c:
+ Added new cache test.
+
+1998-12-04 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/intr.hxx:
+ * src/intr/intr.cxx (cyg_interrupt_post_dsr): Added this function
+ to allow functions in the HAL, which are always only in C, to call
+ Cyg_Interrupt::post_dsr(). Have also returned post_dsr() to
+ private parts of Cyg_Interrupt.
+
+1998-12-04 Jesper Skov <jskov@cygnus.co.uk>
+
+ * include/intr.hxx (class Cyg_Interrupt): Made post_dsr public so
+ it can be called from HAL interrupt arbiters.
+
+1998-12-04 Jesper Skov <jskov@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h (CYGNUM_KERNEL_COUNTERS_RTC_PERIOD):
+ Set to the correct value for a 33.333MHz clock.
+
+1998-12-02 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/intr/intr.cxx (interrupt_end, chain_isr): Got rid of magic
+ interrupt constants.
+
+1998-11-30 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h: Fix spelling of CYGVAR_KERNEL_COUNTERS_CLOCK
+
+1998-11-25 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/common/thread.cxx (check_this): Check that stack_ptr is
+ within its limits.
+
+Wed Nov 25 18:45:12 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/sched.inl (unlock) (lock):
+ * src/common/thread.cxx (thread_entry):
+ * src/sched/sched.cxx (unlock_inner):
+
+ Ensure all accesses to sched_lock cannot be reordered by the
+ optimiser
+
+1998-11-24 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/common/thread.cxx (thread_entry): Prevent scheduler lock
+ from being released too early.
+
+1998-11-23 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ * src/common/clock.cxx:
+ Added CYGIMP_KERNEL_COUNTERS_SORT_LIST option to determine whether
+ the alarm lists in counters are sorted or not.
+
+ * tests/tm_basic.cxx: Added a test for many alarms firing
+ separately.
+
+1998-11-23 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/kcache1.c: Only run with stride 1 on SIMs.
+
+1998-11-19 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Insure appropriate kernel configuration for
+ building tool. Needs at least kernel C API and multi-level scheduler.
+
+1998-11-18 Gary Thomas <gthomas@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Add interrupt latency support. Print
+ results to 10ns accuracy.
+
+ * tests/PKGconf.mak: Add 'tm_basic' (the kernel timing test
+ program) to list of built tests.
+
+ * src/intr/intr.cxx: Change usage of HAL_INTERRUPT_MASK to have
+ trailing ';' to match similar macros.
+
+ * src/common/clock.cxx:
+ * include/pkgconf/kernel.h: Add CDL option
+ CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY used to define if interrupt
+ latency measurements should be built into kernel.
+
+1998-11-17 Jesper Skov <jskov@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h: Renamed CYG_HAL_POWERPC_MP860 to
+ CYG_HAL_POWERPC_MPC860.
+
+
+1998-10-28 David Moore <dsm@keema.cygnus.co.uk>
+
+ * include/pkgconf/kernel.h
+ (CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION): Changed default value for
+ MIPS simulator to be 0.01 secs instead of 0.001 seconds.
+
+1998-10-28 Jesper Skov <jskov@cygnus.co.uk>
+
+ * tests/kcache1.c (HAL_DCACHE_PURGE_ALL): Fixed compiler problem
+ on PowerPC.
+
+1998-10-27 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/kcache1.c:
+ Added calls to HAL_DCACHE_PURGE_ALL() before each test. Added
+ local version of HAL_DCACHE_PURGE_ALL() if this is not supplied by
+ the HAL.
+
+1998-10-27 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/common/thread.cxx (wake):
+ Remove the thread unconditionally from any queue it was on; for we
+ have just become not-asleep, so it must be OK. (Bug was: it
+ didn't happen in transit WAIT-SUSPEND -> SUSPEND, so synch object
+ still believed the task was waiting on it). PR#17998
+
+1998-10-26 Jesper Skov <jskov@cygnus.co.uk>
+ PR 17527, PR 17837
+
+ * tests/kcache1.c:
+ * tests/kclock0.c:
+ * tests/kclock1.c:
+ * tests/clock1.cxx:
+ * tests/clock0.cxx:
+ Do N/A PASS when kernel real-time clock is configured out.
+
+1998-10-26 Jesper Skov <jskov@lassi.cygnus.co.uk>
+ PR 17866
+
+ * include/pkgconf/kernel.h
+ (CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE): Doubled to prevent stack
+ overruns on PowerPC.
+
+1998-10-26 Jesper Skov <jskov@cygnus.co.uk>
+ PR 17987
+
+ * src/debug/dbg_gdb.cxx (dbg_threadinfo): Removed "more: <none>"
+ output.
+
+1998-10-23 John Dallaway <jld@cygnus.co.uk>
+
+ * tests/tm_basic.cxx: Added basic timing test.
+
+1998-10-23 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/instrmnt.h:
+ Improved documentation of cyg_instrument_enable() and
+ cyg_instrument_disable().
+
+ * src/instrmnt/meminst.cxx:
+ Added code to enable and disable whole groups of events.
+
+1998-10-23 Jesper Skov <jskov@lassi.cygnus.co.uk>
+
+ * include/generic-stub.h: Deleted. It was moved to hal common some
+ time ago.
+
+Fri Oct 23 04:45:12 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/kcache1.c:
+ Remove forced warning of a warning which no longer applies
+
+1998-10-22 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/common/clock.cxx:
+ Stop searching the alarm list when the current alarm is in the
+ future in Cyg_Counter::tick(). Changed sense of comparison in
+ Cyg_Counter::add_alarm() to sort alarms in ascending order.
+
+Thu Oct 22 18:21:50 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Fix commenting within CDL "comments"
+
+Thu Oct 22 17:25:45 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Remove CYGVAR_KERNEL_INSTRUMENT_EXTERNAL_BUFFER configuration
+ option. For PR 17838
+
+1998-10-21 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h (CYGNUM_KERNEL_COUNTERS_RTC_PERIOD):
+ Changed value for JMR3904 board to 15360 which is correct for a
+ 24.576MHz board rather than 25MHz as before.
+
+ * src/common/thread.cxx:
+ Exchanged stack_base and stack_size in idle thread constructor.
+
+1998-10-20 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/kflag1.c (kflag1_main):
+ Only mess with f2 if it exists, ie. CYGFUN_KERNEL_THREADS_TIMER.
+
+1998-10-19 Mark Galassi <rosalia@cygnus.com>
+
+ * include/pkgconf/kernel.h: updated the doc URL
+
+1998-10-19 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/kapi.h:
+ * include/kapidata.h (struct cyg_flag_t):
+ * src/common/kapi.cxx:
+ Add flags (Cyg_Flag, kernel.../flag.hxx) to the C API.
+
+ * tests/PKGconf.mak (TESTS):
+ Add new tests for flags via the C API.
+
+ * tests/kflag0.c:
+ * tests/kflag1.c:
+ New tests (well, versions of the plain C++ versions flag0.cxx and
+ flag1.cxx) for flags via the kernel C API.
+
+1998-10-19 Bart Veer <bartv@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Fixed description of clock resolution.
+
+1998-10-17 Bart Veer <bartv@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Added a way of configuring the clock interrupt frequency.
+
+Thu Oct 15 21:31:58 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Allow kernel to be disabled now
+
+ * src/common/delete.cxx, src/common/memcpy.c, src/common/memset.c:
+ Move these files to the infra package
+
+ * src/PKGconf.mak:
+ Don't build the above files any more
+
+ Above changes are required for PR 17229
+
+1998-10-15 Hugo Tyson <hmt@masala.cygnus.co.uk>
+
+ * include/mempoolt.inl (Cyg_Mempoolt):
+ * include/mempolt2.inl (Cyg_Mempolt2):
+ Flesh out the destructors to awaken any waiting threads
+ with reason Cyg_Thread::DESTRUCT to support uITRON
+ create and delete of memory pool objects.
+ Note that only template mempolt2 is actually used.
+
+Wed Oct 14 21:45:54 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/thread_gdb.c:
+ Remove unnecessary inclusion of <cyg/kernel/diag.h>
+
+ * tests/kcache1.c:
+ Add a warning to expect the "function declaration isn't a
+ prototype" warning from infra/diag.h
+
+1998-10-14 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/common/thread.cxx (kill,reinitialize):
+ Do not refer to member timer unless CYGFUN_KERNEL_THREADS_TIMER is
+ defined.
+
+1998-10-14 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/dbg-thread-demux.c:
+ Now get dbg-threads-api.h from HAL.
+
+ * src/debug/dbg_gdb.cxx:
+ Tidied up info sent back by dbg_threadinfo().
+
+ * src/common/thread.cxx:
+ Changed constructor of idle thread to include initial priority and
+ a thread name.
+
+ * include/pkgconf/kernel.h:
+ Moved GDB stub configuration code out to hal.h.
+
+ * include/ktypes.h:
+ Moved definition of CYG_LABEL_NAME() out to cyg_type.h.
+
+ * src/debug/PKGconf.mak:
+ * src/debug/dbg-threads-api.h:
+ * src/debug/generic-stub.c:
+ * src/debug/stubrom.c:
+ * src/debug/thread-packets.c:
+ * src/debug/thread-pkts.h:
+ These files have all be relocated to hal/common.
+
+1998-10-14 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/thread.hxx (class Cyg_Thread):
+ Add public members get_stack_base(), get_stack_size() and
+ get_stack_limit();
+ Add private members add_to_list() and remove_from_list() to
+ centralize handling of the CYGVAR_KERNEL_THREADS_LIST as it is
+ known.
+
+ * include/thread.inl (class Cyg_Thread):
+ Add public members get_stack_base(), get_stack_size() and
+ get_stack_limit();
+
+ * src/common/thread.cxx:
+ Add private members add_to_list() and remove_from_list() to
+ centralize handling of the CYGVAR_KERNEL_THREADS_LIST as it is
+ known.
+ Tidy up the two constructors to use them.
+ Add CYG_REPORT_RETURN()/_RETVAL(...) logging throughout.
+ Tidy up reinitialize() to use the 6-argument constructor,
+ thus preserving the thread name.
+ Fix some bugs in the CYGVAR_KERNEL_THREADS_LIST stuff where
+ re-adding a thread caused loops in the list, and the like.
+ Fix bug in set_priority() when the thread is asleep but NOT on any
+ queue, such as a plain counted_sleep().
+
+1998-10-14 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/debug/thread-packets.c:
+ * src/debug/dbg_gdb.cxx:
+ Don't include hal_stub.h unless it's really, really, really
+ needed.
+
+1998-10-14 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/debug/dbg_gdb.cxx: Don't include hal_stub.h unless it's really
+ needed.
+
+1998-10-13 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/debug/generic-stub.c: Added thread support. Renaming a few
+ functions/variables to match the most recent libstub
+ generic-stub.c.
+ Use thread_get_register & thread_put_register when handling GDB
+ register packets.
+
+ * src/debug/dbg_gdb.cxx (dbg_getthreadreg, dbg_getthreadreg):
+ DTRT for current thread when CygMon is not configured.
+
+ * src/debug/dbg_gdb.cxx (dbg_threadlist, dbg_getthreadreg,
+ dbg_getthreadreg): return true/false rather than 0, 1, -1.
+
+ * src/debug/dbg_gdb.cxx:
+ * src/debug/dbg-threads-api.h:
+ Added dbg_currthread_id.
+
+1998-10-08 Jesper Skov <jskov@lassi.cygnus.co.uk>
+
+ * src/debug/generic-stub.c:
+ * src/debug/generic-stub.h:
+ Added control of interrupts.
+ Removed unused functions set_debug_trap and initialize_stub.
+
+Tue Oct 13 17:36:29 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * src/test/tsttracc.c (cyg_start):
+ Replace CYG_REPORT_FUNCARGSVOID with the correct
+ CYG_REPORT_FUNCARGVOID
+
+1998-10-09 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/common/thread.cxx:
+ clear_timer() is a static which always affects the executing
+ thread and none other. Removed the "foo->" from various
+ "foo->clear_timer()" calls to make this less confusing.
+ Ditto set_timer().
+ Changed a "clear_timer()" call to "timer.disable()" and added one
+ so that they affect _this_ thread, the thread which is being
+ kill()ed or reinitialize()d rather than the killer or the
+ resuscitator. Otherwise the alarm list can still get a loop in
+ it when a thread's killed when waiting with a timeout and
+ restarted soon enough.
+
+1998-10-08 Hugo Tyson <hmt@cygnus.co.uk>
+
+ In general, these changes are to support create/delete of uITRON
+ objects; this requires that an object can be destroyed whilst
+ there are threads waiting on it, and that they shall be awoken
+ with a specific return code.
+
+ * include/thread.hxx:
+ Cyg_Thread::DESTRUCT added to wake reasons, to deal with an object
+ being destroyed whilst a thread is waiting on it; it's handled in
+ a manner very similar to release() and BREAK wake_reason.
+
+ * src/common/thread.cxx:
+ thread_entry(): threads now exit() if the entry_point returns.
+ Cyg_Thread() constructors now initialize wake_reason to NONE.
+ reinitialize() clears any pending timeout before calling
+ constructors.
+ counted_sleep( [timeout] ) now both deal with the wake reason in
+ general, and with DESTRUCT in particular.
+ exit() now clears any pending timeout.
+ kill() now force_resumes the thread first.
+ kill() now does not explicitly remove the thread from any queue
+ it's on; wake() does that for you anyway.
+ delay() clears the timer just in case and handles DESTRUCT
+ properly.
+ DESTRUCT added to various switches for completeness.
+
+ The fixes to counted_sleep()[x2] and kill() are a bugfix for
+ PR#17688.
+
+ * include/flag.hxx:
+ * src/sync/flag.cxx:
+ Add an argument, defaulting to 0, to the constructor which sets
+ the initial flag value.
+ Add handing of DESTRUCT wake reason.
+ Add a destructor which wakes all threads with DESTRUCT
+ wake_reason.
+
+ * include/mboxt2.inl:
+ Add handing of DESTRUCT wake reason.
+ Add a destructor which wakes all threads with DESTRUCT
+ wake_reason.
+
+ * src/sync/cnt_sem2.cxx:
+ Add handing of DESTRUCT wake reason.
+ Add a destructor which wakes all threads with DESTRUCT
+ wake_reason.
+ Correct typo in logic for queueing a waiting thread in
+ Cyg_Counting_Semaphore2::wait( cyg_tick_count abs_timeout ).
+ This is a bugfix for PR#17687.
+
+ * include/mboxt.inl:
+ * include/mempoolt.inl:
+ * include/mempolt2.inl:
+ * src/sync/bin_sem.cxx:
+ * src/sync/cnt_sem.cxx:
+ * src/sync/mutex.cxx:
+ All these gain handling of the DESTRUCT wake_reason, that's all.
+
+1998-10-08 Gary Thomas <gthomas@penang.cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Add support for new architecture
+
+1998-10-07 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/kcache1.c (entry0):
+ Replaced CYG_TEST_FINISH() with CYG_TEST_PASS_FINISH().
+
+ * src/debug/dbg-thread-demux.c:
+ Added dbg_thread_syscall_rmt_1() to save/set and restore the $gp
+ register values when being called from Cygmon.
+
+Sun Sep 27 20:12:15 1998 David Moore <dsm@keema.cygnus.co.uk>
+
+ * include/mlqueue.hxx:
+ * include/bitmap.hxx:
+ Disallow more than 32 priority levels
+
+ * include/pkgconf/kernel.h:
+ Changed range of allowed levels from 64 to 32
+
+1998-09-27 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/memfix2.cxx:
+ Changed message to say "Fixed memory pool 2 OK" rather than
+ "Variable memory pool 2 OK".
+
+1998-09-26 Bart Veer <bartv@cygnus.co.uk>
+
+ * include/intr.hxx (DSRs_pending):
+ PR 17500: if DSR support is disabled completely then this inline
+ function should not be defined at all.
+
+1998-09-26 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/kcache1.c:
+ Added this test program for cache API. Includes some performance
+ testing.
+
+1998-09-25 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/dbg_gdb.cxx:
+ Removed some debugging code.
+
+ * tests/thread_gdb.c:
+ Added this test program to allow for GDB thread support testing.
+
+1998-09-25 Bart Veer <bartv@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ The GDB thread support requires the kernel to keep track of all
+ threads on a linked list. This is a separate option. An additional
+ requires statement enforces the dependency.
+
+1998-09-25 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/dbg-thread-demux.c:
+ Added include of <pkgconf/kernel.h>, removed debug code.
+
+1998-09-24 Bart Veer <bartv@cygnus.co.uk>
+
+ * src/debug/dbg-thread-demux.c (dbg_thread_syscall_rmt):
+ PR 17327. If kernel gdb thread support is disabled, do not compile
+ in the relevant cases in the rmt switch statement. This is a
+ partial solution to the general problem of how the HAL, kernel,
+ cygmon, and gdb interact.
+
+1998-09-24 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/common/clock.cxx (Cyg_RealTimeClock):
+ Changed clock priority from zero to one, since it is now used to
+ set the hardware interrupt priority.
+
+ * src/intr/intr.cxx:
+ Cyg_Interrupt::chain_isr() now only calls interrupt objects that
+ have the matching vector number.
+ Call HAL_INTERRUPT_SET_LEVEL() when attaching interrupts using the
+ priority passed in the constructor.
+ Added call to HAL_TRANSLATE_VECTOR() for attaching chained
+ interrupts.
+
+ * include/instrmnt.h (CYG_INSTRUMENT_EVENT_INTR_CHAIN_ISR):
+ Added this event.
+
+Thu Sep 24 11:07:12 1998 David Moore <dsm@keema.cygnus.co.uk>
+
+ * tests/except1.cxx:
+ * tests/kexcept1.cxx:
+ Made exception tests detect when CYGPKG_KERNEL_EXCEPTIONS
+ is disabled.
+
+
+1998-09-22 Bart Veer <bartv@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Changed the kernel package from type bool to type dummy, since
+ it is not yet possible to disable this package.
+
+1998-09-20 Mark Galassi <rosalia@cygnus.com>
+
+ * include/pkgconf/kernel.h: updated CDL doc strings.
+ fixed some typos in my doc strings.
+
+1998-09-18 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/common/thread.cxx:
+ * include/thread.inl:
+ Modified threads list from a LIFO stack to a ring so that we can
+ add new ones to the end and present the threads to GDB in an order
+ that more closely matches how it assigns thread ids.
+
+Wed Sep 16 19:11:22 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/thread.inl (get_unique_id):
+ Move this declaration to before its first use, so that the user
+ knows it is inline at the point of use. Avoids a warning.
+
+Wed Sep 16 08:49:48 1998 Jesper Skov <jskov@cygnus.co.uk>
+ PR 17269
+
+ * src/common/except.cxx (Cyg_Exception_Control): Replaced
+ CYGNUM_EXCEPTION_MAX (bug!) with CYG_EXCEPTION_COUNT.
+
+ * include/kapidata.h (struct cyg_exception_conrol): Replaced
+ CYG_EXCEPTION_MAX (bug!) with CYG_EXCEPTION_COUNT.
+
+ * src/intr/intr.cxx:
+ * include/intr.hxx (class Cyg_Interrupt): Replaced CYG_ISR_MAX+1
+ with CYG_ISR_COUNT.
+
+ * include/except.hxx: Replaced CYGNUM_EXCEPTION_COUNT with
+ CYG_EXCEPTION_COUNT.
+
+ * tests/kintr0.c:
+ * tests/intr0.cxx: Replaced CYG_ISR_MAX (bug!) with
+ CYG_ISR_COUNT.
+
+Tue Sep 15 19:19:37 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/mboxt2.hxx:
+ Add inclusion of thread.inl to silence warning
+
+ * tests/kexcept1.c:
+ Insert void as parameter list of __default_exception_vsr() to
+ silence warning
+
+Tue Sep 15 19:16:52 1998 David Moore <dsm@keema.cygnus.co.uk>
+
+ * src/sched/sched.cxx: Cleaned up comments.
+
+1998-09-15 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/dbg-thread-demux.c:
+ Stubbed out led() function.
+
+ * src/debug/dbg_gdb.cxx:
+ Decide whether to byteswap thread id depending on reported byte
+ order of target.
+ Many small changes to debug code.
+
+ * include/thread.inl (init_context):
+ Changed CYG_DEBUG to CYGPKG_INFRA_DEBUG.
+
+Tue Sep 15 09:35:14 1998 Jesper Skov <jskov@cygnus.co.uk>
+ PR 17236
+
+ * src/common/clock.cxx (add_alarm): A retriggering alarm called
+ with a trigger time in the past or now will be assigned a new
+ trigger time. Don't find the counter list until the final trigger
+ time is known.
+ Also added a few #else error statements to catch a situation where
+ no CYGIMP_KERNEL_COUNTERS_x_LIST implementation config is
+ selected.
+
+ * tests/clock0.cxx: Added extra ASSERT to ensure alarms enabled
+ with a trigger time of now or in the past actually fire.
+ * tests/kclock0.c: Same.
+
+1998-09-15 Bart Veer <bartv@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Cleaning up coonfiguration data (mostly improving the
+ descriptions).
+
+Mon Sep 14 11:08:59 1998 Jesper Skov <jskov@lassi.cygnus.co.uk>
+ PR 17230
+
+ * include/pkgconf/kernel.h: CYGIMP_KERNEL_INTERRUPTS_CHAIN
+ requires CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN.
+
+1998-09-14 Mark Galassi <rosalia@cygnus.com>
+
+ * include/pkgconf/kernel.h: started adding CDL doc fields.
+
+1998-09-12 Bart Veer <bartv@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Sort out exception handling options (PR 16953)
+ Added missing descriptions (PR 17184)
+
+Fri Sep 11 19:18:28 1998 Hugo Tyson <hmt@masala.cygnus.co.uk>
+
+ * include/clock.hxx (class Cyg_Alarm):
+ * src/common/clock.cxx (Cyg_Alarm::add_alarm):
+ PR#17182
+ Move the code to synchronize a repeating alarm which had been
+ firing in the dim and distant past with times in the future, which
+ had been inline in Cyg_Alarm::enable(), into a function of its
+ own, Cyg_Alarm::synchronize(). Call it from Cyg_Alarm::enable()
+ and also from add_alarm() when the immediate time to fire is now
+ or in the past; otherwise an initial time of, say, NOW-10 with an
+ interval of 5 would just get lost. Also corrected/commented the
+ logic there to allow an alarm's handler to cancel itself.
+
+Wed Sep 9 17:43:26 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/common/delete.cxx:
+ Control the provision of empty delete functions rather better, via
+ an explicit option from the libc package. Read the rather lengthy
+ comment in delete.cxx for the explanation.
+ Also note that the correct place for this functionality is in the
+ infrastructure, and the same should be done for the C++ new
+ functions also.
+
+1998-09-09 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/common/thread.cxx:
+ combined separate next_unique_id variables in both constructors.
+ This would have caused duplicate thread ids to be generated.
+
+ * include/thread.inl:
+ Added code to initialize Cyg_HardwareThread::saved_context.
+
+ * src/debug/dbg-thread-demux.c:
+ * src/debug/dbg_gdb.cxx:
+ Many changes to get thread API working with Cygmon. Debug code
+ currently left in place until complete testing is possible.
+
+Tue Sep 8 17:17:32 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h (CYGNUM_KERNEL_COUNTERS_RTC_PERIOD):
+ Set up a sensible default RTC for CYG_HAL_MN10300_SIM different
+ from that for the MN103002 or CYG_HAL_MN10300_STDEVAL1, so that
+ sim tests run in less than geological time. This is the same as
+ the default value of before.
+
+Fri Sep 4 18:25:02 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/sched/mlqueue.cxx (timeslice):
+ * src/sched/sched.cxx (unlock_inner):
+ Condition out the tracing macros here by default, for tracing
+ these consumes the whole quantum.
+
+1998-09-04 Bart Veer <bartv@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Commented out the ROM monitor-specific option settings for now.
+
+ * tests/kclock1.c:
+ * include/pkgconf/kernel.h:
+ * include/kapidata.h (struct cyg_counter):
+ Fixed typos in configuration option names.
+
+1998-09-03 David Moore <dsm@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h
+ (CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE):
+ Fixed typo in configuration option name.
+
+ * src/intr/intr.cxx:
+ Fixed typo in configuration option name.
+ Fixed cast to incorrect type.
+
+1998-09-03 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/PKGconf.mak (COMPILE):
+ Added debug/dbg-thread-demux.c to COMPILE list.
+
+ * src/debug/dbg_gdb.cxx (dbg_threadinfo):
+ Added first cut at providing thread state string.
+
+ * src/debug/dbg-thread-syscall.h:
+ * src/debug/dbg-thread-demux.c:
+ Added these two files to implement the interface between Cygmon
+ and eCos.
+
+1998-09-03 Bart Veer <bartv@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h (CYGSEM_KERNEL_MEMORY_COALESCE):
+ * include/mvarimpl.inl (Cyg_Mempool_Variable_Implementation):
+ Fixed typo in configuration option name.
+
+ * include/pkgconf/kernel.h:
+ Fixed type in configuration option name.
+
+Wed Sep 2 19:01:02 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/mboxt.hxx:
+ * include/mboxt.inl:
+ * include/mboxt2.hxx:
+ * include/mboxt2.inl:
+ * include/mempolt2.hxx:
+ * include/mempolt2.inl:
+ * include/mempoolt.hxx:
+ * include/mempoolt.inl:
+ * include/sema2.hxx:
+ * src/sync/cnt_sem2.cxx:
+ * include/flag.hxx:
+ * src/sync/flag.cxx:
+ * include/kapi.h:
+ * src/common/kapi.cxx:
+ * tests/kmbox1.c:
+ * tests/kmemfix1.c:
+ * tests/kmemvar1.c:
+ * tests/mbox1.cxx:
+ * tests/memfix1.cxx:
+ * tests/memvar1.cxx:
+ Memory pool (both types) and message boxes (both types) and flags
+ and cnt_sem2-type semaphores now all have absolute timeouts
+ instead of relative ones in the timely wait functions.
+ uITRON has changed to add the current time itself.
+ Kapi changes are mainly name changes to make it clear that
+ timeouts are now absolute.
+ The tests (incl. kapi) add in the time themselves now.
+
+1998-09-01 Tim Goodwin <tgoodwin@cygnus.co.uk>
+
+ * include/kapi.h:
+ * src/common/kapi.cxx:
+ * tests/kclock1.c:
+ * tests/kexcept1.c:
+ * tests/kmbox1.c:
+ * tests/kmemfix1.c:
+ * tests/kmemvar1.c:
+ * tests/kmutex1.c:
+ * tests/ksched1.c:
+ * tests/ksem1.c:
+ * tests/kthread0.c:
+ * tests/kthread1.c:
+ * src/test/kcache1.c:
+ * src/test/kphilo.c:
+ * tests/kphilo.c:
+ * tests/lottery.c:
+ Changes to cyg_thread_create() interface.
+
+Tue Sep 1 18:49:06 1998 Hugo Tyson <hmt@masala.cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Moved and renamed CYG_DIAG_USE_DEVICE to infra and to
+ CYGDBG_INFRA_DIAG_USE_DEVICE; kernel.h now includes infra.h as
+ well as hal.h to ensure all its clients get the info too.
+
+ * include/intr.hxx (class Cyg_Interrupt):
+ Add static member interrupts_enabled() to poll the current status;
+ just to avoid calling the HAL directly, really.
+
+ * include/diag.h:
+ Now just includes cyg/infra/diag.h, so that kernel-specific
+ features can be added later - original diag.h has moved to infra,
+ and is that includee.
+
+ * src/PKGconf.mak:
+ Trace folder and its contents elided, now in infra.
+
+ * src/trace/diag.c:
+ * src/trace/fancy.cxx:
+ * src/trace/null.cxx:
+ * src/trace/simple.cxx:
+ * src/trace/tcdiag.cxx:
+ Deleted; all moved to infra, actually.
+
+1998-09-01 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/dbg-threads-api.h:
+ * src/debug/dbg_gdb.cxx:
+ Converted threadref from long long to char[8] as defined by Cygmon
+ guys.
+
+ * src/common/thread.cxx:
+ Added scheduler lock around manipulations of thread list.
+
+ * include/except.hxx:
+ Now use CYG_EXCEPTION_COUNT to size handler arrays.
+
+Mon Aug 31 17:53:12 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/memfixed.hxx, include/mempolt2.hxx, include/mempolt2.inl,
+ include/mempoolt.hxx, include/mempoolt.inl, include/memvar.hxx,
+ include/mvarimpl.hxx, include/mvarimpl.inl, src/mem/memfixed.cxx,
+ src/mem/memvar.cxx:
+
+ Add new get_allocation_size() method to return the size of a
+ previously allocated block - trivial for fixed block allocator, and
+ requiring a bit of poking around for the variable block allocator.
+
+ This is required for the C library realloc() implementation. Strictly
+ this only uses the variable block allocator, but the API can only be
+ enhanced by also updating the template. As a result, this also meant
+ doing it for the fixed block allocator.
+
+Mon Aug 31 09:51:37 1998 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/debug/stubrom.c (cyg_start): Renamed from main().
+
+Mon Aug 31 09:00:01 1998 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/common/thread.cxx: Fixed typo.
+
+1998-08-28 Bart Veer <bartv@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h, include/bitmap.hxx, include/clock.hxx,
+ include/except.hxx, include/flag.hxx, include/instrmnt.h,
+ include/intr.hxx, include/kapi.h, include/kapidata.h,
+ include/mbox.hxx, include/mboxt.hxx, include/mboxt.inl,
+ include/mboxt2.hxx, include/mboxt2.inl, include/memfixed.hxx,
+ include/mempolt2.hxx, include/mempolt2.inl,
+ include/mempoolt.hxx, include/mempoolt.inl, include/memvar.hxx,
+ include/mlqueue.hxx, include/mutex.hxx, include/mvarimpl.inl,
+ include/sched.hxx, include/sema.hxx, include/sema2.hxx,
+ include/thread.hxx, include/thread.inl,
+ include/pkgconf/kernel.h:
+ src/common/clock.cxx, src/common/except.cxx,
+ src/common/kapi.cxx, src/common/thread.cxx,
+ src/debug/dbg_gdb.cxx, src/debug/generic-stub.c,
+ src/instrmnt/meminst.cxx, src/instrmnt/nullinst.cxx,
+ src/intr/intr.cxx, src/mem/memfixed.cxx, src/mem/memvar.cxx,
+ src/sched/bitmap.cxx, src/sched/lottery.cxx,
+ src/sched/mlqueue.cxx, src/sched/sched.cxx,
+ src/sync/cnt_sem.cxx, src/sync/cnt_sem2.cxx, src/sync/flag.cxx,
+ src/sync/mbox.cxx, src/sync/mutex.cxx, src/test/diag.cxx,
+ src/test/kcache1.c, src/test/main.cxx, src/test/timer.cxx,
+ src/test/tstmbox.cxx:
+ tests/clock0.cxx, tests/clock1.cxx, tests/except1.cxx,
+ tests/flag1.cxx, tests/intr0.cxx, tests/kclock0.c,
+ tests/kclock1.c, tests/kexcept1.c, tests/kintr0.c,
+ tests/kmbox1.c, tests/kmemfix1.c, tests/kmemvar1.c,
+ tests/kmutex0.c, tests/kmutex1.c, tests/ksched1.c,
+ tests/ksem0.c, tests/ksem1.c, tests/kthread0.c,
+ tests/kthread1.c, tests/lottery.c, tests/mbox1.cxx,
+ tests/memfix1.cxx, tests/memvar1.cxx, tests/sync3.cxx,
+ tests/thread2.cxx :
+ Provide configuration data and rename configuration options
+
+Fri Aug 28 15:27:31 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/trace/fancy.cxx:
+ * src/trace/simple.cxx:
+ * src/trace/null.cxx:
+ Condition on newly named symbols from the infra package, whence
+ these units will be moved soon.
+
+Fri Aug 28 09:33:17 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * src/test/demo.cxx, src/test/kcache1.c, src/test/kphilo.c,
+ src/test/main.cxx, src/test/philo.cxx, src/test/sload.c,
+ src/test/timer.cxx, src/test/tstflag.cxx, src/test/tstmbox.cxx,
+ src/test/tstmpf.cxx, src/test/tstmpool.cxx, src/test/tsttracc.c,
+ src/test/tsttrace.cxx, tests/bin_sem0.cxx, tests/bin_sem1.cxx,
+ tests/bin_sem2.cxx, tests/clock0.cxx, tests/clock1.cxx,
+ tests/cnt_sem0.cxx, tests/cnt_sem1.cxx, tests/except1.cxx,
+ tests/flag0.cxx, tests/flag1.cxx, tests/intr0.cxx, tests/kclock0.c,
+ tests/kclock1.c, tests/kexcept1.c, tests/kill.cxx, tests/kintr0.c,
+ tests/kmbox1.c, tests/kmemfix1.c, tests/kmemvar1.c, tests/kmutex0.c,
+ tests/kmutex1.c, tests/kphilo.c, tests/ksched1.c, tests/ksem0.c,
+ tests/ksem1.c, tests/kthread0.c, tests/kthread1.c, tests/lottery.c,
+ tests/mbox1.cxx, tests/memfix1.cxx, tests/memfix2.cxx,
+ tests/memvar1.cxx, tests/memvar2.cxx, tests/mutex0.cxx,
+ tests/mutex1.cxx, tests/philo.cxx, tests/release.cxx,
+ tests/sched1.cxx, tests/sync2.cxx, tests/sync3.cxx,
+ tests/thread0.cxx, tests/thread1.cxx, tests/thread2.cxx:
+ Change entry points from main() to cyg_start(), and remove return
+ codes - while main returned an int, cyg_start() returns void. It has
+ no meaning anyway - what could you do with the code?
+
+ * src/test/tsttracc.c, src/test/tsttrace.cxx:
+ Also change trace calls (CYG_REPORT_...) to reflect that it is a
+ function called cyg_start with no args returning void, rather than
+ what it was for main(argc, argv)
+
+Fri Aug 28 09:24:41 1998 Jesper Skov <jskov@cygnus.co.uk>
+
+ * src/debug/generic-stub.c: Moved strcpy/strlen from hal-stub to
+ generic-stub. Cleaned up a bit to avoid compiler warnings.
+
+Thu Aug 27 19:22:51 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * tests/kphilo.c (Philosopher):
+ * tests/philo.cxx (Philosopher):
+ * src/test/philo.cxx (Philosopher):
+ * src/test/kphilo.c (Philosopher):
+ * src/common/kapi.cxx:
+ Change CYG_RELEASE_DEBUG to CYGPKG_INFRA_DEBUG.
+ These changes are self-contained, so they can go in right now.
+
+Thu Aug 27 15:20:31 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/mvarimpl.inl (free):
+ Remove a couple of warning due to pointer comparison without casts
+ in coallesce(sic.) code.
+
+1998-08-26 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/kapidata.h:
+ Added saved_context to cyg_hardwarethread structure to track
+ GDB support in rest of kernel.
+
+1998-08-25 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Added CYGIMP_KERNEL_THREAD_GDB_SUPPORT to configure for GDB
+ interactions with the kernel.
+
+ * src/debug/dbg-threads-api.h:
+ * src/debug/dbg_gdb.cxx:
+ Added these files to repository to support GDB interactions
+ with the kernel. Note that dbg-threads-api.h is a copy of a
+ file in devo/libstub. Any changes there must be merged in here
+ too.
+
+ * src/PKGconf.mak:
+ Added debug/dbg_gdb.cxx to COMPILE list.
+
+ * include/thread.inl:
+ * include/thread.hxx:
+ Added support for GDB, specifically for thread-aware debugging.
+
+ * include/intr.hxx:
+ * src/intr/intr.cxx:
+ Added an extra argument to interrupt_end(): a pointer to
+ the saved register state. This is optionally used to provide
+ a more interesting saved register state for GDB.
+
+Tue Aug 25 02:36:26 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/generic-stub.h:
+ Add void to empty prototype argument lists to silence compiler
+ warnings
+
+Fri Aug 21 18:46:34 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * src/common/clock.cxx (enable):
+ Make the maths work right if we only just set up the clock
+ thingy. Unsigned has a lot to answer for; when the next scheduled
+ tick was all correct, the delta was -1, which correctly rounds to
+ zero in the division. But it isn't -1 it's 18446744073709551615
+ which gave a shift of 15 in the the uITRON test programs.
+
+Fri Aug 21 11:40:50 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/mboxt2.inl (put):
+ * include/mempolt2.inl (alloc):
+ Tidy Nick's changes (1998-07-27) for set_timer() semantics a bit,
+ make it a bit more efficient and smaller code.
+
+Thu Aug 20 17:37:35 BST 1998 Chris Provenzano <proven@cygnus.com>
+
+ * include/mvarimpl.inl, include/pkgconf/kernel.h:
+ Added memory coallecsing to the variable size memory allocator.
+ This option is enabled my default.
+
+ * tests/stdlib/malloc2.c: Only print 50 messages, not 500.
+
+1998-08-20 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Moved definition of CYG_KERNEL_USE_INIT_PRIORITY from here
+ to hal.h.
+
+ * include/thread.hxx:
+ Changed argument to cyg_thread_entry() to CYG_ADDRWORD from
+ CYG_ADDRESS.
+
+ * include/ktypes.h:
+ Moved constructor priority ordering stuff out to infra/cyg_type.h.
+
+ * include/kapi.h:
+ * src/common/kapi.cxx:
+ Added name and priority parameters to cyg_thread_create() and
+ swapped stack size and base parameters. These changes are
+ currently protected by DAY_OF_CHAOS ifdefs and are therefore
+ inactive.
+
+Wed Aug 19 19:06:16 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * tests/bin_sem1.cxx, tests/bin_sem2.cxx, tests/cnt_sem1.cxx,
+ tests/flag1.cxx, tests/mbox1.cxx, tests/memfix2.cxx,
+ tests/memvar2.cxx, tests/sync2.cxx, tests/sync3.cxx,
+ tests/thread2.cxx, tests/release.cxx, tests/kill.cxx:
+ Reorder inclusion of thread.inl to silence warnings
+
+Wed Aug 19 18:48:03 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/kernel.hxx:
+ Reorder inclusion of thread.inl to silence warnings
+
+Wed Aug 19 18:21:31 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * src/common/kapi.cxx, src/sync/flag.cxx:
+ Reorder inclusion of thread.inl to silence warnings
+
+ * src/sync/bin_sem.cxx, src/sync/cnt_sem.cxx, src/sync/cnt_sem2.cxx,
+ src/sync/mbox.cxx:
+ Add inclusion of thread.inl to silence warnings
+
+ * src/common/memset.c:
+ Make pointer arithmetic be on char *, not void * to silence warnings
+
+ * include/diag.h, src/trace/diag.c:
+ Make diag_init take void parameter, and give diag_printf explicit
+ parameters in prototypes to silence warnings
+
+1998-08-19 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ * src/common/thread.cxx:
+ Added ifdef for CYGIMP_IDLE_THREAD_YIELD to support single
+ priority configurations.
+
+Tue Aug 18 16:56:38 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/thread.hxx, include/thread.inl:
+ To silence compiler warnings, move register_exception inline definition
+ from the .hxx to the .inl. Also move attach_stack to before the
+ constructor where it is invoked from.
+
+1998-08-18 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Moved all HAL specific config options out to a HAL config file.
+
+ * include/kapi.h:
+ * src/common/kapi.cxx:
+ Added cyg_scheduler_lock() and cyg_scheduler_unlock() to provide
+ user access to the scheduler lock.
+
+Mon Aug 17 21:39:20 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/kapi.h:
+ Insert "void" to empty parameter lists to silence warnings
+
+Fri Aug 14 18:10:20 1998 Hugo Tyson <hmt@masala.cygnus.co.uk>
+
+ * src/common/thread.cxx (exit):
+ Set the state explicitly to EXITED rather than or'ing
+ it in; should be safe cos it's what kill does in the normal case.
+ Needed to avoid suspend sort of states persisting after death.
+ One character changes are always aesthetically pleasing.
+
+Fri Aug 14 17:28:01 1998 Hugo Tyson <hmt@cygnus.co.uk>
+
+ * include/pkgconf/kernel.h:
+ Add config options as below:
+
+ * src/common/thread.cxx:
+ Add asserts of CYGNUM_KERNEL_MAX_COUNTED_WAKE_COUNT_ASSERT
+ and CYGNUM_KERNEL_MAX_SUSPEND_COUNT_ASSERT if they are defined.
+ Also lazily tidied format of func hdrs as per code review et al.
+
+1998-08-14 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/kapidata.h:
+ Added support for thread names and thread housekeeping list.
+
+ * src/common/delete.cxx:
+ Added include for cyg_type.h.
+
+ * include/pkgconf/kernel.h:
+ Added CYGIMP_THREAD_NAME and CYGIMP_THREAD_LIST options.
+
+ * include/thread.inl:
+ * include/thread.hxx:
+ Added support for thread names and thread housekeeping list.
+
+ * src/common/thread.cxx:
+ Added support for thread names and thread housekeeping list.
+ Fixed ordering bug in Cyg_Thread::delay().
+
+Thu Aug 13 15:33:48 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * include/ktypes.h:
+ Remove inlined new and delete as they aren't strictly permitted and
+ they prevent a valid new and delete being defined anywhere else!
+
+ * src/common/delete.cxx, src/PKGconf.mak:
+ Add delete.cxx to provide default delete operation for when a C
+ library isn't present
+
+1998-07-28 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/thread.hxx, include/sched.hxx, include/mlqueue.hxx,
+ include/lottery.hxx, include/bitmap.hxx, src/common/thread.cxx,
+ src/sched/sched.cxx, src/sched/mlqueue.cxx, src/sched/lottery.cxx,
+ src/sched/bitmap.cxx:
+ Added an alternative constructor to Cyg_Thread which takes
+ arguments in new order, and includes a scheduling parameters
+ argument. Propagated effects of this through Cyg_SchedThread
+ and Cyg_SchedThread_Implementation. This mostly takes the form
+ of passing the scheduling parameters through to the constructors.
+
+1998-07-27 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/sync/flag.cxx, src/sync/cnt_sem2.cxx, include/mempoolt.inl,
+ include/mempolt2.inl, include/mboxt2.inl, include/mboxt.inl:
+ Modified code in API calls that take a timeout to allow for a
+ timeout in the past.
+ NOTE: The timeouts have for now been left as relative delays, they
+ should be converted to absolute timeouts.
+
+ * src/common/thread.cxx:
+ Modified code in counted_sleep to allow for a timeout in the past.
+ Added handling of EXIT wake_reason in delay().
+
+1998-07-24 Nick Garnett <nickg@cygnus.co.uk>
+
+ * include/thread.inl:
+ Reordered code in Cyg_Thread::set_timer() to init the timer after
+ wake_reason has been assigned.
+
+ * include/clock.inl:
+ Removed Cyg_Alarm::enable().
+
+ * src/sync/mutex.cxx (Cyg_Condition_Variable::wait):
+ Modified order of code in timed version of wait to allow for a
+ timout in the past.
+
+ * src/sync/cnt_sem.cxx (Cyg_Counting_Semaphore::wait):
+ Modified order of code in timed version of wait to allow for a
+ timout in the past. Also modified timeout to be absolute rather
+ than relative.
+
+ * src/common/thread.cxx (Cyg_Thread::wake):
+ Added test for whether a thread is actually asleep before waking
+ it. Allows us to apply wake() to awake threads without damage.
+
+ * src/common/clock.cxx:
+ Added code to Cyg_Counter::add_alarm() to deal with alarms
+ that trigger now or in the past.
+ Moved Cyg_Alarm::enable() here. Added code to do the right thing
+ when reenabling previously disabled interval alarms.
+
+1998-07-23 Nick Garnett <nickg@cygnus.co.uk>
+
+ * src/debug/stubrom.c: Added header comments.
+
+Thu Mar 26 18:25:36 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * src/test/philo.cxx:
+ Rename CYG_DEBUG ifdef to CYG_RELEASE_DEBUG
+
+Wed Mar 25 23:23:39 GMT 1998 Chris Provenzano <proven@cygnus.com>
+
+ * configure.in: Fix so non_arch.h is updated even if
+ config.cache does exists.
+
+ * include/kapi.h, include/kapidata.h, include/kernel.hxx
+ * include/mboxt.inl, include/sched.hxx:
+ #include <eccconf/kernel.h> instead of include <eccconf/kernel.h>
+
+ * include/eccconf/kernel.h: Added. This was old devo/config.h
+
+ * src/Makefile.am : Set CYG_CONFIGURATION to "<eccconf/kernel.h>"
+
+ * src/test/Makefile.am : Build .gdbinit from gdbinit.in
+ and tree from tree.in
+
+Wed Mar 25 18:24:48 1998 Jonathan Larmour <jlarmour@cygnus.co.uk>
+
+ * src/Makefile.am, src/common/memcpy.c, src/common/memset.c:
+ Move memcpy and memset functions from C library into kernel to
+ satisfy the requirements of gcc - namely it must be available at
+ at all time. Changed memcpy and memset to sit more cleanly in the
+ kernel, and lose all dependencies on the C library
+ * src/Makefile.in: regenerated
+
+Fri Mar 13 18:36:42 GMT 1998 Chris Provenzano <proven@cygnus.com>
+
+ * configure.in : Add rule to get correct objcopy for target
+ * src/test/Makefile.am : Add rule to build philo.srec
+
+Fri Mar 13 11:47:23 GMT 1998 Chris Provenzano <proven@cygnus.com>
+
+ * configure.in, non_arch.h.in, non_arch.sh
+ Add support for the mn103000
+
+Thu Mar 12 11:38:28 GMT 1998 David Moore <dsm@cygnus.co.uk>
+
+ * src/Makefile.am:
+ Removed flag to leave comments in generated linker script.
+
+Thu Mar 12 10:55:20 GMT 1998 David Moore <dsm@cygnus.co.uk>
+
+ * configure.in:
+ Fixed setting of platform variable
+
+Wed Mar 11 16:54:28 GMT 1998 Chris Provenzano <proven@cygnus.com>
+
+ * src/test/Makefile.am, tests/Makefile.am:
+ Make sure CXXFLAGS from configure are also used
+
+Wed Mar 11 16:16:57 GMT 1998 Chris Provenzano <proven@cygnus.com>
+
+ * configure.in, non_arch.h.in. non_arch.sh:
+ Added build support for mips
+ * tests/Makefile.am, src/test/Makefile.am
+ Link with -nostdlib -lgcc
+
+Wed Mar 11 14:43:36 GMT 1998 Chris Provenzano <proven@cygnus.com>
+
+ * Makefile.am, configure.in, tests/Makefile.am
+ support building tests in the tests directory
+
+Wed Mar 11 13:18:17 GMT 1998 Chris Provenzano <proven@cygnus.com>
+
+ * acinclude.m4, stamp-h.in, non_arch.h.in, src/Makefile.am:
+ Added to support new kernel configure/make process
+
+ * Makefile.am: Modified to support new kernel configure/make
+ process.
+
+ * src/acinclude.m4, src/aclocal.m4, src/configure, src/configure.in
+ Deleted to support new kernel configure/make process
+
+ * Makefile.in, configure, aclocal.m4, src/Makefile.in,
+ src/configure: regenerated
+
+ * non_arch.sh: New shellscript to change platform/startup/debug
+ options after a configure is done.
+
+ * src/devo/config.h: include non_arch.h, for platform/startup/debug
+ options. This is generated at configure and modified by non_arch.sh
+
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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####
+//===========================================================================
diff --git a/ecos/packages/kernel/current/cdl/counters.cdl b/ecos/packages/kernel/current/cdl/counters.cdl
new file mode 100644
index 0000000000..bfa1483ad6
--- /dev/null
+++ b/ecos/packages/kernel/current/cdl/counters.cdl
@@ -0,0 +1,190 @@
+# ====================================================================
+#
+# counters.cdl
+#
+# configuration data related to the kernel counters and clocks
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## 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): jskov
+# Original data: nickg
+# Contributors:
+# Date: 1999-07-05
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_option CYGVAR_KERNEL_COUNTERS_CLOCK {
+ display "Provide real-time clock"
+ requires CYGIMP_KERNEL_INTERRUPTS_DSRS
+ default_value 1
+ description "
+ On all current target systems the kernel can provide a
+ real-time clock. This clock serves two purposes. First it is
+ necessary to support clock and alarm related functions.
+ Second it is needed to implement timeslicing in some of the
+ schedulers including the mlqueue scheduler. If the
+ application does not require any of these facilities then it
+ is possible to disable the real time clock support
+ completely."
+}
+
+cdl_option CYGNUM_KERNEL_COUNTERS_CLOCK_ISR_PRIORITY {
+ display "Interrupt priority for the real-time clock"
+ active_if CYGVAR_KERNEL_COUNTERS_CLOCK
+ flavor data
+ default_value { is_loaded(CYGNUM_HAL_KERNEL_COUNTERS_CLOCK_ISR_DEFAULT_PRIORITY) ?
+ CYGNUM_HAL_KERNEL_COUNTERS_CLOCK_ISR_DEFAULT_PRIORITY : 1 }
+ description "
+ The implementation of the kernel's real-time clock typically
+ involves installing an interrupt handler on a suitable hardware
+ timer. This option controls the priority level used for that
+ interrupt. On most platforms the value is not important because
+ the clock ISR leaves most of the work to be done by the DSR.
+ However some processors have interrupt controllers with special
+ requirements for the interrupt priorities, in which case
+ application developers must be able to manipulate the clock's
+ priority."
+}
+
+cdl_interface CYGINT_KERNEL_COUNTERS {
+ requires 1 == CYGINT_KERNEL_COUNTERS
+ no_define
+}
+
+# NOTE: these option should really be a single enum.
+cdl_option CYGIMP_KERNEL_COUNTERS_SINGLE_LIST {
+ display "Implement counters using a single list"
+ default_value 1
+ implements CYGINT_KERNEL_COUNTERS
+ description "
+ There are two different implementations of the counter
+ objects. The first implementation stores all alarms in a
+ single linked list. The alternative implementation uses a
+ table of linked lists. A single list is more efficient in
+ terms of memory usage and is generally adequate when the
+ application only makes use of a small number of alarms."
+}
+
+cdl_component CYGIMP_KERNEL_COUNTERS_MULTI_LIST {
+ display "Implement counters using a table of lists"
+ default_value 0
+ implements CYGINT_KERNEL_COUNTERS
+ description "
+ There are two different implementations of the counter
+ objects. The first implementation stores all alarms in a
+ single linked list. The alternative implementation uses a
+ table of linked lists, with the size of the table being a
+ separate configurable option. For more complicated
+ operations it is better to have a table of lists since this
+ reduces the amount of computation whenever the timer goes
+ off. Assuming a table size of 8 (the default value) on
+ average the timer code will only need to check 1/8 of the
+ pending alarms instead of all of them."
+
+ cdl_option CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE {
+ display "Size of counter list table"
+ flavor data
+ legal_values 1 to 1024
+ default_value 8
+ description "
+ If counters are implemented using an array of linked lists
+ then this option controls the size of the array. A larger
+ size reduces the amount of computation that needs to take
+ place whenever the timer goes off, but requires extra
+ memory."
+ }
+}
+
+cdl_option CYGIMP_KERNEL_COUNTERS_SORT_LIST {
+ display "Sort the counter list"
+ default_value 0
+ description "
+ Sorting the counter lists reduces the amount of work that
+ has to be done when a counter tick is processed, since the
+ next alarm to expire is always at the front of the list.
+ However, it makes adding an alarm to the list more expensive
+ since a search must be done for the correct place to put it.
+ Many alarms are used to implement timeouts, which seldom trigger,
+ so it is worthwhile optimizing this case. For this reason
+ sorted list are disabled by default."
+}
+
+cdl_option CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY {
+ display "Measure real-time \[clock\] interrupt latency"
+ requires CYGVAR_KERNEL_COUNTERS_CLOCK
+ default_value 0
+ description "
+ Measure the interrupt latency as seen by the real-time clock
+ timer interrupt. This requires hardware support, defined by
+ the HAL_CLOCK_LATENCY() macro."
+}
+
+cdl_option CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY {
+ display "Measure real-time \[clock\] DSR latency"
+ requires CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY
+ default_value CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY
+ description "
+ Measure the DSR latency as seen by the real-time clock
+ timer interrupt. This requires hardware support, defined by
+ the HAL_CLOCK_LATENCY() macro."
+}
+
+cdl_option CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION {
+ display "RTC resolution"
+ flavor data
+ calculated {"{CYGNUM_HAL_RTC_NUMERATOR, CYGNUM_HAL_RTC_DENOMINATOR}"}
+ description "
+ This option automatically defines the tuple which is used to
+ initialize the RTC resolution, consisting of a numerator and
+ denominator. The values of the numerator and denominator are
+ defined by the HAL."
+}
+
+cdl_option CYGNUM_KERNEL_COUNTERS_RTC_PERIOD {
+ display "RTC period"
+ flavor data
+ calculated {"CYGNUM_HAL_RTC_PERIOD"}
+ description "
+ This option defines the RTC period to be used in
+ setting the system clock hardware. It is essentially
+ an alias for CYGNUM_HAL_RTC_PERIOD, which is defined
+ in the HAL."
+}
+
+# EOF counters.cdl
diff --git a/ecos/packages/kernel/current/cdl/instrument.cdl b/ecos/packages/kernel/current/cdl/instrument.cdl
new file mode 100644
index 0000000000..da78a46047
--- /dev/null
+++ b/ecos/packages/kernel/current/cdl/instrument.cdl
@@ -0,0 +1,312 @@
+# ====================================================================
+#
+# instrument.cdl
+#
+# configuration data related to the kernel instrumentation
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## 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): jskov
+# Original data: nickg
+# Contributors:
+# Date: 1999-07-05
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_option CYGVAR_KERNEL_INSTRUMENT_EXTERNAL_BUFFER {
+ display "Use buffer provided by the application"
+ flavor bool
+ default_value 0
+ description "
+ In most circumstances the kernel should provide the
+ instrumentation circular buffer itself. Occasionally
+ application code may wish to provide the buffer instead,
+ giving the application code more convenient access to the
+ buffer. This also makes it possible to put the circular
+ buffer in special areas of memory, for example a region that
+ is shared with the host."
+}
+
+cdl_option CYGNUM_KERNEL_INSTRUMENT_BUFFER_SIZE {
+ display "Size of instrumentation buffer size"
+ flavor data
+ legal_values 16 to 0x100000
+ default_value 256
+ description "
+ If kernel instrumentation is enabled then the instrumentation
+ data goes into a circular buffer. A larger buffer allows
+ more data to be stored, but at a significant cost in memory.
+ The value of this option corresponds to the number of entries
+ in the table, and typically each entry will require 16 bytes
+ of memory."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_BUFFER_WRAP {
+ display "Wrap instrument buffer"
+ default_value 1
+ description "
+ When the instrumentation buffer is full it can either be restarted
+ from the beginning, overwriting older data, or it can stop at the
+ end. The former is useful if you want to look at the last entries
+ made while the latter is useful if you want to look at the first
+ few."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_FLAGS {
+ display "Perform selective instrumentation"
+ default_value 1
+ description "
+ The kernel can either collect all instrumentation events, or
+ it can filter out events at runtime based on a set of flags.
+ For example it would be possible to decide at runtime that
+ only scheduler and interrupt instrumentation flags are of
+ interest and that all other flags should be ignored. This
+ flag mechanism involves extra code and processor cycle
+ overhead in the instrumentation code, so it can be disabled
+ if the application developer is interested in all
+ instrumentation events."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_SCHED {
+ display "Instrument the scheduler"
+ default_value 1
+ active_if CYGPKG_KERNEL_SCHED
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the scheduling code."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_THREAD {
+ display "Instrument thread operations"
+ default_value 1
+ active_if CYGPKG_KERNEL_THREADS
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the code that manipulates threads."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_INTR {
+ display "Instrument interrupts"
+ default_value 1
+ active_if CYGPKG_KERNEL_INTERRUPTS
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the interrupt handling code."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_MUTEX {
+ display "Instrument mutex operations"
+ default_value 1
+ active_if CYGPKG_KERNEL_SYNCH
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the mutex code."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_CONDVAR {
+ display "Instrument condition variable operations"
+ default_value 1
+ active_if CYGPKG_KERNEL_SYNCH
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the condition variable code."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_BINSEM {
+ display "Instrument binary semaphore operations"
+ default_value 1
+ active_if CYGPKG_KERNEL_SYNCH
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the binary semaphore code."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_CNTSEM {
+ display "Instrument counting semaphore operations"
+ default_value 1
+ active_if CYGPKG_KERNEL_SYNCH
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the counting semaphore code."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_MBOXT {
+ display "Instrument message box operations"
+ default_value 1
+ active_if CYGPKG_KERNEL_SYNCH
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the message box code."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_CLOCK {
+ display "Instrument clock operations"
+ default_value 1
+ active_if CYGVAR_KERNEL_COUNTERS_CLOCK
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the real-time clock code."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_ALARM {
+ display "Instrument alarm-related operations"
+ default_value 1
+ active_if CYGVAR_KERNEL_COUNTERS_CLOCK
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the code related to alarm operations."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_SMP {
+ display "Instrument SMP-related operations"
+ default_value 1
+ active_if CYGVAR_KERNEL_COUNTERS_CLOCK
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not instrumentation support is compiled into
+ the code related to SMP operations."
+}
+
+cdl_option CYGDBG_KERNEL_INSTRUMENT_USER {
+ display "Support application-level instrumentation"
+ default_value 1
+ description "
+ It is possible to perform selective instrumentation at
+ run-time. It is also possible to disable instrumentation
+ in various kernel components at compile-time, thus
+ reducing the code size overheads. This option controls
+ whether or not application-level instrumentation gets
+ compiled in."
+}
+
+cdl_component CYGDBG_KERNEL_INSTRUMENT_MSGS {
+ display "Print user friendly instrument messages"
+ default_value 1
+ description "
+ Include code which will convert the instrument type field
+ into a more human understandable string"
+
+ cdl_option CYGDBG_KERNEL_INSTRUMENT_MSGS_BUILD_HEADERFILE {
+ display "Rebuild the header file"
+ default_value 0
+ description "
+
+ Make (using a shell script) include/cyg/kernel/instrument_desc.h in
+ your build tree; this is normally simply copied from the repository.
+ If you make a permanent change to include/instrmnt.h, such that
+ instrument_desc.h needs updating, it's up to you to first delete the
+ master file
+ ECOS_REPOSITORY/kernel/VERSION/include/instrument_desc.h
+ in your source repository, make the new version by enabling this
+ option then copy the new file
+ back from your build place to its source in
+ ECOS_REPOSITORY/kernel/VERSION/include/instrument_desc.h
+ and/or commit this to any version control system that you use."
+
+ make -priority 50 {
+ <PREFIX>/include/cyg/kernel/instrument_desc.h: <PACKAGE>/include/instrmnt.h <PACKAGE>/cdl/instrument.cdl
+ sh $(REPOSITORY)/$(PACKAGE)/host/instr/instrument.sh $< > $@
+ }
+ }
+
+ cdl_component CYGDBG_KERNEL_INSTRUMENT_BUILD_HOST_DUMP {
+ display "Build the host tool to print out a dump"
+ default_value 0
+ description "
+ Generate a host program which can dump the instrumentation
+ data in a human readable format. You have to somehow get the
+ instrumentation buffer into a file on the host. 'Exercise for
+ the reader' as university lecturers tend to say."
+
+ make -priority 51 {
+ <PREFIX>/bin/dump_instr: <PREFIX>/include/cyg/kernel/instrument_desc.h <PACKAGE>/cdl/instrument.cdl
+ @mkdir -p $(dir $@)
+ @mkdir -p tempinc
+ @cp -r $(PREFIX)/include/cyg tempinc
+ @cp -r $(PREFIX)/include/pkgconf tempinc
+ cc -I./tempinc $(REPOSITORY)/$(PACKAGE)/host/instr/dump_instr.c -o $(PREFIX)/bin/dump_instr
+ @rm -rf tempinc
+ }
+ }
+}
+
+# EOF instrument.cdl
diff --git a/ecos/packages/kernel/current/cdl/interrupts.cdl b/ecos/packages/kernel/current/cdl/interrupts.cdl
new file mode 100644
index 0000000000..f6c02c1222
--- /dev/null
+++ b/ecos/packages/kernel/current/cdl/interrupts.cdl
@@ -0,0 +1,129 @@
+# ====================================================================
+#
+# interrupts.cdl
+#
+# configuration data related to kernel interrupt handling
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## 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): bartv
+# Original data: nickg
+# Contributors:
+# Date: 1999-06-13
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+# NOTE: the choice of list vs table should not be two separate
+# options. There is a single option which must have one of
+# two legal values.
+cdl_component CYGIMP_KERNEL_INTERRUPTS_DSRS {
+ display "Use delayed service routines (DSRs)"
+ default_value 1
+ description "
+ In eCos the recommended way to handle device interrupts is to
+ do a minimum amount of work inside the low level interrupt
+ handler itself, and instead do as much as possible in a
+ Delayed Service Routine or DSR. If an application does not
+ make use of DSRs directly or indirectly then it is possible
+ to disable the DSR support completely, which reduces the
+ overheads of context switches and interrupt handling. Note
+ that the kernel real-time clock makes use of DSRs, as do many
+ of the device drivers. "
+
+ cdl_interface CYGINT_KERNEL_INTERRUPTS_DSRS {
+ requires 1 == CYGINT_KERNEL_INTERRUPTS_DSRS
+ no_define
+ }
+
+ # NOTE: the choice of list vs table should not be two separate
+ # options. There is a single option which must have one of
+ # two legal values.
+ cdl_option CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST {
+ display "Use linked lists for DSRs"
+ default_value 1
+ implements CYGINT_KERNEL_INTERRUPTS_DSRS
+ description "
+ When DSR support is enabled the kernel must keep track of all
+ the DSRs that are pending. This information can be kept in a
+ fixed-size table or in a linked list. The list implementation
+ requires that the kernel disable interrupts for a very short
+ period of time outside interrupt handlers, but there is no
+ possibility of a table overflow occurring."
+ }
+
+ cdl_component CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE {
+ display "Use fixed-size table for DSRs"
+ default_value 0
+ implements CYGINT_KERNEL_INTERRUPTS_DSRS
+ description "
+ When DSR support is enabled the kernel must keep track of all
+ the DSRs that are pending. This information can be kept in a
+ fixed-size table or in a linked list. The table
+ implementation involves a very small risk of overflow at
+ run-time if a given interrupt source is able to have more
+ than one pending DSR. However it has the advantage that
+ the kernel does not need to disable interrupts outside
+ interrupt handlers."
+
+ cdl_option CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE {
+ display "Number of entries in fixed-size DSR table"
+ flavor data
+ legal_values 2 to 1024
+ default_value 32
+ description "
+ When DSR support is enabled the kernel must keep track of all
+ the DSRs that are pending. One approach involves a fixed-size
+ table, which involves a very small risk of overflow at
+ run-time. By increasing the table size it is possible to reduce
+ this risk."
+ }
+ }
+
+ cdl_option CYGIMP_KERNEL_INTERRUPTS_CHAIN {
+ display "Chain all interrupts together"
+ requires CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN
+ default_value 0
+ description "
+ Interrupts can be attached to vectors either singly, or be
+ chained together. The latter is necessary if there is no way
+ of discovering which device has interrupted without
+ inspecting the device itself. It can also reduce the amount
+ of RAM needed for interrupt decoding tables and code."
+ }
+}
diff --git a/ecos/packages/kernel/current/cdl/kernel.cdl b/ecos/packages/kernel/current/cdl/kernel.cdl
new file mode 100644
index 0000000000..a258d2d7dc
--- /dev/null
+++ b/ecos/packages/kernel/current/cdl/kernel.cdl
@@ -0,0 +1,345 @@
+# ====================================================================
+#
+# kernel.cdl
+#
+# eCos kernel configuration data
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## 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): bartv
+# Original data: nickg
+# Contributors:
+# Date: 1999-06-13
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_KERNEL {
+ display "eCos kernel"
+ doc ref/kernel.html
+ include_dir cyg/kernel
+ description "
+ This package contains the core functionality of the eCos
+ kernel. It relies on functionality provided by various HAL
+ packages and by the eCos infrastructure. In turn the eCos
+ kernel provides support for other packages such as the device
+ drivers and the uITRON compatibility layer."
+ # FIXME: The compile statement should be split up and integrated as
+ # part of the components - so files only get comiled when they
+ # will actually be used.
+ compile common/clock.cxx common/timer.cxx common/kapi.cxx \
+ common/thread.cxx common/except.cxx \
+ intr/intr.cxx \
+ sched/bitmap.cxx sched/lottery.cxx sched/mlqueue.cxx \
+ sched/sched.cxx \
+ sync/bin_sem.cxx sync/cnt_sem.cxx sync/flag.cxx \
+ sync/cnt_sem2.cxx sync/mbox.cxx sync/mutex.cxx \
+ debug/dbg-thread-demux.c
+
+ # ---------------------------------------------------------------------
+ # The first component within the kernel is related to interrupt
+ # handling.
+ cdl_component CYGPKG_KERNEL_INTERRUPTS {
+ display "Kernel interrupt handling"
+ flavor none
+ doc ref/kernel-interrupts.html
+ description "
+ The majority of configuration options related to interrupt
+ handling are in the HAL packages, since usually the code has
+ to be platform-specific. There are a number of options
+ provided within the kernel related to slightly higher-level
+ concepts, for example Delayed Service Routines."
+
+ script interrupts.cdl
+ }
+
+ # ---------------------------------------------------------------------
+ # Exceptions. Currently there are only two options. The first
+ # determines whether or not exceptions are enabled at all. The
+ # second controls whether they apply globally or on a per-thread
+ # basis. There should probably be more options, but the boundary
+ # between the HAL and kernel becomes blurred.
+ cdl_component CYGPKG_KERNEL_EXCEPTIONS {
+ display "Exception handling"
+ requires CYGPKG_HAL_EXCEPTIONS
+ default_value 1
+ doc ref/kernel-exceptions.html
+ description "
+ In the context of the eCos kernel exceptions are unexpected
+ events detected by the hardware, for example an attempt to
+ execute an illegal instruction. There is no relation with
+ other forms of exception, for example the catch and throw
+ facilities of languages like C++. It is possible to disable
+ all support for exceptions and thus save some memory."
+
+ cdl_option CYGSEM_KERNEL_EXCEPTIONS_DECODE {
+ display "Decode exception types in kernel"
+ default_value 0
+ description "
+ On targets where several different types of exception are
+ possible, for example executing an illegal instruction and
+ division by zero, it is possible for the kernel to do some
+ decoding of the exception type and deliver the different
+ types of exception to different handlers in the application
+ code. Alternatively the kernel can simply pass all
+ exceptions directly to application code, leaving the
+ decoding to be done by the application"
+ }
+
+ cdl_option CYGSEM_KERNEL_EXCEPTIONS_GLOBAL {
+ display "Use global exception handlers"
+ default_value 1
+ description "
+ In the context of the eCos kernel exceptions are
+ unexpected events detected by the hardware, for
+ example an attempt to execute an illegal
+ instruction. If the kernel is configured
+ to support exceptions then two implementations are
+ possible. The default implementation involves a single set
+ of exception handlers that are in use for the entire
+ system. The alternative implementation allows different
+ exception handlers to be specified for each thread."
+ }
+ }
+
+ # ---------------------------------------------------------------------
+ cdl_component CYGPKG_KERNEL_SCHED {
+ display "Kernel schedulers"
+ flavor none
+ doc ref/kernel-overview.html#KERNEL-OVERVIEW-SCHEDULERS
+ description "
+ The eCos kernel provides a choice of schedulers. In addition
+ there are a number of configuration options to control the
+ detailed behaviour of these schedulers."
+
+ script scheduler.cdl
+ }
+
+ # ---------------------------------------------------------------------
+ # SMP support
+
+ cdl_component CYGPKG_KERNEL_SMP_SUPPORT {
+ display "SMP support"
+ flavor bool
+ requires CYGPKG_HAL_SMP_SUPPORT
+ default_value 0
+ }
+
+ cdl_component CYGPKG_KERNEL_SMP_TEST {
+ display "build SMP test"
+ flavor bool
+ requires CYGPKG_KERNEL_SMP_SUPPORT
+ default_value 0
+ }
+
+ # ---------------------------------------------------------------------
+ cdl_component CYGPKG_KERNEL_COUNTERS {
+ display "Counters and clocks"
+ flavor none
+ doc ref/kernel-counters.html
+ description "
+ The counter objects provided by the kernel provide an
+ abstraction of the clock facility that is generally provided.
+ Application code can associate alarms with counters, where an
+ alarm is identified by the number of ticks until it triggers,
+ the action to be taken on triggering, and whether or not the
+ alarm should be repeated."
+
+ script counters.cdl
+ }
+
+ # ---------------------------------------------------------------------
+ cdl_component CYGPKG_KERNEL_THREADS {
+ display "Thread-related options"
+ flavor none
+ description "
+ There are a number of configuration options related to the
+ implementation of threads, for example whether or not the
+ eCos kernel supports per-thread data."
+
+ script thread.cdl
+ }
+
+ # ---------------------------------------------------------------------
+ cdl_component CYGPKG_KERNEL_SYNCH {
+ display "Synchronization primitives"
+ flavor none
+ description "
+ The eCos kernel supports a number of different
+ synchronization primitives such as mutexes, semaphores,
+ condition variables, and message boxes. There are
+ configuration options to control the exact behaviour of some
+ of these synchronization primitives."
+
+ script synch.cdl
+ }
+
+ # ---------------------------------------------------------------------
+ cdl_component CYGPKG_KERNEL_INSTRUMENT {
+ display "Kernel instrumentation"
+ flavor bool
+ default_value 0
+ description "
+ The current release of the kernel contains an initial version
+ of instrumentation support. The various parts of the kernel
+ will invoke instrumentation routines whenever appropriate
+ events occur, and these will be stored in a circular buffer
+ for later reference."
+
+ compile instrmnt/meminst.cxx
+ script instrument.cdl
+ }
+
+ #===================================================================
+ # Options related to source-level debugging and diagnostics.
+ cdl_component CYGPKG_KERNEL_DEBUG {
+ display "Source-level debugging support"
+ flavor none
+ description "
+ If the source level debugger gdb is to be used for debugging
+ application code then it may be necessary to configure in support
+ for this in the kernel."
+
+ # NOTE: does this require any other support ?
+ cdl_option CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT {
+ display "Include GDB multi-threading debug support"
+ requires CYGVAR_KERNEL_THREADS_LIST
+ requires CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
+ default_value 1
+ compile debug/dbg_gdb.cxx
+ description "
+ This option enables some extra kernel code which is needed
+ to support multi-threaded source level debugging."
+ }
+ }
+
+ # ---------------------------------------------------------------------
+ # Kernel API's. The C++ one is the default. A C API is optional.
+ # Support for other languages is possible.
+ cdl_component CYGPKG_KERNEL_API {
+ display "Kernel APIs"
+ flavor none
+ description "
+ The eCos kernel is implemented in C++, so a C++ interface
+ to the kernel is always available. There is also an optional
+ C API. Additional API's may be provided in future versions."
+
+ cdl_option CYGFUN_KERNEL_API_C {
+ display "Provide C API"
+ default_value 1
+ description "
+ The eCos kernel is implemented in C++, but there is an
+ optional C API for use by application code. This C API can be
+ disabled if the application code does not invoke the kernel
+ directly, but instead uses higher level code such as the
+ uITRON compatibility layer."
+ }
+ }
+
+ define_proc {
+ puts $::cdl_header "/***** proc output start *****/"
+
+ # Clients of pkgconf/kernel.h expects system.h to be included.
+ puts $::cdl_header "#include <pkgconf/system.h>"
+ # FIXME: Some clients may rely on hal.h and infra.h being included.
+ # This should go away when any such client has been fixed.
+ puts $::cdl_header "#include <pkgconf/hal.h>"
+ puts $::cdl_header "#include <pkgconf/infra.h>"
+
+ # Include HAL/Platform specifics
+ puts $::cdl_header "#include CYGBLD_HAL_PLATFORM_H"
+ # Fallback defaults (in case HAL didn't define these)
+ puts $::cdl_header "#ifndef CYGNUM_HAL_RTC_NUMERATOR"
+ puts $::cdl_header "# define CYGNUM_HAL_RTC_NUMERATOR 1000000000"
+ puts $::cdl_header "# define CYGNUM_HAL_RTC_DENOMINATOR 100"
+ puts $::cdl_header "# define CYGNUM_HAL_RTC_PERIOD 9999"
+ puts $::cdl_header "#endif"
+
+ puts $::cdl_header "/***** proc output end *****/"
+ }
+
+ cdl_component CYGPKG_KERNEL_OPTIONS {
+ display "Kernel build options"
+ flavor none
+ description "
+ Package specific build options including control over
+ compiler flags used only in building this package,
+ and details of which tests are built."
+
+
+ cdl_option CYGPKG_KERNEL_CFLAGS_ADD {
+ display "Additional compiler flags"
+ flavor data
+ no_define
+ default_value { "" }
+ description "
+ This option modifies the set of compiler flags for
+ building the eCos kernel. These flags are used in addition
+ to the set of global flags."
+ }
+
+ cdl_option CYGPKG_KERNEL_CFLAGS_REMOVE {
+ display "Suppressed compiler flags"
+ flavor data
+ no_define
+ default_value { "" }
+ description "
+ This option modifies the set of compiler flags for
+ building the eCos kernel. These flags are removed from
+ the set of global flags if present."
+ }
+
+ cdl_option CYGPKG_KERNEL_TESTS {
+ 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" : "")
+ . ((!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" : "")
+ . ((CYGPKG_KERNEL_SMP_TEST) ? " tests_smp/fft.c tests_smp/radix.c tests_smp/lu.c " : "")
+ }
+ description "
+ This option specifies the set of tests for the eCos kernel."
+ }
+ }
+}
+
+# EOF kernel.cdl
diff --git a/ecos/packages/kernel/current/cdl/scheduler.cdl b/ecos/packages/kernel/current/cdl/scheduler.cdl
new file mode 100644
index 0000000000..ecd7a76a58
--- /dev/null
+++ b/ecos/packages/kernel/current/cdl/scheduler.cdl
@@ -0,0 +1,256 @@
+# ====================================================================
+#
+# scheduler.cdl
+#
+# configuration data related to the kernel schedulers
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## 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): jskov
+# Original data: nickg
+# Contributors:
+# Date: 1999-07-05
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_interface CYGINT_KERNEL_SCHEDULER {
+ display "Number of schedulers in this configuration"
+ no_define
+ requires 1 == CYGINT_KERNEL_SCHEDULER
+}
+
+cdl_interface CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES {
+ display "Non-zero if the active schedule only has unique priorities"
+ description "
+ Not all schedulers allow mutiple threads to use the same
+ priority. That property is signalled via this option, allowing
+ scheduler and tests to behave accordingly."
+}
+
+# FIXME: The two below options must be mutually exclusive
+cdl_component CYGSEM_KERNEL_SCHED_MLQUEUE {
+ display "Multi-level queue scheduler"
+ default_value 1
+ implements CYGINT_KERNEL_SCHEDULER
+ description "
+ The multi-level queue scheduler supports multiple priority
+ levels and multiple threads at each priority level.
+ Preemption between priority levels is automatic. Timeslicing
+ within a given priority level is controlled by a separate
+ configuration option."
+
+ cdl_option CYGDBG_KERNEL_TRACE_TIMESLICE {
+ display "Output timeslices when tracing"
+ active_if CYGDBG_USE_TRACING
+ requires !CYGDBG_INFRA_DEBUG_TRACE_ASSERT_SIMPLE
+ requires !CYGDBG_INFRA_DEBUG_TRACE_ASSERT_FANCY
+ default_value 0
+ description "
+ When tracing is enabled, output trace messages every
+ timeslice. This can be quite verbose so is disabled by
+ default."
+ }
+}
+
+cdl_option CYGSEM_KERNEL_SCHED_BITMAP {
+ display "Bitmap scheduler"
+ default_value 0
+ implements CYGINT_KERNEL_SCHEDULER
+ implements CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES
+ requires !CYGPKG_KERNEL_SMP_SUPPORT
+ description "
+ The bitmap scheduler supports multiple priority levels but
+ only one thread can exist at each priority level. This means
+ that scheduling decisions are very simple and hence the
+ scheduler is efficient. Preemption between priority levels is
+ automatic. Timeslicing within a given priority level is
+ irrelevant since there can be only one thread at each
+ priority level."
+}
+
+#cdl_option CYGSEM_KERNEL_SCHED_LOTTERY {
+# display "Lottery scheduler"
+# type radio
+# description "
+# This scheduler is not yet available."
+#}
+
+cdl_option CYGPRI_KERNEL_SCHED_IMPL_HXX {
+ display "Scheduler header file"
+ flavor data
+ description "
+ This option sets a preprocessor symbol which names the header
+ file for the selected scheduler. It is used internally by the
+ common scheduler code to include the correct header file."
+ calculated { \
+ CYGSEM_KERNEL_SCHED_BITMAP ? "<cyg/kernel/bitmap.hxx>" :\
+ CYGSEM_KERNEL_SCHED_MLQUEUE ? "<cyg/kernel/mlqueue.hxx>" :\
+ CYGSEM_KERNEL_SCHED_LOTTERY ? "<cyg/kernel/lottery.hxx>" :\
+ "!!!-- Configuration broken - no scheduler selected --!!!"}
+}
+
+
+
+# NOTE: This option only makes sense if the current scheduler
+# supports multiple priority levels.
+cdl_component CYGNUM_KERNEL_SCHED_PRIORITIES {
+ display "Number of priority levels"
+ flavor data
+ legal_values 1 to 32
+ default_value 32
+ #active_if CYGINT_KERNEL_SCHED_PRIORITY_SCHEDULER
+ description "
+ This option controls the number of priority levels that are
+ available. For some types of scheduler including the bitmap
+ scheduler this may impose an upper bound on the number of
+ threads in the system. For other schedulers such as the
+ mlqueue scheduler the number of threads is independent from
+ the number of priority levels. Note that the lowest priority
+ level is normally used only by the idle thread, although
+ application threads can run at this priority if necessary."
+
+ cdl_option CYGNUM_KERNEL_SCHED_BITMAP_SIZE {
+ display "Bitmap size"
+ flavor data
+ calculated {"CYGNUM_KERNEL_SCHED_PRIORITIES"}
+ description "
+ This option automatically defines the size of bitmap
+ used to track occupied priority levels."
+ }
+
+
+ cdl_option CYGIMP_KERNEL_SCHED_SORTED_QUEUES {
+ display "Dequeue highest priority threads first"
+ flavor bool
+ default_value 0
+ description "
+ With this option enabled, threads queued in a thread queue
+ will be dequeued in priority order, rather than first in,
+ first out (FIFO). Threads of equal priority are dequeued
+ oldest first. The only exception is the scheduler run
+ queues where order is less important as each is already
+ sorted by priority. Note that this makes the thread queueing
+ less deterministic."
+ }
+}
+
+# ---------------------------------------------------------------------
+# Timeslice options
+
+# NOTE: this option only makes sense for some of the schedulers.
+# Timeslicing is irrelevant for bitmap schedulers.
+cdl_component CYGSEM_KERNEL_SCHED_TIMESLICE {
+ display "Scheduler timeslicing"
+ requires !CYGSEM_KERNEL_SCHED_BITMAP
+ requires CYGVAR_KERNEL_COUNTERS_CLOCK
+ default_value 1
+ description "
+ Some schedulers including the mlqueue scheduler support
+ timeslicing. This means that the kernel will check regularly
+ whether or not there is another runnable thread with the
+ same priority, and if there is such a thread there will be
+ an automatic context switch. Not all applications require
+ timeslicing, for example because every thread performs a
+ blocking operation regularly. For these applications it is
+ possible to disable timeslicing, which reduces the overheads
+ associated with timer interrupts."
+
+ cdl_option CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS {
+ display "Number of clock ticks between timeslices"
+ flavor data
+ legal_values 1 to 65535
+ default_value 5
+ description "
+ Assuming timeslicing is enabled, how frequently should it
+ take place? The value of this option corresponds to the
+ number of clock ticks that should occur before a timeslice
+ takes place, so increasing the value reduces the frequency
+ of timeslices."
+ }
+
+ cdl_option CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE {
+ display "Support runtime enable of timeslice per-thread"
+ flavor bool
+ default_value false
+ description "This option makes timslicing a per-thread runtime
+ option. When enabled, threads may have timeslicing
+ turned on or off dynamically. This is generally used
+ by higher level APIs (such as POSIX) to implement
+ differing scheduling policies."
+
+ }
+}
+
+# ---------------------------------------------------------------------
+# ASR support options
+
+cdl_component CYGSEM_KERNEL_SCHED_ASR_SUPPORT {
+ display "Enable ASR support"
+ flavor bool
+ default_value false
+ description "
+ This component controls support for Asynchronous Service
+ Routines (ASRs). This is a function that may be called
+ from the scheduler when it has just exited the scheduler
+ lock. This is primarily for use by API compatibility layers."
+
+ cdl_option CYGSEM_KERNEL_SCHED_ASR_GLOBAL {
+ display "Make ASR function global"
+ flavor bool
+ default_value true
+ description "
+ This option controls whether the ASR function is shared by
+ all threads, or whether each thread may have its own ASR
+ function."
+ }
+
+ cdl_option CYGSEM_KERNEL_SCHED_ASR_DATA_GLOBAL {
+ display "Make ASR data global"
+ flavor bool
+ default_value true
+ description "
+ This option controls whether the ASR data is shared by
+ all threads, or whether each thread may have its own ASR
+ data. This is independent of the previous option because
+ it may be useful to pass per-thread data to a shared ASR
+ function."
+ }
+}
+
+# EOF scheduler.cdl
diff --git a/ecos/packages/kernel/current/cdl/synch.cdl b/ecos/packages/kernel/current/cdl/synch.cdl
new file mode 100644
index 0000000000..ab52d709d7
--- /dev/null
+++ b/ecos/packages/kernel/current/cdl/synch.cdl
@@ -0,0 +1,213 @@
+# ====================================================================
+#
+# synch.cdl
+#
+# configuration data related to the kernel synchronization primitives
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## 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): jskov
+# Original data: nickg
+# Contributors:
+# Date: 1999-07-05
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+
+cdl_component CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL {
+ display "Priority inversion protection protocols"
+ flavor booldata
+ doc ref/kernel-mutexes.html
+ legal_values { "SIMPLE" }
+ default_value { "SIMPLE" }
+ active_if { CYGSEM_KERNEL_SCHED_MLQUEUE }
+ requires { CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES == 0 }
+ description "
+ This component controls the protocols used to protect mutexes against
+ priority inversion. If this option is enabled it defines which
+ algorithm is used to implement this protection. At present only
+ one such algorithm is defined: \"SIMPLE\". The implementation
+ will only work in the mlqueue scheduler, and it does not handle the
+ rare case of nested mutexes completely correctly. However it is
+ both fast and deterministic."
+
+ cdl_option CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT {
+ display "Enable priority inheritance protocol"
+ default_value 1
+ implements CYGINT_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_COUNT
+ description "
+ This option enables priority inheritance protocol. This protocol
+ causes the owner of a mutex to be executed at the highest priority
+ of the threads waiting for access to the mutex."
+ }
+
+ cdl_component CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING {
+ display "Enable priority ceiling protocol"
+ default_value 1
+ implements CYGINT_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_COUNT
+ description "
+ This option enables priority ceiling protocol. This protocol
+ causes the owner of a mutex to be executed at a priority
+ associated with the mutex."
+ cdl_option CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY {
+ display "Default priority ceiling"
+ flavor data
+ legal_values 0 to { CYGNUM_KERNEL_SCHED_PRIORITIES - 1 }
+ default_value 0
+ active_if CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+ description "
+ This option defines the default priority ceiling to be
+ used if the chosen default priority inversion protocol is
+ priority ceoptioniling protocol. The default value for this is zero,
+ making all such mutexes boost threads to the maximum priority."
+ }
+ }
+
+ cdl_option CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_NONE {
+ display "No priority inversion protocol"
+ default_value 1
+ implements CYGINT_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_COUNT
+ description "
+ This option enables the ability to have no priority inversion protocol.
+ It is equivalent to disabling the priority inversion protocol at
+ the top level, but is necessary for the runtime and default
+ selection options."
+ }
+
+ cdl_option CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT {
+ display "Default priority inversion protocol"
+ flavor data
+ active_if { CYGINT_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_COUNT > 1 }
+ legal_values { "INHERIT" "CEILING" "NONE" }
+ default_value { CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT ?
+ "INHERIT" :
+ CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING ?
+ "CEILING" : "NONE" }
+ description "
+ This option defines the default inversion protocol used for mutexes that
+ are created without an explicit protocol being specified. The protocol
+ chosen by default is to use priority inheritance if it is present otherwise
+ priority ceiling, or none if neither is present."
+ }
+
+ cdl_option CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC {
+ display "Specify mutex priority inversion protocol at runtime"
+ default_value 1
+ active_if { CYGINT_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_COUNT > 1 }
+ description "
+ This option controls whether the priority inversion protocol used by
+ a mutex can be specified when that mutex is created."
+ }
+
+ cdl_interface CYGINT_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_COUNT {
+ display "Number of protocols selected"
+ }
+
+}
+
+cdl_option CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT {
+ display "Message box blocking put support"
+ doc ref/kernel-mail-boxes.html
+ default_value 1
+ description "
+ Message boxes can support three different versions of the
+ put-message operation. The first is tryput(), which will fail
+ if the message box is already full. The other two are the
+ ordinary put() function which will block if the message box
+ is full, and a timed put() operation which will block for
+ upto a certain length of time if the message box is currently
+ full. The blocking versions require extra memory in the
+ message box data structure and extra code in the other
+ message box functions, so they can be disabled if the
+ application does not require them. If this option is enabled
+ then the system will always provide the blocking put()
+ function, and it will also provide the timed put() function
+ if thread timers are enabled."
+}
+
+cdl_option CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE {
+ display "Message box queue size"
+ doc ref/kernel-mail-boxes.html
+ flavor data
+ legal_values 1 to 65535
+ default_value 10
+ description "
+ This configuration option controls the number of messages
+ that can be queued in a message box before a non-blocking
+ put() operation will fail or a blocking put() operation will
+ block. The cost in memory is one pointer per message box for
+ each possible message."
+}
+
+cdl_option CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT {
+ display "Condition variable timed-wait support"
+ doc ref/kernel-condition-variables.html
+ requires CYGFUN_KERNEL_THREADS_TIMER
+ default_value 1
+ description "
+ This option enables the condition variable timed wait
+ facility."
+}
+
+cdl_option CYGMFN_KERNEL_SYNCH_CONDVAR_WAIT_MUTEX {
+ display "Condition variable explicit mutex wait support"
+ doc ref/kernel-condition-variables.html
+ default_value 1
+ description "
+ This option enables the condition variable explicit mutex wait
+ facility. By default condition variables in eCos are created with
+ a statically associated mutex. This option permits wait (and timed wait
+ if CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT is enabled) to provide a
+ different mutex as an argument. This makes no difference to the semantics
+ the wait operation except that a different mutex will be used during it."
+}
+
+cdl_option CYGIMP_KERNEL_SYNCH_MQUEUE_NOT_INLINE {
+ display "Avoid inlines in mqueue implementation"
+ default_value 0
+ description "
+ With this option disabled, the 'mqueue' message queue implementation
+ provides most of its implementation via inlines. However this can
+ adversely affect code size in application that make lots of mqueue
+ calls from different places, so enabling this option provides
+ non-inline versions to be used instead."
+ compile sync/mqueue.cxx
+}
+
+# EOF synch.cdl
diff --git a/ecos/packages/kernel/current/cdl/thread.cdl b/ecos/packages/kernel/current/cdl/thread.cdl
new file mode 100644
index 0000000000..f1766342c9
--- /dev/null
+++ b/ecos/packages/kernel/current/cdl/thread.cdl
@@ -0,0 +1,332 @@
+# ====================================================================
+#
+# thread.cdl
+#
+# configuration data related to the kernel threads
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## 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): jskov
+# Original data: nickg
+# Contributors:
+# Date: 1999-07-05
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_option CYGFUN_KERNEL_THREADS_TIMER {
+ display "Allow per-thread timers"
+ requires CYGVAR_KERNEL_COUNTERS_CLOCK
+ default_value 1
+ description "
+ This option controls whether or not the kernel should support
+ per-thread clock and alarm related functions. Also some of
+ the synchronization primitives such as semaphore and
+ condition variable timed wait operations require per-thread
+ timer support. If none of these facilities are required then
+ the option can be disabled."
+}
+
+cdl_option CYGVAR_KERNEL_THREADS_NAME {
+ display "Support optional name for each thread"
+ default_value 1
+ description "
+ Threads may optionally be supplied with a name string that is
+ used to identify them during debugging. This name is only
+ present if `this option is defined. Disabling it reduces both
+ code and data size."
+}
+
+cdl_option CYGVAR_KERNEL_THREADS_LIST {
+ display "Keep track of all threads using a linked list"
+ default_value 1
+ description "
+ Threads may optionally be placed on a housekeeping list so
+ that all threads may be located easily. This is useful mainly
+ in conjunction with source-level debugging."
+}
+
+cdl_option CYGFUN_KERNEL_THREADS_STACK_LIMIT {
+ display "Keep track of the base of each thread's stack"
+ default_value 1
+ description "
+ This option makes the kernel keep track of the lower limit on
+ each thread's stack. It allows the kernel to adjust the lower
+ limit, thus making space for per-thread data. Note that it
+ does not imply any form of run-time stack overflow checking."
+}
+
+cdl_component CYGFUN_KERNEL_THREADS_STACK_CHECKING {
+ display "Check thread stacks for overflows"
+ active_if CYGPKG_INFRA_DEBUG
+ active_if CYGDBG_USE_ASSERTS
+ default_value 1
+ description "
+ This option enables a variety of checks for stack overflow
+ including signatures at the top and base of thread stacks,
+ which are asserted for correctness whenever a thread switches."
+
+ cdl_option CYGFUN_KERNEL_ALL_THREADS_STACK_CHECKING {
+ display "Check all threads whenever possible"
+ requires CYGVAR_KERNEL_THREADS_LIST
+ default_value 0
+ description "
+ This option enables more active checking of all threads for
+ wrongdoing. In theory, checking threads other than the old and new
+ executing threads in a thread-switch is pointless, because no other
+ thread has run, so no other stack can be exceeded. But errors such
+ as memory scribbling, dangling pointers, overlapping use of store
+ or errors accessing objects adjacent to a stack which can be very
+ hard to find can be detected this way, saving debug time."
+ }
+
+ cdl_option CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE {
+ display "Signature size in bytes, at stack top and bottom"
+ flavor data
+ default_value 32
+ legal_values 8 to 512
+ description "
+ This is the size of the area reserved for a signature at the top
+ and bottom of all stacks. It also provides a buffer zone for
+ detecting overflow before external objects are corrupted, hence the
+ ability to vary it here. But if you are short of stack, increasing
+ this value will make the overflow more, not less likely, of course."
+ }
+}
+
+cdl_component CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT {
+ display "Measure stack usage"
+ default_value { 0 != CYGPKG_INFRA_DEBUG }
+ description "
+ This option allows measurement of each thread's stack by initializing
+ it to a predefined value at thread creation time. Later use of the
+ cyg_thread_measure_stack_usage() function allows the maximum stack
+ usage of the thread so far to be obtained. Note that this is not
+ necessarily the true maximum stack usage that the thread will ever
+ use since all that has been measured is the stack usage corresponding
+ to the code path followed this time, and not the code path that may
+ be followed in future."
+
+ cdl_option CYGDBG_KERNEL_THREADS_STACK_MEASUREMENT_VERBOSE_EXIT {
+ display "Output stack usage on thread exit"
+ default_value 0
+ description "
+ This will output the measured stack usage on the diagnostic
+ output when a thread exits."
+ }
+}
+
+cdl_component CYGVAR_KERNEL_THREADS_DATA {
+ display "Support for per-thread data"
+ requires CYGFUN_KERNEL_THREADS_STACK_LIMIT
+ doc ref/kernel-thread-data.html
+ default_value 1
+ description "
+ It is possible for the kernel to support per-thread data, in
+ other words an area of memory specific to each thread which
+ can be used to store data for that thread. This per-thread
+ data can be used by applications or by other packages such as
+ the ISO C library."
+
+ cdl_option CYGNUM_KERNEL_THREADS_DATA_MAX {
+ display "Number of words of per-thread data"
+ flavor data
+ legal_values 4 to 32
+ default_value 6
+ description "
+ It is possible for the kernel to support per-thread data, in
+ other words an area of memory specific to each thread which
+ can be used to store data for that thread. This per-thread
+ data can be used by applications or by other packages such as
+ the ISO C library. This configuration option controls the
+ number of words of per-thread data that the kernel will
+ allow. In the current implementation a bitmask is used to identify
+ used per-thread data slots and so the maximum legal value must
+ remain 32."
+ }
+
+ cdl_component CYGNUM_KERNEL_THREADS_DATA_ALL {
+ display "Bitmap of preallocated slots of thread data"
+ flavor data
+ calculated 15
+ description "
+ Per thread data options. Per thread data support is based loosely
+ on that defined by POSIX. Each thread has an array of slots, up to
+ CYGNUM_KERNEL_THREADS_DATA_MAX, that may contain data. Some of the
+ slots have been preallocated to specific packages. Others may be
+ allocated dynamically."
+
+ cdl_option CYGNUM_KERNEL_THREADS_DATA_KERNEL {
+ display "Slot 0 preallocated for the kernel"
+ flavor data
+ calculated 0
+ description "
+ This option defines the index of a per-thread data
+ slot which is reserved by
+ the eCos kernel
+ for private use."
+ }
+ cdl_option CYGNUM_KERNEL_THREADS_DATA_ITRON {
+ display "Slot 1 preallocated for uITRON"
+ flavor data
+ calculated 1
+ description "
+ This option defines the index of a per-thread data
+ slot which is reserved by
+ the uITRON compatibility layer
+ for private use."
+ }
+ cdl_option CYGNUM_KERNEL_THREADS_DATA_ERRNO {
+ display "Slot 2 preallocated for errno"
+ flavor data
+ calculated 2
+ description "
+ This option defines the index of a per-thread data
+ slot which is reserved for use by an errno variable."
+ }
+ cdl_option CYGNUM_KERNEL_THREADS_DATA_POSIX {
+ display "Slot 3 preallocated for POSIX"
+ flavor data
+ calculated 3
+ description "
+ This option defines the index of a per-thread data
+ slot which is reserved by
+ POSIX
+ for private use."
+ }
+ }
+}
+
+cdl_component CYGPKG_KERNEL_THREADS_DESTRUCTORS {
+ display "Thread destructors"
+ doc ref/kernel-thread-destructors.html
+ default_value 0
+ description "
+ This option enables support for registered destructor functions to
+ be called on thread exit."
+
+
+ cdl_option CYGNUM_KERNEL_THREADS_DESTRUCTORS {
+ display "Number of possible destructors"
+ flavor data
+ legal_values 1 to 65535
+ default_value 8
+ description "
+ This option gives the number of possible destructors allowed.
+ Increasing this will increase the size of every
+ thread control structure if per-thread destructors are
+ enabled."
+ }
+
+ cdl_option CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD {
+ display "Per-thread destructors"
+ default_value 1
+ description "
+ Enabling this option makes the thread destructors a per-thread
+ property, with each thread having its own list of destructors.
+ Disabling this option makes the thread destructor list
+ global so all threads have the same destructors."
+ }
+
+}
+
+cdl_option CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE {
+ display "Stack size for the idle thread"
+ flavor data
+ legal_values 512 to 65536
+ default_value 2048
+ description "
+ This configuration option specifies the stack size in bytes
+ for the idle thread. Unless the HAL is configured to use a
+ separate interrupt stack this size must be sufficient to meet
+ the requirements of all interrupt handlers - these
+ requirements are cumulative if nested interrupted are
+ enabled. Depending on the target architecture, the stack size
+ typically has to be a multiple of eight or sixteen bytes.
+ This will be overridden where it is used if the
+ architectural HAL requires a minimum stack size
+ to handle interrupts correctly."
+}
+
+# ---------------------------------------------------------------------
+# Thread-related miscellania.
+
+cdl_option CYGNUM_KERNEL_MAX_SUSPEND_COUNT_ASSERT {
+ display "Maximal suspend count"
+ flavor data
+ default_value 500
+ description "
+ This option provides for an assertion that the count value for
+ counted thread suspends do not exceed set limits. This is to help
+ with debugging, to allow a runaway loop, for example, to be
+ detected more easily.
+
+ If the option is not defined, no assert is included. Whether asserts
+ are themselves included depends on infrastructure configury in
+ infra.h"
+}
+
+cdl_option CYGNUM_KERNEL_MAX_COUNTED_WAKE_COUNT_ASSERT {
+ display "Maximal wake count"
+ flavor data
+ default_value 500
+ description "
+ This option provides for an assertion that the count value for
+ counted thread wakeups do not exceed set limits. This is to
+ help with debugging, to allow a runaaway loop, for example, to
+ be detected more easily.
+
+ If the option is not defined, no assert is included. Whether asserts
+ are themselves included depends on infrastructure configury in
+ infra.h"
+}
+
+
+#if CYGNUM_KERNEL_SCHED_PRIORITIES == 1
+# define CYGIMP_IDLE_THREAD_YIELD
+#endif
+cdl_option CYGIMP_IDLE_THREAD_YIELD {
+ display "Idle thread must always yield"
+ calculated 1
+ active_if (CYGNUM_KERNEL_SCHED_PRIORITIES == 1)
+ description "
+ If the scheduler configuration only has a single priority
+ level, then the idle thread must yield each time around its loop."
+}
+
+# EOF thread.cdl
diff --git a/ecos/packages/kernel/current/doc/SMP.txt b/ecos/packages/kernel/current/doc/SMP.txt
new file mode 100644
index 0000000000..f7353e3da2
--- /dev/null
+++ b/ecos/packages/kernel/current/doc/SMP.txt
@@ -0,0 +1,544 @@
+
+eCos SMP Support
+================
+
+eCos contains support for limited Symmetric Multi-Processing
+(SMP). This is only available on selected architectures and platforms.
+
+This first part of this document describes the platform-independent
+parts of the SMP support. Annexes at the end of this document describe
+any details that are specific to a particular platform.
+
+Target Hardware Limitations
+---------------------------
+
+To allow a reasonable implementation of SMP, and to reduce the
+disruption to the existing source base, a number of assumptions have
+been made about the features of the target hardware.
+
+- Modest multiprocessing. The typical number of CPUs supported is two
+ to four, with an upper limit around eight. While there are no
+ inherent limits in the code, hardware and algorithmic limitations
+ will probably become significant beyond this point.
+
+- SMP synchronization support. The hardware must supply a mechanism to
+ allow software on two CPUs to synchronize. This is normally provided
+ as part of the instruction set in the form of test-and-set,
+ compare-and-swap or load-link/store-conditional instructions. An
+ alternative approach is the provision of hardware semaphore
+ registers which can be used to serialize implementations of these
+ operations. Whatever hardware facilities are available, they are
+ used in eCos to implement spinlocks.
+
+- Coherent caches. It is assumed that no extra effort will be required
+ to access shared memory from any processor. This means that either
+ there are no caches, they are shared by all processors, or are
+ maintained in a coherent state by the hardware. It would be too
+ disruptive to the eCos sources if every memory access had to be
+ bracketed by cache load/flush operations. Any hardware that requires
+ this is not supported.
+
+- Uniform addressing. It is assumed that all memory that is
+ shared between CPUs is addressed at the same location from all
+ CPUs. Like non-coherent caches, dealing with CPU-specific address
+ translation is considered too disruptive to the eCos source
+ base. This does not, however, preclude systems with non-uniform
+ access costs for different CPUs.
+
+- Uniform device addressing. As with access to memory, it is assumed
+ that all devices are equally accessible to all CPUs. Since device
+ access is often made from thread contexts, it is not possible to
+ restrict access to device control registers to certain CPUs, since
+ there is currently no support for binding or migrating threads to CPUs.
+
+- Interrupt routing. The target hardware must have an interrupt
+ controller that can route interrupts to specific CPUs. It is
+ acceptable for all interrupts to be delivered to just one CPU, or
+ for some interrupts to be bound to specific CPUs, or for some
+ interrupts to be local to each CPU. At present dynamic routing,
+ where a different CPU may be chosen each time an interrupt is
+ delivered, is not supported. ECos cannot support hardware where all
+ interrupts are delivered to all CPUs simultaneously with the
+ expectation that software will resolve any conflicts.
+
+- Inter-CPU interrupts. A mechanism to allow one CPU to interrupt
+ another is needed. This is necessary so that events on one CPU can
+ cause rescheduling on other CPUs.
+
+- CPU Identifiers. Code running on a CPU must be able to determine
+ which CPU it is running on. The CPU Id is usually provided either in
+ a CPU status register, or in a register associated with the
+ inter-CPU interrupt delivery subsystem. Ecos expects CPU Ids to be
+ small positive integers, although alternative representations, such
+ as bitmaps, can be converted relatively easily. Complex mechanisms
+ for getting the CPU Id cannot be supported. Getting the CPU Id must
+ be a cheap operation, since it is done often, and in performance
+ critical places such as interrupt handlers and the scheduler.
+
+Kernel Support
+--------------
+
+This section describes how SMP is handled in the kernel, and where
+system behaviour differs from a single CPU system.
+
+System Startup
+~~~~~~~~~~~~~~
+
+System startup takes place on only one CPU, called the primary
+CPU. All other CPUs, the secondary CPUs, are either placed in
+suspended state at reset, or are captured by the HAL and put into
+a spin as they start up.
+
+The primary CPU is responsible for copying the DATA segment and
+zeroing the BSS (if required), calling HAL variant and platform
+initialization routines and invoking constructors. It then calls
+cyg_start() to enter the application. The application may then create
+extra threads and other objects.
+
+It is only when the application calls Cyg_Scheduler::start() that the
+secondary CPUs are initialized. This routine scans the list of
+available secondary CPUs and calls HAL_SMP_CPU_START() to start each one.
+Finally it calls Cyg_Scheduler::start_cpu().
+
+Each secondary CPU starts in the HAL, where it completes any per-CPU
+initialization before calling into the kernel at
+cyg_kernel_cpu_startup(). Here it claims the scheduler lock and calls
+Cyg_Scheduler::start_cpu().
+
+Cyg_Scheduler::start_cpu() is common to both the primary and secondary
+CPUs. The first thing this code does is to install an interrupt object
+for this CPU's inter-CPU interrupt. From this point on the code is the
+same as for the single CPU case: an initial thread is chosen and
+entered.
+
+From this point on the CPUs are all equal, eCos makes no further
+distinction between the primary and secondary CPUs. However, the
+hardware may still distinguish them as far as interrupt delivery is
+concerned.
+
+
+Scheduling
+~~~~~~~~~~
+
+To function correctly an operating system kernel must protect its
+vital data structures, such as the run queues, from concurrent
+access. In a single CPU system the only concurrent activities to worry
+about are asynchronous interrupts. The kernel can easily guard its
+data structures against these by disabling interrupts. However, in a
+multi-CPU system, this is inadequate since it does not block access by
+other CPUs.
+
+The eCos kernel protects its vital data structures using the scheduler
+lock. In single CPU systems this is a simple counter that is
+atomically incremented to acquire the lock and decremented to release
+it. If the lock is decremented to zero then the scheduler may be
+invoked to choose a different thread to run. Because interrupts may
+continue to be serviced while the scheduler lock is claimed, ISRs are
+not allowed to access kernel data structures, or call kernel routines
+that can. Instead all such operations are deferred to an associated
+DSR routine that is run during the lock release operation, when the
+data structures are in a consistent state.
+
+By choosing a kernel locking mechanism that does not rely on interrupt
+manipulation to protect data structures, it is easier to convert eCos
+to SMP than would otherwise be the case. The principal change needed to
+make eCos SMP-safe is to convert the scheduler lock into a nestable
+spin lock. This is done by adding a spinlock and a CPU id to the
+original counter.
+
+The algorithm for acquiring the scheduler lock is very simple. If the
+scheduler lock's CPU id matches the current CPU then it can increment
+the counter and continue. If it does not match, the CPU must spin on
+the spinlock, after which it may increment the counter and store its
+own identity in the CPU id.
+
+To release the lock, the counter is decremented. If it goes to zero
+the CPU id value must be set to NONE and the spinlock cleared.
+
+To protect these sequences against interrupts, they must be performed
+with interrupts disabled. However, since these are very short code
+sequences, they will not have an adverse effect on the interrupt
+latency.
+
+Beyond converting the scheduler lock, further preparing the kernel for
+SMP is a relatively minor matter. The main changes are to convert
+various scalar housekeeping variables into arrays indexed by CPU
+id. These include the current thread pointer, the need_reschedule
+flag and the timeslice counter.
+
+At present only the Multi-Level Queue (MLQ) scheduler is capable of
+supporting SMP configurations. The main change made to this scheduler
+is to cope with having several threads in execution at the same
+time. Running threads are marked with the CPU they are executing on.
+When scheduling a thread, the scheduler skips past any running threads
+until it finds a thread that is pending. While not a constant-time
+algorithm, as in the single CPU case, this is still deterministic,
+since the worst case time is bounded by the number of CPUs in the
+system.
+
+A second change to the scheduler is in the code used to decide when
+the scheduler should be called to choose a new thread. The scheduler
+attempts to keep the *n* CPUs running the *n* highest priority
+threads. Since an event or interrupt on one CPU may require a
+reschedule on another CPU, there must be a mechanism for deciding
+this. The algorithm currently implemented is very simple. Given a
+thread that has just been awakened (or had its priority changed), the
+scheduler scans the CPUs, starting with the one it is currently
+running on, for a current thread that is of lower priority than the
+new one. If one is found then a reschedule interrupt is sent to that
+CPU and the scan continues, but now using the current thread of the
+rescheduled CPU as the candidate thread. In this way the new thread
+gets to run as quickly as possible, hopefully on the current CPU, and
+the remaining CPUs will pick up the remaining highest priority
+threads as a consequence of processing the reschedule interrupt.
+
+The final change to the scheduler is in the handling of
+timeslicing. Only one CPU receives timer interrupts, although all CPUs
+must handle timeslicing. To make this work, the CPU that receives the
+timer interrupt decrements the timeslice counter for all CPUs, not
+just its own. If the counter for a CPU reaches zero, then it sends a
+timeslice interrupt to that CPU. On receiving the interrupt the
+destination CPU enters the scheduler and looks for another thread at
+the same priority to run. This is somewhat more efficient than
+distributing clock ticks to all CPUs, since the interrupt is only
+needed when a timeslice occurs.
+
+Device Drivers
+~~~~~~~~~~~~~~
+
+The main area where the SMP nature of a system will be most apparent
+is in device drivers. It is quite possible for the ISR, DSR and thread
+components of a device driver to execute on different CPUs. For this
+reason it is much more important that SMP-capable device drivers use
+the driver API routines correctly.
+
+Synchronization between threads and DSRs continues to require that the
+thread-side code use cyg_drv_dsr_lock() and cyg_drv_dsr_unlock() to
+protect access to shared data. Synchronization between ISRs and DSRs
+or threads requires that access to sensitive data be protected, in all
+places, by calls to cyg_drv_isr_lock() and cyg_drv_isr_unlock().
+
+The ISR lock, for SMP systems, not only disables local interrupts, but
+also acquires a spinlock to protect against concurrent access from
+other CPUs. This is necessary because ISRs are not run with the
+scheduler lock claimed. Hence they can run in parallel with other
+components of the device driver.
+
+The ISR lock provided by the driver API is just a shared spinlock that
+is available for use by all drivers. If a driver needs to implement a
+finer grain of locking, it can use private spinlocks, accessed via the
+cyg_drv_spinlock_*() functions (see API later).
+
+
+API Extensions
+--------------
+
+In general, the SMP support is invisible to application code. All
+synchronization and communication operations function exactly as
+before. The main area where code needs to be SMP aware is in the
+handling of interrupt routing, and in the synchronization of ISRs,
+DSRs and threads.
+
+The following sections contain brief descriptions of the API
+extensions added for SMP support. More details will be found in the
+Kernel C API and Device Driver API documentation.
+
+Interrupt Routing
+~~~~~~~~~~~~~~~~~
+
+Two new functions have been added to the Kernel API and the device
+driver API to do interrupt routing. These are:
+
+void cyg_interrupt_set_cpu( cyg_vector_t vector, cyg_cpu_t cpu );
+void cyg_drv_interrupt_set_cpu( cyg_vector_t vector, cyg_cpu_t cpu );
+
+cyg_cpu_t cyg_interrupt_get_cpu( cyg_vector_t vector );
+cyg_cpu_t cyg_drv_interrupt_get_cpu( cyg_vector_t vector );
+
+the *_set_cpu() functions cause the given interrupt to be handled by
+the nominated CPU.
+
+The *_get_cpu() functions return the CPU to which the vector is
+routed.
+
+Although not currently supported, special values for the cpu argument
+may be used to indicate that the interrupt is being routed dynamically
+or is CPU-local.
+
+Once a vector has been routed to a new CPU, all other interrupt
+masking and configuration operations are relative to that CPU, where
+relevant.
+
+Synchronization
+~~~~~~~~~~~~~~~
+
+All existing synchronization mechanisms work as before in an SMP
+system. Additional synchronization mechanisms have been added to
+provide explicit synchronization for SMP.
+
+A set of functions have been added to the Kernel and device driver
+APIs to provide spinlocks:
+
+void cyg_spinlock_init( cyg_spinlock_t *lock, cyg_bool_t locked );
+void cyg_drv_spinlock_init( cyg_spinlock_t *lock, cyg_bool_t locked );
+
+void cyg_spinlock_destroy( cyg_spinlock_t *lock );
+void cyg_drv_spinlock_destroy( cyg_spinlock_t *lock );
+
+void cyg_spinlock_spin( cyg_spinlock_t *lock );
+void cyg_drv_spinlock_spin( cyg_spinlock_t *lock );
+
+void cyg_spinlock_clear( cyg_spinlock_t *lock );
+void cyg_drv_spinlock_clear( cyg_spinlock_t *lock );
+
+cyg_bool_t cyg_spinlock_try( cyg_spinlock_t *lock );
+cyg_bool_t cyg_drv_spinlock_try( cyg_spinlock_t *lock );
+
+cyg_bool_t cyg_spinlock_test( cyg_spinlock_t *lock );
+cyg_bool_t cyg_drv_spinlock_test( cyg_spinlock_t *lock );
+
+void cyg_spinlock_spin_intsave( cyg_spinlock_t *lock,
+ cyg_addrword_t *istate );
+void cyg_drv_spinlock_spin_intsave( cyg_spinlock_t *lock,
+ cyg_addrword_t *istate );
+
+void cyg_spinlock_clear_intsave( cyg_spinlock_t *lock,
+ cyg_addrword_t istate );
+void cyg_drv_spinlock_clear_intsave( cyg_spinlock_t *lock,
+ cyg_addrword_t istate );
+
+The *_init() functions initialize the lock, to either locked or clear,
+and the *_destroy() functions destroy the lock. Init() should be called
+before the lock is used and destroy() should be called when it is
+finished with.
+
+The *_spin() functions will cause the calling CPU to spin until it can
+claim the lock and the *_clear() functions clear the lock so that the
+next CPU can claim it. The *_try() functions attempts to claim the lock
+but returns false if it cannot. The *_test() functions simply return
+the state of the lock.
+
+None of these functions will necessarily block interrupts while they
+spin. If the spinlock is only to be used between threads on different
+CPUs, or in circumstances where it is known that the relevant
+interrupts are disabled, then these functions will suffice. However,
+if the spinlock is also to be used from an ISR, which may be called at
+any point, a straightforward spinlock may result in deadlock. Hence
+the *_intsave() variants are supplied to disable interrupts while the
+lock is held.
+
+The *_spin_intsave() function disables interrupts, saving the current
+state in *istate, and then claims the lock. The *_clear_intsave()
+function clears the spinlock and restores the interrupt enable state
+from *istate.
+
+
+HAL Support
+-----------
+
+SMP support in any platform depends on the HAL supplying the
+appropriate operations. All HAL SMP support is defined in the
+hal_smp.h header (and if necessary var_smp.h and plf_smp.h).
+
+SMP support falls into a number of functional groups.
+
+CPU Control
+~~~~~~~~~~~
+
+This group consists of descriptive and control macros for managing the
+CPUs in an SMP system.
+
+HAL_SMP_CPU_TYPE A type that can contain a CPU id. A CPU id is
+ usually a small integer that is used to index
+ arrays of variables that are managed on an
+ per-CPU basis.
+
+HAL_SMP_CPU_MAX The maximum number of CPUs that can be
+ supported. This is used to provide the size of
+ any arrays that have an element per CPU.
+
+HAL_SMP_CPU_COUNT() Returns the number of CPUs currently
+ operational. This may differ from
+ HAL_SMP_CPU_MAX depending on the runtime
+ environment.
+
+HAL_SMP_CPU_THIS() Returns the CPU id of the current CPU.
+
+HAL_SMP_CPU_NONE A value that does not match any real CPU
+ id. This is uses where a CPU type variable
+ must be set to a nul value.
+
+HAL_SMP_CPU_START( cpu )
+ Starts the given CPU executing at a defined
+ HAL entry point. After performing any HAL
+ level initialization, the CPU calls up into
+ the kernel at cyg_kernel_cpu_startup().
+
+HAL_SMP_CPU_RESCHEDULE_INTERRUPT( cpu, wait )
+ Sends the CPU a reschedule interrupt, and if
+ _wait_ is non-zero, waits for an
+ acknowledgment. The interrupted CPU should
+ call cyg_scheduler_set_need_reschedule() in
+ its DSR to cause the reschedule to occur.
+
+HAL_SMP_CPU_TIMESLICE_INTERRUPT( cpu, wait )
+ Sends the CPU a timeslice interrupt, and if
+ _wait_ is non-zero, waits for an
+ acknowledgment. The interrupted CPU should
+ call cyg_scheduler_timeslice_cpu() to cause
+ the timeslice event to be processed.
+
+Test-and-set Support
+~~~~~~~~~~~~~~~~~~~~
+
+Test-and-set is the foundation of the SMP synchronization
+mechanisms.
+
+HAL_TAS_TYPE The type for all test-and-set variables. The
+ test-and-set macros only support operations on
+ a single bit (usually the least significant
+ bit) of this location. This allows for maximum
+ flexibility in the implementation.
+
+HAL_TAS_SET( tas, oldb )
+ Performs a test and set operation on the
+ location _tas_. _oldb_ will contain *true* if
+ the location was already set, and *false* if
+ it was clear.
+
+HAL_TAS_CLEAR( tas, oldb )
+ Performs a test and clear operation on the
+ location _tas_. _oldb_ will contain *true* if
+ the location was already set, and *false* if
+ it was clear.
+
+Spinlocks
+~~~~~~~~~
+
+Spinlocks provide inter-CPU locking. Normally they will be implemented
+on top of the test-and-set mechanism above, but may also be
+implemented by other means if, for example, the hardware has more
+direct support for spinlocks.
+
+HAL_SPINLOCK_TYPE The type for all spinlock variables.
+
+HAL_SPINLOCK_INIT_CLEAR A value that may be assigned to a spinlock
+ variable to initialize it to clear.
+
+HAL_SPINLOCK_INIT_SET A value that may be assigned to a spinlock
+ variable to initialize it to set.
+
+HAL_SPINLOCK_SPIN( lock )
+ The caller spins in a busy loop waiting for
+ the lock to become clear. It then sets it and
+ continues. This is all handled atomically, so
+ that there are no race conditions between CPUs.
+
+HAL_SPINLOCK_CLEAR( lock )
+ The caller clears the lock. One of any waiting
+ spinners will then be able to proceed.
+
+HAL_SPINLOCK_TRY( lock, val )
+ Attempts to set the lock. The value put in
+ _val_ will be *true* if the lock was
+ claimed successfully, and *false* if it was
+ not.
+
+HAL_SPINLOCK_TEST( lock, val )
+ Tests the current value of the lock. The value
+ put in _val_ will be *true* if the lock is
+ claimed and *false* of it is clear.
+
+Scheduler Lock
+~~~~~~~~~~~~~~
+
+The scheduler lock is the main protection for all kernel data
+structures. By default the kernel implements the scheduler lock itself
+using a spinlock. However, if spinlocks cannot be supported by the
+hardware, or there is a more efficient implementation available, the
+HAL may provide macros to implement the scheduler lock.
+
+HAL_SMP_SCHEDLOCK_DATA_TYPE
+ A data type, possibly a structure, that
+ contains any data items needed by the
+ scheduler lock implementation. A variable of
+ this type will be instantiated as a static
+ member of the Cyg_Scheduler_SchedLock class
+ and passed to all the following macros.
+
+HAL_SMP_SCHEDLOCK_INIT( lock, data )
+ Initialize the scheduler lock. The _lock_
+ argument is the scheduler lock counter and the
+ _data_ argument is a variable of
+ HAL_SMP_SCHEDLOCK_DATA_TYPE type.
+
+HAL_SMP_SCHEDLOCK_INC( lock, data )
+ Increment the scheduler lock. The first
+ increment of the lock from zero to one for any
+ CPU may cause it to wait until the lock is
+ zeroed by another CPU. Subsequent increments
+ should be less expensive since this CPU
+ already holds the lock.
+
+HAL_SMP_SCHEDLOCK_ZERO( lock, data )
+ Zero the scheduler lock. This operation will
+ also clear the lock so that other CPUs may
+ claim it.
+
+HAL_SMP_SCHEDLOCK_SET( lock, data, new )
+
+ Set the lock to a different value, in
+ _new_. This is only called when the lock is
+ already known to be owned by the current
+ CPU. It is never called to zero the lock, or
+ to increment it from zero.
+
+
+Interrupt Routing
+~~~~~~~~~~~~~~~~~
+
+The routing of interrupts to different CPUs is supported by two new
+interfaces in hal_intr.h.
+
+Once an interrupt has been routed to a new CPU, the existing vector
+masking and configuration operations should take account of the CPU
+routing. For example, if the operation is not invoked on the
+destination CPU itself, then the HAL may need to arrange to transfer
+the operation to the destination CPU for correct application.
+
+HAL_INTERRUPT_SET_CPU( vector, cpu )
+ Route the interrupt for the given _vector_ to
+ the given _cpu_.
+
+HAL_INTERRUPT_GET_CPU( vector, cpu )
+ Set _cpu_ to the id of the CPU to which this
+ vector is routed.
+
+
+
+
+
+Annex 1 - Pentium SMP Support
+=============================
+
+ECos supports SMP working on Pentium class IA32 CPUs with integrated
+SMP support. It uses the per-CPU APIC's and the IOAPIC to provide CPU
+control and identification, and to distribute interrupts. Only PCI
+interrupts that map into the ISA interrupt space are currently
+supported. The code relies on the MP Configuration Table supplied by
+the BIOS to discover the number of CPUs, IOAPIC location and interrupt
+assignments - hardware based MP configuration discovery is
+not currently supported.
+
+Inter-CPU interrupts are mapped into interrupt vectors from 64
+up. Each CPU has its own vector at 64+CPUID.
+
+Interrupt delivery is initially configured to deliver all interrupts
+to the initial CPU. HAL_INTERRUPT_SET_CPU() currently only supports
+the ability to deliver interrupts to specific CPUs, dynamic CPU
+selection is not currently supported.
+
+eCos has only been tested in a dual processor configuration. While the
+code has been written to handle an arbitrary number of CPUs, this has
+not been tested.
+
diff --git a/ecos/packages/kernel/current/doc/kernel.sgml b/ecos/packages/kernel/current/doc/kernel.sgml
new file mode 100644
index 0000000000..694ecafee1
--- /dev/null
+++ b/ecos/packages/kernel/current/doc/kernel.sgml
@@ -0,0 +1,5456 @@
+<!-- {{{ Banner -->
+
+<!-- =============================================================== -->
+<!-- -->
+<!-- kernel.sgml -->
+<!-- -->
+<!-- eCos kernel documentation. -->
+<!-- -->
+<!-- =============================================================== -->
+<!-- ####COPYRIGHTBEGIN#### -->
+<!-- -->
+<!-- =============================================================== -->
+<!-- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -->
+<!-- This material may be distributed only subject to the terms -->
+<!-- and conditions set forth in the Open Publication License, v1.0 -->
+<!-- or later (the latest version is presently available at -->
+<!-- http://www.opencontent.org/openpub/) -->
+<!-- Distribution of the work or derivative of the work in any -->
+<!-- standard (paper) book form is prohibited unless prior -->
+<!-- permission obtained from the copyright holder -->
+<!-- =============================================================== -->
+<!-- -->
+<!-- ####COPYRIGHTEND#### -->
+<!-- =============================================================== -->
+<!-- #####DESCRIPTIONBEGIN#### -->
+<!-- -->
+<!-- Author(s): nickg, bartv, markg -->
+<!-- Contributors: eCos team -->
+<!-- Date: 2002/02/13 -->
+<!-- Version: 0.02 -->
+<!-- -->
+<!-- ####DESCRIPTIONEND#### -->
+<!-- =============================================================== -->
+
+<!-- }}} -->
+
+<part id="kernel">
+ <title>The eCos Kernel</title>
+
+<!-- {{{ Overview -->
+
+ <refentry id="kernel-overview">
+
+ <refmeta>
+ <refentrytitle>Kernel Overview</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>Kernel</refname>
+ <refpurpose>Overview of the eCos Kernel</refpurpose>
+ </refnamediv>
+
+<!-- {{{ Description -->
+
+ <refsect1 id="kernel-overview-description">
+ <title>Description</title>
+ <para>
+The kernel is one of the key packages in all of eCos. It provides the
+core functionality needed for developing multi-threaded applications:
+ </para>
+ <orderedlist>
+ <listitem><para>
+The ability to create new threads in the system, either during startup
+or when the system is already running.
+ </para></listitem>
+ <listitem><para>
+Control over the various threads in the system, for example
+manipulating their priorities.
+ </para></listitem>
+ <listitem><para>
+A choice of schedulers, determining which thread should currently be
+running.
+ </para></listitem>
+ <listitem><para>
+A range of synchronization primitives, allowing threads to interact
+and share data safely.
+ </para></listitem>
+ <listitem><para>
+Integration with the system's support for interrupts and exceptions.
+ </para></listitem>
+ </orderedlist>
+ <para>
+In some other operating systems the kernel provides additional
+functionality. For example the kernel may also provide memory
+allocation functionality, and device drivers may be part of the kernel
+as well. This is not the case for eCos. Memory allocation is handled
+by a separate package. Similary each device driver will typically be a
+separate package. Various packages are combined and configured using
+the eCos configuration technology to meet the requirements of the
+application.
+ </para>
+ <para>
+The eCos kernel package is optional. It is possible to write
+single-threaded applications which do not use any kernel
+functionality, for example RedBoot. Typically such applications are
+based around a central polling loop, continually checking all devices
+and taking appropriate action when I/O occurs. A small amount of
+calculation is possible every iteration, at the cost of an increased
+delay between an I/O event occurring and the polling loop detecting
+the event. When the requirements are straightforward it may well be
+easier to develop the application using a polling loop, avoiding the
+complexities of multiple threads and synchronization between threads.
+As requirements get more complicated a multi-threaded solution becomes
+more appropriate, requiring the use of the kernel. In fact some of the
+more advanced packages in eCos, for example the TCP/IP stack, use
+multi-threading internally. Therefore if the application uses any of
+those packages then the kernel becomes a required package, not an
+optional one.
+ </para>
+ <para>
+The kernel functionality can be used in one of two ways. The kernel
+provides its own C API, with functions like
+<function>cyg_thread_create</function> and
+<function>cyg_mutex_lock</function>. These can be called directly from
+application code or from other packages. Alternatively there are a
+number of packages which provide compatibility with existing API's,
+for example POSIX threads or &micro;ITRON. These allow application
+code to call standard functions such as
+<function>pthread_create</function>, and those functions are
+implemented using the basic functionality provided by the eCos kernel.
+Using compatibility packages in an eCos application can make it much
+easier to reuse code developed in other environments, and to share
+code.
+ </para>
+ <para>
+Although the different compatibility packages have similar
+requirements on the underlying kernel, for example the ability to
+create a new thread, there are differences in the exact semantics. For
+example, strict &micro;ITRON compliance requires that kernel
+timeslicing is disabled. This is achieved largely through the
+configuration technology. The kernel provides a number of
+configuration options that control the exact semantics that are
+provided, and the various compatibility packages require particular
+settings for those options. This has two important consequences.
+First, it is not usually possible to have two different compatibility
+packages in one eCos configuration because they will have conflicting
+requirements on the underlying kernel. Second, the semantics of the
+kernel's own API are only loosely defined because of the many
+configuration options. For example <function>cyg_mutex_lock</function>
+will always attempt to lock a mutex, but various configuration options
+determine the behaviour when the mutex is already locked and there is
+a possibility of priority inversion.
+ </para>
+ <para>
+The optional nature of the kernel package presents some complications
+for other code, especially device drivers. Wherever possible a device
+driver should work whether or not the kernel is present. However there
+are some parts of the system, especially those related to interrupt
+handling, which should be implemented differently in multi-threaded
+environments containing the eCos kernel and in single-threaded
+environments without the kernel. To cope with both scenarios the
+common HAL package provides a driver API, with functions such as
+<function>cyg_drv_interrupt_attach</function>. When the kernel package
+is present these driver API functions map directly on to the
+equivalent kernel functions such as
+<function>cyg_interrupt_attach</function>, using macros to avoid any
+overheads. When the kernel is absent the common HAL package implements
+the driver API directly, but this implementation is simpler than the
+one in the kernel because it can assume a single-threaded environment.
+ </para>
+ </refsect1>
+
+<!-- }}} -->
+<!-- {{{ Schedulers -->
+
+ <refsect1 id="kernel-overview-schedulers">
+ <title>Schedulers</title>
+ <para>
+When a system involves multiple threads, a scheduler is needed to
+determine which thread should currently be running. The eCos kernel
+can be configured with one of two schedulers, the bitmap scheduler and
+the multi-level queue (MLQ) scheduler. The bitmap scheduler is
+somewhat more efficient, but has a number of limitations. Most systems
+will instead use the MLQ scheduler. Other schedulers may be added in
+the future, either as extensions to the kernel package or in separate
+packages.
+ </para>
+ <para>
+Both the bitmap and the MLQ scheduler use a simple numerical priority
+to determine which thread should be running. The number of priority
+levels is configurable via the option
+<varname>CYGNUM_KERNEL_SCHED_PRIORITIES</varname>, but a typical
+system will have up to 32 priority levels. Therefore thread priorities
+will be in the range 0 to 31, with 0 being the highest priority and 31
+the lowest. Usually only the system's idle thread will run at the
+lowest priority. Thread priorities are absolute, so the kernel will
+only run a lower-priority thread if all higher-priority threads are
+currently blocked.
+ </para>
+ <para>
+The bitmap scheduler only allows one thread per priority level, so if
+the system is configured with 32 priority levels then it is limited to
+only 32 threads &mdash; still enough for many applications. A simple
+bitmap can be used to keep track of which threads are currently
+runnable. Bitmaps can also be used to keep track of threads waiting on
+a mutex or other synchronization primitive. Identifying the
+highest-priority runnable or waiting thread involves a simple
+operation on the bitmap, and an array index operation can then be used
+to get hold of the thread data structure itself. This makes the
+bitmap scheduler fast and totally deterministic.
+ </para>
+ <para>
+The MLQ scheduler allows multiple threads to run at the same priority.
+This means that there is no limit on the number of threads in the
+system, other than the amount of memory available. However operations
+such as finding the highest priority runnable thread are a little bit
+more expensive than for the bitmap scheduler.
+ </para>
+ <para>
+Optionally the MLQ scheduler supports timeslicing, where the scheduler
+automatically switches from one runnable thread to another when some
+number of clock ticks have occurred. Timeslicing only comes into play
+when there are two runnable threads at the same priority and no higher
+priority runnable threads. If timeslicing is disabled then a thread
+will not be preempted by another thread of the same priority, and will
+continue running until either it explicitly yields the processor or
+until it blocks by, for example, waiting on a synchronization
+primitive. The configuration options
+<varname>CYGSEM_KERNEL_SCHED_TIMESLICE</varname> and
+<varname>CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS</varname> control
+timeslicing. The bitmap scheduler does not provide timeslicing
+support. It only allows one thread per priority level, so it is not
+possible to preempt the current thread in favour of another one with
+the same priority.
+ </para>
+ <para>
+Another important configuration option that affects the MLQ scheduler
+is <varname>CYGIMP_KERNEL_SCHED_SORTED_QUEUES</varname>. This
+determines what happens when a thread blocks, for example by waiting
+on a semaphore which has no pending events. The default behaviour of
+the system is last-in-first-out queuing. For example if several
+threads are waiting on a semaphore and an event is posted, the thread
+that gets woken up is the last one that called
+<function>cyg_semaphore_wait</function>. This allows for a simple and
+fast implementation of both the queue and dequeue operations. However
+if there are several queued threads with different priorities, it may
+not be the highest priority one that gets woken up. In practice this
+is rarely a problem: usually there will be at most one thread waiting
+on a queue, or when there are several threads they will be of the same
+priority. However if the application does require strict priority
+queueing then the option
+<varname>CYGIMP_KERNEL_SCHED_SORTED_QUEUES</varname> should be
+enabled. There are disadvantages: more work is needed whenever a
+thread is queued, and the scheduler needs to be locked for this
+operation so the system's dispatch latency is worse. If the bitmap
+scheduler is used then priority queueing is automatic and does not
+involve any penalties.
+ </para>
+ <para>
+Some kernel functionality is currently only supported with the MLQ
+scheduler, not the bitmap scheduler. This includes support for SMP
+systems, and protection against priority inversion using either mutex
+priority ceilings or priority inheritance.
+ </para>
+ </refsect1>
+
+<!-- }}} -->
+<!-- {{{ Synch primitives -->
+
+ <refsect1 id="kernel-overview-synch-primitives">
+ <title>Synchronization Primitives</title>
+ <para>
+The eCos kernel provides a number of different synchronization
+primitives: <link linkend="kernel-mutexes">mutexes</link>,
+<link linkend="kernel-condition-variables">condition variables</link>,
+<link linkend="kernel-semaphores">counting semaphores</link>,
+<link linkend="kernel-mail-boxes">mail boxes</link> and
+<link linkend="kernel-flags">event flags</link>.
+ </para>
+ <para>
+Mutexes serve a very different purpose from the other primitives. A
+mutex allows multiple threads to share a resource safely: a thread
+locks a mutex, manipulates the shared resource, and then unlocks the
+mutex again. The other primitives are used to communicate information
+between threads, or alternatively from a DSR associated with an
+interrupt handler to a thread.
+ </para>
+ <para>
+When a thread that has locked a mutex needs to wait for some condition
+to become true, it should use a condition variable. A condition
+variable is essentially just a place for a thread to wait, and which
+another thread, or DSR, can use to wake it up. When a thread waits on
+a condition variable it releases the mutex before waiting, and when it
+wakes up it reacquires it before proceeding. These operations are
+atomic so that synchronization race conditions cannot be introduced.
+ </para>
+ <para>
+A counting semaphore is used to indicate that a particular event has
+occurred. A consumer thread can wait for this event to occur, and a
+producer thread or a DSR can post the event. There is a count
+associated with the semaphore so if the event occurs multiple times in
+quick succession this information is not lost, and the appropriate
+number of semaphore wait operations will succeed.
+ </para>
+ <para>
+Mail boxes are also used to indicate that a particular event has
+occurred, and allows for one item of data to be exchanged per event.
+Typically this item of data would be a pointer to some data structure.
+Because of the need to store this extra data, mail boxes have a
+finite capacity. If a producer thread generates mail box events
+faster than they can be consumed then, to avoid overflow, it will be
+blocked until space is again available in the mail box. This means
+that mail boxes usually cannot be used by a DSR to wake up a
+thread. Instead mail boxes are typically only used between threads.
+ </para>
+ <para>
+Event flags can be used to wait on some number of different events,
+and to signal that one or several of these events have occurred. This
+is achieved by associating bits in a bit mask with the different
+events. Unlike a counting semaphore no attempt is made to keep track
+of the number of events that have occurred, only the fact that an
+event has occurred at least once. Unlike a mail box it is not
+possible to send additional data with the event, but this does mean
+that there is no possibility of an overflow and hence event flags can
+be used between a DSR and a thread as well as between threads.
+ </para>
+ <para>
+The eCos common HAL package provides its own device driver API which
+contains some of the above synchronization primitives. These allow
+the DSR for an interrupt handler to signal events to higher-level
+code. If the configuration includes the eCos kernel package then
+the driver API routines map directly on to the equivalent kernel
+routines, allowing interrupt handlers to interact with threads. If the
+kernel package is not included and the application consists of just a
+single thread running in polled mode then the driver API is
+implemented entirely within the common HAL, and with no need to worry
+about multiple threads the implementation can obviously be rather
+simpler.
+ </para>
+ </refsect1>
+
+<!-- }}} -->
+<!-- {{{ Threads and interrupts -->
+
+ <refsect1 id="kernel-overview-threads-interrupts">
+ <title>Threads and Interrupt Handling</title>
+ <para>
+During normal operation the processor will be running one of the
+threads in the system. This may be an application thread, a system
+thread running inside say the TCP/IP stack, or the idle thread. From
+time to time a hardware interrupt will occur, causing control to be
+transferred briefly to an interrupt handler. When the interrupt has
+been completed the system's scheduler will decide whether to return
+control to the interrupted thread or to some other runnable thread.
+ </para>
+ <para>
+Threads and interrupt handlers must be able to interact. If a thread
+is waiting for some I/O operation to complete, the interrupt handler
+associated with that I/O must be able to inform the thread that the
+operation has completed. This can be achieved in a number of ways. One
+very simple approach is for the interrupt handler to set a volatile
+variable. A thread can then poll continuously until this flag is set,
+possibly sleeping for a clock tick in between. Polling continuously
+means that the cpu time is not available for other activities, which
+may be acceptable for some but not all applications. Polling once
+every clock tick imposes much less overhead, but means that the thread
+may not detect that the I/O event has occurred until an entire clock
+tick has elapsed. In typical systems this could be as long as 10
+milliseconds. Such a delay might be acceptable for some applications,
+but not all.
+ </para>
+ <para>
+A better solution would be to use one of the synchronization
+primitives. The interrupt handler could signal a condition variable,
+post to a semaphore, or use one of the other primitives. The thread
+would perform a wait operation on the same primitive. It would not
+consume any cpu cycles until the I/O event had occurred, and when the
+event does occur the thread can start running again immediately
+(subject to any higher priority threads that might also be runnable).
+ </para>
+ <para>
+Synchronization primitives constitute shared data, so care must be
+taken to avoid problems with concurrent access. If the thread that was
+interrupted was just performing some calculations then the interrupt
+handler could manipulate the synchronization primitive quite safely.
+However if the interrupted thread happened to be inside some kernel
+call then there is a real possibility that some kernel data structure
+will be corrupted.
+ </para>
+ <para>
+One way of avoiding such problems would be for the kernel functions to
+disable interrupts when executing any critical region. On most
+architectures this would be simple to implement and very fast, but it
+would mean that interrupts would be disabled often and for quite a
+long time. For some applications that might not matter, but many
+embedded applications require that the interrupt handler run as soon
+as possible after the hardware interrupt has occurred. If the kernel
+relied on disabling interrupts then it would not be able to support
+such applications.
+ </para>
+ <para>
+Instead the kernel uses a two-level approach to interrupt handling.
+Associated with every interrupt vector is an Interrupt Service Routine
+or ISR, which will run as quickly as possible so that it can service
+the hardware. However an ISR can make only a small number of kernel
+calls, mostly related to the interrupt subsystem, and it cannot make
+any call that would cause a thread to wake up. If an ISR detects that
+an I/O operation has completed and hence that a thread should be woken
+up, it can cause the associated Deferred Service Routine or DSR to
+run. A DSR is allowed to make more kernel calls, for example it can
+signal a condition variable or post to a semaphore.
+ </para>
+ <para>
+Disabling interrupts prevents ISRs from running, but very few parts of
+the system disable interrupts and then only for short periods of time.
+The main reason for a thread to disable interrupts is to manipulate
+some state that is shared with an ISR. For example if a thread needs
+to add another buffer to a linked list of free buffers and the ISR may
+remove a buffer from this list at any time, the thread would need to
+disable interrupts for the few instructions needed to manipulate the
+list. If the hardware raises an interrupt at this time, it remains
+pending until interrupts are reenabled.
+ </para>
+ <para>
+Analogous to interrupts being disabled or enabled, the kernel has a
+scheduler lock. The various kernel functions such as
+<function>cyg_mutex_lock</function> and
+<function>cyg_semaphore_post</function> will claim the scheduler lock,
+manipulate the kernel data structures, and then release the scheduler
+lock. If an interrupt results in a DSR being requested and the
+scheduler is currently locked, the DSR remains pending. When the
+scheduler lock is released any pending DSRs will run. These may post
+events to synchronization primitives, causing other higher priority
+threads to be woken up.
+ </para>
+ <para>
+For an example, consider the following scenario. The system has a high
+priority thread A, responsible for processing some data coming from an
+external device. This device will raise an interrupt when data is
+available. There are two other threads B and C which spend their time
+performing calculations and occasionally writing results to a display
+of some sort. This display is a shared resource so a mutex is used to
+control access.
+ </para>
+ <para>
+At a particular moment in time thread A is likely to be blocked,
+waiting on a semaphore or another synchronization primitive until data
+is available. Thread B might be running performing some calculations,
+and thread C is runnable waiting for its next timeslice. Interrupts
+are enabled, and the scheduler is unlocked because none of the threads
+are in the middle of a kernel operation. At this point the device
+raises an interrupt. The hardware transfers control to a low-level
+interrupt handler provided by eCos which works out exactly which
+interrupt occurs, and then the corresponding ISR is run. This ISR
+manipulates the hardware as appropriate, determines that there is now
+data available, and wants to wake up thread A by posting to the
+semaphore. However ISR's are not allowed to call
+<function>cyg_semaphore_post</function> directly, so instead the ISR
+requests that its associated DSR be run and returns. There are no more
+interrupts to be processed, so the kernel next checks for DSR's. One
+DSR is pending and the scheduler is currently unlocked, so the DSR can
+run immediately and post the semaphore. This will have the effect of
+making thread A runnable again, so the scheduler's data structures are
+adjusted accordingly. When the DSR returns thread B is no longer the
+highest priority runnable thread so it will be suspended, and instead
+thread A gains control over the cpu.
+ </para>
+ <para>
+In the above example no kernel data structures were being manipulated
+at the exact moment that the interrupt happened. However that cannot
+be assumed. Suppose that thread B had finished its current set of
+calculations and wanted to write the results to the display. It would
+claim the appropriate mutex and manipulate the display. Now suppose
+that thread B was timesliced in favour of thread C, and that thread C
+also finished its calculations and wanted to write the results to the
+display. It would call <function>cyg_mutex_lock</function>. This
+kernel call locks the scheduler, examines the current state of the
+mutex, discovers that the mutex is already owned by another thread,
+suspends the current thread, and switches control to another runnable
+thread. Another interrupt happens in the middle of this
+<function>cyg_mutex_lock</function> call, causing the ISR to run
+immediately. The ISR decides that thread A should be woken up so it
+requests that its DSR be run and returns back to the kernel. At this
+point there is a pending DSR, but the scheduler is still locked by the
+call to <function>cyg_mutex_lock</function> so the DSR cannot run
+immediately. Instead the call to <function>cyg_mutex_lock</function>
+is allowed to continue, which at some point involves unlocking the
+scheduler. The pending DSR can now run, safely post the semaphore, and
+thus wake up thread A.
+ </para>
+ <para>
+If the ISR had called <function>cyg_semaphore_post</function> directly
+rather than leaving it to a DSR, it is likely that there would have
+been some sort of corruption of a kernel data structure. For example
+the kernel might have completely lost track of one of the threads, and
+that thread would never have run again. The two-level approach to
+interrupt handling, ISR's and DSR's, prevents such problems with no
+need to disable interrupts.
+ </para>
+ </refsect1>
+
+<!-- }}} -->
+<!-- {{{ Calling contexts -->
+
+ <refsect1 id="kernel-overview-contexts">
+ <title>Calling Contexts</title>
+ <para>
+eCos defines a number of contexts. Only certain calls are allowed from
+inside each context, for example most operations on threads or
+synchronization primitives are not allowed from ISR context. The
+different contexts are initialization, thread, ISR and DSR.
+ </para>
+ <para>
+When eCos starts up it goes through a number of phases, including
+setting up the hardware and invoking C++ static constructors. During
+this time interrupts are disabled and the scheduler is locked. When a
+configuration includes the kernel package the final operation is a
+call to <link
+linkend="kernel-schedcontrol"><function>cyg_scheduler_start</function></link>.
+At this point interrupts are enabled, the scheduler is unlocked, and
+control is transferred to the highest priority runnable thread. If the
+configuration also includes the C library package then usually the C
+library startup package will have created a thread which will call the
+application's <function>main</function> entry point.
+ </para>
+ <para>
+Some application code can also run before the scheduler is started,
+and this code runs in initialization context. If the application is
+written partly or completely in C++ then the constructors for any
+static objects will be run. Alternatively application code can define
+a function <function>cyg_user_start</function> which gets called after
+any C++ static constructors. This allows applications to be written
+entirely in C.
+ </para>
+ <programlisting width=72>
+void
+cyg_user_start(void)
+{
+ /* Perform application-specific initialization here */
+}
+ </programlisting>
+ <para>
+It is not necessary for applications to provide a
+<function>cyg_user_start</function> function since the system will
+provide a default implementation which does nothing.
+ </para>
+ <para>
+Typical operations that are performed from inside static constructors
+or <function>cyg_user_start</function> include creating threads,
+synchronization primitives, setting up alarms, and registering
+application-specific interrupt handlers. In fact for many applications
+all such creation operations happen at this time, using statically
+allocated data, avoiding any need for dynamic memory allocation or
+other overheads.
+ </para>
+ <para>
+Code running in initialization context runs with interrupts disabled
+and the scheduler locked. It is not permitted to reenable interrupts
+or unlock the scheduler because the system is not guaranteed to be in
+a totally consistent state at this point. A consequence is that
+initialization code cannot use synchronization primitives such as
+<function>cyg_semaphore_wait</function> to wait for an external event.
+It is permitted to lock and unlock a mutex: there are no other threads
+running so it is guaranteed that the mutex is not yet locked, and
+therefore the lock operation will never block; this is useful when
+making library calls that may use a mutex internally.
+ </para>
+ <para>
+At the end of the startup sequence the system will call
+<function>cyg_scheduler_start</function> and the various threads will
+start running. In thread context nearly all of the kernel functions
+are available. There may be some restrictions on interrupt-related
+operations, depending on the target hardware. For example the hardware
+may require that interrupts be acknowledged in the ISR or DSR before
+control returns to thread context, in which case
+<filename>cyg_interrupt_acknowledge</filename> should not be called
+by a thread.
+ </para>
+ <para>
+At any time the processor may receive an external interrupt, causing
+control to be transferred from the current thread. Typically a VSR
+provided by eCos will run and determine exactly which interrupt
+occurred. Then the VSR will switch to the appropriate ISR, which can
+be provided by a HAL package, a device driver, or by the application.
+During this time the system is running at ISR context, and most of the
+kernel function calls are disallowed. This includes the various
+synchronization primitives, so for example an ISR is not allowed to
+post to a semaphore to indicate that an event has happened. Usually
+the only operations that should be performed from inside an ISR are
+ones related to the interrupt subsystem itself, for example masking an
+interrupt or acknowledging that an interrupt has been processed. On
+SMP systems it is also possible to use spinlocks from ISR context.
+ </para>
+ <para>
+When an ISR returns it can request that the corresponding DSR be run
+as soon as it is safe to do so, and that will run in DSR context. This
+context is also used for running alarm functions, and threads can
+switch temporarily to DSR context by locking the scheduler. Only
+certain kernel functions can be called from DSR context, although more
+than in ISR context. In particular it is possible to use any
+synchronization primitives which cannot block. These include
+<function>cyg_semaphore_post</function>,
+<filename>cyg_cond_signal</filename>,
+<function>cyg_cond_broadcast</function>,
+<function>cyg_flag_setbits</function>, and
+<function>cyg_mbox_tryput</function>. It is not possible to use any
+primitives that may block such as
+<function>cyg_semaphore_wait</function>,
+<function>cyg_mutex_lock</function>, or
+<function>cyg_mbox_put</function>. Calling such functions from inside
+a DSR may cause the system to hang.
+ </para>
+ <para>
+The specific documentation for the various kernel functions gives more
+details about valid contexts.
+ </para>
+ </refsect1>
+
+<!-- }}} -->
+<!-- {{{ Error handling -->
+
+ <refsect1 id="kernel-overview-errors">
+ <title>Error Handling and Assertions</title>
+ <para>
+In many APIs each function is expected to perform some validation of
+its parameters and possibly of the current state of the system. This
+is supposed to ensure that each function is used correctly, and that
+application code is not attempting to perform a semaphore operation on
+a mutex or anything like that. If an error is detected then a suitable
+error code is returned, for example the POSIX function
+<function>pthread_mutex_lock</function> can return various error codes
+including <literal>EINVAL</literal> and <literal>EDEADLK</literal>.
+There are a number of problems with this approach, especially in the
+context of deeply embedded systems:
+ </para>
+ <orderedlist>
+ <listitem><para>
+Performing these checks inside the mutex lock and all the other
+functions requires extra cpu cycles and adds significantly to the code
+size. Even if the application is written correctly and only makes
+system function calls with sensible arguments and under the right
+conditions, these overheads still exist.
+ </para></listitem>
+ <listitem><para>
+Returning an error code is only useful if the calling code detects
+these error codes and takes appropriate action. In practice the
+calling code will often ignore any errors because the programmer
+<emphasis>&ldquo;knows&rdquo;</emphasis> that the function is being
+used correctly. If the programmer is mistaken then an error condition
+may be detected and reported, but the application continues running
+anyway and is likely to fail some time later in mysterious ways.
+ </para></listitem>
+ <listitem><para>
+If the calling code does always check for error codes, that adds yet
+more cpu cycles and code size overhead.
+ </para></listitem>
+ <listitem><para>
+Usually there will be no way to recover from certain errors, so if the
+application code detected an error such as <literal>EINVAL</literal>
+then all it could do is abort the application somehow.
+ </para></listitem>
+ </orderedlist>
+ <para>
+The approach taken within the eCos kernel is different. Functions such
+as <function>cyg_mutex_lock</function> will not return an error code.
+Instead they contain various assertions, which can be enabled or
+disabled. During the development process assertions are normally left
+enabled, and the various kernel functions will perform parameter
+checks and other system consistency checks. If a problem is detected
+then an assertion failure will be reported and the application will be
+terminated. In a typical debug session a suitable breakpoint will have
+been installed and the developer can now examine the state of the
+system and work out exactly what is going on. Towards the end of the
+development cycle assertions will be disabled by manipulating
+configuration options within the eCos infrastructure package, and all
+assertions will be eliminated at compile-time. The assumption is that
+by this time the application code has been mostly debugged: the
+initial version of the code might have tried to perform a semaphore
+operation on a mutex, but any problems like that will have been fixed
+some time ago. This approach has a number of advantages:
+ </para>
+ <orderedlist>
+ <listitem><para>
+In the final application there will be no overheads for checking
+parameters and other conditions. All that code will have been
+eliminated at compile-time.
+ </para></listitem>
+ <listitem><para>
+Because the final application will not suffer any overheads, it is
+reasonable for the system to do more work during the development
+process. In particular the various assertions can test for more error
+conditions and more complicated errors. When an error is detected
+it is possible to give a text message describing the error rather than
+just return an error code.
+ </para></listitem>
+ <listitem><para>
+There is no need for application programmers to handle error codes
+returned by various kernel function calls. This simplifies the
+application code.
+ </para></listitem>
+ <listitem><para>
+If an error is detected then an assertion failure will be reported
+immediately and the application will be halted. There is no
+possibility of an error condition being ignored because application
+code did not check for an error code.
+ </para></listitem>
+ </orderedlist>
+ <para>
+Although none of the kernel functions return an error code, many of
+them do return a status condition. For example the function
+<function>cyg_semaphore_timed_wait</function> waits until either an
+event has been posted to a semaphore, or until a certain number of
+clock ticks have occurred. Usually the calling code will need to know
+whether the wait operation succeeded or whether a timeout occurred.
+<function>cyg_semaphore_timed_wait</function> returns a boolean: a
+return value of zero or false indicates a timeout, a non-zero return
+value indicates that the wait succeeded.
+ </para>
+ <para>
+In conventional APIs one common error conditions is lack of memory.
+For example the POSIX function <function>pthread_create</function>
+usually has to allocate some memory dynamically for the thread stack
+and other per-thread data. If the target hardware does not have enough
+memory to meet all demands, or more commonly if the application
+contains a memory leak, then there may not be enough memory available
+and the function call would fail. The eCos kernel avoids such problems
+by never performing any dynamic memory allocation. Instead it is the
+responsibility of the application code to provide all the memory
+required for kernel data structures and other needs. In the case of
+<function>cyg_thread_create</function> this means a
+<structname>cyg_thread</structname> data structure to hold the thread
+details, and a <type>char</type> array for the thread stack.
+ </para>
+ <para>
+In many applications this approach results in all data structures
+being allocated statically rather than dynamically. This has several
+advantages. If the application is in fact too large for the target
+hardware's memory then there will be an error at link-time rather than
+at run-time, making the problem much easier to diagnose. Static
+allocation does not involve any of the usual overheads associated with
+dynamic allocation, for example there is no need to keep track of the
+various free blocks in the system, and it may be possible to eliminate
+<function>malloc</function> from the system completely. Problems such
+as fragmentation and memory leaks cannot occur if all data is
+allocated statically. However, some applications are sufficiently
+complicated that dynamic memory allocation is required, and the
+various kernel functions do not distinguish between statically and
+dynamically allocated memory. It still remains the responsibility of
+the calling code to ensure that sufficient memory is available, and
+passing null pointers to the kernel will result in assertions or
+system failure.
+ </para>
+ </refsect1>
+
+<!-- }}} -->
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ SMP -->
+
+ <refentry id="kernel-SMP">
+
+ <refmeta>
+ <refentrytitle>SMP Support</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>SMP</refname>
+ <refpurpose>Support Symmetric Multiprocessing Systems</refpurpose>
+ </refnamediv>
+
+ <refsect1 id="kernel-smp-description">
+ <title>Description</title>
+ <para>
+eCos contains support for limited Symmetric Multi-Processing (SMP).
+This is only available on selected architectures and platforms.
+The implementation has a number of restrictions on the kind of
+hardware supported. These are described in <xref linkend="hal-smp-support">.
+ </para>
+
+ <para>
+The following sections describe the changes that have been made to the
+eCos kernel to support SMP operation.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-smp-startup">
+ <title>System Startup</title>
+ <para>
+The system startup sequence needs to be somewhat different on an SMP
+system, although this is largely transparent to application code. The
+main startup takes place on only one CPU, called the primary CPU. All
+other CPUs, the secondary CPUs, are either placed in suspended state
+at reset, or are captured by the HAL and put into a spin as they start
+up. The primary CPU is responsible for copying the DATA segment and
+zeroing the BSS (if required), calling HAL variant and platform
+initialization routines and invoking constructors. It then calls
+<function>cyg_start</function> to enter the application. The
+application may then create extra threads and other objects.
+ </para>
+ <para>
+It is only when the application calls
+<function>cyg_scheduler_start</function> that the secondary CPUs are
+initialized. This routine scans the list of available secondary CPUs
+and invokes <function>HAL_SMP_CPU_START</function> to start each
+CPU. Finally it calls an internal function
+<function>Cyg_Scheduler::start_cpu</function> to enter the scheduler
+for the primary CPU.
+ </para>
+ <para>
+Each secondary CPU starts in the HAL, where it completes any per-CPU
+initialization before calling into the kernel at
+<function>cyg_kernel_cpu_startup</function>. Here it claims the
+scheduler lock and calls
+<function>Cyg_Scheduler::start_cpu</function>.
+ </para>
+ <para>
+<function>Cyg_Scheduler::start_cpu</function> is common to both the
+primary and secondary CPUs. The first thing this code does is to
+install an interrupt object for this CPU's inter-CPU interrupt. From
+this point on the code is the same as for the single CPU case: an
+initial thread is chosen and entered.
+ </para>
+ <para>
+From this point on the CPUs are all equal, eCos makes no further
+distinction between the primary and secondary CPUs. However, the
+hardware may still distinguish between them as far as interrupt
+delivery is concerned.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-smp-scheduling">
+ <title>Scheduling</title>
+ <para>
+To function correctly an operating system kernel must protect its
+vital data structures, such as the run queues, from concurrent
+access. In a single CPU system the only concurrent activities to worry
+about are asynchronous interrupts. The kernel can easily guard its
+data structures against these by disabling interrupts. However, in a
+multi-CPU system, this is inadequate since it does not block access by
+other CPUs.
+ </para>
+ <para>
+The eCos kernel protects its vital data structures using the scheduler
+lock. In single CPU systems this is a simple counter that is
+atomically incremented to acquire the lock and decremented to release
+it. If the lock is decremented to zero then the scheduler may be
+invoked to choose a different thread to run. Because interrupts may
+continue to be serviced while the scheduler lock is claimed, ISRs are
+not allowed to access kernel data structures, or call kernel routines
+that can. Instead all such operations are deferred to an associated
+DSR routine that is run during the lock release operation, when the
+data structures are in a consistent state.
+ </para>
+ <para>
+By choosing a kernel locking mechanism that does not rely on interrupt
+manipulation to protect data structures, it is easier to convert eCos
+to SMP than would otherwise be the case. The principal change needed to
+make eCos SMP-safe is to convert the scheduler lock into a nestable
+spin lock. This is done by adding a spinlock and a CPU id to the
+original counter.
+ </para>
+ <para>
+The algorithm for acquiring the scheduler lock is very simple. If the
+scheduler lock's CPU id matches the current CPU then it can just increment
+the counter and continue. If it does not match, the CPU must spin on
+the spinlock, after which it may increment the counter and store its
+own identity in the CPU id.
+ </para>
+ <para>
+To release the lock, the counter is decremented. If it goes to zero
+the CPU id value must be set to NONE and the spinlock cleared.
+ </para>
+ <para>
+To protect these sequences against interrupts, they must be performed
+with interrupts disabled. However, since these are very short code
+sequences, they will not have an adverse effect on the interrupt
+latency.
+ </para>
+ <para>
+Beyond converting the scheduler lock, further preparing the kernel for
+SMP is a relatively minor matter. The main changes are to convert
+various scalar housekeeping variables into arrays indexed by CPU
+id. These include the current thread pointer, the need_reschedule
+flag and the timeslice counter.
+ </para>
+ <para>
+At present only the Multi-Level Queue (MLQ) scheduler is capable of
+supporting SMP configurations. The main change made to this scheduler
+is to cope with having several threads in execution at the same
+time. Running threads are marked with the CPU that they are executing on.
+When scheduling a thread, the scheduler skips past any running threads
+until it finds a thread that is pending. While not a constant-time
+algorithm, as in the single CPU case, this is still deterministic,
+since the worst case time is bounded by the number of CPUs in the
+system.
+ </para>
+ <para>
+A second change to the scheduler is in the code used to decide when
+the scheduler should be called to choose a new thread. The scheduler
+attempts to keep the <property>n</property> CPUs running the
+<property>n</property> highest priority threads. Since an event or
+interrupt on one CPU may require a reschedule on another CPU, there
+must be a mechanism for deciding this. The algorithm currently
+implemented is very simple. Given a thread that has just been awakened
+(or had its priority changed), the scheduler scans the CPUs, starting
+with the one it is currently running on, for a current thread that is
+of lower priority than the new one. If one is found then a reschedule
+interrupt is sent to that CPU and the scan continues, but now using
+the current thread of the rescheduled CPU as the candidate thread. In
+this way the new thread gets to run as quickly as possible, hopefully
+on the current CPU, and the remaining CPUs will pick up the remaining
+highest priority threads as a consequence of processing the reschedule
+interrupt.
+ </para>
+ <para>
+The final change to the scheduler is in the handling of
+timeslicing. Only one CPU receives timer interrupts, although all CPUs
+must handle timeslicing. To make this work, the CPU that receives the
+timer interrupt decrements the timeslice counter for all CPUs, not
+just its own. If the counter for a CPU reaches zero, then it sends a
+timeslice interrupt to that CPU. On receiving the interrupt the
+destination CPU enters the scheduler and looks for another thread at
+the same priority to run. This is somewhat more efficient than
+distributing clock ticks to all CPUs, since the interrupt is only
+needed when a timeslice occurs.
+ </para>
+ <para>
+All existing synchronization mechanisms work as before in an SMP
+system. Additional synchronization mechanisms have been added to
+provide explicit synchronization for SMP, in the form of
+<link linkend="kernel-spinlocks">spinlocks</link>.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-smp-interrupts">
+ <title>SMP Interrupt Handling</title>
+ <para>
+The main area where the SMP nature of a system requires special
+attention is in device drivers and especially interrupt handling. It
+is quite possible for the ISR, DSR and thread components of a device
+driver to execute on different CPUs. For this reason it is much more
+important that SMP-capable device drivers use the interrupt-related
+functions correctly. Typically a device driver would use the driver
+API rather than call the kernel directly, but it is unlikely that
+anybody would attempt to use a multiprocessor system without the
+kernel package.
+ </para>
+ <para>
+Two new functions have been added to the Kernel API
+to do <link linkend="kernel-interrupts-smp">interrupt
+routing</link>: <function>cyg_interrupt_set_cpu</function> and
+<function>cyg_interrupt_get_cpu</function>. Although not currently
+supported, special values for the cpu argument may be used in future
+to indicate that the interrupt is being routed dynamically or is
+CPU-local. Once a vector has been routed to a new CPU, all other
+interrupt masking and configuration operations are relative to that
+CPU, where relevant.
+ </para>
+
+ <para>
+There are more details of how interrupts should be handled in SMP
+systems in <xref linkend="devapi-smp-support">.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+
+<!-- {{{ cyg_thread_create() -->
+
+ <refentry id="kernel-thread-create">
+
+ <refmeta>
+ <refentrytitle>Thread creation</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_thread_create</refname>
+ <refpurpose>Create a new thread</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_create</function></funcdef>
+ <paramdef>cyg_addrword_t <parameter>sched_info</parameter></paramdef>
+ <paramdef>cyg_thread_entry_t* <parameter>entry</parameter></paramdef>
+ <paramdef>cyg_addrword_t <parameter>entry_data</parameter></paramdef>
+ <paramdef>char* <parameter>name</parameter></paramdef>
+ <paramdef>void* <parameter>stack_base</parameter></paramdef>
+ <paramdef>cyg_ucount32 <parameter>stack_size</parameter></paramdef>
+ <paramdef>cyg_handle_t* <parameter>handle</parameter></paramdef>
+ <paramdef>cyg_thread* <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-thread-create-description"><title>Description</title>
+ <para>
+The <function>cyg_thread_create</function> function allows application
+code and eCos packages to create new threads. In many applications
+this only happens during system initialization and all required data
+is allocated statically. However additional threads can be created at
+any time, if necessary. A newly created thread is always in suspended
+state and will not start running until it has been resumed via a call
+to <function>cyg_thread_resume</function>. Also, if threads are
+created during system initialization then they will not start running
+until the eCos scheduler has been started.
+ </para>
+ <para>
+The <parameter class="function">name</parameter> argument is used
+primarily for debugging purposes, making it easier to keep track of
+which <structname>cyg_thread</structname> structure is associated with
+which application-level thread. The kernel configuration option
+<varname>CYGVAR_KERNEL_THREADS_NAME</varname> controls whether or not
+this name is actually used.
+ </para>
+ <para>
+On creation each thread is assigned a unique handle, and this will be
+stored in the location pointed at by the <parameter
+class="function">handle</parameter> argument. Subsequent operations on
+this thread including the required
+<function>cyg_thread_resume</function> should use this handle to
+identify the thread.
+ </para>
+ <para>
+The kernel requires a small amount of space for each thread, in the
+form of a <structname>cyg_thread</structname> data structure, to hold
+information such as the current state of that thread. To avoid any
+need for dynamic memory allocation within the kernel this space has to
+be provided by higher-level code, typically in the form of a static
+variable. The <parameter class="function">thread</parameter> argument
+provides this space.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-create-entry"><title>Thread Entry Point</title>
+ <para>
+The entry point for a thread takes the form:
+ </para>
+ <programlisting width=72>
+void
+thread_entry_function(cyg_addrword_t data)
+{
+ &hellip;
+}
+ </programlisting>
+ <para>
+The second argument to <function>cyg_thread_create</function> is a
+pointer to such a function. The third argument <parameter
+class="function">entry_data</parameter> is used to pass additional
+data to the function. Typically this takes the form of a pointer to
+some static data, or a small integer, or <literal>0</literal> if the
+thread does not require any additional data.
+ </para>
+ <para>
+If the thread entry function ever returns then this is equivalent to
+the thread calling <function>cyg_thread_exit</function>. Even though
+the thread will no longer run again, it remains registered with the
+scheduler. If the application needs to re-use the
+<structname>cyg_thread</structname> data structure then a call to
+<function>cyg_thread_delete</function> is required first.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-create-priorities"><title>Thread Priorities</title>
+ <para>
+The <parameter class="function">sched_info</parameter> argument
+provides additional information to the scheduler. The exact details
+depend on the scheduler being used. For the bitmap and mlqueue
+schedulers it is a small integer, typically in the range 0 to 31, with
+0 being the highest priority. The lowest priority is normally used
+only by the system's idle thread. The exact number of priorities is
+controlled by the kernel configuration option
+<varname>CYGNUM_KERNEL_SCHED_PRIORITIES</varname>.
+ </para>
+ <para>
+It is the responsibility of the application developer to be aware of
+the various threads in the system, including those created by eCos
+packages, and to ensure that all threads run at suitable priorities.
+For threads created by other packages the documentation provided by
+those packages should indicate any requirements.
+ </para>
+ <para>
+The functions <function>cyg_thread_set_priority</function>,
+<function>cyg_thread_get_priority</function>, and
+<function>cyg_thread_get_current_priority</function> can be used to
+manipulate a thread's priority.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-create-stack"><title>Stacks and Stack Sizes</title>
+ <para>
+Each thread needs its own stack for local variables and to keep track
+of function calls and returns. Again it is expected that this stack is
+provided by the calling code, usually in the form of static data, so
+that the kernel does not need any dynamic memory allocation
+facilities. <function>cyg_thread_create</function> takes two arguments
+related to the stack, a pointer to the base of the stack and the total
+size of this stack. On many processors stacks actually descend from the
+top down, so the kernel will add the stack size to the base address to
+determine the starting location.
+ </para>
+ <para>
+The exact stack size requirements for any given thread depend on a
+number of factors. The most important is of course the code that will
+be executed in the context of this code: if this involves significant
+nesting of function calls, recursion, or large local arrays, then the
+stack size needs to be set to a suitably high value. There are some
+architectural issues, for example the number of cpu registers and the
+calling conventions will have some effect on stack usage. Also,
+depending on the configuration, it is possible that some other code
+such as interrupt handlers will occasionally run on the current
+thread's stack. This depends in part on configuration options such as
+<varname>CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK</varname>
+and <varname>CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING</varname>.
+ </para>
+ <para>
+Determining an application's actual stack size requirements is the
+responsibility of the application developer, since the kernel cannot
+know in advance what code a given thread will run. However, the system
+does provide some hints about reasonable stack sizes in the form of
+two constants: <varname>CYGNUM_HAL_STACK_SIZE_MINIMUM</varname> and
+<varname>CYGNUM_HAL_STACK_SIZE_TYPICAL</varname>. These are defined by
+the appropriate HAL package. The <varname>MINIMUM</varname> value is
+appropriate for a thread that just runs a single function and makes
+very simple system calls. Trying to create a thread with a smaller
+stack than this is illegal. The <varname>TYPICAL</varname> value is
+appropriate for applications where application calls are nested no
+more than half a dozen or so levels, and there are no large arrays on
+the stack.
+ </para>
+ <para>
+If the stack sizes are not estimated correctly and a stack overflow
+occurs, the probably result is some form of memory corruption. This
+can be very hard to track down. The kernel does contain some code to
+help detect stack overflows, controlled by the configuration option
+<varname>CYGFUN_KERNEL_THREADS_STACK_CHECKING</varname>: a small
+amount of space is reserved at the stack limit and filled with a
+special signature: every time a thread context switch occurs this
+signature is checked, and if invalid that is a good indication (but
+not absolute proof) that a stack overflow has occurred. This form of
+stack checking is enabled by default when the system is built with
+debugging enabled. A related configuration option is
+<varname>CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT</varname>: enabling
+this option means that a thread can call the function
+<function>cyg_thread_measure_stack_usage</function> to find out the
+maximum stack usage to date. Note that this is not necessarily the
+true maximum because, for example, it is possible that in the current
+run no interrupt occurred at the worst possible moment.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-create-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_thread_create</function> may be called during
+initialization and from within thread context. It may not be called
+from inside a DSR.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-create-example"><title>Example</title>
+ <para>
+A simple example of thread creation is shown below. This involves
+creating five threads, one producer and four consumers or workers. The
+threads are created in the system's
+<function>cyg_user_start</function>: depending on the configuration it
+might be more appropriate to do this elsewhere, for example inside
+<function>main</function>.
+ </para>
+ <programlisting width=72>
+#include &lt;cyg/hal/hal_arch.h&gt;
+#include &lt;cyg/kernel/kapi.h&gt;
+
+// These numbers depend entirely on your application
+#define NUMBER_OF_WORKERS 4
+#define PRODUCER_PRIORITY 10
+#define WORKER_PRIORITY 11
+#define PRODUCER_STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define WORKER_STACKSIZE (CYGNUM_HAL_STACK_SIZE_MINIMUM + 1024)
+
+static unsigned char producer_stack[PRODUCER_STACKSIZE];
+static unsigned char worker_stacks[NUMBER_OF_WORKERS][WORKER_STACKSIZE];
+static cyg_handle_t producer_handle, worker_handles[NUMBER_OF_WORKERS];
+static cyg_thread producer_thread, worker_threads[NUMBER_OF_WORKERS];
+
+static void
+producer(cyg_addrword_t data)
+{
+ &hellip;
+}
+
+static void
+worker(cyg_addrword_t data)
+{
+ &hellip;
+}
+
+void
+cyg_user_start(void)
+{
+ int i;
+
+ cyg_thread_create(PRODUCER_PRIORITY, &amp;producer, 0, "producer",
+ producer_stack, PRODUCER_STACKSIZE,
+ &amp;producer_handle, &amp;producer_thread);
+ cyg_thread_resume(producer_handle);
+ for (i = 0; i < NUMBER_OF_WORKERS; i++) {
+ cyg_thread_create(WORKER_PRIORITY, &amp;worker, i, "worker",
+ worker_stacks[i], WORKER_STACKSIZE,
+ &amp;(worker_handles[i]), &amp;(worker_threads[i]));
+ cyg_thread_resume(worker_handles[i]);
+ }
+}
+ </programlisting>
+ </refsect1>
+
+
+ <refsect1 id="kernel-thread-create-cxx"><title>Thread Entry Points and C++</title>
+ <para>
+For code written in C++ the thread entry function must be either a
+static member function of a class or an ordinary function outside any
+class. It cannot be a normal member function of a class because such
+member functions take an implicit additional argument
+<varname>this</varname>, and the kernel has no way of knowing what
+value to use for this argument. One way around this problem is to make
+use of a special static member function, for example:
+ </para>
+ <programlisting width=72>
+class fred {
+ public:
+ void thread_function();
+ static void static_thread_aux(cyg_addrword_t);
+};
+
+void
+fred::static_thread_aux(cyg_addrword_t objptr)
+{
+ fred* object = static_cast&lt;fred*&gt;(objptr);
+ object-&gt;thread_function();
+}
+
+static fred instance;
+
+extern "C" void
+cyg_start( void )
+{
+ &hellip;
+ cyg_thread_create( &hellip;,
+ &amp;fred::static_thread_aux,
+ static_cast&lt;cyg_addrword_t&gt;(&amp;instance),
+ &hellip;);
+ &hellip;
+}
+ </programlisting>
+ <para>
+Effectively this uses the <parameter
+class="function">entry_data</parameter> argument to
+<function>cyg_thread_create</function> to hold the
+<varname>this</varname> pointer. Unfortunately this approach does
+require the use of some C++ casts, so some of the type safety that can
+be achieved when programming in C++ is lost.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Thread info -->
+
+ <refentry id="kernel-thread-info">
+
+ <refmeta>
+ <refentrytitle>Thread information</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_thread_self</refname>
+ <refname>cyg_thread_idle_thread</refname>
+ <refname>cyg_thread_get_stack_base</refname>
+ <refname>cyg_thread_get_stack_size</refname>
+ <refname>cyg_thread_measure_stack_usage</refname>
+ <refname>cyg_thread_get_next</refname>
+ <refname>cyg_thread_get_info</refname>
+ <refname>cyg_thread_get_id</refname>
+ <refname>cyg_thread_find</refname>
+ <refpurpose>Get basic thread information</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>cyg_handle_t <function>cyg_thread_self</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_handle_t <function>cyg_thread_idle_thread</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_addrword_t <function>cyg_thread_get_stack_base</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_uint32 <function>cyg_thread_get_stack_size</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_uint32 <function>cyg_thread_measure_stack_usage</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool <function>cyg_thread_get_next</function></funcdef>
+ <paramdef>cyg_handle_t *<parameter>thread</parameter></paramdef>
+ <paramdef>cyg_uint16 *<parameter>id</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool <function>cyg_thread_get_info</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ <paramdef>cyg_uint16 <parameter>id</parameter></paramdef>
+ <paramdef>cyg_thread_info *<parameter>info</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_uint16 <function>cyg_thread_get_id</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_handle_t <function>cyg_thread_find</function></funcdef>
+ <paramdef>cyg_uint16 <parameter>id</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-thread-info-description"><title>Description</title>
+ <para>
+These functions can be used to obtain some basic information about
+various threads in the system. Typically they serve little or no
+purpose in real applications, but they can be useful during debugging.
+ </para>
+ <para>
+<function>cyg_thread_self</function> returns a handle corresponding
+to the current thread. It will be the same as the value filled in by
+<function>cyg_thread_create</function> when the current thread was
+created. This handle can then be passed to other functions such as
+<function>cyg_thread_get_priority</function>.
+ </para>
+ <para>
+<function>cyg_thread_idle_thread</function> returns the handle
+corresponding to the idle thread. This thread is created automatically
+by the kernel, so application-code has no other way of getting hold of
+this information.
+ </para>
+ <para>
+<function>cyg_thread_get_stack_base</function> and
+<function>cyg_thread_get_stack_size</function> return information
+about a specific thread's stack. The values returned will match the
+values passed to <function>cyg_thread_create</function> when this
+thread was created.
+ </para>
+ <para>
+<function>cyg_thread_measure_stack_usage</function> is only available
+if the configuration option
+<varname>CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT</varname> is enabled.
+The return value is the maximum number of bytes of stack space used so
+far by the specified thread. Note that this should not be considered a
+true upper bound, for example it is possible that in the current test
+run the specified thread has not yet been interrupted at the deepest
+point in the function call graph. Never the less the value returned
+can give some useful indication of the thread's stack requirements.
+ </para>
+ <para>
+<function>cyg_thread_get_next</function> is used to enumerate all the
+current threads in the system. It should be called initially with the
+locations pointed to by <parameter>thread</parameter> and
+<parameter>id</parameter> set to zero. On return these will be set to
+the handle and ID of the first thread. On subsequent calls, these
+parameters should be left set to the values returned by the previous
+call. The handle and ID of the next thread in the system will be
+installed each time, until a <literal>false</literal> return value
+indicates the end of the list.
+ </para>
+ <para>
+<function>cyg_thread_get_info</function> fills in the
+<type>cyg_thread_info</type> structure with information about the
+thread described by the <parameter>thread</parameter> and
+<parameter>id</parameter> arguments. The information returned includes
+the thread's handle and id, its state and name, priorities and stack
+parameters. If the thread does not exist the function returns
+<literal>false</literal>.
+ </para>
+ <para>
+The <type>cyg_thread_info</type> structure is defined as follows by
+&lt;<filename class=headerfile>cyg/kernel/kapi.h</filename>&gt;, but may
+be extended in future with additional members, and so its size should
+not be relied upon:
+<programlisting>
+typedef struct
+{
+ <type>cyg_handle_t</type> <structfield>handle</structfield>;
+ <type>cyg_uint16</type> <structfield>id</structfield>;
+ <type>cyg_uint32</type> <structfield>state</structfield>;
+ <type>char</type> <structfield>*name</structfield>;
+ <type>cyg_priority_t</type> <structfield>set_pri</structfield>;
+ <type>cyg_priority_t</type> <structfield>cur_pri</structfield>;
+ <type>cyg_addrword_t</type> <structfield>stack_base</structfield>;
+ <type>cyg_uint32</type> <structfield>stack_size</structfield>;
+ <type>cyg_uint32</type> <structfield>stack_used</structfield>;
+} cyg_thread_info;
+</programlisting>
+ </para>
+ <para>
+<function>cyg_thread_get_id</function> returns the unique thread ID for
+the thread identified by <parameter>thread</parameter>.
+ </para>
+ <para>
+<function>cyg_thread_find</function> returns a handle for the thread
+whose ID is <parameter>id</parameter>. If no such thread exists, a
+zero handle is returned.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-info-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_thread_self</function> may only be called from thread
+context. <function>cyg_thread_idle_thread</function> may be called
+from thread or DSR context, but only after the system has been
+initialized. <function>cyg_thread_get_stack_base</function>,
+<function>cyg_thread_get_stack_size</function> and
+<function>cyg_thread_measure_stack_usage</function> may be called
+any time after the specified thread has been created, but measuring
+stack usage involves looping over at least part of the thread's stack
+so this should normally only be done from thread context.
+<function>cyg_thread_get_id</function> may be called from any context
+as long as the caller can guarantee that the supplied thread handle
+remains valid.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-info-examples"><title>Examples</title>
+ <para>
+A simple example of the use of the
+<function>cyg_thread_get_next</function> and
+<function>cyg_thread_get_info</function> follows:
+ </para>
+ <programlisting width=72>
+
+#include &lt;cyg/kernel/kapi.h&gt;
+#include &lt;stdio.h&gt;
+
+void show_threads(void)
+{
+ cyg_handle_t thread = 0;
+ cyg_uint16 id = 0;
+
+ while( cyg_thread_get_next( &amp;thread, &amp;id ) )
+ {
+ cyg_thread_info info;
+
+ if( !cyg_thread_get_info( thread, id, &amp;info ) )
+ break;
+
+ printf("ID: %04x name: %10s pri: %d\n",
+ info.id, info.name?info.name:"----", info.set_pri );
+ }
+}
+
+ </programlisting>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Thread control -->
+
+ <refentry id="kernel-thread-control">
+
+ <refmeta>
+ <refentrytitle>Thread control</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_thread_yield</refname>
+ <refname>cyg_thread_delay</refname>
+ <refname>cyg_thread_suspend</refname>
+ <refname>cyg_thread_resume</refname>
+ <refname>cyg_thread_release</refname>
+ <refpurpose>Control whether or not a thread is running</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_yield</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_delay</function></funcdef>
+ <paramdef>cyg_tick_count_t <parameter>delay</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_suspend</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_resume</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_release</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1><title id="kernel-thread-control-description">Description</title>
+ <para>
+These functions provide some control over whether or not a particular
+thread can run. Apart from the required use of
+<function>cyg_thread_resume</function> to start a newly-created
+thread, application code should normally use proper synchronization
+primitives such as condition variables or mail boxes.
+ </para>
+ </refsect1>
+
+ <refsect1><title id="kernel-thread-control-yield">Yield</title>
+ <para>
+<function>cyg_thread_yield</function> allows a thread to relinquish
+control of the processor to some other runnable thread which has the
+same priority. This can have no effect on any higher-priority thread
+since, if such a thread were runnable, the current thread would have
+been preempted in its favour. Similarly it can have no effect on any
+lower-priority thread because the current thread will always be run in
+preference to those. As a consequence this function is only useful
+in configurations with a scheduler that allows multiple threads to run
+at the same priority, for example the mlqueue scheduler. If instead
+the bitmap scheduler was being used then
+<function>cyg_thread_yield()</function> would serve no purpose.
+ </para>
+ <para>
+Even if a suitable scheduler such as the mlqueue scheduler has been
+configured, <function>cyg_thread_yield</function> will still rarely
+prove useful: instead timeslicing will be used to ensure that all
+threads of a given priority get a fair slice of the available
+processor time. However it is possible to disable timeslicing via the
+configuration option <varname>CYGSEM_KERNEL_SCHED_TIMESLICE</varname>,
+in which case <function>cyg_thread_yield</function> can be used to
+implement a form of cooperative multitasking.
+ </para>
+ </refsect1>
+
+ <refsect1><title id="kernel-thread-control-delay">Delay</title>
+ <para>
+<function>cyg_thread_delay</function> allows a thread to suspend until
+the specified number of clock ticks have occurred. For example, if a
+value of 1 is used and the system clock runs at a frequency of 100Hz
+then the thread will sleep for up to 10 milliseconds. This
+functionality depends on the presence of a real-time system clock, as
+controlled by the configuration option
+<varname>CYGVAR_KERNEL_COUNTERS_CLOCK</varname>.
+ </para>
+ <para>
+If the application requires delays measured in milliseconds or similar
+units rather than in clock ticks, some calculations are needed to
+convert between these units as described in <xref
+linkend="kernel-clocks">. Usually these calculations can be done by
+the application developer, or at compile-time. Performing such
+calculations prior to every call to
+<function>cyg_thread_delay</function> adds unnecessary overhead to the
+system.
+ </para>
+ </refsect1>
+
+ <refsect1><title id="kernel-thread-control-suspend">Suspend and Resume</title>
+ <para>
+Associated with each thread is a suspend counter. When a thread is
+first created this counter is initialized to 1.
+<function>cyg_thread_suspend</function> can be used to increment the
+suspend counter, and <function>cyg_thread_resume</function> decrements
+it. The scheduler will never run a thread with a non-zero suspend
+counter. Therefore a newly created thread will not run until it has
+been resumed.
+ </para>
+ <para>
+An occasional problem with the use of suspend and resume functionality
+is that a thread gets suspended more times than it is resumed and
+hence never becomes runnable again. This can lead to very confusing
+behaviour. To help with debugging such problems the kernel provides a
+configuration option
+<varname>CYGNUM_KERNEL_MAX_SUSPEND_COUNT_ASSERT</varname> which
+imposes an upper bound on the number of suspend calls without matching
+resumes, with a reasonable default value. This functionality depends
+on infrastructure assertions being enabled.
+ </para>
+ </refsect1>
+
+ <refsect1><title id="kernel-thread-control-release">Releasing a Blocked Thread</title>
+ <para>
+When a thread is blocked on a synchronization primitive such as a
+semaphore or a mutex, or when it is waiting for an alarm to trigger,
+it can be forcibly woken up using
+<function>cyg_thread_release</function>. Typically this will call the
+affected synchronization primitive to return false, indicating that
+the operation was not completed successfully. This function has to be
+used with great care, and in particular it should only be used on
+threads that have been designed appropriately and check all return
+codes. If instead it were to be used on, say, an arbitrary thread that
+is attempting to claim a mutex then that thread might not bother to
+check the result of the mutex lock operation - usually there would be
+no reason to do so. Therefore the thread will now continue running in
+the false belief that it has successfully claimed a mutex lock, and
+the resulting behaviour is undefined. If the system has been built
+with assertions enabled then it is possible that an assertion will
+trigger when the thread tries to release the mutex it does not
+actually own.
+ </para>
+ <para>
+The main use of <function>cyg_thread_release</function> is in the
+POSIX compatibility layer, where it is used in the implementation of
+per-thread signals and cancellation handlers.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-control-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_thread_yield</function> can only be called from thread
+context, A DSR must always run to completion and cannot yield the
+processor to some thread. <function>cyg_thread_suspend</function>,
+<function>cyg_thread_resume</function>, and
+<function>cyg_thread_release</function> may be called from thread or
+DSR context.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Thread termination -->
+
+ <refentry id="kernel-thread-termination">
+
+ <refmeta>
+ <refentrytitle>Thread termination</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_thread_exit</refname>
+ <refname>cyg_thread_kill</refname>
+ <refname>cyg_thread_delete</refname>
+ <refpurpose>Allow threads to terminate</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_exit</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_kill</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_thread_delete</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1><title id="kernel-thread-termination-description">Description</title>
+ <para>
+In many embedded systems the various threads are allocated statically,
+created during initialization, and never need to terminate. This
+avoids any need for dynamic memory allocation or other resource
+management facilities. However if a given application does have a
+requirement that some threads be created dynamically, must terminate,
+and their resources such as the stack be reclaimed, then the kernel
+provides the functions <function>cyg_thread_exit</function>,
+<function>cyg_thread_kill</function>, and
+<function>cyg_thread_delete</function>.
+ </para>
+ <para>
+<function>cyg_thread_exit</function> allows a thread to terminate
+itself, thus ensuring that it will not be run again by the scheduler.
+However the <structname>cyg_thread</structname> data structure passed
+to <function>cyg_thread_create</function> remains in use, and the
+handle returned by <function>cyg_thread_create</function> remains
+valid. This allows other threads to perform certain operations on the
+terminated thread, for example to determine its stack usage via
+<function>cyg_thread_measure_stack_usage</function>. When the handle
+and <structname>cyg_thread</structname> structure are no longer
+required, <function>cyg_thread_delete</function> should be called to
+release these resources. If the stack was dynamically allocated then
+this should not be freed until after the call to
+<function>cyg_thread_delete</function>.
+ </para>
+ <para>
+Alternatively, one thread may use <function>cyg_thread_kill</function>
+on another This has much the same effect as the affected thread
+calling <function>cyg_thread_exit</function>. However killing a thread
+is generally rather dangerous because no attempt is made to unlock any
+synchronization primitives currently owned by that thread or release
+any other resources that thread may have claimed. Therefore use of
+this function should be avoided, and
+<function>cyg_thread_exit</function> is preferred.
+<function>cyg_thread_kill</function> cannot be used by a thread to
+kill itself.
+ </para>
+ <para>
+<function>cyg_thread_delete</function> should be used on a thread
+after it has exited and is no longer required. After this call the
+thread handle is no longer valid, and both the
+<structname>cyg_thread</structname> structure and the thread stack can
+be re-used or freed. If <function>cyg_thread_delete</function> is
+invoked on a thread that is still running then there is an implicit
+call to <function>cyg_thread_kill</function>. This function returns
+<literal>true</literal> if the delete was successful, and
+<literal>false</literal> if the delete did not happen. The delete
+may not happen for example if the thread being destroyed is a lower
+priority thread than the running thread, and will thus not wake up
+in order to exit until it is rescheduled.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-termination-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_thread_exit</function>,
+<function>cyg_thread_kill</function> and
+<function>cyg_thread_delete</function> can only be called from thread
+context.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Thread priorities -->
+
+ <refentry id="kernel-thread-priorities">
+
+ <refmeta>
+ <refentrytitle>Thread priorities</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_thread_get_priority</refname>
+ <refname>cyg_thread_get_current_priority</refname>
+ <refname>cyg_thread_set_priority</refname>
+ <refpurpose>Examine and manipulate thread priorities</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>cyg_priority_t <function>cyg_thread_get_priority</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_priority_t <function>cyg_thread_get_current_priority</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_set_priority</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ <paramdef>cyg_priority_t <parameter>priority</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1><title id="kernel-thread-priorities-description">Description</title>
+ <para>
+Typical schedulers use the concept of a thread priority to determine
+which thread should run next. Exactly what this priority consists of
+will depend on the scheduler, but a typical implementation would be a
+small integer in the range 0 to 31, with 0 being the highest priority.
+Usually only the idle thread will run at the lowest priority. The
+exact number of priority levels available depends on the
+configuration, typically the option
+<varname>CYGNUM_KERNEL_SCHED_PRIORITIES</varname>.
+ </para>
+ <para>
+<function>cyg_thread_get_priority</function> can be used to determine
+the priority of a thread, or more correctly the value last used in a
+<function>cyg_thread_set_priority</function> call or when the thread
+was first created. In some circumstances it is possible that the
+thread is actually running at a higher priority. For example, if it
+owns a mutex and priority ceilings or inheritance is being used to
+prevent priority inversion problems, then the thread's priority may
+have been boosted temporarily.
+<function>cyg_thread_get_current_priority</function> returns the real
+current priority.
+ </para>
+ <para>
+In many applications appropriate thread priorities can be determined
+and allocated statically. However, if it is necessary for a thread's
+priority to change at run-time then the
+<function>cyg_thread_set_priority</function> function provides this
+functionality.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-priorities-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_thread_get_priority</function> and
+<function>cyg_thread_get_current_priority</function> can be called
+from thread or DSR context, although the latter is rarely useful.
+<function>cyg_thread_set_priority</function> should also only be
+called from thread context.
+ </para>
+ </refsect1>
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Per-thread data -->
+
+ <refentry id="kernel-thread-data">
+
+ <refmeta>
+ <refentrytitle>Per-thread data</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_thread_new_data_index</refname>
+ <refname>cyg_thread_free_data_index</refname>
+ <refname>cyg_thread_get_data</refname>
+ <refname>cyg_thread_get_data_ptr</refname>
+ <refname>cyg_thread_set_data</refname>
+ <refpurpose>Manipulate per-thread data</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>cyg_ucount32 <function>cyg_thread_new_data_index</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_free_data_index</function></funcdef>
+ <paramdef>cyg_ucount32 <parameter>index</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_addrword_t <function>cyg_thread_get_data</function></funcdef>
+ <paramdef>cyg_ucount32 <parameter>index</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_addrword_t* <function>cyg_thread_get_data_ptr</function></funcdef>
+ <paramdef>cyg_ucount32 <parameter>index</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_thread_set_data</function></funcdef>
+ <paramdef>cyg_ucount32 <parameter>index</parameter></paramdef>
+ <paramdef>cyg_addrword_t <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1><title id="kernel-thread-data-description">Description</title>
+ <para>
+In some applications and libraries it is useful to have some data that
+is specific to each thread. For example, many of the functions in the
+POSIX compatibility package return -1 to indicate an error and store
+additional information in what appears to be a global variable
+<varname>errno</varname>. However, if multiple threads make concurrent
+calls into the POSIX library and if <varname>errno</varname> were
+really a global variable then a thread would have no way of knowing
+whether the current <varname>errno</varname> value really corresponded
+to the last POSIX call it made, or whether some other thread had run
+in the meantime and made a different POSIX call which updated the
+variable. To avoid such confusion <varname>errno</varname> is instead
+implemented as a per-thread variable, and each thread has its own
+instance.
+ </para>
+ <para>
+The support for per-thread data can be disabled via the configuration
+option <varname>CYGVAR_KERNEL_THREADS_DATA</varname>. If enabled, each
+<structname>cyg_thread</structname> data structure holds a small array
+of words. The size of this array is determined by the configuration
+option <varname>CYGNUM_KERNEL_THREADS_DATA_MAX</varname>. When a
+thread is created the array is filled with zeroes.
+ </para>
+ <para>
+If an application needs to use per-thread data then it needs an index
+into this array which has not yet been allocated to other code. This
+index can be obtained by calling
+<function>cyg_thread_new_data_index</function>, and then used in
+subsequent calls to <function>cyg_thread_get_data</function>.
+Typically indices are allocated during system initialization and
+stored in static variables. If for some reason a slot in the array is
+no longer required and can be re-used then it can be released by calling
+<function>cyg_thread_free_data_index</function>,
+ </para>
+ <para>
+The current per-thread data in a given slot can be obtained using
+<function>cyg_thread_get_data</function>. This implicitly operates on
+the current thread, and its single argument should be an index as
+returned by <function>cyg_thread_new_data_index</function>. The
+per-thread data can be updated using
+<function>cyg_thread_set_data</function>. If a particular item of
+per-thread data is needed repeatedly then
+<function>cyg_thread_get_data_ptr</function> can be used to obtain the
+address of the data, and indirecting through this pointer allows the
+data to be examined and updated efficiently.
+ </para>
+ <para>
+Some packages, for example the error and POSIX packages, have
+pre-allocated slots in the array of per-thread data. These slots
+should not normally be used by application code, and instead slots
+should be allocated during initialization by a call to
+<function>cyg_thread_new_data_index</function>. If it is known that,
+for example, the configuration will never include the POSIX
+compatibility package then application code may instead decide to
+re-use the slot allocated to that package,
+<varname>CYGNUM_KERNEL_THREADS_DATA_POSIX</varname>, but obviously
+this does involve a risk of strange and subtle bugs if the
+application's requirements ever change.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-data-context"><title>Valid contexts</title>
+ <para>
+Typically <function>cyg_thread_new_data_index</function> is only
+called during initialization, but may also be called at any time in
+thread context. <function>cyg_thread_free_data_index</function>, if
+used at all, can also be called during initialization or from thread
+context. <function>cyg_thread_get_data</function>,
+<function>cyg_thread_get_data_ptr</function>, and
+<function>cyg_thread_set_data</function> may only be called from
+thread context because they implicitly operate on the current thread.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Thread destructors -->
+
+ <refentry id="kernel-thread-destructors">
+
+ <refmeta>
+ <refentrytitle>Thread destructors</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_thread_add_destructor</refname>
+ <refname>cyg_thread_rem_destructor</refname>
+ <refpurpose>Call functions on thread termination</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+typedef void (*<type>cyg_thread_destructor_fn</type>)(<type>cyg_addrword_t</type>);
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_thread_add_destructor</function></funcdef>
+ <paramdef>cyg_thread_destructor_fn <parameter>fn</parameter></paramdef>
+ <paramdef>cyg_addrword_t <parameter>data</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_thread_rem_destructor</function></funcdef>
+ <paramdef>cyg_thread_destructor_fn <parameter>fn</parameter></paramdef>
+ <paramdef>cyg_addrword_t <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1><title id="kernel-thread-destructors-description">Description</title>
+ <para>
+These functions are provided for cases when an application requires a
+function to be automatically called when a thread exits. This is often
+useful when, for example, freeing up resources allocated by the thread.
+ </para>
+ <para>
+This support must be enabled with the configuration option
+<varname>CYGPKG_KERNEL_THREADS_DESTRUCTORS</varname>. When enabled,
+you may register a function of type
+<type>cyg_thread_destructor_fn</type> to be called on thread
+termination using <function>cyg_thread_add_destructor</function>. You
+may also provide it with a piece of arbitrary information in the
+<parameter>data</parameter> argument which will be passed to the
+destructor function <parameter>fn</parameter> when the thread
+terminates. If you no longer wish to call a function previous
+registered with <function>cyg_thread_add_destructor</function>, you
+may call <function>cyg_thread_rem_destructor</function> with the same
+parameters used to register the destructor function. Both these
+functions return <literal>true</literal> on success and
+<literal>false</literal> on failure.
+ </para>
+ <para>
+By default, thread destructors are per-thread, which means that registering
+a destructor function only registers that function for the current thread.
+In other words, each thread has its own list of destructors.
+Alternatively you may disable the configuration option
+<varname>CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD</varname> in which
+case any registered destructors will be run when <emphasis>any</emphasis>
+threads exit. In other words, the thread destructor list is global and all
+threads have the same destructors.
+ </para>
+ <para>
+There is a limit to the number of destructors which may be registered,
+which can be controlled with the
+<varname>CYGNUM_KERNEL_THREADS_DESTRUCTORS</varname> configuration
+option. Increasing this value will very slightly increase the amount
+of memory in use, and when
+<varname>CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD</varname> is
+enabled, the amount of memory used per thread will increase. When the
+limit has been reached, <function>cyg_thread_add_destructor</function>
+will return <literal>false</literal>.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-thread-destructors-context"><title>Valid contexts</title>
+ <para>
+When <varname>CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD</varname>
+is enabled, these functions must only be called from a thread context
+as they implicitly operate on the current thread. When
+<varname>CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD</varname> is
+disabled, these functions may be called from thread or DSR context,
+or at initialization time.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Exceptions -->
+
+ <refentry id="kernel-exceptions">
+
+ <refmeta>
+ <refentrytitle>Exception handling</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_exception_set_handler</refname>
+ <refname>cyg_exception_clear_handler</refname>
+ <refname>cyg_exception_call_handler</refname>
+ <refpurpose>Handle processor exceptions</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_exception_set_handler</function></funcdef>
+ <paramdef>cyg_code_t <parameter>exception_number</parameter></paramdef>
+ <paramdef>cyg_exception_handler_t* <parameter>new_handler</parameter></paramdef>
+ <paramdef>cyg_addrword_t <parameter>new_data</parameter></paramdef>
+ <paramdef>cyg_exception_handler_t** <parameter>old_handler</parameter></paramdef>
+ <paramdef>cyg_addrword_t* <parameter>old_data</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_exception_clear_handler</function></funcdef>
+ <paramdef>cyg_code_t <parameter>exception_number</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_exception_call_handler</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>thread</parameter></paramdef>
+ <paramdef>cyg_code_t <parameter>exception_number</parameter></paramdef>
+ <paramdef>cyg_addrword_t <parameter>exception_info</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1><title id="kernel-exceptions-description">Description</title>
+ <para>
+Sometimes code attempts operations that are not legal on the current
+hardware, for example dividing by zero, or accessing data through a
+pointer that is not properly aligned. When this happens the hardware
+will raise an exception. This is very similar to an interrupt, but
+happens synchronously with code execution rather than asynchronously
+and hence can be tied to the thread that is currently running.
+ </para>
+ <para>
+The exceptions that can be raised depend very much on the hardware,
+especially the processor. The corresponding documentation should be
+consulted for more details. Alternatively the architectural HAL header
+file <filename class="headerfile">hal_intr.h</filename>, or one of the
+variant or platform header files it includes, will contain appropriate
+definitions. The details of how to handle exceptions, including
+whether or not it is possible to recover from them, also depend on the
+hardware.
+ </para>
+ <para>
+Exception handling is optional, and can be disabled through the
+configuration option <varname>CYGPKG_KERNEL_EXCEPTIONS</varname>. If
+an application has been exhaustively tested and is trusted never to
+raise a hardware exception then this option can be disabled and code
+and data sizes will be reduced somewhat. If exceptions are left
+enabled then the system will provide default handlers for the various
+exceptions, but these do nothing. Even the specific type of exception
+is ignored, so there is no point in attempting to decode this and
+distinguish between say a divide-by-zero and an unaligned access.
+If the application installs its own handlers and wants details of the
+specific exception being raised then the configuration option
+<varname>CYGSEM_KERNEL_EXCEPTIONS_DECODE</varname> has to be enabled.
+ </para>
+ <para>
+An alternative handler can be installed using
+<function>cyg_exception_set_handler</function>. This requires a code
+for the exception, a function pointer for the new exception handler,
+and a parameter to be passed to this handler. Details of the
+previously installed exception handler will be returned via the
+remaining two arguments, allowing that handler to be reinstated, or
+null pointers can be used if this information is of no interest. An
+exception handling function should take the following form:
+ </para>
+ <programlisting width=72>
+void
+my_exception_handler(cyg_addrword_t data, cyg_code_t exception, cyg_addrword_t info)
+{
+ &hellip;
+}
+ </programlisting>
+ <para>
+The data argument corresponds to the <parameter class="function">new_data</parameter>
+parameter supplied to <function>cyg_exception_set_handler</function>.
+The exception code is provided as well, in case a single handler is
+expected to support multiple exceptions. The <parameter class="function">info</parameter>
+argument will depend on the hardware and on the specific exception.
+ </para>
+ <para>
+<function>cyg_exception_clear_handler</function> can be used to
+restore the default handler, if desired. It is also possible for
+software to raise an exception and cause the current handler to be
+invoked, but generally this is useful only for testing.
+ </para>
+ <para>
+By default the system maintains a single set of global exception
+handlers. However, since exceptions occur synchronously it is
+sometimes useful to handle them on a per-thread basis, and have a
+different set of handlers for each thread. This behaviour can be
+obtained by disabling the configuration option
+<varname>CYGSEM_KERNEL_EXCEPTIONS_GLOBAL</varname>. If per-thread
+exception handlers are being used then
+<function>cyg_exception_set_handler</function> and
+<function>cyg_exception_clear_handler</function> apply to the current
+thread. Otherwise they apply to the global set of handlers.
+ </para>
+
+ <caution><para>
+In the current implementation
+<function>cyg_exception_call_handler</function> can only be used on
+the current thread. There is no support for delivering an exception to
+another thread.
+ </para></caution>
+ <note><para>
+Exceptions at the eCos kernel level refer specifically to
+hardware-related events such as unaligned accesses to memory or
+division by zero. There is no relation with other concepts that are
+also known as exceptions, for example the <literal>throw</literal> and
+<literal>catch</literal> facilities associated with C++.
+ </para></note>
+
+ </refsect1>
+
+ <refsect1 id="kernel-exceptions-context"><title>Valid contexts</title>
+ <para>
+If the system is configured with a single set of global exception
+handlers then
+<function>cyg_exception_set_handler</function> and
+<function>cyg_exception_clear_handler</function> may be called during
+initialization or from thread context. If instead per-thread exception
+handlers are being used then it is not possible to install new
+handlers during initialization because the functions operate
+implicitly on the current thread, so they can only be called from
+thread context. <function>cyg_exception_call_handler</function> should
+only be called from thread context.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Counters -->
+
+ <refentry id="kernel-counters">
+
+ <refmeta>
+ <refentrytitle>Counters</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_counter_create</refname>
+ <refname>cyg_counter_delete</refname>
+ <refname>cyg_counter_current_value</refname>
+ <refname>cyg_counter_set_value</refname>
+ <refname>cyg_counter_tick</refname>
+ <refpurpose>Count event occurrences</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_counter_create</function></funcdef>
+ <paramdef>cyg_handle_t* <parameter>handle</parameter></paramdef>
+ <paramdef>cyg_counter* <parameter>counter</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_counter_delete</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>counter</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_tick_count_t <function>cyg_counter_current_value</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>counter</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_counter_set_value</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>counter</parameter></paramdef>
+ <paramdef>cyg_tick_count_t <parameter>new_value</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_counter_tick</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>counter</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-counters-description"><title>Description</title>
+ <para>
+Kernel counters can be used to keep track of how many times a
+particular event has occurred. Usually this event is an external
+signal of some sort. The most common use of counters is in the
+implementation of clocks, but they can be useful with other event
+sources as well. Application code can attach <link
+linkend="kernel-alarms">alarms</link> to counters, causing a function
+to be called when some number of events have occurred.
+ </para>
+ <para>
+A new counter is initialized by a call to
+<function>cyg_counter_create</function>. The first argument is used to
+return a handle to the new counter which can be used for subsequent
+operations. The second argument allows the application to provide the
+memory needed for the object, thus eliminating any need for dynamic
+memory allocation within the kernel. If a counter is no longer
+required and does not have any alarms attached then
+<function>cyg_counter_delete</function> can be used to release the
+resources, allowing the <structname>cyg_counter</structname> data
+structure to be re-used.
+ </para>
+ <para>
+Initializing a counter does not automatically attach it to any source
+of events. Instead some other code needs to call
+<function>cyg_counter_tick</function> whenever a suitable event
+occurs, which will cause the counter to be incremented and may cause
+alarms to trigger. The current value associated with the counter can
+be retrieved using <function>cyg_counter_current_value</function> and
+modified with <function>cyg_counter_set_value</function>. Typically
+the latter function is only used during initialization, for example to
+set a clock to wallclock time, but it can be used to reset a counter
+if necessary. However <function>cyg_counter_set_value</function> will
+never trigger any alarms. A newly initialized counter has a starting
+value of 0.
+ </para>
+ <para>
+The kernel provides two different implementations of counters. The
+default is <varname>CYGIMP_KERNEL_COUNTERS_SINGLE_LIST</varname> which
+stores all alarms attached to the counter on a single list. This is
+simple and usually efficient. However when a tick occurs the kernel
+code has to traverse this list, typically at DSR level, so if there
+are a significant number of alarms attached to a single counter this
+will affect the system's dispatch latency. The alternative
+implementation, <varname>CYGIMP_KERNEL_COUNTERS_MULTI_LIST</varname>,
+stores each alarm in one of an array of lists such that at most one of
+the lists needs to be searched per clock tick. This involves extra
+code and data, but can improve real-time responsiveness in some
+circumstances. Another configuration option that is relevant here
+is <varname>CYGIMP_KERNEL_COUNTERS_SORT_LIST</varname>, which is
+disabled by default. This provides a trade off between doing work
+whenever a new alarm is added to a counter and doing work whenever a
+tick occurs. It is application-dependent which of these is more
+appropriate.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-counters-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_counter_create</function> is typically called during
+system initialization but may also be called in thread context.
+Similarly <function>cyg_counter_delete</function> may be called during
+initialization or in thread context.
+<function>cyg_counter_current_value</function>,
+<function>cyg_counter_set_value</function> and
+<function>cyg_counter_tick</function> may be called during
+initialization or from thread or DSR context. In fact,
+<function>cyg_counter_tick</function> is usually called from inside a
+DSR in response to an external event of some sort.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Clocks -->
+
+ <refentry id="kernel-clocks">
+
+ <refmeta>
+ <refentrytitle>Clocks</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_clock_create</refname>
+ <refname>cyg_clock_delete</refname>
+ <refname>cyg_clock_to_counter</refname>
+ <refname>cyg_clock_set_resolution</refname>
+ <refname>cyg_clock_get_resolution</refname>
+ <refname>cyg_real_time_clock</refname>
+ <refname>cyg_current_time</refname>
+ <refpurpose>Provide system clocks</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_clock_create</function></funcdef>
+ <paramdef>cyg_resolution_t <parameter>resolution</parameter></paramdef>
+ <paramdef>cyg_handle_t* <parameter>handle</parameter></paramdef>
+ <paramdef>cyg_clock* <parameter>clock</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_clock_delete</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>clock</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_clock_to_counter</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>clock</parameter></paramdef>
+ <paramdef>cyg_handle_t* <parameter>counter</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_clock_set_resolution</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>clock</parameter></paramdef>
+ <paramdef>cyg_resolution_t <parameter>resolution</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_resolution_t <function>cyg_clock_get_resolution</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>clock</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_handle_t <function>cyg_real_time_clock</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_tick_count_t <function>cyg_current_time</function></funcdef>
+ <void>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-clocks-description"><title>Description</title>
+ <para>
+In the eCos kernel clock objects are a special form of <link
+linkend="kernel-counters">counter</link> objects. They are attached to
+a specific type of hardware, clocks that generate ticks at very
+specific time intervals, whereas counters can be used with any event
+source.
+ </para>
+ <para>
+In a default configuration the kernel provides a single clock
+instance, the real-time clock. This gets used for timeslicing and for
+operations that involve a timeout, for example
+<function>cyg_semaphore_timed_wait</function>. If this functionality
+is not required it can be removed from the system using the
+configuration option <varname>CYGVAR_KERNEL_COUNTERS_CLOCK</varname>.
+Otherwise the real-time clock can be accessed by a call to
+<function>cyg_real_time_clock</function>, allowing applications to
+attach alarms, and the current counter value can be obtained using
+<function>cyg_current_time</function>.
+ </para>
+ <para>
+Applications can create and destroy additional clocks if desired,
+using <function>cyg_clock_create</function> and
+<function>cyg_clock_delete</function>. The first argument to
+<function>cyg_clock_create</function> specifies the
+<link linkend="kernel-clocks-resolution">resolution</link> this clock
+will run at. The second argument is used to return a handle for this
+clock object, and the third argument provides the kernel with the
+memory needed to hold this object. This clock will not actually tick
+by itself. Instead it is the responsibility of application code to
+initialize a suitable hardware timer to generate interrupts at the
+appropriate frequency, install an interrupt handler for this, and
+call <function>cyg_counter_tick</function> from inside the DSR.
+Associated with each clock is a kernel counter, a handle for which can
+be obtained using <function>cyg_clock_to_counter</function>.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-clocks-resolution"><title>Clock Resolutions and Ticks</title>
+ <para>
+At the kernel level all clock-related operations including delays,
+timeouts and alarms work in units of clock ticks, rather than in units
+of seconds or milliseconds. If the calling code, whether the
+application or some other package, needs to operate using units such
+as milliseconds then it has to convert from these units to clock
+ticks.
+ </para>
+ <para>
+The main reason for this is that it accurately reflects the
+hardware: calling something like <function>nanosleep</function> with a
+delay of ten nanoseconds will not work as intended on any real
+hardware because timer interrupts simply will not happen that
+frequently; instead calling <function>cyg_thread_delay</function> with
+the equivalent delay of 0 ticks gives a much clearer indication that
+the application is attempting something inappropriate for the target
+hardware. Similarly, passing a delay of five ticks to
+<function>cyg_thread_delay</function> makes it fairly obvious that
+the current thread will be suspended for somewhere between four and
+five clock periods, as opposed to passing 50000000 to
+<function>nanosleep</function> which suggests a granularity that is
+not actually provided.
+ </para>
+ <para>
+A secondary reason is that conversion between clock ticks and units
+such as milliseconds can be somewhat expensive, and whenever possible
+should be done at compile-time or by the application developer rather
+than at run-time. This saves code size and cpu cycles.
+ </para>
+ <para>
+The information needed to perform these conversions is the clock
+resolution. This is a structure with two fields, a dividend and a
+divisor, and specifies the number of nanoseconds between clock ticks.
+For example a clock that runs at 100Hz will have 10 milliseconds
+between clock ticks, or 10000000 nanoseconds. The ratio between the
+resolution's dividend and divisor will therefore be 10000000 to 1, and
+typical values for these might be 1000000000 and 100. If the clock
+runs at a different frequency, say 60Hz, the numbers could be
+1000000000 and 60 respectively. Given a delay in nanoseconds, this can
+be converted to clock ticks by multiplying with the the divisor and
+then dividing by the dividend. For example a delay of 50 milliseconds
+corresponds to 50000000 nanoseconds, and with a clock frequency of
+100Hz this can be converted to
+((50000000&nbsp;*&nbsp;100)&nbsp;/&nbsp;1000000000)&nbsp;=&nbsp;5
+clock ticks. Given the large numbers involved this arithmetic normally
+has to be done using 64-bit precision and the
+<type>long&nbsp;long</type> data type, but allows code to run on
+hardware with unusual clock frequencies.
+ </para>
+ <para>
+The default frequency for the real-time clock on any platform is
+usually about 100Hz, but platform-specific documentation should be
+consulted for this information. Usually it is possible to override
+this default by configuration options, but again this depends on the
+capabilities of the underlying hardware. The resolution for any clock
+can be obtained using <function>cyg_clock_get_resolution</function>.
+For clocks created by application code, there is also a function
+<function>cyg_clock_set_resolution</function>. This does not affect
+the underlying hardware timer in any way, it merely updates the
+information that will be returned in subsequent calls to
+<function>cyg_clock_get_resolution</function>: changing the actual
+underlying clock frequency will require appropriate manipulation of
+the timer hardware.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-clocks-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_clock_create</function> is usually only called during
+system initialization (if at all), but may also be called from thread
+context. The same applies to <function>cyg_clock_delete</function>.
+The remaining functions may be called during initialization, from
+thread context, or from DSR context, although it should be noted that
+there is no locking between
+<function>cyg_clock_get_resolution</function> and
+<function>cyg_clock_set_resolution</function> so theoretically it is
+possible that the former returns an inconsistent data structure.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Alarms -->
+
+ <refentry id="kernel-alarms">
+
+ <refmeta>
+ <refentrytitle>Alarms</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_alarm_create</refname>
+ <refname>cyg_alarm_delete</refname>
+ <refname>cyg_alarm_initialize</refname>
+ <refname>cyg_alarm_enable</refname>
+ <refname>cyg_alarm_disable</refname>
+ <refpurpose>Run an alarm function when a number of events have occurred</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_alarm_create</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>counter</parameter></paramdef>
+ <paramdef>cyg_alarm_t* <parameter>alarmfn</parameter></paramdef>
+ <paramdef>cyg_addrword_t <parameter>data</parameter></paramdef>
+ <paramdef>cyg_handle_t* <parameter>handle</parameter></paramdef>
+ <paramdef>cyg_alarm* <parameter>alarm</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_alarm_delete</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>alarm</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_alarm_initialize</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>alarm</parameter></paramdef>
+ <paramdef>cyg_tick_count_t <parameter>trigger</parameter></paramdef>
+ <paramdef>cyg_tick_count_t <parameter>interval</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_alarm_enable</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>alarm</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_alarm_disable</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>alarm</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-alarms-description"><title>Description</title>
+ <para>
+Kernel alarms are used together with counters and allow for action to
+be taken when a certain number of events have occurred. If the counter
+is associated with a clock then the alarm action happens when the
+appropriate number of clock ticks have occurred, in other words after
+a certain period of time.
+ </para>
+ <para>
+Setting up an alarm involves a two-step process. First the alarm must
+be created with a call to <function>cyg_alarm_create</function>. This
+takes five arguments. The first identifies the counter to which the
+alarm should be attached. If the alarm should be attached to the
+system's real-time clock then <function>cyg_real_time_clock</function>
+and <function>cyg_clock_to_counter</function> can be used to get hold
+of the appropriate handle. The next two arguments specify the action
+to be taken when the alarm is triggered, in the form of a function
+pointer and some data. This function should take the form:
+ </para>
+ <programlisting width=72>
+void
+alarm_handler(cyg_handle_t alarm, cyg_addrword_t data)
+{
+ &hellip;
+}
+ </programlisting>
+ <para>
+The data argument passed to the alarm function corresponds to the
+third argument passed to <function>cyg_alarm_create</function>.
+The fourth argument to <function>cyg_alarm_create</function> is used
+to return a handle to the newly-created alarm object, and the final
+argument provides the memory needed for the alarm object and thus
+avoids any need for dynamic memory allocation within the kernel.
+ </para>
+ <para>
+Once an alarm has been created a further call to
+<function>cyg_alarm_initialize</function> is needed to activate it.
+The first argument specifies the alarm. The second argument indicates
+the number of events, for example clock ticks, that need to occur
+before the alarm triggers. If the third argument is 0 then the alarm
+will only trigger once. A non-zero value specifies that the alarm
+should trigger repeatedly, with an interval of the specified number of
+events.
+ </para>
+ <para>
+Alarms can be temporarily disabled and reenabled using
+<function>cyg_alarm_disable</function> and
+<function>cyg_alarm_enable</function>. Alternatively another call to
+<function>cyg_alarm_initialize</function> can be used to modify the
+behaviour of an existing alarm. If an alarm is no longer required then
+the associated resources can be released using
+<function>cyg_alarm_delete</function>.
+ </para>
+ <para>
+The alarm function is invoked when a counter tick occurs, in other
+words when there is a call to <function>cyg_counter_tick</function>,
+and will happen in the same context. If the alarm is associated with
+the system's real-time clock then this will be DSR context, following
+a clock interrupt. If the alarm is associated with some other
+application-specific counter then the details will depend on how that
+counter is updated.
+ </para>
+ <para>
+If two or more alarms are registered for precisely the same counter tick,
+the order of execution of the alarm functions is unspecified.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-alarms-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_alarm_create</function>
+<function>cyg_alarm_initialize</function> is typically called during
+system initialization but may also be called in thread context. The
+same applies to <function>cyg_alarm_delete</function>.
+<function>cyg_alarm_initialize</function>,
+<function>cyg_alarm_disable</function> and
+<function>cyg_alarm_enable</function> may be called during
+initialization or from thread or DSR context, but
+<function>cyg_alarm_enable</function> and
+<function>cyg_alarm_initialize</function> may be expensive operations
+and should only be called when necessary.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Mutexes -->
+
+ <refentry id="kernel-mutexes">
+
+ <refmeta>
+ <refentrytitle>Mutexes</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_mutex_init</refname>
+ <refname>cyg_mutex_destroy</refname>
+ <refname>cyg_mutex_lock</refname>
+ <refname>cyg_mutex_trylock</refname>
+ <refname>cyg_mutex_unlock</refname>
+ <refname>cyg_mutex_release</refname>
+ <refname>cyg_mutex_set_ceiling</refname>
+ <refname>cyg_mutex_set_protocol</refname>
+ <refpurpose>Synchronization primitive</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_mutex_init</function></funcdef>
+ <paramdef>cyg_mutex_t* <parameter>mutex</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_mutex_destroy</function></funcdef>
+ <paramdef>cyg_mutex_t* <parameter>mutex</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_mutex_lock</function></funcdef>
+ <paramdef>cyg_mutex_t* <parameter>mutex</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_mutex_trylock</function></funcdef>
+ <paramdef>cyg_mutex_t* <parameter>mutex</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_mutex_unlock</function></funcdef>
+ <paramdef>cyg_mutex_t* <parameter>mutex</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_mutex_release</function></funcdef>
+ <paramdef>cyg_mutex_t* <parameter>mutex</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_mutex_set_ceiling</function></funcdef>
+ <paramdef>cyg_mutex_t* <parameter>mutex</parameter></paramdef>
+ <paramdef>cyg_priority_t <parameter>priority</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_mutex_set_protocol</function></funcdef>
+ <paramdef>cyg_mutex_t* <parameter>mutex</parameter></paramdef>
+ <paramdef>enum cyg_mutex_protocol <parameter>protocol/</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-mutexes-description"><title>Description</title>
+ <para>
+The purpose of mutexes is to let threads share resources safely. If
+two or more threads attempt to manipulate a data structure with no
+locking between them then the system may run for quite some time
+without apparent problems, but sooner or later the data structure will
+become inconsistent and the application will start behaving strangely
+and is quite likely to crash. The same can apply even when
+manipulating a single variable or some other resource. For example,
+consider:
+ </para>
+<programlisting width=72>
+static volatile int counter = 0;
+
+void
+process_event(void)
+{
+ &hellip;
+
+ counter++;
+}
+</programlisting>
+ <para>
+Assume that after a certain period of time <varname>counter</varname>
+has a value of 42, and two threads A and B running at the same
+priority call <function>process_event</function>. Typically thread A
+will read the value of <varname>counter</varname> into a register,
+increment this register to 43, and write this updated value back to
+memory. Thread B will do the same, so usually
+<varname>counter</varname> will end up with a value of 44. However if
+thread A is timesliced after reading the old value 42 but before
+writing back 43, thread B will still read back the old value and will
+also write back 43. The net result is that the counter only gets
+incremented once, not twice, which depending on the application may
+prove disastrous.
+ </para>
+ <para>
+Sections of code like the above which involve manipulating shared data
+are generally known as critical regions. Code should claim a lock
+before entering a critical region and release the lock when leaving.
+Mutexes provide an appropriate synchronization primitive for this.
+ </para>
+ <programlisting width=72>
+static volatile int counter = 0;
+static cyg_mutex_t lock;
+
+void
+process_event(void)
+{
+ &hellip;
+
+ cyg_mutex_lock(&amp;lock);
+ counter++;
+ cyg_mutex_unlock(&amp;lock);
+}
+ </programlisting>
+ <para>
+A mutex must be initialized before it can be used, by calling
+<function>cyg_mutex_init</function>. This takes a pointer to a
+<structname>cyg_mutex_t</structname> data structure which is typically
+statically allocated, and may be part of a larger data structure. If a
+mutex is no longer required and there are no threads waiting on it
+then <function>cyg_mutex_destroy</function> can be used.
+ </para>
+ <para>
+The main functions for using a mutex are
+<function>cyg_mutex_lock</function> and
+<function>cyg_mutex_unlock</function>. In normal operation
+<function>cyg_mutex_lock</function> will return success after claiming
+the mutex lock, blocking if another thread currently owns the mutex.
+However the lock operation may fail if other code calls
+<function>cyg_mutex_release</function> or
+<function>cyg_thread_release</function>, so if these functions may get
+used then it is important to check the return value. The current owner
+of a mutex should call <function>cyg_mutex_unlock</function> when a
+lock is no longer required. This operation must be performed by the
+owner, not by another thread.
+ </para>
+ <para>
+<function>cyg_mutex_trylock</function> is a variant of
+<function>cyg_mutex_lock</function> that will always return
+immediately, returning success or failure as appropriate. This
+function is rarely useful. Typical code locks a mutex just before
+entering a critical region, so if the lock cannot be claimed then
+there may be nothing else for the current thread to do. Use of this
+function may also cause a form of priority inversion if the owner
+owner runs at a lower priority, because the priority inheritance code
+will not be triggered. Instead the current thread continues running,
+preventing the owner from getting any cpu time, completing the
+critical region, and releasing the mutex.
+ </para>
+ <para>
+<function>cyg_mutex_release</function> can be used to wake up all
+threads that are currently blocked inside a call to
+<function>cyg_mutex_lock</function> for a specific mutex. These lock
+calls will return failure. The current mutex owner is not affected.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-mutexes-priority-inversion"><title>Priority Inversion</title>
+ <para>
+The use of mutexes gives rise to a problem known as priority
+inversion. In a typical scenario this requires three threads A, B, and
+C, running at high, medium and low priority respectively. Thread A and
+thread B are temporarily blocked waiting for some event, so thread C
+gets a chance to run, needs to enter a critical region, and locks
+a mutex. At this point threads A and B are woken up - the exact order
+does not matter. Thread A needs to claim the same mutex but has to
+wait until C has left the critical region and can release the mutex.
+Meanwhile thread B works on something completely different and can
+continue running without problems. Because thread C is running a lower
+priority than B it will not get a chance to run until B blocks for
+some reason, and hence thread A cannot run either. The overall effect
+is that a high-priority thread A cannot proceed because of a lower
+priority thread B, and priority inversion has occurred.
+ </para>
+ <para>
+In simple applications it may be possible to arrange the code such
+that priority inversion cannot occur, for example by ensuring that a
+given mutex is never shared by threads running at different priority
+levels. However this may not always be possible even at the
+application level. In addition mutexes may be used internally by
+underlying code, for example the memory allocation package, so careful
+analysis of the whole system would be needed to be sure that priority
+inversion cannot occur. Instead it is common practice to use one of
+two techniques: priority ceilings and priority inheritance.
+ </para>
+ <para>
+Priority ceilings involve associating a priority with each mutex.
+Usually this will match the highest priority thread that will ever
+lock the mutex. When a thread running at a lower priority makes a
+successful call to <function>cyg_mutex_lock</function> or
+<function>cyg_mutex_trylock</function> its priority will be boosted to
+that of the mutex. For example, given the previous example the
+priority associated with the mutex would be that of thread A, so for
+as long as it owns the mutex thread C will run in preference to thread
+B. When C releases the mutex its priority drops to the normal value
+again, allowing A to run and claim the mutex. Setting the
+priority for a mutex involves a call to
+<function>cyg_mutex_set_ceiling</function>, which is typically called
+during initialization. It is possible to change the ceiling
+dynamically but this will only affect subsequent lock operations, not
+the current owner of the mutex.
+ </para>
+ <para>
+Priority ceilings are very suitable for simple applications, where for
+every thread in the system it is possible to work out which mutexes
+will be accessed. For more complicated applications this may prove
+difficult, especially if thread priorities change at run-time. An
+additional problem occurs for any mutexes outside the application, for
+example used internally within eCos packages. A typical eCos package
+will be unaware of the details of the various threads in the system,
+so it will have no way of setting suitable ceilings for its internal
+mutexes. If those mutexes are not exported to application code then
+using priority ceilings may not be viable. The kernel does provide a
+configuration option
+<varname>CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY</varname>
+that can be used to set the default priority ceiling for all mutexes,
+which may prove sufficient.
+ </para>
+ <para>
+The alternative approach is to use priority inheritance: if a thread
+calls <function>cyg_mutex_lock</function> for a mutex that it
+currently owned by a lower-priority thread, then the owner will have
+its priority raised to that of the current thread. Often this is more
+efficient than priority ceilings because priority boosting only
+happens when necessary, not for every lock operation, and the required
+priority is determined at run-time rather than by static analysis.
+However there are complications when multiple threads running at
+different priorities try to lock a single mutex, or when the current
+owner of a mutex then tries to lock additional mutexes, and this makes
+the implementation significantly more complicated than priority
+ceilings.
+ </para>
+ <para>
+There are a number of configuration options associated with priority
+inversion. First, if after careful analysis it is known that priority
+inversion cannot arise then the component
+<function>CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL</function>
+can be disabled. More commonly this component will be enabled, and one
+of either
+<varname>CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT</varname>
+or
+<varname>CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING</varname>
+will be selected, so that one of the two protocols is available for
+all mutexes. It is possible to select multiple protocols, so that some
+mutexes can have priority ceilings while others use priority
+inheritance or no priority inversion protection at all. Obviously this
+flexibility will add to the code size and to the cost of mutex
+operations. The default for all mutexes will be controlled by
+<varname>CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT</varname>,
+and can be changed at run-time using
+<function>cyg_mutex_set_protocol</function>.
+ </para>
+ <para>
+Priority inversion problems can also occur with other synchronization
+primitives such as semaphores. For example there could be a situation
+where a high-priority thread A is waiting on a semaphore, a
+low-priority thread C needs to do just a little bit more work before
+posting the semaphore, but a medium priority thread B is running and
+preventing C from making progress. However a semaphore does not have
+the concept of an owner, so there is no way for the system to know
+that it is thread C which would next post to the semaphore. Hence
+there is no way for the system to boost the priority of C
+automatically and prevent the priority inversion. Instead situations
+like this have to be detected by application developers and
+appropriate precautions have to be taken, for example making sure that
+all the threads run at suitable priorities at all times.
+ </para>
+ <warning><para>
+The current implementation of priority inheritance within the eCos
+kernel does not handle certain exceptional circumstances completely
+correctly. Problems will only arise if a thread owns one mutex,
+then attempts to claim another mutex, and there are other threads
+attempting to lock these same mutexes. Although the system will
+continue running, the current owners of the various mutexes involved
+may not run at the priority they should. This situation never arises
+in typical code because a mutex will only be locked for a small
+critical region, and there is no need to manipulate other shared resources
+inside this region. A more complicated implementation of priority
+inheritance is possible but would add significant overhead and certain
+operations would no longer be deterministic.
+ </para></warning>
+ <warning><para>
+Support for priority ceilings and priority inheritance is not
+implemented for all schedulers. In particular neither priority
+ceilings nor priority inheritance are currently available for the
+bitmap scheduler.
+ </para></warning>
+ </refsect1>
+
+ <refsect1 id="kernel-mutexes-alternatives"><title>Alternatives</title>
+ <para>
+In nearly all circumstances, if two or more threads need to share some
+data then protecting this data with a mutex is the correct thing to
+do. Mutexes are the only primitive that combine a locking mechanism
+and protection against priority inversion problems. However this
+functionality is achieved at a cost, and in exceptional circumstances
+such as an application's most critical inner loop it may be desirable
+to use some other means of locking.
+ </para>
+ <para>
+When a critical region is very very small it is possible to lock the
+scheduler, thus ensuring that no other thread can run until the
+scheduler is unlocked again. This is achieved with calls to <link
+linkend="kernel-schedcontrol"><function>cyg_scheduler_lock</function></link>
+and <function>cyg_scheduler_unlock</function>. If the critical region
+is sufficiently small then this can actually improve both performance
+and dispatch latency because <function>cyg_mutex_lock</function> also
+locks the scheduler for a brief period of time. This approach will not
+work on SMP systems because another thread may already be running on a
+different processor and accessing the critical region.
+ </para>
+ <para>
+Another way of avoiding the use of mutexes is to make sure that all
+threads that access a particular critical region run at the same
+priority and configure the system with timeslicing disabled
+(<varname>CYGSEM_KERNEL_SCHED_TIMESLICE</varname>). Without
+timeslicing a thread can only be preempted by a higher-priority one,
+or if it performs some operation that can block. This approach
+requires that none of the operations in the critical region can block,
+so for example it is not legal to call
+<function>cyg_semaphore_wait</function>. It is also vulnerable to
+any changes in the configuration or to the various thread priorities:
+any such changes may now have unexpected side effects. It will not
+work on SMP systems.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-mutexes-recursive"><title>Recursive Mutexes</title>
+ <para>
+The implementation of mutexes within the eCos kernel does not support
+recursive locks. If a thread has locked a mutex and then attempts to
+lock the mutex again, typically as a result of some recursive call in
+a complicated call graph, then either an assertion failure will be
+reported or the thread will deadlock. This behaviour is deliberate.
+When a thread has just locked a mutex associated with some data
+structure, it can assume that that data structure is in a consistent
+state. Before unlocking the mutex again it must ensure that the data
+structure is again in a consistent state. Recursive mutexes allow a
+thread to make arbitrary changes to a data structure, then in a
+recursive call lock the mutex again while the data structure is still
+inconsistent. The net result is that code can no longer make any
+assumptions about data structure consistency, which defeats the
+purpose of using mutexes.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-mutexes-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_mutex_init</function>,
+<function>cyg_mutex_set_ceiling</function> and
+<function>cyg_mutex_set_protocol</function> are normally called during
+initialization but may also be called from thread context. The
+remaining functions should only be called from thread context. Mutexes
+serve as a mutual exclusion mechanism between threads, and cannot be
+used to synchronize between threads and the interrupt handling
+subsystem. If a critical region is shared between a thread and a DSR
+then it must be protected using <link
+linkend="kernel-schedcontrol"><function>cyg_scheduler_lock</function></link>
+and <function>cyg_scheduler_unlock</function>. If a critical region is
+shared between a thread and an ISR, it must be protected by disabling
+or masking interrupts. Obviously these operations must be used with
+care because they can affect dispatch and interrupt latencies.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Condition variables -->
+
+ <refentry id="kernel-condition-variables">
+
+ <refmeta>
+ <refentrytitle>Condition Variables</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_cond_init</refname>
+ <refname>cyg_cond_destroy</refname>
+ <refname>cyg_cond_wait</refname>
+ <refname>cyg_cond_timed_wait</refname>
+ <refname>cyg_cond_signal</refname>
+ <refname>cyg_cond_broadcast</refname>
+ <refpurpose>Synchronization primitive</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_cond_init</function></funcdef>
+ <paramdef>cyg_cond_t* <parameter>cond</parameter></paramdef>
+ <paramdef>cyg_mutex_t* <parameter>mutex</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_cond_destroy</function></funcdef>
+ <paramdef>cyg_cond_t* <parameter>cond</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_cond_wait</function></funcdef>
+ <paramdef>cyg_cond_t* <parameter>cond</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_cond_timed_wait</function></funcdef>
+ <paramdef>cyg_cond_t* <parameter>cond</parameter></paramdef>
+ <paramdef>cyg_tick_count_t <parameter>abstime</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_cond_signal</function></funcdef>
+ <paramdef>cyg_cond_t* <parameter>cond</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_cond_broadcast</function></funcdef>
+ <paramdef>cyg_cond_t* <parameter>cond</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-condition-variables-description"><title>Description</title>
+
+ <para>
+Condition variables are used in conjunction with mutexes to implement
+long-term waits for some condition to become true. For example
+consider a set of functions that control access to a pool of
+resources:
+ </para>
+
+ <programlisting width=72>
+
+cyg_mutex_t res_lock;
+res_t res_pool[RES_MAX];
+int res_count = RES_MAX;
+
+void res_init(void)
+{
+ cyg_mutex_init(&amp;res_lock);
+ &lt;fill pool with resources&gt;
+}
+
+res_t res_allocate(void)
+{
+ res_t res;
+
+ cyg_mutex_lock(&amp;res_lock); // lock the mutex
+
+ if( res_count == 0 ) // check for free resource
+ res = RES_NONE; // return RES_NONE if none
+ else
+ {
+ res_count--; // allocate a resources
+ res = res_pool[res_count];
+ }
+
+ cyg_mutex_unlock(&amp;res_lock); // unlock the mutex
+
+ return res;
+}
+
+void res_free(res_t res)
+{
+ cyg_mutex_lock(&amp;res_lock); // lock the mutex
+
+ res_pool[res_count] = res; // free the resource
+ res_count++;
+
+ cyg_mutex_unlock(&amp;res_lock); // unlock the mutex
+}
+ </programlisting>
+
+ <para>
+These routines use the variable <varname>res_count</varname> to keep
+track of the resources available. If there are none then
+<function>res_allocate</function> returns <literal>RES_NONE</literal>,
+which the caller must check for and take appropriate error handling
+actions.
+ </para>
+
+ <para>
+Now suppose that we do not want to return
+<literal>RES_NONE</literal> when there are no resources, but want to
+wait for one to become available. This is where a condition variable
+can be used:
+ </para>
+
+ <programlisting width=72>
+
+cyg_mutex_t res_lock;
+cyg_cond_t res_wait;
+res_t res_pool[RES_MAX];
+int res_count = RES_MAX;
+
+void res_init(void)
+{
+ cyg_mutex_init(&amp;res_lock);
+ cyg_cond_init(&amp;res_wait, &amp;res_lock);
+ &lt;fill pool with resources&gt;
+}
+
+res_t res_allocate(void)
+{
+ res_t res;
+
+ cyg_mutex_lock(&amp;res_lock); // lock the mutex
+
+ while( res_count == 0 ) // wait for a resources
+ cyg_cond_wait(&amp;res_wait);
+
+ res_count--; // allocate a resource
+ res = res_pool[res_count];
+
+ cyg_mutex_unlock(&amp;res_lock); // unlock the mutex
+
+ return res;
+}
+
+void res_free(res_t res)
+{
+ cyg_mutex_lock(&amp;res_lock); // lock the mutex
+
+ res_pool[res_count] = res; // free the resource
+ res_count++;
+
+ cyg_cond_signal(&amp;res_wait); // wake up any waiting allocators
+
+ cyg_mutex_unlock(&amp;res_lock); // unlock the mutex
+}
+ </programlisting>
+
+ <para>
+In this version of the code, when <function>res_allocate</function>
+detects that there are no resources it calls
+<function>cyg_cond_wait</function>. This does two things: it unlocks
+the mutex, and puts the calling thread to sleep on the condition
+variable. When <function>res_free</function> is eventually called, it
+puts a resource back into the pool and calls
+<function>cyg_cond_signal</function> to wake up any thread waiting on
+the condition variable. When the waiting thread eventually gets to run again,
+it will re-lock the mutex before returning from
+<function>cyg_cond_wait</function>.
+ </para>
+
+ <para>
+There are two important things to note about the way in which this
+code works. The first is that the mutex unlock and wait in
+<function>cyg_cond_wait</function> are atomic: no other thread can run
+between the unlock and the wait. If this were not the case then a call
+to <function>res_free</function> by that thread would release the
+resource but the call to <function>cyg_cond_signal</function> would be
+lost, and the first thread would end up waiting when there were
+resources available.
+ </para>
+
+ <para>
+The second feature is that the call to
+<function>cyg_cond_wait</function> is in a <literal>while</literal>
+loop and not a simple <literal>if</literal> statement. This is because
+of the need to re-lock the mutex in <function>cyg_cond_wait</function>
+when the signalled thread reawakens. If there are other threads
+already queued to claim the lock then this thread must wait. Depending
+on the scheduler and the queue order, many other threads may have
+entered the critical section before this one gets to run. So the
+condition that it was waiting for may have been rendered false. Using
+a loop around all condition variable wait operations is the only way
+to guarantee that the condition being waited for is still true after
+waiting.
+ </para>
+
+ <para>
+Before a condition variable can be used it must be initialized with a
+call to <function>cyg_cond_init</function>. This requires two
+arguments, memory for the data structure and a pointer to an existing
+mutex. This mutex will not be initialized by
+<function>cyg_cond_init</function>, instead a separate call to
+<function>cyg_mutex_init</function> is required. If a condition
+variable is no longer required and there are no threads waiting on it
+then <function>cyg_cond_destroy</function> can be used.
+ </para>
+ <para>
+When a thread needs to wait for a condition to be satisfied it can
+call <function>cyg_cond_wait</function>. The thread must have already
+locked the mutex that was specified in the
+<function>cyg_cond_init</function> call. This mutex will be unlocked
+and the current thread will be suspended in an atomic operation. When
+some other thread performs a signal or broadcast operation the current
+thread will be woken up and automatically reclaim ownership of the mutex
+again, allowing it to examine global state and determine whether or
+not the condition is now satisfied.
+ </para>
+ <para>
+The kernel supplies a variant of this function,
+<function>cyg_cond_timed_wait</function>, which can be used to wait on
+the condition variable or until some number of clock ticks have
+occurred. The number of ticks is specified as an absolute, not
+relative tick count, and so in order to wait for a relative number of
+ticks, the return value of the <function>cyg_current_time()</function>
+function should be added to determine the absolute number of ticks.
+The mutex will always be reclaimed before
+<function>cyg_cond_timed_wait</function> returns, regardless of
+whether it was a result of a signal operation or a timeout.
+ </para>
+ <para>
+There is no <function>cyg_cond_trywait</function> function because
+this would not serve any purpose. If a thread has locked the mutex and
+determined that the condition is satisfied, it can just release the
+mutex and return. There is no need to perform any operation on the
+condition variable.
+ </para>
+ <para>
+When a thread changes shared state that may affect some other thread
+blocked on a condition variable, it should call either
+<function>cyg_cond_signal</function> or
+<function>cyg_cond_broadcast</function>. These calls do not require
+ownership of the mutex, but usually the mutex will have been claimed
+before updating the shared state. A signal operation only wakes up the
+first thread that is waiting on the condition variable, while a
+broadcast wakes up all the threads. If there are no threads waiting on
+the condition variable at the time, then the signal or broadcast will
+have no effect: past signals are not counted up or remembered in any
+way. Typically a signal should be used when all threads will check the
+same condition and at most one thread can continue running. A
+broadcast should be used if threads check slightly different
+conditions, or if the change to the global state might allow multiple
+threads to proceed.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-condition-variables-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_cond_init</function> is typically called during system
+initialization but may also be called in thread context. The same
+applies to <function>cyg_cond_delete</function>.
+<function>cyg_cond_wait</function> and
+<function>cyg_cond_timedwait</function> may only be called from thread
+context since they may block. <function>cyg_cond_signal</function> and
+<function>cyg_cond_broadcast</function> may be called from thread or
+DSR context.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Semaphores -->
+
+ <refentry id="kernel-semaphores">
+
+ <refmeta>
+ <refentrytitle>Semaphores</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_semaphore_init</refname>
+ <refname>cyg_semaphore_destroy</refname>
+ <refname>cyg_semaphore_wait</refname>
+ <refname>cyg_semaphore_timed_wait</refname>
+ <refname>cyg_semaphore_post</refname>
+ <refname>cyg_semaphore_peek</refname>
+ <refpurpose>Synchronization primitive</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_semaphore_init</function></funcdef>
+ <paramdef>cyg_sem_t* <parameter>sem</parameter></paramdef>
+ <paramdef>cyg_count32 <parameter>val</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_semaphore_destroy</function></funcdef>
+ <paramdef>cyg_sem_t* <parameter>sem</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_semaphore_wait</function></funcdef>
+ <paramdef>cyg_sem_t* <parameter>sem</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_semaphore_timed_wait</function></funcdef>
+ <paramdef>cyg_sem_t* <parameter>sem</parameter></paramdef>
+ <paramdef>cyg_tick_count_t <parameter>abstime</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_semaphore_trywait</function></funcdef>
+ <paramdef>cyg_sem_t* <parameter>sem</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_semaphore_post</function></funcdef>
+ <paramdef>cyg_sem_t* <parameter>sem</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_semaphore_peek</function></funcdef>
+ <paramdef>cyg_sem_t* <parameter>sem</parameter></paramdef>
+ <paramdef>cyg_count32* <parameter>val</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-semaphores-description"><title>Description</title>
+ <para>
+Counting semaphores are a <link
+linkend="kernel-overview-synch-primitives">synchronization
+primitive</link> that allow threads to wait until an event has
+occurred. The event may be generated by a producer thread, or by a DSR
+in response to a hardware interrupt. Associated with each semaphore is
+an integer counter that keeps track of the number of events that have
+not yet been processed. If this counter is zero, an attempt by a
+consumer thread to wait on the semaphore will block until some other
+thread or a DSR posts a new event to the semaphore. If the counter is
+greater than zero then an attempt to wait on the semaphore will
+consume one event, in other words decrement the counter, and return
+immediately. Posting to a semaphore will wake up the first thread that
+is currently waiting, which will then resume inside the semaphore wait
+operation and decrement the counter again.
+ </para>
+ <para>
+Another use of semaphores is for certain forms of resource management.
+The counter would correspond to how many of a certain type of resource
+are currently available, with threads waiting on the semaphore to
+claim a resource and posting to release the resource again. In
+practice <link linkend="kernel-condition-variables">condition
+variables</link> are usually much better suited for operations like
+this.
+ </para>
+ <para>
+<function>cyg_semaphore_init</function> is used to initialize a
+semaphore. It takes two arguments, a pointer to a
+<structname>cyg_sem_t</structname> structure and an initial value for
+the counter. Note that semaphore operations, unlike some other parts
+of the kernel API, use pointers to data structures rather than
+handles. This makes it easier to embed semaphores in a larger data
+structure. The initial counter value can be any number, zero, positive
+or negative, but typically a value of zero is used to indicate that no
+events have occurred yet.
+ </para>
+ <para>
+<function>cyg_semaphore_wait</function> is used by a consumer thread
+to wait for an event. If the current counter is greater than 0, in
+other words if the event has already occurred in the past, then the
+counter will be decremented and the call will return immediately.
+Otherwise the current thread will be blocked until there is a
+<function>cyg_semaphore_post</function> call.
+ </para>
+ <para>
+<function>cyg_semaphore_post</function> is called when an event has
+occurs. This increments the counter and wakes up the first thread
+waiting on the semaphore (if any). Usually that thread will then
+continue running inside <function>cyg_semaphore_wait</function> and
+decrement the counter again. However other scenarioes are possible.
+For example the thread calling <function>cyg_semaphore_post</function>
+may be running at high priority, some other thread running at medium
+priority may be about to call <function>cyg_semaphore_wait</function>
+when it next gets a chance to run, and a low priority thread may be
+waiting on the semaphore. What will happen is that the current high
+priority thread continues running until it is descheduled for some
+reason, then the medium priority thread runs and its call to
+<function>cyg_semaphore_wait</function> succeeds immediately, and
+later on the low priority thread runs again, discovers a counter value
+of 0, and blocks until another event is posted. If there are multiple
+threads blocked on a semaphore then the configuration option
+<varname>CYGIMP_KERNEL_SCHED_SORTED_QUEUES</varname> determines which
+one will be woken up by a post operation.
+ </para>
+ <para>
+<function>cyg_semaphore_wait</function> returns a boolean. Normally it
+will block until it has successfully decremented the counter, retrying
+as necessary, and return success. However the wait operation may be
+aborted by a call to <link
+linkend="kernel-thread-control"><function>cyg_thread_release</function></link>,
+and <function>cyg_semaphore_wait</function> will then return false.
+ </para>
+ <para>
+<function>cyg_semaphore_timed_wait</function> is a variant of
+<function>cyg_semaphore_wait</function>. It can be used to wait until
+either an event has occurred or a number of clock ticks have happened.
+The number of ticks is specified as an absolute, not relative tick
+count, and so in order to wait for a relative number of ticks, the
+return value of the <function>cyg_current_time()</function> function
+should be added to determine the absolute number of ticks. The
+function returns success if the semaphore wait operation succeeded, or
+false if the operation timed out or was aborted by
+<function>cyg_thread_release</function>.
+If support for the real-time
+clock has been removed from the current configuration then this
+function will not be available.
+<function>cyg_semaphore_trywait</function> is another variant which
+will always return immediately rather than block, again returning
+success or failure. If <function>cyg_semaphore_timedwait</function>
+is given a timeout in the past, it operates like
+<function>cyg_semaphore_trywait</function>.
+ </para>
+ <para>
+<function>cyg_semaphore_peek</function> can be used to get hold of the
+current counter value. This function is rarely useful except for
+debugging purposes since the counter value may change at any time if
+some other thread or a DSR performs a semaphore operation.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-semaphores-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_semaphore_init</function> is normally called during
+initialization but may also be called from thread context.
+<function>cyg_semaphore_wait</function> and
+<function>cyg_semaphore_timed_wait</function> may only be called from
+thread context because these operations may block.
+<function>cyg_semaphore_trywait</function>,
+<function>cyg_semaphore_post</function> and
+<function>cyg_semaphore_peek</function> may be called from thread or
+DSR context.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Mail boxes -->
+
+ <refentry id="kernel-mail-boxes">
+
+ <refmeta>
+ <refentrytitle>Mail boxes</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_mbox_create</refname>
+ <refname>cyg_mbox_delete</refname>
+ <refname>cyg_mbox_get</refname>
+ <refname>cyg_mbox_timed_get</refname>
+ <refname>cyg_mbox_tryget</refname>
+ <refname>cyg_mbox_peek_item</refname>
+ <refname>cyg_mbox_put</refname>
+ <refname>cyg_mbox_timed_put</refname>
+ <refname>cyg_mbox_tryput</refname>
+ <refname>cyg_mbox_peek</refname>
+ <refname>cyg_mbox_waiting_to_get</refname>
+ <refname>cyg_mbox_waiting_to_put</refname>
+ <refpurpose>Synchronization primitive</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_mbox_create</function></funcdef>
+ <paramdef>cyg_handle_t* <parameter>handle</parameter></paramdef>
+ <paramdef>cyg_mbox* <parameter>mbox</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_mbox_delete</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void* <function>cyg_mbox_get</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void* <function>cyg_mbox_timed_get</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ <paramdef>cyg_tick_count_t <parameter>abstime</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void* <function>cyg_mbox_tryget</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_count32 <function>cyg_mbox_peek</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void* <function>cyg_mbox_peek_item</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_mbox_put</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ <paramdef>void* <parameter>item</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_mbox_timed_put</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ <paramdef>void* <parameter>item</parameter></paramdef>
+ <paramdef>cyg_tick_count_t <parameter>abstime</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_mbox_tryput</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ <paramdef>void* <parameter>item</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_mbox_waiting_to_get</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_mbox_waiting_to_put</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>mbox</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-mail-boxes-description"><title>Description</title>
+ <para>
+Mail boxes are a synchronization primitive. Like semaphores they
+can be used by a consumer thread to wait until a certain event has
+occurred, but the producer also has the ability to transmit some data
+along with each event. This data, the message, is normally a pointer
+to some data structure. It is stored in the mail box itself, so the
+producer thread that generates the event and provides the data usually
+does not have to block until some consumer thread is ready to receive
+the event. However a mail box will only have a finite capacity,
+typically ten slots. Even if the system is balanced and events are
+typically consumed at least as fast as they are generated, a burst of
+events can cause the mail box to fill up and the generating thread
+will block until space is available again. This behaviour is very
+different from semaphores, where it is only necessary to maintain a
+counter and hence an overflow is unlikely.
+ </para>
+ <para>
+Before a mail box can be used it must be created with a call to
+<function>cyg_mbox_create</function>. Each mail box has a unique
+handle which will be returned via the first argument and which should
+be used for subsequent operations.
+<function>cyg_mbox_create</function> also requires an area of memory
+for the kernel structure, which is provided by the
+<structname>cyg_mbox</structname> second argument. If a mail box is
+no longer required then <function>cyg_mbox_delete</function> can be
+used. This will simply discard any messages that remain posted.
+ </para>
+ <para>
+The main function for waiting on a mail box is
+<function>cyg_mbox_get</function>. If there is a pending message
+because of a call to <function>cyg_mbox_put</function> then
+<function>cyg_mbox_get</function> will return immediately with the
+message that was put into the mail box. Otherwise this function
+will block until there is a put operation. Exceptionally the thread
+can instead be unblocked by a call to
+<function>cyg_thread_release</function>, in which case
+<function>cyg_mbox_get</function> will return a null pointer. It is
+assumed that there will never be a call to
+<function>cyg_mbox_put</function> with a null pointer, because it
+would not be possible to distinguish between that and a release
+operation. Messages are always retrieved in the order in which they
+were put into the mail box, and there is no support for messages
+with different priorities.
+ </para>
+ <para>
+There are two variants of <function>cyg_mbox_get</function>. The
+first, <function>cyg_mbox_timed_get</function> will wait until either
+a message is available or until a number of clock ticks have occurred.
+The number of ticks is specified as an absolute, not relative tick
+count, and so in order to wait for a relative number of ticks, the
+return value of the <function>cyg_current_time()</function> function
+should be added to determine the absolute number of ticks. If no
+message is posted within the timeout then a null pointer will be
+returned. <function>cyg_mbox_tryget</function> is a non-blocking
+operation which will either return a message if one is available or a
+null pointer.
+ </para>
+ <para>
+New messages are placed in the mail box by calling
+<function>cyg_mbox_put</function> or one of its variants. The main put
+function takes two arguments, a handle to the mail box and a
+pointer for the message itself. If there is a spare slot in the
+mail box then the new message can be placed there immediately, and
+if there is a waiting thread it will be woken up so that it can
+receive the message. If the mail box is currently full then
+<function>cyg_mbox_put</function> will block until there has been a
+get operation and a slot is available. The
+<function>cyg_mbox_timed_put</function> variant imposes a time limit
+on the put operation, returning false if the operation cannot be
+completed within the specified number of clock ticks and as for
+<function>cyg_mbox_timed_get</function> this is an absolute tick
+count. The <function>cyg_mbox_tryput</function> variant is
+non-blocking, returning false if there are no free slots available and
+the message cannot be posted without blocking.
+ </para>
+ <para>
+There are a further four functions available for examining the current
+state of a mailbox. The results of these functions must be used with
+care because usually the state can change at any time as a result of
+activity within other threads, but they may prove occasionally useful
+during debugging or in special situations.
+<function>cyg_mbox_peek</function> returns a count of the number of
+messages currently stored in the mail box.
+<function>cyg_mbox_peek_item</function> retrieves the first message,
+but it remains in the mail box until a get operation is performed.
+<function>cyg_mbox_waiting_to_get</function> and
+<function>cyg_mbox_waiting_to_put</function> indicate whether or not
+there are currently threads blocked in a get or a put operation on a
+given mail box.
+ </para>
+ <para>
+The number of slots in each mail box is controlled by a
+configuration option
+<varname>CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE</varname>, with a default
+value of 10. All mail boxes are the same size.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-mail-boxes-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_mbox_create</function> is typically called during
+system initialization but may also be called in thread context.
+The remaining functions are normally called only during thread
+context. Of special note is <function>cyg_mbox_put</function> which
+can be a blocking operation when the mail box is full, and which
+therefore must never be called from DSR context. It is permitted to
+call <function>cyg_mbox_tryput</function>,
+<function>cyg_mbox_tryget</function>, and the information functions
+from DSR context but this is rarely useful.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Flags -->
+
+ <refentry id="kernel-flags">
+
+ <refmeta>
+ <refentrytitle>Event Flags</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_flag_init</refname>
+ <refname>cyg_flag_destroy</refname>
+ <refname>cyg_flag_setbits</refname>
+ <refname>cyg_flag_maskbits</refname>
+ <refname>cyg_flag_wait</refname>
+ <refname>cyg_flag_timed_wait</refname>
+ <refname>cyg_flag_poll</refname>
+ <refname>cyg_flag_peek</refname>
+ <refname>cyg_flag_waiting</refname>
+ <refpurpose>Synchronization primitive</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_flag_init</function></funcdef>
+ <paramdef>cyg_flag_t* <parameter>flag</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_flag_destroy</function></funcdef>
+ <paramdef>cyg_flag_t* <parameter>flag</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_flag_setbits</function></funcdef>
+ <paramdef>cyg_flag_t* <parameter>flag</parameter></paramdef>
+ <paramdef>cyg_flag_value_t <parameter>value</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_flag_maskbits</function></funcdef>
+ <paramdef>cyg_flag_t* <parameter>flag</parameter></paramdef>
+ <paramdef>cyg_flag_value_t <parameter>value</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_flag_value_t <function>cyg_flag_wait</function></funcdef>
+ <paramdef>cyg_flag_t* <parameter>flag</parameter></paramdef>
+ <paramdef>cyg_flag_value_t <parameter>pattern</parameter></paramdef>
+ <paramdef>cyg_flag_mode_t <parameter>mode</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_flag_value_t <function>cyg_flag_timed_wait</function></funcdef>
+ <paramdef>cyg_flag_t* <parameter>flag</parameter></paramdef>
+ <paramdef>cyg_flag_value_t <parameter>pattern</parameter></paramdef>
+ <paramdef>cyg_flag_mode_t <parameter>mode</parameter></paramdef>
+ <paramdef>cyg_tick_count_t <parameter>abstime</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_flag_value_t <function>cyg_flag_poll</function></funcdef>
+ <paramdef>cyg_flag_t* <parameter>flag</parameter></paramdef>
+ <paramdef>cyg_flag_value_t <parameter>pattern</parameter></paramdef>
+ <paramdef>cyg_flag_mode_t <parameter>mode</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_flag_value_t <function>cyg_flag_peek</function></funcdef>
+ <paramdef>cyg_flag_t* <parameter>flag</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_flag_waiting</function></funcdef>
+ <paramdef>cyg_flag_t* <parameter>flag</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-flags-description"><title>Description</title>
+ <para>
+Event flags allow a consumer thread to wait for one of several
+different types of event to occur. Alternatively it is possible to
+wait for some combination of events. The implementation is relatively
+straightforward. Each event flag contains a 32-bit integer.
+Application code associates these bits with specific events, so for
+example bit 0 could indicate that an I/O operation has completed and
+data is available, while bit 1 could indicate that the user has
+pressed a start button. A producer thread or a DSR can cause one or
+more of the bits to be set, and a consumer thread currently waiting
+for these bits will be woken up.
+ </para>
+ <para>
+Unlike semaphores no attempt is made to keep track of event counts. It
+does not matter whether a given event occurs once or multiple times
+before being consumed, the corresponding bit in the event flag will
+change only once. However semaphores cannot easily be used to handle
+multiple event sources. Event flags can often be used as an
+alternative to condition variables, although they cannot be used for
+completely arbitrary conditions and they only support the equivalent
+of condition variable broadcasts, not signals.
+ </para>
+ <para>
+Before an event flag can be used it must be initialized by a call to
+<function>cyg_flag_init</function>. This takes a pointer to a
+<structname>cyg_flag_t</structname> data structure, which can be part of a
+larger structure. All 32 bits in the event flag will be set to 0,
+indicating that no events have yet occurred. If an event flag is no
+longer required it can be cleaned up with a call to
+<function>cyg_flag_destroy</function>, allowing the memory for the
+<structfield>cyg_flag_t</structfield> structure to be re-used.
+ </para>
+ <para>
+A consumer thread can wait for one or more events by calling
+<function>cyg_flag_wait</function>. This takes three arguments. The
+first identifies a particular event flag. The second is some
+combination of bits, indicating which events are of interest. The
+final argument should be one of the following:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>CYG_FLAG_WAITMODE_AND</literal></term>
+ <listitem><para>
+The call to <function>cyg_flag_wait</function> will block until all
+the specified event bits are set. The event flag is not cleared when
+the wait succeeds, in other words all the bits remain set.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>CYG_FLAG_WAITMODE_OR</literal></term>
+ <listitem><para>
+The call will block until at least one of the specified event bits is
+set. The event flag is not cleared on return.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR</literal></term>
+ <listitem><para>
+The call will block until all the specified event bits are set, and
+the entire event flag is cleared when the call succeeds. Note that
+if this mode of operation is used then a single event flag cannot be
+used to store disjoint sets of events, even though enough bits might
+be available. Instead each disjoint set of events requires its own
+event flag.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>CYG_FLAG_WAITMODE_OR | CYG_FLAG_WAITMODE_CLR</literal></term>
+ <listitem><para>
+The call will block until at least one of the specified event bits is
+set, and the entire flag is cleared when the call succeeds.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+A call to <function>cyg_flag_wait</function> normally blocks until the
+required condition is satisfied. It will return the value of the event
+flag at the point that the operation succeeded, which may be a
+superset of the requested events. If
+<function>cyg_thread_release</function> is used to unblock a thread
+that is currently in a wait operation, the
+<function>cyg_flag_wait</function> call will instead return 0.
+ </para>
+ <para>
+<function>cyg_flag_timed_wait</function> is a variant of
+<function>cyg_flag_wait</function> which adds a timeout: the wait
+operation must succeed within the specified number of ticks, or it
+will fail with a return value of 0. The number of ticks is specified
+as an absolute, not relative tick count, and so in order to wait for a
+relative number of ticks, the return value of the
+<function>cyg_current_time()</function> function should be added to
+determine the absolute number of ticks.
+<function>cyg_flag_poll</function> is a non-blocking variant: if the
+wait operation can succeed immediately it acts like
+<function>cyg_flag_wait</function>, otherwise it returns immediately
+with a value of 0.
+ </para>
+ <para>
+<function>cyg_flag_setbits</function> is called by a producer thread
+or from inside a DSR when an event occurs. The specified bits are or'd
+into the current event flag value. This may cause one or more waiting
+threads to be woken up, if their conditions are now satisfied. How many
+threads are awoken depends on the use of <literal>CYG_FLAG_WAITMODE_CLR
+</literal>. The queue of threads waiting on the flag is walked to find
+threads which now have their wake condition fulfilled. If the awoken thread
+has passed <literal>CYG_FLAG_WAITMODE_CLR</literal> the walking of the queue
+is terminated, otherwise the walk continues. Thus if no threads have passed
+<literal>CYG_FLAG_WAITMORE_CLR</literal> all threads with fulfilled
+conditions will be awoken. If <literal>CYG_FLAG_WAITMODE_CLR</literal> is
+passed by threads with fulfilled conditions, the number of awoken threads
+will depend on the order the threads are in the queue.
+ </para>
+ <para>
+<function>cyg_flag_maskbits</function> can be used to clear one or
+more bits in the event flag. This can be called from a producer when a
+particular condition is no longer satisfied, for example when the user
+is no longer pressing a particular button. It can also be used by a
+consumer thread if <literal>CYG_FLAG_WAITMODE_CLR</literal> was not
+used as part of the wait operation, to indicate that some but not all
+of the active events have been consumed. If there are multiple
+consumer threads performing wait operations without using
+<function>CYG_FLAG_WAITMODE_CLR</function> then typically some
+additional synchronization such as a mutex is needed to prevent
+multiple threads consuming the same event.
+ </para>
+ <para>
+Two additional functions are provided to query the current state of an
+event flag. <function>cyg_flag_peek</function> returns the current
+value of the event flag, and <function>cyg_flag_waiting</function> can
+be used to find out whether or not there are any threads currently
+blocked on the event flag. Both of these functions must be used with
+care because other threads may be operating on the event flag.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-flags-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_flag_init</function> is typically called during system
+initialization but may also be called in thread context. The same
+applies to <function>cyg_flag_destroy</function>.
+<function>cyg_flag_wait</function> and
+<function>cyg_flag_timed_wait</function> may only be called from
+thread context. The remaining functions may be called from thread or
+DSR context.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Spinlocks -->
+
+ <refentry id="kernel-spinlocks">
+
+ <refmeta>
+ <refentrytitle>Spinlocks</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_spinlock_create</refname>
+ <refname>cyg_spinlock_destroy</refname>
+ <refname>cyg_spinlock_spin</refname>
+ <refname>cyg_spinlock_clear</refname>
+ <refname>cyg_spinlock_test</refname>
+ <refname>cyg_spinlock_spin_intsave</refname>
+ <refname>cyg_spinlock_clear_intsave</refname>
+ <refpurpose>Low-level Synchronization Primitive</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_spinlock_init</function></funcdef>
+ <paramdef>cyg_spinlock_t* <parameter>lock</parameter></paramdef>
+ <paramdef>cyg_bool_t <parameter>locked</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_spinlock_destroy</function></funcdef>
+ <paramdef>cyg_spinlock_t* <parameter>lock</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_spinlock_spin</function></funcdef>
+ <paramdef>cyg_spinlock_t* <parameter>lock</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_spinlock_clear</function></funcdef>
+ <paramdef>cyg_spinlock_t* <parameter>lock</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_spinlock_try</function></funcdef>
+ <paramdef>cyg_spinlock_t* <parameter>lock</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_bool_t <function>cyg_spinlock_test</function></funcdef>
+ <paramdef>cyg_spinlock_t* <parameter>lock</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_spinlock_spin_intsave</function></funcdef>
+ <paramdef>cyg_spinlock_t* <parameter>lock</parameter></paramdef>
+ <paramdef>cyg_addrword_t* <parameter>istate</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_spinlock_clear_intsave</function></funcdef>
+ <paramdef>cyg_spinlock_t* <parameter>lock</parameter></paramdef>
+ <paramdef>cyg_addrword_t <parameter>istate</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-spinlocks-description"><title>Description</title>
+ <para>
+Spinlocks provide an additional synchronization primitive for
+applications running on SMP systems. They operate at a lower level
+than the other primitives such as mutexes, and for most purposes the
+higher-level primitives should be preferred. However there are some
+circumstances where a spinlock is appropriate, especially when
+interrupt handlers and threads need to share access to hardware, and
+on SMP systems the kernel implementation itself depends on spinlocks.
+ </para>
+ <para>
+Essentially a spinlock is just a simple flag. When code tries to claim
+a spinlock it checks whether or not the flag is already set. If not
+then the flag is set and the operation succeeds immediately. The exact
+implementation of this is hardware-specific, for example it may use a
+test-and-set instruction to guarantee the desired behaviour even if
+several processors try to access the spinlock at the exact same time.
+If it is not possible to claim a spinlock then the current thead spins
+in a tight loop, repeatedly checking the flag until it is clear. This
+behaviour is very different from other synchronization primitives such
+as mutexes, where contention would cause a thread to be suspended. The
+assumption is that a spinlock will only be held for a very short time.
+If claiming a spinlock could cause the current thread to be suspended
+then spinlocks could not be used inside interrupt handlers, which is
+not acceptable.
+ </para>
+ <para>
+This does impose a constraint on any code which uses spinlocks.
+Specifically it is important that spinlocks are held only for a short
+period of time, typically just some dozens of instructions. Otherwise
+another processor could be blocked on the spinlock for a long time,
+unable to do any useful work. It is also important that a thread which
+owns a spinlock does not get preempted because that might cause
+another processor to spin for a whole timeslice period, or longer. One
+way of achieving this is to disable interrupts on the current
+processor, and the function
+<function>cyg_spinlock_spin_intsave</function> is provided to
+facilitate this.
+ </para>
+ <para>
+Spinlocks should not be used on single-processor systems. Consider a
+high priority thread which attempts to claim a spinlock already held
+by a lower priority thread: it will just loop forever and the lower
+priority thread will never get another chance to run and release the
+spinlock. Even if the two threads were running at the same priority,
+the one attempting to claim the spinlock would spin until it was
+timesliced and a lot of cpu time would be wasted. If an interrupt
+handler tried to claim a spinlock owned by a thread, the interrupt
+handler would loop forever. Therefore spinlocks are only appropriate
+for SMP systems where the current owner of a spinlock can continue
+running on a different processor.
+ </para>
+ <para>
+Before a spinlock can be used it must be initialized by a call to
+<function>cyg_spinlock_init</function>. This takes two arguments, a
+pointer to a <function>cyg_spinlock_t</function> data structure, and
+a flag to specify whether the spinlock starts off locked or unlocked.
+If a spinlock is no longer required then it can be destroyed by a call
+to <function>cyg_spinlock_destroy</function>.
+ </para>
+ <para>
+There are two routines for claiming a spinlock:
+<function>cyg_spinlock_spin</function> and
+<function>cyg_spinlock_spin_intsave</function>. The former can be used
+when it is known the current code will not be preempted, for example
+because it is running in an interrupt handler or because interrupts
+are disabled. The latter will disable interrupts in addition to
+claiming the spinlock, so is safe to use in all circumstances. The
+previous interrupt state is returned via the second argument, and
+should be used in a subsequent call to
+<function>cyg_spinlock_clear_intsave</function>.
+ </para>
+ <para>
+Similarly there are two routines for releasing a spinlock:
+<function>cyg_spinlock_clear</function> and
+<function>cyg_spinlock_clear_intsave</function>. Typically
+the former will be used if the spinlock was claimed by a call to
+<function>cyg_spinlock_spin</function>, and the latter when
+<function>cyg_spinlock_intsave</function> was used.
+ </para>
+ <para>
+There are two additional routines.
+<function>cyg_spinlock_try</function> is a non-blocking version of
+<function>cyg_spinlock_spin</function>: if possible the lock will be
+claimed and the function will return <literal>true</literal>; otherwise the function
+will return immediately with failure.
+<function>cyg_spinlock_test</function> can be used to find out whether
+or not the spinlock is currently locked. This function must be used
+with care because, especially on a multiprocessor system, the state of
+the spinlock can change at any time.
+ </para>
+ <para>
+Spinlocks should only be held for a short period of time, and
+attempting to claim a spinlock will never cause a thread to be
+suspended. This means that there is no need to worry about priority
+inversion problems, and concepts such as priority ceilings and
+inheritance do not apply.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-spinlocks-context"><title>Valid contexts</title>
+ <para>
+All of the spinlock functions can be called from any context,
+including ISR and DSR context. Typically
+<function>cyg_spinlock_init</function> is only called during system
+initialization.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Scheduler control -->
+
+ <refentry id="kernel-schedcontrol">
+
+ <refmeta>
+ <refentrytitle>Scheduler Control</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_scheduler_start</refname>
+ <refname>cyg_scheduler_lock</refname>
+ <refname>cyg_scheduler_unlock</refname>
+ <refname>cyg_scheduler_safe_lock</refname>
+ <refname>cyg_scheduler_read_lock</refname>
+ <refpurpose>Control the state of the scheduler</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_scheduler_start</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_scheduler_lock</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_scheduler_unlock</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_ucount32 <function>cyg_scheduler_read_lock</function></funcdef>
+ <void>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-schedcontrol-description"><title>Description</title>
+ <para>
+<function>cyg_scheduler_start</function> should only be called once,
+to mark the end of system initialization. In typical configurations it
+is called automatically by the system startup, but some applications
+may bypass the standard startup in which case
+<function>cyg_scheduler_start</function> will have to be called
+explicitly. The call will enable system interrupts, allowing I/O
+operations to commence. Then the scheduler will be invoked and control
+will be transferred to the highest priority runnable thread. The call
+will never return.
+ </para>
+ <para>
+The various data structures inside the eCos kernel must be protected
+against concurrent updates. Consider a call to
+<function>cyg_semaphore_post</function> which causes a thread to be
+woken up: the semaphore data structure must be updated to remove the
+thread from its queue; the scheduler data structure must also be
+updated to mark the thread as runnable; it is possible that the newly
+runnable thread has a higher priority than the current one, in which
+case preemption is required. If in the middle of the semaphore post
+call an interrupt occurred and the interrupt handler tried to
+manipulate the same data structures, for example by making another
+thread runnable, then it is likely that the structures will be left in
+an inconsistent state and the system will fail.
+ </para>
+ <para>
+To prevent such problems the kernel contains a special lock known as
+the scheduler lock. A typical kernel function such as
+<function>cyg_semaphore_post</function> will claim the scheduler lock,
+do all its manipulation of kernel data structures, and then release
+the scheduler lock. The current thread cannot be preempted while it
+holds the scheduler lock. If an interrupt occurs and a DSR is supposed
+to run to signal that some event has occurred, that DSR is postponed
+until the scheduler unlock operation. This prevents concurrent updates
+of kernel data structures.
+ </para>
+ <para>
+The kernel exports three routines for manipulating the scheduler lock.
+<function>cyg_scheduler_lock</function> can be called to claim the
+lock. On return it is guaranteed that the current thread will not be
+preempted, and that no other code is manipulating any kernel data
+structures. <function>cyg_scheduler_unlock</function> can be used to
+release the lock, which may cause the current thread to be preempted.
+<function>cyg_scheduler_read_lock</function> can be used to query the
+current state of the scheduler lock. This function should never be
+needed because well-written code should always know whether or not the
+scheduler is currently locked, but may prove useful during debugging.
+ </para>
+ <para>
+The implementation of the scheduler lock involves a simple counter.
+Code can call <function>cyg_scheduler_lock</function> multiple times,
+causing the counter to be incremented each time, as long as
+<function>cyg_scheduler_unlock</function> is called the same number of
+times. This behaviour is different from mutexes where an attempt by a
+thread to lock a mutex multiple times will result in deadlock or an
+assertion failure.
+ </para>
+ <para>
+Typical application code should not use the scheduler lock. Instead
+other synchronization primitives such as mutexes and semaphores should
+be used. While the scheduler is locked the current thread cannot be
+preempted, so any higher priority threads will not be able to run.
+Also no DSRs can run, so device drivers may not be able to service
+I/O requests. However there is one situation where locking the
+scheduler is appropriate: if some data structure needs to be shared
+between an application thread and a DSR associated with some interrupt
+source, the thread can use the scheduler lock to prevent concurrent
+invocations of the DSR and then safely manipulate the structure. It is
+desirable that the scheduler lock is held for only a short period of
+time, typically some tens of instructions. In exceptional cases there
+may also be some performance-critical code where it is more
+appropriate to use the scheduler lock rather than a mutex, because the
+former is more efficient.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-schedcontrol-context"><title>Valid contexts</title>
+ <para>
+<function>cyg_scheduler_start</function> can only be called during
+system initialization, since it marks the end of that phase. The
+remaining functions may be called from thread or DSR context. Locking
+the scheduler from inside the DSR has no practical effect because the
+lock is claimed automatically by the interrupt subsystem before
+running DSRs, but allows functions to be shared between normal thread
+code and DSRs.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ Interrupt handling -->
+
+ <refentry id="kernel-interrupts">
+
+ <refmeta>
+ <refentrytitle>Interrupt Handling</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>cyg_interrupt_create</refname>
+ <refname>cyg_interrupt_delete</refname>
+ <refname>cyg_interrupt_attach</refname>
+ <refname>cyg_interrupt_detach</refname>
+ <refname>cyg_interrupt_configure</refname>
+ <refname>cyg_interrupt_acknowledge</refname>
+ <refname>cyg_interrupt_enable</refname>
+ <refname>cyg_interrupt_disable</refname>
+ <refname>cyg_interrupt_mask</refname>
+ <refname>cyg_interrupt_mask_intunsafe</refname>
+ <refname>cyg_interrupt_unmask</refname>
+ <refname>cyg_interrupt_unmask_intunsafe</refname>
+ <refname>cyg_interrupt_set_cpu</refname>
+ <refname>cyg_interrupt_get_cpu</refname>
+ <refname>cyg_interrupt_get_vsr</refname>
+ <refname>cyg_interrupt_set_vsr</refname>
+ <refpurpose>Manage interrupt handlers</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>
+#include &lt;cyg/kernel/kapi.h&gt;
+ </funcsynopsisinfo>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_create</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ <paramdef>cyg_priority_t <parameter>priority</parameter></paramdef>
+ <paramdef>cyg_addrword_t <parameter>data</parameter></paramdef>
+ <paramdef>cyg_ISR_t* <parameter>isr</parameter></paramdef>
+ <paramdef>cyg_DSR_t* <parameter>dsr</parameter></paramdef>
+ <paramdef>cyg_handle_t* <parameter>handle</parameter></paramdef>
+ <paramdef>cyg_interrupt* <parameter>intr</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_delete</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>interrupt</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_attach</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>interrupt</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_detach</function></funcdef>
+ <paramdef>cyg_handle_t <parameter>interrupt</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_configure</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ <paramdef>cyg_bool_t <parameter>level</parameter></paramdef>
+ <paramdef>cyg_bool_t <parameter>up</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_acknowledge</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_disable</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_enable</function></funcdef>
+ <void>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_mask</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_mask_intunsafe</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_unmask</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_unmask_intunsafe</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_set_cpu</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ <paramdef>cyg_cpu_t <parameter>cpu</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>cyg_cpu_t <function>cyg_interrupt_get_cpu</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_get_vsr</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ <paramdef>cyg_VSR_t** <parameter>vsr</parameter></paramdef>
+ </funcprototype>
+ <funcprototype>
+ <funcdef>void <function>cyg_interrupt_set_vsr</function></funcdef>
+ <paramdef>cyg_vector_t <parameter>vector</parameter></paramdef>
+ <paramdef>cyg_VSR_t* <parameter>vsr</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="kernel-interrupts-description"><title>Description</title>
+ <para>
+The kernel provides an interface for installing interrupt handlers and
+controlling when interrupts occur. This functionality is used
+primarily by eCos device drivers and by any application code that
+interacts directly with hardware. However in most cases it is better
+to avoid using this kernel functionality directly, and instead the
+device driver API provided by the common HAL package should be used.
+Use of the kernel package is optional, and some applications such as
+RedBoot work with no need for multiple threads or synchronization
+primitives. Any code which calls the kernel directly rather than the
+device driver API will not function in such a configuration. When the
+kernel package is present the device driver API is implemented as
+<literal>#define</literal>'s to the equivalent kernel calls, otherwise
+it is implemented inside the common HAL package. The latter
+implementation can be simpler than the kernel one because there is no
+need to consider thread preemption and similar issues.
+ </para>
+ <para>
+The exact details of interrupt handling vary widely between
+architectures. The functionality provided by the kernel abstracts away
+from many of the details of the underlying hardware, thus simplifying
+application development. However this is not always successful. For
+example, if some hardware does not provide any support at all for
+masking specific interrupts then calling
+<function>cyg_interrupt_mask</function> may not behave as intended:
+instead of masking just the one interrupt source it might disable all
+interrupts, because that is as close to the desired behaviour as is
+possible given the hardware restrictions. Another possibility is that
+masking a given interrupt source also affects all lower-priority
+interrupts, but still allows higher-priority ones. The documentation
+for the appropriate HAL packages should be consulted for more
+information about exactly how interrupts are handled on any given
+hardware. The HAL header files will also contain useful information.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-interrupts-handlers"><title>Interrupt Handlers</title>
+ <para>
+Interrupt handlers are created by a call to
+<function>cyg_interrupt_create</function>. This takes the following
+arguments:
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>cyg_vector_t <parameter>vector</parameter></term>
+ <listitem><para>
+The interrupt vector, a small integer, identifies the specific
+interrupt source. The appropriate hardware documentation or HAL header
+files should be consulted for details of which vector corresponds to
+which device.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cyg_priority_t <parameter>priority</parameter></term>
+ <listitem><para>
+Some hardware may support interrupt priorities, where a low priority
+interrupt handler can in turn be interrupted by a higher priority one.
+Again hardware-specific documentation should be consulted for details
+about what the valid interrupt priority levels are.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cyg_addrword_t <parameter>data</parameter></term>
+ <listitem><para>
+When an interrupt occurs eCos will first call the associated
+interrupt service routine or ISR, then optionally a deferred service
+routine or DSR. The <parameter>data</parameter> argument to
+<function>cyg_interrupt_create</function> will be passed to both these
+functions. Typically it will be a pointer to some data structure.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cyg_ISR_t <parameter>isr</parameter></term>
+ <listitem><para>
+When an interrupt occurs the hardware will transfer control to the
+appropriate vector service routine or VSR, which is usually provided
+by eCos. This performs any appropriate processing, for example to work
+out exactly which interrupt occurred, and then as quickly as possible
+transfers control the installed ISR. An ISR is a C function which
+takes the following form:
+ </para>
+ <programlisting width=72>
+cyg_uint32
+isr_function(cyg_vector_t vector, cyg_addrword_t data)
+{
+ cyg_bool_t dsr_required = 0;
+
+ &hellip;
+
+ return dsr_required ? CYG_ISR_CALL_DSR : CYG_ISR_HANDLED;
+}
+ </programlisting>
+ <para>
+The first argument identifies the particular interrupt source,
+especially useful if there multiple instances of a given device and a
+single ISR can be used for several different interrupt vectors. The
+second argument is the <parameter>data</parameter> field passed to
+<function>cyg_interrupt_create</function>, usually a pointer to some
+data structure. The exact conditions under which an ISR runs will
+depend partly on the hardware and partly on configuration options.
+Interrupts may currently be disabled globally, especially if the
+hardware does not support interrupt priorities. Alternatively
+interrupts may be enabled such that higher priority interrupts are
+allowed through. The ISR may be running on a separate interrupt stack,
+or on the stack of whichever thread was running at the time the
+interrupt happened.
+ </para>
+ <para>
+A typical ISR will do as little work as possible, just enough to meet
+the needs of the hardware and then acknowledge the interrupt by
+calling <function>cyg_interrupt_acknowledge</function>. This ensures
+that interrupts will be quickly reenabled, so higher priority devices
+can be serviced. For some applications there may be one device which
+is especially important and whose ISR can take much longer than
+normal. However eCos device drivers usually will not assume that they
+are especially important, so their ISRs will be as short as possible.
+ </para>
+ <para>
+The return value of an ISR is normally one of
+<literal>CYG_ISR_CALL_DSR</literal> or
+<literal>CYG_ISR_HANDLED</literal>. The former indicates that further
+processing is required at DSR level, and the interrupt handler's DSR
+will be run as soon as possible. The latter indicates that the
+interrupt has been fully handled and no further effort is required.
+ </para>
+ <para>
+An ISR is allowed to make very few kernel calls. It can manipulate the
+interrupt mask, and on SMP systems it can use spinlocks. However an
+ISR must not make higher-level kernel calls such as posting to a
+semaphore, instead any such calls must be made from the DSR. This
+avoids having to disable interrupts throughout the kernel and thus
+improves interrupt latency.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cyg_DSR_t <parameter>dsr</parameter></term>
+ <listitem><para>
+If an interrupt has occurred and the ISR has returned a value
+<literal>CYG_ISR_CALL_DSR</literal>, the system will call the
+deferred service routine or DSR associated with this interrupt
+handler. If the scheduler is not currently locked then the DSR will
+run immediately. However if the interrupted thread was in the middle
+of a kernel call and had locked the scheduler, then the DSR will be
+deferred until the scheduler is again unlocked. This allows the
+DSR to make certain kernel calls safely, for example posting to a
+semaphore or signalling a condition variable. A DSR is a C function
+which takes the following form:
+ </para>
+ <programlisting width=72>
+void
+dsr_function(cyg_vector_t vector,
+ cyg_ucount32 count,
+ cyg_addrword_t data)
+{
+}
+ </programlisting>
+ <para>
+The first argument identifies the specific interrupt that has caused
+the DSR to run. The second argument indicates the number of these
+interrupts that have occurred and for which the ISR requested a DSR.
+Usually this will be <literal>1</literal>, unless the system is
+suffering from a very heavy load. The third argument is the
+<parameter>data</parameter> field passed to
+<function>cyg_interrupt_create</function>.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cyg_handle_t* <parameter>handle</parameter></term>
+ <listitem><para>
+The kernel will return a handle to the newly created interrupt handler
+via this argument. Subsequent operations on the interrupt handler such
+as attaching it to the interrupt source will use this handle.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cyg_interrupt* <parameter>intr</parameter></term>
+ <listitem><para>
+This provides the kernel with an area of memory for holding this
+interrupt handler and associated data.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ <para>
+The call to <function>cyg_interrupt_create</function> simply fills in
+a kernel data structure. A typical next step is to call
+<function>cyg_interrupt_attach</function> using the handle returned by
+the create operation. This makes it possible to have several different
+interrupt handlers for a given vector, attaching whichever one is
+currently appropriate. Replacing an interrupt handler requires a call
+to <function>cyg_interrupt_detach</function>, followed by another call
+to <function>cyg_interrupt_attach</function> for the replacement
+handler. <function>cyg_interrupt_delete</function> can be used if an
+interrupt handler is no longer required.
+ </para>
+ <para>
+Some hardware may allow for further control over specific interrupts,
+for example whether an interrupt is level or edge triggered. Any such
+hardware functionality can be accessed using
+<function>cyg_interrupt_configure</function>: the
+<parameter>level</parameter> argument selects between level versus
+edge triggered; the <parameter>up</parameter> argument selects between
+high and low level, or between rising and falling edges.
+ </para>
+ <para>
+Usually interrupt handlers are created, attached and configured during
+system initialization, while global interrupts are still disabled. On
+most hardware it will also be necessary to call
+<function>cyg_interrupt_unmask</function>, since the sensible default
+for interrupt masking is to ignore any interrupts for which no handler
+is installed.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-interrupts-enable"><title>Controlling Interrupts</title>
+ <para>
+eCos provides two ways of controlling whether or not interrupts
+happen. It is possible to disable and reenable all interrupts
+globally, using <function>cyg_interrupt_disable</function> and
+<function>cyg_interrupt_enable</function>. Typically this works by
+manipulating state inside the cpu itself, for example setting a flag
+in a status register or executing special instructions. Alternatively
+it may be possible to mask a specific interrupt source by writing to
+one or to several interrupt mask registers. Hardware-specific
+documentation should be consulted for the exact details of how
+interrupt masking works, because a full implementation is not possible
+on all hardware.
+ </para>
+ <para>
+The primary use for these functions is to allow data to be shared
+between ISRs and other code such as DSRs or threads. If both a thread
+and an ISR need to manipulate either a data structure or the hardware
+itself, there is a possible conflict if an interrupt happens just when
+the thread is doing such manipulation. Problems can be avoided by the
+thread either disabling or masking interrupts during the critical
+region. If this critical region requires only a few instructions then
+usually it is more efficient to disable interrupts. For larger
+critical regions it may be more appropriate to use interrupt masking,
+allowing other interrupts to occur. There are other uses for interrupt
+masking. For example if a device is not currently being used by the
+application then it may be desirable to mask all interrupts generated
+by that device.
+ </para>
+ <para>
+There are two functions for masking a specific interrupt source,
+<function>cyg_interrupt_mask</function> and
+<function>cyg_interrupt_mask_intunsafe</function>. On typical hardware
+masking an interrupt is not an atomic operation, so if two threads
+were to perform interrupt masking operations at the same time there
+could be problems. <function>cyg_interrupt_mask</function> disables
+all interrupts while it manipulates the interrupt mask. In situations
+where interrupts are already know to be disabled,
+<function>cyg_interrupt_mask_intunsafe</function> can be used
+instead. There are matching functions
+<function>cyg_interrupt_unmask</function> and
+<function>cyg_interrupt_unmask_intsafe</function>.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-interrupts-smp"><title>SMP Support</title>
+ <para>
+On SMP systems the kernel provides an additional two functions related
+to interrupt handling. <function>cyg_interrupt_set_cpu</function>
+specifies that a particular hardware interrupt should always be
+handled on one specific processor in the system. In other words when
+the interrupt triggers it is only that processor which detects it, and
+it is only on that processor that the VSR and ISR will run. If a DSR
+is requested then it will also run on the same CPU. The
+function <function>cyg_interrupt_get_cpu</function> can be used to
+find out which interrupts are handled on which processor.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-interrupts-vsr"><title>VSR Support</title>
+ <para>
+When an interrupt occurs the hardware will transfer control to a piece
+of code known as the VSR, or Vector Service Routine. By default this
+code is provided by eCos. Usually it is written in assembler, but on
+some architectures it may be possible to implement VSRs in C by
+specifying an interrupt attribute. Compiler documentation should be
+consulted for more information on this. The default eCos VSR will work
+out which ISR function should process the interrupt, and set up a C
+environment suitable for this ISR.
+ </para>
+ <para>
+For some applications it may be desirable to replace the default eCos
+VSR and handle some interrupts directly. This minimizes interrupt
+latency, but it requires application developers to program at a lower
+level. Usually the best way to write a custom VSR is to copy the
+existing one supplied by eCos and then make appropriate modifications.
+The function <function>cyg_interrupt_get_vsr</function> can be used to
+get hold of the current VSR for a given interrupt vector, allowing it
+to be restored if the custom VSR is no longer required.
+<function>cyg_interrupt_set_vsr</function> can be used to install a
+replacement VSR. Usually the <parameter>vsr</parameter> argument will
+correspond to an exported label in an assembler source file.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-interrupts-context"><title>Valid contexts</title>
+ <para>
+In a typical configuration interrupt handlers are created and attached
+during system initialization, and never detached or deleted. However
+it is possible to perform these operations at thread level, if
+desired. Similarly <function>cyg_interrupt_configure</function>,
+<function>cyg_interrupt_set_vsr</function>, and
+<function>cyg_interrupt_set_cpu</function> are usually called only
+during system initialization, but on typical hardware may be called at
+any time. <function>cyg_interrupt_get_vsr</function> and
+<function>cyg_interrupt_get_cpu</function> may be called at any time.
+ </para>
+ <para>
+The functions for enabling, disabling, masking and unmasking
+interrupts can be called in any context, when appropriate. It is the
+responsibility of application developers to determine when the use of
+these functions is appropriate.
+ </para>
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+<!-- {{{ tm_basic -->
+
+ <refentry id="kernel-characterization">
+
+ <refmeta>
+ <refentrytitle>Kernel Real-time Characterization</refentrytitle>
+ </refmeta>
+ <refnamediv>
+ <refname>tm_basic</refname>
+ <refpurpose>Measure the performance of the eCos kernel</refpurpose>
+ </refnamediv>
+
+ <refsect1 id="kernel-characterization-description">
+ <title>Description</title>
+ <para>
+When building a real-time system, care must be taken to ensure that
+the system will be able to perform properly within the constraints of
+that system. One of these constraints may be how fast certain
+operations can be performed. Another might be how deterministic the
+overall behavior of the system is. Lastly the memory footprint (size)
+and unit cost may be important.
+ </para>
+ <para>
+One of the major problems encountered while evaluating a system will
+be how to compare it with possible alternatives. Most manufacturers of
+real-time systems publish performance numbers, ostensibly so that
+users can compare the different offerings. However, what these numbers
+mean and how they were gathered is often not clear. The values are
+typically measured on a particular piece of hardware, so in order to
+truly compare, one must obtain measurements for exactly the same set
+of hardware that were gathered in a similar fashion.
+ </para>
+ <para>
+Two major items need to be present in any given set of measurements.
+First, the raw values for the various operations; these are typically
+quite easy to measure and will be available for most systems. Second,
+the determinacy of the numbers; in other words how much the value
+might change depending on other factors within the system. This value
+is affected by a number of factors: how long interrupts might be
+masked, whether or not the function can be interrupted, even very
+hardware-specific effects such as cache locality and pipeline usage.
+It is very difficult to measure the determinacy of any given
+operation, but that determinacy is fundamentally important to proper
+overall characterization of a system.
+ </para>
+ <para>
+In the discussion and numbers that follow, three key measurements are
+provided. The first measurement is an estimate of the interrupt
+latency: this is the length of time from when a hardware interrupt
+occurs until its Interrupt Service Routine (ISR) is called. The second
+measurement is an estimate of overall interrupt overhead: this is the
+length of time average interrupt processing takes, as measured by the
+real-time clock interrupt (other interrupt sources will certainly take
+a different amount of time, but this data cannot be easily gathered).
+The third measurement consists of the timings for the various kernel
+primitives.
+ </para>
+ </refsect1>
+ <refsect1 id="kernel-characterization-methodology">
+ <title>Methodology</title>
+ <para>
+Key operations in the kernel were measured by using a simple test
+program which exercises the various kernel primitive operations. A
+hardware timer, normally the one used to drive the real-time clock,
+was used for these measurements. In most cases this timer can be read
+with quite high resolution, typically in the range of a few
+microseconds. For each measurement, the operation was repeated a
+number of times. Time stamps were obtained directly before and after
+the operation was performed. The data gathered for the entire set of
+operations was then analyzed, generating average (mean), maximum and
+minimum values. The sample variance (a measure of how close most
+samples are to the mean) was also calculated. The cost of obtaining
+the real-time clock timer values was also measured, and was subtracted
+from all other times.
+ </para>
+ <para>
+Most kernel functions can be measured separately. In each case, a
+reasonable number of iterations are performed. Where the test case
+involves a kernel object, for example creating a task, each iteration
+is performed on a different object. There is also a set of tests which
+measures the interactions between multiple tasks and certain kernel
+primitives. Most functions are tested in such a way as to determine
+the variations introduced by varying numbers of objects in the system.
+For example, the mailbox tests measure the cost of a 'peek' operation
+when the mailbox is empty, has a single item, and has multiple items
+present. In this way, any effects of the state of the object or how
+many items it contains can be determined.
+ </para>
+ <para>
+There are a few things to consider about these measurements. Firstly,
+they are quite micro in scale and only measure the operation in
+question. These measurements do not adequately describe how the
+timings would be perturbed in a real system with multiple interrupting
+sources. Secondly, the possible aberration incurred by the real-time
+clock (system heartbeat tick) is explicitly avoided. Virtually all
+kernel functions have been designed to be interruptible. Thus the
+times presented are typical, but best case, since any particular
+function may be interrupted by the clock tick processing. This number
+is explicitly calculated so that the value may be included in any
+deadline calculations required by the end user. Lastly, the reported
+measurements were obtained from a system built with all options at
+their default values. Kernel instrumentation and asserts are also
+disabled for these measurements. Any number of configuration options
+can change the measured results, sometimes quite dramatically. For
+example, mutexes are using priority inheritance in these measurements.
+The numbers will change if the system is built with priority
+inheritance on mutex variables turned off.
+ </para>
+ <para>
+The final value that is measured is an estimate of interrupt latency.
+This particular value is not explicitly calculated in the test program
+used, but rather by instrumenting the kernel itself. The raw number of
+timer ticks that elapse between the time the timer generates an
+interrupt and the start of the timer ISR is kept in the kernel. These
+values are printed by the test program after all other operations have
+been tested. Thus this should be a reasonable estimate of the
+interrupt latency over time.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-characterization-using-measurements">
+ <title>Using these Measurements</title>
+ <para>
+These measurements can be used in a number of ways. The most typical
+use will be to compare different real-time kernel offerings on similar
+hardware, another will be to estimate the cost of implementing a task
+using eCos (applications can be examined to see what effect the kernel
+operations will have on the total execution time). Another use would
+be to observe how the tuning of the kernel affects overall operation.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-characterization-influences">
+ <title>Influences on Performance</title>
+ <para>
+A number of factors can affect real-time performance in a system. One
+of the most common factors, yet most difficult to characterize, is the
+effect of device drivers and interrupts on system timings. Different
+device drivers will have differing requirements as to how long
+interrupts are suppressed, for example. The eCos system has been
+designed with this in mind, by separating the management of interrupts
+(ISR handlers) and the processing required by the interrupt
+(DSR&mdash;Deferred Service Routine&mdash; handlers). However, since
+there is so much variability here, and indeed most device drivers will
+come from the end users themselves, these effects cannot be reliably
+measured. Attempts have been made to measure the overhead of the
+single interrupt that eCos relies on, the real-time clock timer. This
+should give you a reasonable idea of the cost of executing interrupt
+handling for devices.
+ </para>
+ </refsect1>
+
+ <refsect1 id="kernel-characterization-measured-items">
+ <title>Measured Items</title>
+ <para>
+This section describes the various tests and the numbers presented.
+All tests use the C kernel API (available by way of
+<filename>cyg/kernel/kapi.h</filename>). There is a single main thread
+in the system that performs the various tests. Additional threads may
+be created as part of the testing, but these are short lived and are
+destroyed between tests unless otherwise noted. The terminology
+&ldquo;lower priority&rdquo; means a priority that is less important,
+not necessarily lower in numerical value. A higher priority thread
+will run in preference to a lower priority thread even though the
+priority value of the higher priority thread may be numerically less
+than that of the lower priority thread.
+ </para>
+
+ <refsect2 id="kernel-characterization-measure-threads">
+ <title>Thread Primitives</title>
+ <variablelist>
+ <varlistentry>
+ <term>Create thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_create()</function> call.
+Each call creates a totally new thread. The set of threads created by
+this test will be reused in the subsequent thread primitive tests.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Yield thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_yield()</function> call.
+For this test, there are no other runnable threads, thus the test
+should just measure the overhead of trying to give up the CPU.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Suspend &lsqb;suspended&rsqb; thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_suspend()</function> call.
+A thread may be suspended multiple times; each thread is already
+suspended from its initial creation, and is suspended again.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Resume thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_resume()</function> call.
+All of the threads have a suspend count of 2, thus this call does not
+make them runnable. This test just measures the overhead of resuming a
+thread.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Set priority</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_set_priority()</function>
+call. Each thread, currently suspended, has its priority set to a new
+value.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Get priority</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_get_priority()</function>
+call.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Kill &lsqb;suspended&rsqb; thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_kill()</function> call.
+Each thread in the set is killed. All threads are known to be
+suspended before being killed.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Yield &lsqb;no other&rsqb; thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_yield()</function> call
+again. This is to demonstrate that the
+<function>cyg_thread_yield()</function> call has a fixed overhead,
+regardless of whether there are other threads in the system.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Resume &lsqb;suspended low priority&rsqb; thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_resume()</function> call
+again. In this case, the thread being resumed is lower priority than
+the main thread, thus it will simply become ready to run but not be
+granted the CPU. This test measures the cost of making a thread ready
+to run.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Resume &lsqb;runnable low priority&rsqb; thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_resume()</function> call
+again. In this case, the thread being resumed is lower priority than
+the main thread and has already been made runnable, so in fact the
+resume call has no effect.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Suspend &lsqb;runnable&rsqb; thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_suspend()</function> call
+again. In this case, each thread has already been made runnable (by
+previous tests).
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Yield &lsqb;only low priority&rsqb; thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_yield()</function> call.
+In this case, there are many other runnable threads, but they are all
+lower priority than the main thread, thus no thread switches will take
+place.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Suspend &lsqb;runnable-&gt;not runnable&rsqb; thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_suspend()</function> call
+again. The thread being suspended will become non-runnable by this
+action.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Kill &lsqb;runnable&rsqb; thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_kill()</function> call
+again. In this case, the thread being killed is currently runnable,
+but lower priority than the main thread.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Resume &lsqb;high priority&rsqb; thread</term>
+ <listitem><para>
+This test measures the <function>cyg_thread_resume()</function> call.
+The thread being resumed is higher priority than the main thread, thus
+a thread switch will take place on each call. In fact there will be
+two thread switches; one to the new higher priority thread and a
+second back to the test thread. The test thread exits immediately.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Thread switch</term>
+ <listitem><para>
+This test attempts to measure the cost of switching from one thread to
+another. Two equal priority threads are started and they will each
+yield to the other for a number of iterations. A time stamp is
+gathered in one thread before the
+<function>cyg_thread_yield()</function> call and after the call in the
+other thread.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2 id="kernel-characterization-measure-scheduler"
+ <title>Scheduler Primitives</title>
+ <variablelist>
+ <varlistentry>
+ <term>Scheduler lock</term>
+ <listitem><para>
+This test measures the <function>cyg_scheduler_lock()</function> call.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Scheduler unlock &lsqb;0 threads&rsqb;</term>
+ <listitem><para>
+This test measures the <function>cyg_scheduler_unlock()</function>
+call. There are no other threads in the system and the unlock happens
+immediately after a lock so there will be no pending DSR&rsquo;s to
+run.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Scheduler unlock &lsqb;1 suspended thread&rsqb;</term>
+ <listitem><para>
+This test measures the <function>cyg_scheduler_unlock()</function>
+call. There is one other thread in the system which is currently
+suspended.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Scheduler unlock &lsqb;many suspended threads&rsqb;</term>
+ <listitem><para>
+This test measures the <function>cyg_scheduler_unlock()</function>
+call. There are many other threads in the system which are currently
+suspended. The purpose of this test is to determine the cost of having
+additional threads in the system when the scheduler is activated by
+way of <function>cyg_scheduler_unlock()</function>.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Scheduler unlock &lsqb;many low priority threads&rsqb;</term>
+ <listitem><para>
+This test measures the <function>cyg_scheduler_unlock()</function>
+call. There are many other threads in the system which are runnable
+but are lower priority than the main thread. The purpose of this test
+is to determine the cost of having additional threads in the system
+when the scheduler is activated by way of
+<function>cyg_scheduler_unlock()</function>.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2 id="kernel-characterization-measure-mutex">
+ <title>Mutex Primitives</title>
+ <variablelist>
+ <varlistentry>
+ <term>Init mutex</term>
+ <listitem><para>
+This test measures the <function>cyg_mutex_init()</function> call. A
+number of separate mutex variables are created. The purpose of this
+test is to measure the cost of creating a new mutex and introducing it
+to the system.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Lock &lsqb;unlocked&rsqb; mutex</term>
+ <listitem><para>
+This test measures the <function>cyg_mutex_lock()</function> call. The
+purpose of this test is to measure the cost of locking a mutex which
+is currently unlocked. There are no other threads executing in the
+system while this test runs.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Unlock &lsqb;locked&rsqb; mutex</term>
+ <listitem><para>
+This test measures the <function>cyg_mutex_unlock()</function> call.
+The purpose of this test is to measure the cost of unlocking a mutex
+which is currently locked. There are no other threads executing in the
+system while this test runs.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Trylock &lsqb;unlocked&rsqb; mutex</term>
+ <listitem><para>
+This test measures the <function>cyg_mutex_trylock()</function> call.
+The purpose of this test is to measure the cost of locking a mutex
+which is currently unlocked. There are no other threads executing in
+the system while this test runs.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Trylock &lsqb;locked&rsqb; mutex</term>
+ <listitem><para>
+This test measures the <function>cyg_mutex_trylock()</function> call.
+The purpose of this test is to measure the cost of locking a mutex
+which is currently locked. There are no other threads executing in the
+system while this test runs.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Destroy mutex</term>
+ <listitem><para>
+This test measures the <function>cyg_mutex_destroy()</function> call.
+The purpose of this test is to measure the cost of deleting a mutex
+from the system. There are no other threads executing in the system
+while this test runs.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Unlock/Lock mutex</term>
+ <listitem><para>
+This test attempts to measure the cost of unlocking a mutex for which
+there is another higher priority thread waiting. When the mutex is
+unlocked, the higher priority waiting thread will immediately take the
+lock. The time from when the unlock is issued until after the lock
+succeeds in the second thread is measured, thus giving the round-trip
+or circuit time for this type of synchronizer.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2 id="kernel-characterization-measure-mailbox">
+ <title>Mailbox Primitives</title>
+ <variablelist>
+ <varlistentry>
+ <term>Create mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_create()</function> call. A
+number of separate mailboxes is created. The purpose of this test is
+to measure the cost of creating a new mailbox and introducing it to
+the system.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Peek &lsqb;empty&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_peek()</function> call. An
+attempt is made to peek the value in each mailbox, which is currently
+empty. The purpose of this test is to measure the cost of checking a
+mailbox for a value without blocking.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Put &lsqb;first&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_put()</function> call. One
+item is added to a currently empty mailbox. The purpose of this test
+is to measure the cost of adding an item to a mailbox. There are no
+other threads currently waiting for mailbox items to arrive.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Peek &lsqb;1 msg&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_peek()</function> call. An
+attempt is made to peek the value in each mailbox, which contains a
+single item. The purpose of this test is to measure the cost of
+checking a mailbox which has data to deliver.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Put &lsqb;second&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_put()</function> call. A
+second item is added to a mailbox. The purpose of this test is to
+measure the cost of adding an additional item to a mailbox. There are
+no other threads currently waiting for mailbox items to arrive.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Peek &lsqb;2 msgs&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_peek()</function> call. An
+attempt is made to peek the value in each mailbox, which contains two
+items. The purpose of this test is to measure the cost of checking a
+mailbox which has data to deliver.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Get &lsqb;first&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_get()</function> call. The
+first item is removed from a mailbox that currently contains two
+items. The purpose of this test is to measure the cost of obtaining an
+item from a mailbox without blocking.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Get &lsqb;second&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_get()</function> call. The
+last item is removed from a mailbox that currently contains one item.
+The purpose of this test is to measure the cost of obtaining an item
+from a mailbox without blocking.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Tryput &lsqb;first&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_tryput()</function> call. A
+single item is added to a currently empty mailbox. The purpose of this
+test is to measure the cost of adding an item to a mailbox.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Peek item &lsqb;non-empty&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_peek_item()</function> call.
+A single item is fetched from a mailbox that contains a single item.
+The purpose of this test is to measure the cost of obtaining an item
+without disturbing the mailbox.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Tryget &lsqb;non-empty&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_tryget()</function> call. A
+single item is removed from a mailbox that contains exactly one item.
+The purpose of this test is to measure the cost of obtaining one item
+from a non-empty mailbox.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Peek item &lsqb;empty&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_peek_item()</function> call.
+An attempt is made to fetch an item from a mailbox that is empty. The
+purpose of this test is to measure the cost of trying to obtain an
+item when the mailbox is empty.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Tryget &lsqb;empty&rsqb; mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_tryget()</function> call. An
+attempt is made to fetch an item from a mailbox that is empty. The
+purpose of this test is to measure the cost of trying to obtain an
+item when the mailbox is empty.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Waiting to get mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_waiting_to_get()</function>
+call. The purpose of this test is to measure the cost of determining
+how many threads are waiting to obtain a message from this mailbox.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Waiting to put mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_waiting_to_put()</function>
+call. The purpose of this test is to measure the cost of determining
+how many threads are waiting to put a message into this mailbox.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Delete mbox</term>
+ <listitem><para>
+This test measures the <function>cyg_mbox_delete()</function> call.
+The purpose of this test is to measure the cost of destroying a
+mailbox and removing it from the system.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Put/Get mbox</term>
+ <listitem><para>
+In this round-trip test, one thread is sending data to a mailbox that
+is being consumed by another thread. The time from when the data is
+put into the mailbox until it has been delivered to the waiting thread
+is measured. Note that this time will contain a thread switch.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2 id="kernel-characterization-measure-semaphore">
+ <title>Semaphore Primitives</title>
+ <variablelist>
+ <varlistentry>
+ <term>Init semaphore</term>
+ <listitem><para>
+This test measures the <function>cyg_semaphore_init()</function> call.
+A number of separate semaphore objects are created and introduced to
+the system. The purpose of this test is to measure the cost of
+creating a new semaphore.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Post &lsqb;0&rsqb; semaphore</term>
+ <listitem><para>
+This test measures the <function>cyg_semaphore_post()</function> call.
+Each semaphore currently has a value of 0 and there are no other
+threads in the system. The purpose of this test is to measure the
+overhead cost of posting to a semaphore. This cost will differ if
+there is a thread waiting for the semaphore.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Wait &lsqb;1&rsqb; semaphore</term>
+ <listitem><para>
+This test measures the <function>cyg_semaphore_wait()</function> call.
+The semaphore has a current value of 1 so the call is non-blocking.
+The purpose of the test is to measure the overhead of
+&ldquo;taking&rdquo; a semaphore.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Trywait &lsqb;0&rsqb; semaphore</term>
+ <listitem><para>
+This test measures the <function>cyg_semaphore_trywait()</function>
+call. The semaphore has a value of 0 when the call is made. The
+purpose of this test is to measure the cost of seeing if a semaphore
+can be &ldquo;taken&rdquo; without blocking. In this case, the answer
+would be no.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Trywait &lsqb;1&rsqb; semaphore</term>
+ <listitem><para>
+This test measures the <function>cyg_semaphore_trywait()</function>
+call. The semaphore has a value of 1 when the call is made. The
+purpose of this test is to measure the cost of seeing if a semaphore
+can be &ldquo;taken&rdquo; without blocking. In this case, the answer
+would be yes.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Peek semaphore</term>
+ <listitem><para>
+This test measures the <function>cyg_semaphore_peek()</function> call.
+The purpose of this test is to measure the cost of obtaining the
+current semaphore count value.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Destroy semaphore</term>
+ <listitem><para>
+This test measures the <function>cyg_semaphore_destroy()</function>
+call. The purpose of this test is to measure the cost of deleting a
+semaphore from the system.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Post/Wait semaphore</term>
+ <listitem><para>
+In this round-trip test, two threads are passing control back and
+forth by using a semaphore. The time from when one thread calls
+<function>cyg_semaphore_post()</function> until the other thread
+completes its <function>cyg_semaphore_wait()</function> is measured.
+Note that each iteration of this test will involve a thread switch.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2 id="kernel-characterization-measure-counters">
+ <title>Counters</title>
+ <variablelist>
+ <varlistentry>
+ <term>Create counter</term>
+ <listitem><para>
+This test measures the <function>cyg_counter_create()</function> call.
+A number of separate counters are created. The purpose of this test is
+to measure the cost of creating a new counter and introducing it to
+the system.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Get counter value</term>
+ <listitem><para>
+This test measures the
+<function>cyg_counter_current_value()</function> call. The current
+value of each counter is obtained.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Set counter value</term>
+ <listitem><para>
+This test measures the <function>cyg_counter_set_value()</function>
+call. Each counter is set to a new value.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Tick counter</term>
+ <listitem><para>
+This test measures the <function>cyg_counter_tick()</function> call.
+Each counter is &ldquo;ticked&rdquo; once.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Delete counter</term>
+ <listitem><para>
+This test measures the <function>cyg_counter_delete()</function> call.
+Each counter is deleted from the system. The purpose of this test is
+to measure the cost of deleting a counter object.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2 id="kernel-characterization-measure-alarms">
+ <title>Alarms</title>
+ <variablelist>
+ <varlistentry>
+ <term>Create alarm</term>
+ <listitem><para>
+This test measures the <function>cyg_alarm_create()</function> call. A
+number of separate alarms are created, all attached to the same
+counter object. The purpose of this test is to measure the cost of
+creating a new counter and introducing it to the system.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Initialize alarm</term>
+ <listitem><para>
+This test measures the <function>cyg_alarm_initialize()</function>
+call. Each alarm is initialized to a small value.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Disable alarm</term>
+ <listitem><para>
+This test measures the <function>cyg_alarm_disable()</function> call.
+Each alarm is explicitly disabled.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Enable alarm</term>
+ <listitem><para>
+This test measures the <function>cyg_alarm_enable()</function> call.
+Each alarm is explicitly enabled.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Delete alarm</term>
+ <listitem><para>
+This test measures the <function>cyg_alarm_delete()</function> call.
+Each alarm is destroyed. The purpose of this test is to measure the
+cost of deleting an alarm and removing it from the system.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Tick counter &lsqb;1 alarm&rsqb;</term>
+ <listitem><para>
+This test measures the <function>cyg_counter_tick()</function> call. A
+counter is created that has a single alarm attached to it. The purpose
+of this test is to measure the cost of &ldquo;ticking&rdquo; a counter
+when it has a single attached alarm. In this test, the alarm is not
+activated (fired).
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Tick counter &lsqb;many alarms&rsqb;</term>
+ <listitem><para>
+This test measures the <function>cyg_counter_tick()</function> call. A
+counter is created that has multiple alarms attached to it. The
+purpose of this test is to measure the cost of &ldquo;ticking&rdquo; a
+counter when it has many attached alarms. In this test, the alarms are
+not activated (fired).
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Tick &amp; fire counter &lsqb;1 alarm&rsqb;</term>
+ <listitem><para>
+This test measures the <function>cyg_counter_tick()</function> call. A
+counter is created that has a single alarm attached to it. The purpose
+of this test is to measure the cost of &ldquo;ticking&rdquo; a counter
+when it has a single attached alarm. In this test, the alarm is
+activated (fired). Thus the measured time will include the overhead of
+calling the alarm callback function.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Tick &amp; fire counter &lsqb;many alarms&rsqb;</term>
+ <listitem><para>
+This test measures the <function>cyg_counter_tick()</function> call. A
+counter is created that has multiple alarms attached to it. The
+purpose of this test is to measure the cost of &ldquo;ticking&rdquo; a
+counter when it has many attached alarms. In this test, the alarms are
+activated (fired). Thus the measured time will include the overhead of
+calling the alarm callback function.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Alarm latency &lsqb;0 threads&rsqb;</term>
+ <listitem><para>
+This test attempts to measure the latency in calling an alarm callback
+function. The time from the clock interrupt until the alarm function
+is called is measured. In this test, there are no threads that can be
+run, other than the system idle thread, when the clock interrupt
+occurs (all threads are suspended).
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Alarm latency &lsqb;2 threads&rsqb;</term>
+ <listitem><para>
+This test attempts to measure the latency in calling an alarm callback
+function. The time from the clock interrupt until the alarm function
+is called is measured. In this test, there are exactly two threads
+which are running when the clock interrupt occurs. They are simply
+passing back and forth by way of the
+<function>cyg_thread_yield()</function> call. The purpose of this test
+is to measure the variations in the latency when there are executing
+threads.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Alarm latency &lsqb;many threads&rsqb;</term>
+ <listitem><para>
+This test attempts to measure the latency in calling an alarm callback
+function. The time from the clock interrupt until the alarm function
+is called is measured. In this test, there are a number of threads
+which are running when the clock interrupt occurs. They are simply
+passing back and forth by way of the
+<function>cyg_thread_yield()</function> call. The purpose of this test
+is to measure the variations in the latency when there are many
+executing threads.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ </refsect1>
+
+ </refentry>
+
+<!-- }}} -->
+
+</part>
diff --git a/ecos/packages/kernel/current/host/instr/dump_instr.c b/ecos/packages/kernel/current/host/instr/dump_instr.c
new file mode 100644
index 0000000000..0bdb7b0e39
--- /dev/null
+++ b/ecos/packages/kernel/current/host/instr/dump_instr.c
@@ -0,0 +1,106 @@
+
+#include <pkgconf/kernel.h>
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/kernel/instrmnt.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// -------------------------------------------------------------------------
+// Instrumentation record.
+
+struct Instrument_Record
+{
+ CYG_WORD16 type; // record type
+ CYG_WORD16 thread; // current thread id
+ CYG_WORD timestamp; // 32 bit timestamp
+ CYG_WORD arg1; // first arg
+ CYG_WORD arg2; // second arg
+};
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS
+#define CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE
+#include <cyg/kernel/instrument_desc.h>
+#define NELEM(x) (sizeof(x)/sizeof*(x))
+externC char * cyg_instrument_msg(CYG_WORD16 type) {
+
+ struct instrument_desc_s *record;
+ struct instrument_desc_s *end_record;
+ CYG_WORD cl, event;
+
+ record = instrument_desc;
+ end_record = &instrument_desc[NELEM(instrument_desc)-1];
+ cl = type & 0xff00;
+ event = type & 0x00ff;
+
+ while ((record != end_record) && (record->num != cl)) {
+ record++;
+ }
+
+ if (record->num == cl) {
+ record++;
+ while ((record != end_record) && (record->num != event) &&
+ (record->num < 0xff)) {
+ record++;
+ }
+
+ if (record->num == event) {
+ return (record->msg);
+ }
+ }
+ return("Unknown event");
+}
+#endif // CYGDBG_KERNEL_INSTRUMENT_MSGS
+
+void usage(char *myname)
+{
+ fprintf(stderr,"Usage: %s <filename>\n",myname);
+ fprintf(stderr,"where filename is that of the instrumentation data");
+}
+
+int main(int argc, char * argv[])
+{
+
+ FILE * file;
+ char * filename;
+ struct Instrument_Record record;
+ int cnt=0;
+
+ if (argc != 2) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ filename = argv[1];
+
+ file = fopen(filename, "r");
+ if (!file) {
+ fprintf(stderr,"Error opening file %s: ",filename);
+ perror("");
+ exit(1);
+ }
+
+ while (!feof(file)) {
+ fread(&record,sizeof(record),1,file);
+ if (record.type == 0) {
+ break;
+ }
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS
+ printf("%4d Record type (0x%04x): %-20s thread %2d, ",
+ cnt++,record.type,cyg_instrument_msg(record.type),
+ record.thread);
+#else
+ printf("%4d Record type 0x%04x, thread %2d, ",
+ cnt++,record.type, record.thread);
+#endif
+ printf("time %5d, arg1 0x%08x, arg2 0x%08x\n",
+ record.timestamp, record.arg1,
+ record.arg2);
+ }
+
+ fclose(file);
+ return (0);
+}
diff --git a/ecos/packages/kernel/current/host/instr/instrument.sh b/ecos/packages/kernel/current/host/instr/instrument.sh
new file mode 100755
index 0000000000..14c64e3689
--- /dev/null
+++ b/ecos/packages/kernel/current/host/instr/instrument.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+echo "/* This is an automatically generated file. Do not edit. */"
+echo "/* Repository name: PACKAGES/kernel/VERSION/include/instrument_desc.h */"
+echo "/* Install tree : INSTALL/include/cyg/kernel/instrument_desc.h */"
+echo
+echo "struct instrument_desc_s { "
+echo " char * msg; "
+echo " CYG_WORD num; "
+echo "}; "
+echo
+echo "#ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE "
+echo struct instrument_desc_s instrument_desc[] = {
+
+grep -e \#define.CYG_INSTRUMENT_EVENT -e \#define.CYG_INSTRUMENT_CLASS $1 | grep -v MAX | cut -d " " -f 2- | cut -d "_" -f 4- | sort | awk '{ print("{\""$1"\", " $2 "},") }'
+
+echo { 0, 0 }
+echo }\;
+echo "#else /* CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE */ "
+echo "extern struct instrument_desc_s instrument_desc[]; "
+echo "#endif /* CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE */ "
+echo
+echo "/* EOF instrument_desc.h */"
+
diff --git a/ecos/packages/kernel/current/host/instr/readme.txt b/ecos/packages/kernel/current/host/instr/readme.txt
new file mode 100644
index 0000000000..51c3b99546
--- /dev/null
+++ b/ecos/packages/kernel/current/host/instr/readme.txt
@@ -0,0 +1,80 @@
+
+README for User Friendly Instrumentation Messages
+=================================================
+
+The CDL option CYGDBG_KERNEL_INSTRUMENT_MSGS controls whether the
+system is capable of displaying user friendly instrumentation
+messages. To do this it needs to know what event numbers mean
+what events - as a text string to print for you.
+
+It gets the information from a table created by the header file
+instrument_desc.h in the kernel. If the instrumentation numbers
+change, you must rebuild that header to match.
+
+A further CDL option is provided to help you with that. The
+procedure is as follows:
+
+1) Remove kernel/VERSION/include/instrument_desc.h from your
+ repository. Is is probably a good idea to move it away rather
+ than deleting it in case the next stages fail.
+
+2) Make a build configuration, enabling options
+ CYGDBG_KERNEL_INSTRUMENT, CYGDBG_KERNEL_INSTRUMENT_MSGS and
+ CYGDBG_KERNEL_INSTRUMENT_MSGS_BUILD_HEADERFILE in the kernel.
+ Viewed in the GUI configtool, "Kernel instrumentation", "Print
+ user friendly instrument messages" and "Rebuild the header
+ file" respectively.
+
+3) Make eCos within this build configuration. It should create
+ install/include/cyg/kernel/instrument_desc.h
+
+4) Copy that new file back to your repository, to
+ kernel/VERSION/include/instrument_desc.h replacing the file
+ you moved aside in step 1.
+
+5) Commit the new file to your version control system or whatever
+ you use.
+
+If you wish to rebuild the file "by hand" the command to use, in
+a suitable shell, is this:
+
+ $ECOS_REPOSITORY/kernel/$ECOS_VERSION/host/instr/instrument.sh
+ $ECOS_REPOSITORY/kernel/$ECOS_VERSION/include/instrmnt.h
+ > $ECOS_BUILD_PREFIX/include/cyg/kernel/instrument_desc.h
+
+(all on one line of course) or to rebuild it directly into the
+kernel source repository:
+
+ $ECOS_REPOSITORY/kernel/$ECOS_VERSION/host/instr/instrument.sh
+ $ECOS_REPOSITORY/kernel/$ECOS_VERSION/include/instrmnt.h
+ > $ECOS_REPOSITORY/kernel/$ECOS_VERSION/include/instrument_desc.h
+
+It's up to you to sort out file permissions for this to work, and
+to set environment variables as required or edit these lines as
+you type them.
+
+
+There is also a host-based program which can print a buffer
+nicely for you - if you can get the data into your host.
+Enabling CDL option CYGDBG_KERNEL_INSTRUMENT_BUILD_HOST_DUMP or
+"Build the host tool to print out a dump" will build it for you
+in install/bin. To build it instead "by hand", use
+
+ mkdir -p tempinc
+ cp -r $(ECOS_BUILD_PREFIX)/include/cyg tempinc
+ cp -r $(ECOS_BUILD_PREFIX)/include/pkgconf tempinc
+ cc -I./tempinc
+ $(ECOS_REPOSITORY)/kernel/${ECOS_VERSION}/host/instr/dump_instr.c
+ -o $(PREFIX)/bin/dump_instr
+
+again with environment variables as required, or type in whatever
+is appropriate. You still have to somehow get the
+instrumentation buffer into a file on the host. 'Exercise for the
+reader' as university lecturers tend to say.
+
+One possibility is to set up a tftp *server* in the target which
+will serve the instrumentation buffer. This hint is as far as
+support for this goes.
+
+
+
diff --git a/ecos/packages/kernel/current/include/bitmap.hxx b/ecos/packages/kernel/current/include/bitmap.hxx
new file mode 100644
index 0000000000..2941f3ec99
--- /dev/null
+++ b/ecos/packages/kernel/current/include/bitmap.hxx
@@ -0,0 +1,201 @@
+#ifndef CYGONCE_KERNEL_BITMAP_HXX
+#define CYGONCE_KERNEL_BITMAP_HXX
+
+//==========================================================================
+//
+// bitmap.hxx
+//
+// Bitmap scheduler class declaration(s)
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-10
+// Purpose: Define bitmap scheduler implementation
+// Description: The classes defined here are used as base classes
+// by the common classes that define schedulers and thread
+// things.
+// Usage: Included according to configuration by
+// <cyg/kernel/sched.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+
+// -------------------------------------------------------------------------
+// The macro CYGNUM_KERNEL_SCHED_BITMAP_SIZE contains the number of bits
+// that the scheduler bitmap should contain. It is derived from the number
+// of threads that the system is allowed to use during configuration.
+
+#ifndef CYGNUM_KERNEL_SCHED_BITMAP_SIZE
+#define CYGNUM_KERNEL_SCHED_BITMAP_SIZE 32
+#endif
+
+#if CYGNUM_KERNEL_SCHED_BITMAP_SIZE <= 8
+typedef cyg_ucount8 cyg_sched_bitmap;
+#elif CYGNUM_KERNEL_SCHED_BITMAP_SIZE <= 16
+typedef cyg_ucount16 cyg_sched_bitmap;
+#elif CYGNUM_KERNEL_SCHED_BITMAP_SIZE <= 32
+typedef cyg_ucount32 cyg_sched_bitmap;
+#else
+#error Bitmaps greater than 32 bits not currently allowed
+#endif
+
+// -------------------------------------------------------------------------
+// Customize the scheduler
+
+#define CYGIMP_THREAD_PRIORITY 1
+
+#define CYG_THREAD_MIN_PRIORITY (CYGNUM_KERNEL_SCHED_BITMAP_SIZE-1)
+#define CYG_THREAD_MAX_PRIORITY 0
+
+// set default scheduling info value for thread constructors.
+#define CYG_SCHED_DEFAULT_INFO CYG_THREAD_MAX_PRIORITY
+
+// -------------------------------------------------------------------------
+// This class contains the implementation details of the scheduler, and
+// provides a standard API for accessing it.
+
+class Cyg_Scheduler_Implementation
+ : public Cyg_Scheduler_Base
+{
+ friend class Cyg_ThreadQueue_Implementation;
+ friend class Cyg_SchedThread_Implementation;
+
+ cyg_sched_bitmap run_queue;
+
+ Cyg_Thread *thread_table[CYGNUM_KERNEL_SCHED_BITMAP_SIZE];
+
+
+protected:
+
+ Cyg_Scheduler_Implementation(); // Constructor
+
+ // The following functions provide the scheduler implementation
+ // interface to the Cyg_Scheduler class. These are protected
+ // so that only the scheduler can call them.
+
+ // choose a new thread
+ Cyg_Thread *schedule();
+
+ // make thread schedulable
+ void add_thread(Cyg_Thread *thread);
+
+ // make thread un-schedulable
+ void rem_thread(Cyg_Thread *thread);
+
+ // register thread with scheduler
+ void register_thread(Cyg_Thread *thread);
+
+ // deregister thread
+ void deregister_thread(Cyg_Thread *thread);
+
+ // Test the given priority for uniqueness
+ cyg_bool unique( cyg_priority priority);
+
+public:
+ void set_idle_thread( Cyg_Thread *thread, HAL_SMP_CPU_TYPE cpu );
+
+};
+
+// -------------------------------------------------------------------------
+// Scheduler thread implementation.
+// This class provides the implementation of the scheduler specific parts
+// of each thread.
+
+class Cyg_SchedThread_Implementation
+{
+ friend class Cyg_Scheduler_Implementation;
+ friend class Cyg_ThreadQueue_Implementation;
+
+protected:
+
+ cyg_priority priority; // current thread priority
+
+ Cyg_SchedThread_Implementation(CYG_ADDRWORD sched_info);
+
+ 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 ) { };
+};
+
+// -------------------------------------------------------------------------
+// Thread queue implementation.
+// This class provides the (scheduler specific) implementation of the
+// thread queue class.
+
+class Cyg_ThreadQueue_Implementation
+{
+ cyg_sched_bitmap wait_queue;
+
+protected:
+
+ // API used by Cyg_ThreadQueue
+
+ Cyg_ThreadQueue_Implementation(); // Constructor
+
+ // Add thread to queue
+ void enqueue(Cyg_Thread *thread);
+
+ // return first thread on queue
+ Cyg_Thread *highpri();
+
+ // remove first thread on queue
+ Cyg_Thread *dequeue();
+
+ // remove specified thread from queue
+ void remove(Cyg_Thread *thread);
+
+ // test if queue is empty
+ cyg_bool empty();
+
+};
+
+inline cyg_bool Cyg_ThreadQueue_Implementation::empty()
+{
+ return wait_queue == 0;
+}
+
+// -------------------------------------------------------------------------
+
+#endif // ifndef CYGONCE_KERNEL_BITMAP_HXX
+// EOF bitmap.hxx
diff --git a/ecos/packages/kernel/current/include/clock.hxx b/ecos/packages/kernel/current/include/clock.hxx
new file mode 100644
index 0000000000..2ce6f93c09
--- /dev/null
+++ b/ecos/packages/kernel/current/include/clock.hxx
@@ -0,0 +1,261 @@
+#ifndef CYGONCE_KERNEL_CLOCK_HXX
+#define CYGONCE_KERNEL_CLOCK_HXX
+
+//==========================================================================
+//
+// clock.hxx
+//
+// Clock and Alarm class declaration(s)
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-09
+// Purpose: Define Clock and Alarm class interfaces
+// Description: The classes defined here collectively implement the
+// internal API used to create, configure and manage Counters,
+// Clocks and Alarms.
+// Usage: #include <cyg/kernel/clock.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <cyg/infra/clist.hxx>
+
+// -------------------------------------------------------------------------
+// Forward definitions and typedefs.
+
+class Cyg_Alarm;
+
+typedef void cyg_alarm_fn(Cyg_Alarm *alarm, CYG_ADDRWORD data);
+
+typedef Cyg_CList_T<Cyg_Alarm> Cyg_Alarm_List;
+
+// -------------------------------------------------------------------------
+// Counter object.
+
+class Cyg_Counter
+{
+
+ friend class Cyg_Alarm;
+
+#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)
+
+ Cyg_Alarm_List alarm_list; // Linear list of Alarms
+
+#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)
+
+ Cyg_Alarm_List alarm_list[CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE];
+
+#endif
+
+ volatile cyg_tick_count counter; // counter value
+
+ cyg_uint32 increment; // increment per tick
+
+ // Add an alarm to this counter
+ void add_alarm( Cyg_Alarm *alarm );
+
+ // Remove an alarm from this counter
+ void rem_alarm( Cyg_Alarm *alarm );
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Counter(
+ cyg_uint32 increment = 1
+ );
+
+ ~Cyg_Counter();
+
+ // Return current value of counter
+ cyg_tick_count current_value();
+
+ // Return low and high halves of the
+ // counter value.
+ cyg_uint32 current_value_lo();
+ cyg_uint32 current_value_hi();
+
+ // Set the counter's current value
+ void set_value( cyg_tick_count new_value);
+
+ // Advance counter by some number of ticks
+ void tick( cyg_uint32 ticks = 1);
+
+};
+
+// -------------------------------------------------------------------------
+// Clock class. This is derived from a Counter and defines extra
+// features to support clock-like behaviour.
+
+class Cyg_Clock
+ : public Cyg_Counter
+{
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ // This structure allows a more accurate representation
+ // of the resolution than a single integer would allow.
+ // The resolution is defined as dividend/divisor nanoseconds
+ // per tick.
+ struct cyg_resolution {
+ cyg_uint32 dividend;
+ cyg_uint32 divisor;
+ };
+
+private:
+
+ cyg_resolution resolution; // Current clock resolution
+
+public:
+
+ Cyg_Clock( // Create clock with given resolution
+ cyg_resolution resolution
+ );
+
+ ~Cyg_Clock(); // Destructor
+
+ cyg_resolution get_resolution(); // Return current resolution
+
+ void set_resolution( // Set new resolution
+ cyg_resolution resolution
+ );
+
+ // There is a need for converting from "other" ticks to clock ticks.
+ // We will construct 4 numbers to do the conversion as:
+ // clock_ticks = (((otherticks*mul1)/div1)*mul2/div2)
+ // with the values chosen to minimize the possibility of overflow.
+ // Do the arithmetic in cyg_uint64s throughout.
+ struct converter {
+ cyg_uint64 mul1, div1, mul2, div2;
+ };
+
+ // There are two of these because the 4 numbers are different depending
+ // on the direction of the conversion, to prevent loss of significance.
+ // NB these relate to the resolution of the clock object they are
+ // called against, not necessarily "the" system real time clock.
+ void get_other_to_clock_converter( cyg_uint64 ns_per_other_tick,
+ struct converter *pcc );
+
+ void get_clock_to_other_converter( cyg_uint64 ns_per_other_tick,
+ struct converter *pcc );
+
+ // A utility to perform the conversion in the obvious way, with
+ // rounding to nearest at each stage. Static because it uses a
+ // previously acquired converter.
+ static cyg_tick_count convert( cyg_tick_count value,
+ struct converter *pcc );
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+
+ // There is a system supplied real time clock...
+
+ static Cyg_Clock *real_time_clock;
+
+#endif
+
+};
+
+// -------------------------------------------------------------------------
+// Alarm class. An alarm may be attached to a counter (or a clock) to be
+// called when the trigger value is reached.
+
+class Cyg_Alarm
+#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST) || defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)
+ : public Cyg_DNode_T<Cyg_Alarm>
+#endif
+{
+ friend class Cyg_Counter;
+
+protected:
+ Cyg_Counter *counter; // Attached to this counter/clock
+
+ cyg_alarm_fn *alarm; // Call-back function
+
+ CYG_ADDRWORD data; // Call-back data
+
+ cyg_tick_count trigger; // Absolute trigger time
+
+ cyg_tick_count interval; // Retrigger interval
+
+ cyg_bool enabled; // True if enabled
+
+ Cyg_Alarm();
+
+ void synchronize( void ); // deal with times in the past,
+ // make next alarm in synch.
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Alarm // Constructor
+ (
+ Cyg_Counter *counter, // Attached to this counter
+ cyg_alarm_fn *alarm, // Call-back function
+ CYG_ADDRWORD data // Call-back data
+ );
+
+ ~Cyg_Alarm(); // Destructor
+
+ void initialize( // Initialize Alarm
+ cyg_tick_count trigger, // Absolute trigger time
+ cyg_tick_count interval = 0 // Relative retrigger interval
+ );
+
+ void enable(); // Ensure alarm enabled
+
+ void disable(); // Ensure alarm disabled
+
+ void get_times(
+ cyg_tick_count *trigger, // Next trigger time
+ cyg_tick_count *interval // Current interval
+ );
+};
+
+// -------------------------------------------------------------------------
+
+#endif // ifndef CYGONCE_KERNEL_CLOCK_HXX
+// EOF clock.hxx
diff --git a/ecos/packages/kernel/current/include/clock.inl b/ecos/packages/kernel/current/include/clock.inl
new file mode 100644
index 0000000000..15c7d43546
--- /dev/null
+++ b/ecos/packages/kernel/current/include/clock.inl
@@ -0,0 +1,125 @@
+#ifndef CYGONCE_KERNEL_CLOCK_INL
+#define CYGONCE_KERNEL_CLOCK_INL
+
+//==========================================================================
+//
+// clock.inl
+//
+// Clock and Alarm class inlines
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-30
+// Purpose: Define Clock and Alarm class inlines
+// Description: Define inline functions for counter, clock and alarm
+// classes.
+// Usage: #include <cyg/kernel/clock.hxx>
+// #include <cyg/kernel/clock.inl>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/clock.hxx>
+
+// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
+// Counter class inlines
+
+// Return current value of counter
+inline cyg_tick_count Cyg_Counter::current_value()
+{
+ return counter;
+}
+
+inline cyg_uint32 Cyg_Counter::current_value_lo()
+{
+ return counter&0xFFFFFFFF;
+}
+
+inline cyg_uint32 Cyg_Counter::current_value_hi()
+{
+ return (counter>>32)&0xFFFFFFFF;
+}
+
+// Set the counter's current value
+inline void Cyg_Counter::set_value( cyg_tick_count new_value)
+{
+ counter = new_value;
+}
+
+// -------------------------------------------------------------------------
+// -------------------------------------------------------------------------
+// Clock class inlines
+
+// Return current resolution
+inline Cyg_Clock::cyg_resolution Cyg_Clock::get_resolution()
+{
+ return resolution;
+}
+
+// Set new resolution
+inline void Cyg_Clock::set_resolution(
+ Cyg_Clock::cyg_resolution new_resolution
+ )
+{
+ resolution = new_resolution;
+}
+
+inline cyg_tick_count Cyg_Clock::convert(
+ cyg_tick_count value,
+ struct converter *pcc )
+{
+ cyg_uint64 t = (cyg_uint64)value;
+ // Do this in an order to prevent overflow at the expense of
+ // accuracy:
+ t *= pcc->mul1;
+ t += pcc->div1 / 2;
+ t /= pcc->div1;
+ t *= pcc->mul2;
+ t += pcc->div2 / 2;
+ t /= pcc->div2;
+ // The alternative would be to do the 2 multiplies first
+ // for smaller arguments.
+ return (cyg_tick_count)t;
+}
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_CLOCK_INL
+// EOF clock.inl
diff --git a/ecos/packages/kernel/current/include/diag.h b/ecos/packages/kernel/current/include/diag.h
new file mode 100644
index 0000000000..ac0cfb205c
--- /dev/null
+++ b/ecos/packages/kernel/current/include/diag.h
@@ -0,0 +1,66 @@
+#ifndef CYGONCE_KERNEL_DIAG_H
+#define CYGONCE_KERNEL_DIAG_H
+
+/*=============================================================================
+//
+// diag.h
+//
+// Diagnostic Routines for Kernel Development
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1998-03-02
+// Purpose: Diagnostic Routines for Kernel Development
+// Description: Diagnostic routines for use during kernel development.
+// Usage: #include <cyg/kernel/diag.h>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================*/
+
+// These have now migrated to here:
+
+#include <cyg/infra/diag.h>
+
+// this file is retained for the kernel to add to the functionality
+// in the knowledge that there _is_ a kernel.
+
+/*---------------------------------------------------------------------------*/
+#endif /* CYGONCE_KERNEL_DIAG_H */
+/* EOF diag.h */
diff --git a/ecos/packages/kernel/current/include/errors.h b/ecos/packages/kernel/current/include/errors.h
new file mode 100644
index 0000000000..26d797828d
--- /dev/null
+++ b/ecos/packages/kernel/current/include/errors.h
@@ -0,0 +1,83 @@
+#ifndef CYGONCE_KERNEL_ERRORS_H
+#define CYGONCE_KERNEL_ERRORS_H
+
+//==========================================================================
+//
+// errors.h
+//
+// Error values from kernel
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-10-07
+// Purpose: Define error codes
+// Description: Error codes returned by various bits of the kernel.
+// Usage: #include <cyg/kernel/errors.h>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// General successful result:
+
+#define CYGERR_OK 0
+
+// -------------------------------------------------------------------------
+// Define base of codes:
+
+#define CYGERR_KERNEL_BASE 0xEE000000
+
+// -------------------------------------------------------------------------
+// Thread related errors
+
+#define CYGERR_KERNEL_THREAD_BASE (CYGERR_KERNEL_BASE+0x00010000)
+
+#define CYGERR_KERNEL_THREAD_PRIORITY_INVALID (CYGERR_KERNEL_THREAD_BASE+1)
+#define CYGERR_KERNEL_THREAD_PRIORITY_DUPLICATE (CYGERR_KERNEL_THREAD_BASE+2)
+
+// -------------------------------------------------------------------------
+// Interrupt related errors
+
+#define CYGERR_KERNEL_INTR_BASE (CYGERR_KERNEL_BASE+0x00020000)
+
+#define CYGERR_KERNEL_INTR_VECTOR_INVALID (CYGERR_KERNEL_INTR_BASE+1)
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_ERRORS_H
+// EOF errors.h
diff --git a/ecos/packages/kernel/current/include/except.hxx b/ecos/packages/kernel/current/include/except.hxx
new file mode 100644
index 0000000000..38ed3ea5b8
--- /dev/null
+++ b/ecos/packages/kernel/current/include/except.hxx
@@ -0,0 +1,128 @@
+#ifndef CYGONCE_KERNEL_EXCEPT_HXX
+#define CYGONCE_KERNEL_EXCEPT_HXX
+
+//==========================================================================
+//
+// except.hxx
+//
+// Exception handling declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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, jlarmour
+// Date: 1999-02-16
+// Purpose: Define exception interfaces
+// Description: The classes defined here collectively implement the
+// internal API used to register, manage and deliver
+// exceptions.
+// Usage: #include <cyg/kernel/thread.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/hal/hal_intr.h> // exception defines
+
+// -------------------------------------------------------------------------
+// Exception handler function prototype
+
+typedef void cyg_exception_handler(
+ CYG_ADDRWORD data, // user supplied data
+ cyg_code exception_number, // exception being raised
+ CYG_ADDRWORD exception_info // any exception specific info
+ );
+
+// -------------------------------------------------------------------------
+// Exception delivery interface. This function is exported to the HAL which
+// invokes it for all exceptions that it is not able to handle itself.
+
+externC void cyg_hal_deliver_exception( CYG_WORD code, CYG_ADDRWORD data );
+
+// -------------------------------------------------------------------------
+// Exception control class. Depending on the configuration there is either
+// one of these per thread, or one for the entire system.
+
+#ifdef CYGPKG_KERNEL_EXCEPTIONS
+
+class Cyg_Exception_Control
+{
+
+#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE
+ cyg_exception_handler *exception_handler[CYGNUM_HAL_EXCEPTION_COUNT];
+
+ CYG_ADDRWORD exception_data[CYGNUM_HAL_EXCEPTION_COUNT];
+#else
+ cyg_exception_handler *exception_handler; // Handler function
+
+ CYG_ADDRWORD exception_data; // Handler data
+#endif
+
+public:
+
+ Cyg_Exception_Control();
+
+ // Register an exception handler for either the specific exception
+ // or for all exceptions.
+ void register_exception(
+ cyg_code exception_number, // exception number
+ cyg_exception_handler handler, // handler function
+ CYG_ADDRWORD data, // data argument
+ cyg_exception_handler **old_handler, // handler function
+ CYG_ADDRWORD *old_data // data argument
+ );
+
+ // Remove an exception handler.
+ void deregister_exception(
+ cyg_code exception_number // exception number
+ );
+
+ // Deliver the given exception now by invoking the appropriate
+ // exception handler.
+ void deliver_exception(
+ cyg_code exception_number, // exception being raised
+ CYG_ADDRWORD exception_info // exception specific info
+ );
+};
+
+#endif
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_EXCEPT_HXX
+// EOF except.hxx
diff --git a/ecos/packages/kernel/current/include/flag.hxx b/ecos/packages/kernel/current/include/flag.hxx
new file mode 100644
index 0000000000..2f6a1ce35b
--- /dev/null
+++ b/ecos/packages/kernel/current/include/flag.hxx
@@ -0,0 +1,166 @@
+#ifndef CYGONCE_KERNEL_FLAG_HXX
+#define CYGONCE_KERNEL_FLAG_HXX
+
+//==========================================================================
+//
+// flag.hxx
+//
+// Flag object class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 1998-02-10
+// Purpose: Define Flag class interfaces
+// Description: The classes defined here provide the APIs for flags.
+// Usage: #include <cyg/kernel/flag.hxx>
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+
+// -------------------------------------------------------------------------
+
+// Flag object. This class implements a queue of threads waiting for a
+// boolean expression of the flag value (an integer) to become true; all
+// relevant threads are awoken, not just the first. A variant on this is
+// the single-bit flag, which is implemented by means of default arguments.
+
+#ifdef CYGIMP_FLAGS_16BIT
+typedef cyg_uint16 Cyg_FlagValue;
+#define CYG_FLAGS_SIZE 16
+#endif
+#ifdef CYGIMP_FLAGS_32BIT
+typedef cyg_uint32 Cyg_FlagValue;
+#define CYG_FLAGS_SIZE 32
+#endif
+#ifdef CYGIMP_FLAGS_64BIT
+typedef cyg_uint64 Cyg_FlagValue;
+#define CYG_FLAGS_SIZE 64
+#endif
+
+#ifndef CYG_FLAGS_SIZE
+typedef cyg_uint32 Cyg_FlagValue;
+#define CYG_FLAGS_SIZE 32
+#endif
+
+
+
+class Cyg_Flag
+{
+private:
+ Cyg_FlagValue value;
+
+ class FlagWaitInfo
+ {
+ public:
+ Cyg_FlagValue allmask; // these are separate words to
+ Cyg_FlagValue anymask; // save time in wakeup.
+ Cyg_FlagValue value_out; // return the value that satisfied
+ cyg_bool do_clear;
+
+ FlagWaitInfo() { value_out = 0; }
+ };
+
+ Cyg_ThreadQueue queue; // Queue of waiting threads
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Flag( Cyg_FlagValue init = 0 ); // Constructor
+ ~Cyg_Flag(); // Destructor
+
+ void
+ setbits( Cyg_FlagValue arg = ~0 ); // -OR- the arg in
+ // not inlined; this function awakens affected threads.
+
+ void
+ maskbits( Cyg_FlagValue arg = 0 ); // -AND- it in
+ // this is not inlined because it needs to lock the scheduler;
+ // it only really does value &= arg; nobody can be awoken in consequence.
+
+ typedef cyg_uint8 WaitMode;
+ // These values are chosen to map directly to uITRON for emulation
+ // purposes:
+ static const WaitMode AND = 0; // all specified bits must be set
+ static const WaitMode OR = 2; // any specified bit must be set
+ static const WaitMode CLR = 1; // clear value when satisfied
+ static const WaitMode MASK= 3; // might be useful
+
+ // Wait for a match on our pattern, according to the flags given.
+ // Return the matching value, or zero if interrupted.
+ Cyg_FlagValue
+ wait( Cyg_FlagValue pattern, WaitMode mode );
+
+ // Wait for a match on our pattern, with an absolute timeout.
+ // Return the matching value, or zero if timed out/interrupted.
+ // (zero cannot match any pattern).
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ Cyg_FlagValue
+ wait( Cyg_FlagValue pattern, WaitMode mode,
+ cyg_tick_count abs_timeout );
+#endif
+ // Test for a match on our pattern, according to the flags given.
+ // Return the matching value if success, else zero.
+ Cyg_FlagValue
+ poll( Cyg_FlagValue pattern, WaitMode mode );
+
+ inline Cyg_FlagValue
+ peek() // Get current value
+ {
+ return value; // NOT atomic wrt threads
+ }
+
+ inline cyg_bool
+ waiting() // Any threads waiting?
+ {
+ return !queue.empty();
+ }
+};
+
+
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_FLAG_HXX
+// EOF flag.hxx
diff --git a/ecos/packages/kernel/current/include/instrmnt.h b/ecos/packages/kernel/current/include/instrmnt.h
new file mode 100644
index 0000000000..d17b261d5e
--- /dev/null
+++ b/ecos/packages/kernel/current/include/instrmnt.h
@@ -0,0 +1,465 @@
+#ifndef CYGONCE_KERNEL_INSTRMNT_HXX
+#define CYGONCE_KERNEL_INSTRMNT_HXX
+
+//==========================================================================
+//
+// instrmnt.hxx
+//
+// Kernel Instrumentation mechanism
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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, andrew.lunn@ascom.ch
+// Date: 2000-05-04
+// Purpose: Define kernel instrumentation
+// Description: A set of definitions and macros used to implement an
+// instrumentation interface for the kernel.
+// NOTE: Don't use CYG_UNUSED_PARAM (or similar) here to
+// silence warnings about unused variables when using the
+// empty macro definitions. Otherwise this can cause problems
+// with volatile arguments and cause other side-effects.
+// Instead it is up to the caller to ensure that unused
+// arguments don't cause warnings
+// Usage: #include <cyg/kernel/instrmnt.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+// -------------------------------------------------------------------------
+// Underlying instrumentation function
+
+externC void cyg_instrument( cyg_uint32 type, CYG_ADDRWORD arg1, CYG_ADDRWORD arg2 );
+
+// -------------------------------------------------------------------------
+// The following functions are used to enable and disable specific
+// instrumentation classes and events. The class must be one of the
+// class defines below. The event may be one of the event defines below
+// or zero, in which case all of the events in the class are enabled or
+// disabled.
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_FLAGS
+
+externC void cyg_instrument_enable( cyg_uint32 cl, cyg_uint32 event );
+
+externC void cyg_instrument_disable( cyg_uint32 cl, cyg_uint32 event );
+
+externC cyg_bool cyg_instrument_state( cyg_uint32 cl, cyg_uint32 event );
+
+#endif
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS
+externC char * cyg_instrument_msg(CYG_WORD16 type);
+#endif
+
+// -------------------------------------------------------------------------
+// Instrumentation macros
+
+#ifdef CYGPKG_KERNEL_INSTRUMENT
+
+#define CYG_INSTRUMENT(_type_,_arg1_,_arg2_) cyg_instrument(_type_, (CYG_ADDRWORD)(_arg1_), (CYG_ADDRWORD)(_arg2_))
+
+#else // ifdef CYGPKG_KERNEL_INSTRUMENT
+
+#define CYG_INSTRUMENT(_type_,_arg1_,_arg2_)
+
+#endif // ifdef CYGPKG_KERNEL_INSTRUMENT
+
+// -------------------------------------------------------------------------
+// Type codes.
+// Each code is 16 bit with an event class in the top 8 bits
+// and an event code in the lower 8 bits.
+
+// Event classes
+#define CYG_INSTRUMENT_CLASS_SCHED 0x0100
+#define CYG_INSTRUMENT_CLASS_THREAD 0x0200
+#define CYG_INSTRUMENT_CLASS_INTR 0x0300
+#define CYG_INSTRUMENT_CLASS_MUTEX 0x0400
+#define CYG_INSTRUMENT_CLASS_CONDVAR 0x0500
+#define CYG_INSTRUMENT_CLASS_BINSEM 0x0600
+#define CYG_INSTRUMENT_CLASS_CNTSEM 0x0700
+#define CYG_INSTRUMENT_CLASS_CLOCK 0x0800
+#define CYG_INSTRUMENT_CLASS_ALARM 0x0900
+#define CYG_INSTRUMENT_CLASS_MBOXT 0x0a00
+#define CYG_INSTRUMENT_CLASS_SMP 0x0b00
+#define CYG_INSTRUMENT_CLASS_MLQ 0x0c00
+
+#define CYG_INSTRUMENT_CLASS_USER 0x0f00
+
+#define CYG_INSTRUMENT_CLASS_MAX CYG_INSTRUMENT_CLASS_USER
+
+// Scheduler events
+#define CYG_INSTRUMENT_EVENT_SCHED_LOCK 1
+#define CYG_INSTRUMENT_EVENT_SCHED_UNLOCK 2
+#define CYG_INSTRUMENT_EVENT_SCHED_RESCHEDULE 3
+#define CYG_INSTRUMENT_EVENT_SCHED_TIMESLICE 4
+
+// Thread events
+#define CYG_INSTRUMENT_EVENT_THREAD_SWITCH 1
+#define CYG_INSTRUMENT_EVENT_THREAD_SLEEP 2
+#define CYG_INSTRUMENT_EVENT_THREAD_WAKE 3
+#define CYG_INSTRUMENT_EVENT_THREAD_SUSPEND 4
+#define CYG_INSTRUMENT_EVENT_THREAD_RESUME 5
+#define CYG_INSTRUMENT_EVENT_THREAD_PRIORITY 6
+#define CYG_INSTRUMENT_EVENT_THREAD_DELAY 7
+#define CYG_INSTRUMENT_EVENT_THREAD_ALARM 8
+#define CYG_INSTRUMENT_EVENT_THREAD_ENTER 9
+#define CYG_INSTRUMENT_EVENT_THREAD_CHECK_STACK 10
+#define CYG_INSTRUMENT_EVENT_THREAD_ATTACH_STACK 11
+#define CYG_INSTRUMENT_EVENT_THREAD_CREATE 12
+
+// Interrupt events
+#define CYG_INSTRUMENT_EVENT_INTR_RAISE 1
+#define CYG_INSTRUMENT_EVENT_INTR_END 2
+#define CYG_INSTRUMENT_EVENT_INTR_RESTORE 3
+#define CYG_INSTRUMENT_EVENT_INTR_POST_DSR 4
+#define CYG_INSTRUMENT_EVENT_INTR_CALL_DSR 5
+#define CYG_INSTRUMENT_EVENT_INTR_ATTACH 6
+#define CYG_INSTRUMENT_EVENT_INTR_DETACH 7
+#define CYG_INSTRUMENT_EVENT_INTR_SET_VSR 8
+#define CYG_INSTRUMENT_EVENT_INTR_DISABLE 9
+#define CYG_INSTRUMENT_EVENT_INTR_ENABLE 10
+#define CYG_INSTRUMENT_EVENT_INTR_MASK 11
+#define CYG_INSTRUMENT_EVENT_INTR_UNMASK 12
+#define CYG_INSTRUMENT_EVENT_INTR_CONFIGURE 13
+#define CYG_INSTRUMENT_EVENT_INTR_ACK 14
+#define CYG_INSTRUMENT_EVENT_INTR_CHAIN_ISR 15
+#define CYG_INSTRUMENT_EVENT_INTR_SET_CPU 16
+#define CYG_INSTRUMENT_EVENT_INTR_GET_CPU 17
+
+// Mutex events
+#define CYG_INSTRUMENT_EVENT_MUTEX_LOCK 1
+#define CYG_INSTRUMENT_EVENT_MUTEX_WAIT 2
+#define CYG_INSTRUMENT_EVENT_MUTEX_LOCKED 3
+#define CYG_INSTRUMENT_EVENT_MUTEX_TRY 4
+#define CYG_INSTRUMENT_EVENT_MUTEX_UNLOCK 5
+#define CYG_INSTRUMENT_EVENT_MUTEX_WAKE 6
+#define CYG_INSTRUMENT_EVENT_MUTEX_RELEASE 7
+#define CYG_INSTRUMENT_EVENT_MUTEX_RELEASED 8
+
+// Condition variable events
+#define CYG_INSTRUMENT_EVENT_CONDVAR_WAIT 1
+#define CYG_INSTRUMENT_EVENT_CONDVAR_WOKE 2
+#define CYG_INSTRUMENT_EVENT_CONDVAR_SIGNAL 3
+#define CYG_INSTRUMENT_EVENT_CONDVAR_WAKE 4
+#define CYG_INSTRUMENT_EVENT_CONDVAR_BROADCAST 5
+#define CYG_INSTRUMENT_EVENT_CONDVAR_TIMED_WAIT 6
+
+// Binary semaphore events
+#define CYG_INSTRUMENT_EVENT_BINSEM_CLAIM 1
+#define CYG_INSTRUMENT_EVENT_BINSEM_WAIT 2
+#define CYG_INSTRUMENT_EVENT_BINSEM_WOKE 3
+#define CYG_INSTRUMENT_EVENT_BINSEM_TRY 4
+#define CYG_INSTRUMENT_EVENT_BINSEM_POST 5
+#define CYG_INSTRUMENT_EVENT_BINSEM_WAKE 6
+#define CYG_INSTRUMENT_EVENT_BINSEM_TIMEOUT 7
+
+// Counting semaphore events
+#define CYG_INSTRUMENT_EVENT_CNTSEM_CLAIM 1
+#define CYG_INSTRUMENT_EVENT_CNTSEM_WAIT 2
+#define CYG_INSTRUMENT_EVENT_CNTSEM_WOKE 3
+#define CYG_INSTRUMENT_EVENT_CNTSEM_TRY 4
+#define CYG_INSTRUMENT_EVENT_CNTSEM_POST 5
+#define CYG_INSTRUMENT_EVENT_CNTSEM_WAKE 6
+#define CYG_INSTRUMENT_EVENT_CNTSEM_TIMEOUT 7
+
+// Clock events
+#define CYG_INSTRUMENT_EVENT_CLOCK_TICK_START 1
+#define CYG_INSTRUMENT_EVENT_CLOCK_TICK_END 2
+#define CYG_INSTRUMENT_EVENT_CLOCK_ISR 3
+
+// Alarm events
+#define CYG_INSTRUMENT_EVENT_ALARM_ADD 1
+#define CYG_INSTRUMENT_EVENT_ALARM_REM 2
+#define CYG_INSTRUMENT_EVENT_ALARM_CALL 3
+#define CYG_INSTRUMENT_EVENT_ALARM_INIT 4
+#define CYG_INSTRUMENT_EVENT_ALARM_TRIGGER 5
+#define CYG_INSTRUMENT_EVENT_ALARM_INTERVAL 6
+
+// Mboxt events
+#define CYG_INSTRUMENT_EVENT_MBOXT_WAIT 1
+#define CYG_INSTRUMENT_EVENT_MBOXT_GET 2
+#define CYG_INSTRUMENT_EVENT_MBOXT_GOT 3
+#define CYG_INSTRUMENT_EVENT_MBOXT_TIMEOUT 4
+#define CYG_INSTRUMENT_EVENT_MBOXT_WAKE 5
+#define CYG_INSTRUMENT_EVENT_MBOXT_TRY 6
+#define CYG_INSTRUMENT_EVENT_MBOXT_PUT 7
+
+// SMP events
+#define CYG_INSTRUMENT_EVENT_SMP_LOCK_INC 1
+#define CYG_INSTRUMENT_EVENT_SMP_LOCK_ZERO 2
+#define CYG_INSTRUMENT_EVENT_SMP_LOCK_SET 3
+#define CYG_INSTRUMENT_EVENT_SMP_CPU_START 4
+#define CYG_INSTRUMENT_EVENT_SMP_LOCK_WAIT 5
+#define CYG_INSTRUMENT_EVENT_SMP_LOCK_GOT 6
+#define CYG_INSTRUMENT_EVENT_SMP_RESCHED_SEND 8
+#define CYG_INSTRUMENT_EVENT_SMP_RESCHED_RECV 9
+
+// MLQ scheduler events
+
+#define CYG_INSTRUMENT_EVENT_MLQ_SCHEDULE 1
+#define CYG_INSTRUMENT_EVENT_MLQ_RESCHEDULE 2
+#define CYG_INSTRUMENT_EVENT_MLQ_ADD 3
+#define CYG_INSTRUMENT_EVENT_MLQ_REM 4
+#define CYG_INSTRUMENT_EVENT_MLQ_TIMESLICE 5
+#define CYG_INSTRUMENT_EVENT_MLQ_YIELD 6
+#define CYG_INSTRUMENT_EVENT_MLQ_ENQUEUE 7
+#define CYG_INSTRUMENT_EVENT_MLQ_DEQUEUE 8
+#define CYG_INSTRUMENT_EVENT_MLQ_REMOVE 9
+
+
+// User events
+
+#define CYG_INSTRUMENT_EVENT_USER_1 1
+#define CYG_INSTRUMENT_EVENT_USER_2 2
+#define CYG_INSTRUMENT_EVENT_USER_3 3
+#define CYG_INSTRUMENT_EVENT_USER_4 4
+#define CYG_INSTRUMENT_EVENT_USER_5 5
+#define CYG_INSTRUMENT_EVENT_USER_6 6
+#define CYG_INSTRUMENT_EVENT_USER_7 7
+#define CYG_INSTRUMENT_EVENT_USER_8 8
+#define CYG_INSTRUMENT_EVENT_USER_9 9
+#define CYG_INSTRUMENT_EVENT_USER_10 10
+#define CYG_INSTRUMENT_EVENT_USER_11 11
+#define CYG_INSTRUMENT_EVENT_USER_12 12
+#define CYG_INSTRUMENT_EVENT_USER_13 13
+#define CYG_INSTRUMENT_EVENT_USER_14 14
+#define CYG_INSTRUMENT_EVENT_USER_15 15
+#define CYG_INSTRUMENT_EVENT_USER_16 16
+#define CYG_INSTRUMENT_EVENT_USER_17 17
+#define CYG_INSTRUMENT_EVENT_USER_18 18
+#define CYG_INSTRUMENT_EVENT_USER_19 19
+
+// -------------------------------------------------------------------------
+// Handy-dandy macro to make event codes.
+// Note that this relies on the definitions above
+// having a well defined form.
+
+#define CYGINST_EVENT(_class_,_event_) \
+((CYG_INSTRUMENT_CLASS_##_class_)|(CYG_INSTRUMENT_EVENT_##_class_##_##_event_))
+
+// -------------------------------------------------------------------------
+// Scheduler instrumentation macros
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_SCHED
+
+#define CYG_INSTRUMENT_SCHED(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(SCHED,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_SCHED(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Thread instrumentation macros
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_THREAD
+
+#define CYG_INSTRUMENT_THREAD(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(THREAD,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_THREAD(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Interrupt instrumentation macros
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_INTR
+
+#define CYG_INSTRUMENT_INTR(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(INTR,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_INTR(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Mutex instrumentation macros
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_MUTEX
+
+#define CYG_INSTRUMENT_MUTEX(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(MUTEX,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_MUTEX(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Condition variable instrumentation macros
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_CONDVAR
+
+#define CYG_INSTRUMENT_CONDVAR(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(CONDVAR,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_CONDVAR(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Binary semaphore instrumentation macros
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_BINSEM
+
+#define CYG_INSTRUMENT_BINSEM(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(BINSEM,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_BINSEM(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Counting semaphore instrumentation macros
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_CNTSEM
+
+#define CYG_INSTRUMENT_CNTSEM(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(CNTSEM,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_CNTSEM(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Clock instrumentation macros
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_CLOCK
+
+#define CYG_INSTRUMENT_CLOCK(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(CLOCK,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_CLOCK(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Alarm instrumentation macros
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_ALARM
+
+#define CYG_INSTRUMENT_ALARM(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(ALARM,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_ALARM(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// Mboxt instrumentation macros
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_MBOXT
+
+#define CYG_INSTRUMENT_MBOXT(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(MBOXT,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_MBOXT(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// SMP instrumentation
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_SMP
+
+#define CYG_INSTRUMENT_SMP(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(SMP,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_SMP(_event_,_arg1_,_arg2_)
+
+#endif
+
+
+// -------------------------------------------------------------------------
+// MLQ instrumentation
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_MLQ
+
+#define CYG_INSTRUMENT_MLQ(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT(CYGINST_EVENT(MLQ,_event_),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_MLQ(_event_,_arg1_,_arg2_)
+
+#endif
+
+// -------------------------------------------------------------------------
+// User instrumentation
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_USER
+
+#define CYG_INSTRUMENT_USER(_event_,_arg1_,_arg2_) \
+ CYG_INSTRUMENT((CYG_INSTRUMENT_CLASS_USER|(_event_)),_arg1_,_arg2_)
+
+#else
+
+#define CYG_INSTRUMENT_USER(_event_,_arg1_,_arg2_)
+
+#endif
+
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_INSTRMNT_HXX
+// EOF instrmnt.h
diff --git a/ecos/packages/kernel/current/include/instrument_desc.h b/ecos/packages/kernel/current/include/instrument_desc.h
new file mode 100644
index 0000000000..03d0445654
--- /dev/null
+++ b/ecos/packages/kernel/current/include/instrument_desc.h
@@ -0,0 +1,143 @@
+/* This is an automatically generated file. Do not edit. */
+/* Repository name: PACKAGES/kernel/VERSION/include/instrument_desc.h */
+/* Install tree : INSTALL/include/cyg/kernel/instrument_desc.h */
+
+struct instrument_desc_s {
+ char * msg;
+ CYG_WORD num;
+};
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE
+struct instrument_desc_s instrument_desc[] = {
+{"ALARM", 0x0900},
+{"ALARM_ADD", 1},
+{"ALARM_CALL", 3},
+{"ALARM_INIT", 4},
+{"ALARM_INTERVAL", 6},
+{"ALARM_REM", 2},
+{"ALARM_TRIGGER", 5},
+{"BINSEM", 0x0600},
+{"BINSEM_CLAIM", 1},
+{"BINSEM_POST", 5},
+{"BINSEM_TRY", 4},
+{"BINSEM_WAIT", 2},
+{"BINSEM_WAKE", 6},
+{"BINSEM_WOKE", 3},
+{"CLOCK", 0x0800},
+{"CLOCK_ISR", 3},
+{"CLOCK_TICK_END", 2},
+{"CLOCK_TICK_START", 1},
+{"CNTSEM", 0x0700},
+{"CNTSEM_CLAIM", 1},
+{"CNTSEM_POST", 5},
+{"CNTSEM_TIMEOUT", 7},
+{"CNTSEM_TRY", 4},
+{"CNTSEM_WAIT", 2},
+{"CNTSEM_WAKE", 6},
+{"CNTSEM_WOKE", 3},
+{"CONDVAR", 0x0500},
+{"CONDVAR_BROADCAST", 5},
+{"CONDVAR_SIGNAL", 3},
+{"CONDVAR_TIMED_WAIT", 6},
+{"CONDVAR_WAIT", 1},
+{"CONDVAR_WAKE", 4},
+{"CONDVAR_WOKE", 2},
+{"INTR", 0x0300},
+{"INTR_ACK", 14},
+{"INTR_ATTACH", 6},
+{"INTR_CALL_DSR", 5},
+{"INTR_CHAIN_ISR", 15},
+{"INTR_CONFIGURE", 13},
+{"INTR_DETACH", 7},
+{"INTR_DISABLE", 9},
+{"INTR_ENABLE", 10},
+{"INTR_END", 2},
+{"INTR_GET_CPU", 17},
+{"INTR_MASK", 11},
+{"INTR_POST_DSR", 4},
+{"INTR_RAISE", 1},
+{"INTR_RESTORE", 3},
+{"INTR_SET_CPU", 16},
+{"INTR_SET_VSR", 8},
+{"INTR_UNMASK", 12},
+{"MBOXT", 0x0a00},
+{"MBOXT_GET", 2},
+{"MBOXT_GOT", 3},
+{"MBOXT_PUT", 7},
+{"MBOXT_TIMEOUT", 4},
+{"MBOXT_TRY", 6},
+{"MBOXT_WAIT", 1},
+{"MBOXT_WAKE", 5},
+{"MLQ", 0x0c00},
+{"MLQ_ADD", 3},
+{"MLQ_DEQUEUE", 8},
+{"MLQ_ENQUEUE", 7},
+{"MLQ_REM", 4},
+{"MLQ_REMOVE", 9},
+{"MLQ_RESCHEDULE", 2},
+{"MLQ_SCHEDULE", 1},
+{"MLQ_TIMESLICE", 5},
+{"MLQ_YIELD", 6},
+{"MUTEX", 0x0400},
+{"MUTEX_LOCK", 1},
+{"MUTEX_LOCKED", 3},
+{"MUTEX_RELEASE", 7},
+{"MUTEX_RELEASED", 8},
+{"MUTEX_TRY", 4},
+{"MUTEX_UNLOCK", 5},
+{"MUTEX_WAIT", 2},
+{"MUTEX_WAKE", 6},
+{"SCHED", 0x0100},
+{"SCHED_LOCK", 1},
+{"SCHED_RESCHEDULE", 3},
+{"SCHED_TIMESLICE", 4},
+{"SCHED_UNLOCK", 2},
+{"SMP", 0x0b00},
+{"SMP_CPU_START", 4},
+{"SMP_LOCK_GOT", 6},
+{"SMP_LOCK_INC", 1},
+{"SMP_LOCK_SET", 3},
+{"SMP_LOCK_WAIT", 5},
+{"SMP_LOCK_ZERO", 2},
+{"SMP_RESCHED_RECV", 9},
+{"SMP_RESCHED_SEND", 8},
+{"THREAD", 0x0200},
+{"THREAD_ALARM", 8},
+{"THREAD_ATTACH_STACK", 11},
+{"THREAD_CHECK_STACK", 10},
+{"THREAD_CREATE", 12},
+{"THREAD_DELAY", 7},
+{"THREAD_ENTER", 9},
+{"THREAD_PRIORITY", 6},
+{"THREAD_RESUME", 5},
+{"THREAD_SLEEP", 2},
+{"THREAD_SUSPEND", 4},
+{"THREAD_SWITCH", 1},
+{"THREAD_WAKE", 3},
+{"USER", 0x0f00},
+{"USER_10", 10},
+{"USER_1", 1},
+{"USER_11", 11},
+{"USER_12", 12},
+{"USER_13", 13},
+{"USER_14", 14},
+{"USER_15", 15},
+{"USER_16", 16},
+{"USER_17", 17},
+{"USER_18", 18},
+{"USER_19", 19},
+{"USER_2", 2},
+{"USER_3", 3},
+{"USER_4", 4},
+{"USER_5", 5},
+{"USER_6", 6},
+{"USER_7", 7},
+{"USER_8", 8},
+{"USER_9", 9},
+{ 0, 0 }
+};
+#else /* CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE */
+extern struct instrument_desc_s instrument_desc[];
+#endif /* CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE */
+
+/* EOF instrument_desc.h */
diff --git a/ecos/packages/kernel/current/include/intr.hxx b/ecos/packages/kernel/current/include/intr.hxx
new file mode 100644
index 0000000000..7c39d16a5d
--- /dev/null
+++ b/ecos/packages/kernel/current/include/intr.hxx
@@ -0,0 +1,371 @@
+#ifndef CYGONCE_KERNEL_INTR_HXX
+#define CYGONCE_KERNEL_INTR_HXX
+
+//==========================================================================
+//
+// intr.hxx
+//
+// Interrupt class declaration(s)
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-09
+// Purpose: Define Interrupt class interfaces
+// Description: The classes defined here provide the APIs for handling
+// interrupts.
+// Usage: #include "intr.hxx"
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+
+#include <cyg/kernel/smp.hxx>
+
+// -------------------------------------------------------------------------
+// Default definitions
+
+// Some HALs define the ISR table to be a different size to the number
+// of ISR vectors. These HALs will define CYGNUM_HAL_ISR_TABLE_SIZE. All
+// other HALs will have the table size equal to the number of vectors.
+
+#ifndef CYGNUM_HAL_ISR_TABLE_SIZE
+# define CYGNUM_HAL_ISR_TABLE_SIZE CYGNUM_HAL_ISR_COUNT
+#endif
+
+// -------------------------------------------------------------------------
+// Function prototype typedefs
+
+
+// VSR = Vector Service Routine. This is the code attached directly to an
+// interrupt vector. It is very architecture/platform specific and usually
+// must be written in assembler.
+
+typedef void cyg_VSR();
+
+// ISR = Interrupt Service Routine. This is called from the default
+// VSR in response to an interrupt. It may access shared data but may
+// not call kernel routines. The return value may be
+// Cyg_Interrupt::HANDLED and/or Cyg_Interrupt::CALL_DSR.
+
+typedef cyg_uint32 cyg_ISR(cyg_vector vector, CYG_ADDRWORD data);
+
+// DSR = Deferred Service Routine. This is called if the ISR returns
+// the Cyg_Interrupt::CALL_DSR bit. It is called at a "safe" point in
+// the kernel where it may make calls on kernel routines. The count
+// argument indicates how many times the ISR has asked for the DSR to
+// be posted since the last time the DSR ran.
+
+typedef void cyg_DSR(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data);
+
+// -------------------------------------------------------------------------
+// Include HAL definitions
+
+class Cyg_Interrupt;
+
+#include <cyg/hal/hal_arch.h>
+
+#include <cyg/hal/hal_intr.h>
+
+#ifndef HAL_INTERRUPT_STACK_CALL_PENDING_DSRS
+#define HAL_INTERRUPT_STACK_CALL_PENDING_DSRS() \
+ Cyg_Interrupt::call_pending_DSRs_inner()
+#endif
+
+externC void interrupt_end(
+ cyg_uint32 isr_ret,
+ Cyg_Interrupt *intr,
+ HAL_SavedRegisters *ctx
+ );
+
+externC void cyg_interrupt_post_dsr( CYG_ADDRWORD intr_obj );
+externC void cyg_interrupt_call_pending_DSRs( void );
+
+// -------------------------------------------------------------------------
+// Interrupt class. This both represents each interrupt and provides a static
+// interface for controlling the interrupt hardware.
+
+class Cyg_Interrupt
+{
+
+ friend class Cyg_Scheduler;
+ friend void interrupt_end( cyg_uint32,
+ Cyg_Interrupt *,
+ HAL_SavedRegisters *);
+ friend void cyg_interrupt_post_dsr( CYG_ADDRWORD intr_obj );
+ friend void cyg_interrupt_call_pending_DSRs( void );
+
+ cyg_vector vector; // Interrupt vector
+
+ cyg_priority priority; // Queuing priority
+
+ cyg_ISR *isr; // Pointer to ISR
+
+ cyg_DSR *dsr; // Pointer to DSR
+
+ CYG_ADDRWORD data; // Data pointer
+
+
+
+ // DSR handling interface called by the scheduler
+
+ // Check for pending DSRs
+ static cyg_bool DSRs_pending();
+
+ // Call any pending DSRs
+ static void call_pending_DSRs();
+ static void call_pending_DSRs_inner();
+
+ // DSR handling interface called by the scheduler and HAL
+ // interrupt arbiters.
+
+ void post_dsr(); // Post the DSR for this interrupt
+
+
+
+ // Data structures for handling DSR calls. We implement two DSR
+ // handling mechanisms, a list based one and a table based
+ // one. The list based mechanism is safe with respect to temporary
+ // overloads and will not run out of resource. However it requires
+ // extra data per interrupt object, and interrupts must be turned
+ // off briefly when delivering the DSR. The table based mechanism
+ // does not need unnecessary interrupt switching, but may be prone
+ // to overflow on overload. However, since a correctly programmed
+ // real time application should not experience such a condition,
+ // the table based mechanism is more efficient for real use. The
+ // list based mechainsm is enabled by default since it is safer to
+ // use during development.
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
+
+ static Cyg_Interrupt *dsr_table[CYGNUM_KERNEL_CPU_MAX]
+ [CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE]
+ CYGBLD_ANNOTATE_VARIABLE_INTR;
+
+ static cyg_ucount32 dsr_table_head[CYGNUM_KERNEL_CPU_MAX]
+ CYGBLD_ANNOTATE_VARIABLE_INTR;
+
+ static volatile cyg_ucount32 dsr_table_tail[CYGNUM_KERNEL_CPU_MAX]
+ CYGBLD_ANNOTATE_VARIABLE_INTR;
+
+#endif
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
+
+ // Number of DSR posts made
+ volatile cyg_ucount32 dsr_count CYGBLD_ANNOTATE_VARIABLE_INTR;
+
+ // next DSR in list
+ Cyg_Interrupt* volatile next_dsr CYGBLD_ANNOTATE_VARIABLE_INTR;
+
+ // static list of pending DSRs
+ static Cyg_Interrupt* volatile dsr_list[CYGNUM_KERNEL_CPU_MAX]
+ CYGBLD_ANNOTATE_VARIABLE_INTR;
+
+#endif
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
+
+ // The default mechanism for handling interrupts is to attach just
+ // one Interrupt object to each vector. In some cases, and on some
+ // hardware, this is not possible, and each vector must carry a chain
+ // of interrupts.
+
+ Cyg_Interrupt *next; // Next Interrupt in list
+
+ // Chaining ISR inserted in HAL vector
+ static cyg_uint32 chain_isr(cyg_vector vector, CYG_ADDRWORD data);
+
+ // Table of interrupt chains
+ static Cyg_Interrupt *chain_list[CYGNUM_HAL_ISR_TABLE_SIZE];
+
+#endif
+
+ // Interrupt disable data. Interrupt disable can be nested. On
+ // each CPU this is controlled by disable_counter[cpu]. When the
+ // counter is first incremented from zero to one, the
+ // interrupt_disable_spinlock is claimed using spin_intsave(), the
+ // original interrupt enable state being saved in
+ // interrupt_disable_state[cpu]. When the counter is decremented
+ // back to zero the spinlock is cleared using clear_intsave().
+
+ // The spinlock is necessary in SMP systems since a thread
+ // accessing data shared with an ISR may be scheduled on a
+ // different CPU to the one that handles the interrupt. So, merely
+ // blocking local interrupts would be ineffective. SMP aware
+ // device drivers should either use their own spinlocks to protect
+ // data, or use the API supported by this class, via
+ // cyg_drv_isr_lock()/_unlock(). Note that it now becomes
+ // essential that ISRs do this if they are to be SMP-compatible.
+
+ // In a single CPU system, this mechanism reduces to just
+ // disabling/enabling interrupts.
+
+ // Disable level counter. This counts the number of times
+ // interrupts have been disabled.
+ static volatile cyg_int32 disable_counter[CYGNUM_KERNEL_CPU_MAX]
+ CYGBLD_ANNOTATE_VARIABLE_INTR;
+
+ // Interrupt disable spinlock. This is claimed by any CPU that has
+ // disabled interrupts via the Cyg_Interrupt API.
+ static Cyg_SpinLock interrupt_disable_spinlock CYGBLD_ANNOTATE_VARIABLE_INTR;
+
+ // Saved interrupt state. When each CPU first disables interrupts
+ // the original state of the interrupts are saved here to be
+ // restored later.
+ static CYG_INTERRUPT_STATE interrupt_disable_state[CYGNUM_KERNEL_CPU_MAX]
+ CYGBLD_ANNOTATE_VARIABLE_INTR;
+
+
+public:
+
+ Cyg_Interrupt // Initialize interrupt
+ (
+ cyg_vector vector, // Vector to attach to
+ cyg_priority priority, // Queue priority
+ CYG_ADDRWORD data, // Data pointer
+ cyg_ISR *isr, // Interrupt Service Routine
+ cyg_DSR *dsr // Deferred Service Routine
+ );
+
+ ~Cyg_Interrupt();
+
+ // ISR return values
+ enum {
+ HANDLED = 1, // Interrupt was handled
+ CALL_DSR = 2 // Schedule DSR
+ };
+
+ // Interrupt management
+
+ void attach(); // Attach to vector
+
+
+ void detach(); // Detach from vector
+
+
+ // Static Interrupt management functions
+
+ // Get the current service routine
+ static void get_vsr(cyg_vector vector, cyg_VSR **vsr);
+
+ // Install a vector service routine
+ static void set_vsr(
+ cyg_vector vector, // hardware vector to replace
+ cyg_VSR *vsr, // my new service routine
+ cyg_VSR **old = NULL // pointer to old vsr, if required
+ );
+
+
+ // Static interrupt masking functions
+
+ // Disable interrupts at the CPU
+ static void disable_interrupts();
+
+ // Re-enable CPU interrupts
+ static void enable_interrupts();
+
+ // Are interrupts enabled at the CPU?
+ static inline cyg_bool interrupts_enabled()
+ {
+ return (0 == disable_counter[CYG_KERNEL_CPU_THIS()]);
+ }
+
+ // Get the vector for the following calls
+ inline cyg_vector get_vector()
+ {
+ return vector;
+ }
+
+ // Static PIC control functions
+
+ // Mask a specific interrupt in a PIC
+ static void mask_interrupt(cyg_vector vector);
+ // The same but not interrupt safe
+ static void mask_interrupt_intunsafe(cyg_vector vector);
+
+ // Clear PIC mask
+ static void unmask_interrupt(cyg_vector vector);
+ // The same but not interrupt safe
+ static void unmask_interrupt_intunsafe(cyg_vector vector);
+
+ // Acknowledge interrupt at PIC
+ static void acknowledge_interrupt(cyg_vector vector);
+
+ // Change interrupt detection at PIC
+ static void configure_interrupt(
+ cyg_vector vector, // vector to control
+ cyg_bool level, // level or edge triggered
+ cyg_bool up // hi/lo level, rising/falling edge
+ );
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ // SMP support for associating an interrupt with a specific CPU.
+
+ static void set_cpu( cyg_vector, HAL_SMP_CPU_TYPE cpu );
+ static HAL_SMP_CPU_TYPE get_cpu( cyg_vector );
+
+#endif
+};
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS
+// -------------------------------------------------------------------------
+// Check for pending DSRs
+
+inline cyg_bool Cyg_Interrupt::DSRs_pending()
+{
+ HAL_SMP_CPU_TYPE cpu = CYG_KERNEL_CPU_THIS();
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
+
+ return dsr_table_head[cpu] != dsr_table_tail[cpu];
+
+#endif
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
+
+ return dsr_list[cpu] != NULL;
+
+#endif
+};
+#endif // CYGIMP_KERNEL_INTERRUPTS_DSRS
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_INTR_HXX
+// EOF intr.hxx
diff --git a/ecos/packages/kernel/current/include/kapi.h b/ecos/packages/kernel/current/include/kapi.h
new file mode 100644
index 0000000000..7b4964c698
--- /dev/null
+++ b/ecos/packages/kernel/current/include/kapi.h
@@ -0,0 +1,681 @@
+#ifndef CYGONCE_KERNEL_KAPI_H
+#define CYGONCE_KERNEL_KAPI_H
+
+/*==========================================================================
+//
+// kapi.h
+//
+// Native API for Kernel
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2002 Bart Veer
+// Copyright (C) 2002 Nick Garnett
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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, dsm
+// Contributors: nickg
+// Date: 1998-03-02
+// Purpose: Native API for Kernel
+// Description: This file describes the native API for using the kernel.
+// It is essentially a set of C wrappers for the C++ class
+// member functions.
+// Usage: #include <cyg/kernel/kapi.h>
+//
+//####DESCRIPTIONEND####
+//
+//========================================================================*/
+
+#include <pkgconf/system.h>
+#include <pkgconf/kernel.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+#include <cyg/infra/cyg_type.h>
+
+/*---------------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* The following are derived types, they may have different */
+/* definitions from these depending on configuration. */
+
+typedef CYG_ADDRWORD cyg_addrword_t; /* May hold pointer or word */
+typedef cyg_addrword_t cyg_handle_t; /* Object handle */
+typedef cyg_uint32 cyg_priority_t; /* type for priorities */
+typedef cyg_int32 cyg_code_t; /* type for various codes */
+typedef cyg_uint32 cyg_vector_t; /* Interrupt vector id */
+typedef cyg_uint32 cyg_cpu_t; /* CPU id type */
+
+typedef cyg_uint64 cyg_tick_count_t;
+
+typedef int cyg_bool_t;
+
+/* Exception handler function definition */
+typedef void cyg_exception_handler_t(
+ cyg_addrword_t data,
+ cyg_code_t exception_number,
+ cyg_addrword_t info
+);
+
+/*---------------------------------------------------------------------------*/
+struct cyg_thread;
+typedef struct cyg_thread cyg_thread;
+
+struct cyg_interrupt;
+typedef struct cyg_interrupt cyg_interrupt;
+
+struct cyg_counter;
+typedef struct cyg_counter cyg_counter;
+
+struct cyg_clock;
+typedef struct cyg_clock cyg_clock;
+
+struct cyg_alarm;
+typedef struct cyg_alarm cyg_alarm;
+
+struct cyg_mbox;
+typedef struct cyg_mbox cyg_mbox;
+
+struct cyg_sem_t;
+typedef struct cyg_sem_t cyg_sem_t;
+
+struct cyg_flag_t;
+typedef struct cyg_flag_t cyg_flag_t;
+
+struct cyg_mutex_t;
+typedef struct cyg_mutex_t cyg_mutex_t;
+
+struct cyg_cond_t;
+typedef struct cyg_cond_t cyg_cond_t;
+
+struct cyg_spinlock_t;
+typedef struct cyg_spinlock_t cyg_spinlock_t;
+
+/*---------------------------------------------------------------------------*/
+/* Scheduler operations */
+
+/* Starts scheduler with created threads. Never returns. */
+void cyg_scheduler_start(void) __THROW CYGBLD_ATTRIB_NORET;
+
+/* Lock and unlock the scheduler. When the scheduler is */
+/* locked thread preemption is disabled. */
+void cyg_scheduler_lock(void) __THROW;
+
+void cyg_scheduler_unlock(void) __THROW;
+
+/* Just like 'cyg_scheduler_lock()', but never take the lock higher than 1 */
+/* Thus this call is safe even if the scheduler is already locked and a */
+/* subsequent call to 'cyg_scheduler_unlock()' will completely unlock. */
+void cyg_scheduler_safe_lock(void) __THROW;
+
+/* Read the scheduler lock value. */
+cyg_ucount32 cyg_scheduler_read_lock(void) __THROW;
+
+/*---------------------------------------------------------------------------*/
+/* Thread operations */
+
+typedef void cyg_thread_entry_t(cyg_addrword_t);
+
+void cyg_thread_create(
+ cyg_addrword_t sched_info, /* scheduling info (eg pri) */
+ cyg_thread_entry_t *entry, /* entry point function */
+ cyg_addrword_t entry_data, /* entry data */
+ char *name, /* optional thread name */
+ void *stack_base, /* stack base, NULL = alloc */
+ cyg_ucount32 stack_size, /* stack size, 0 = default */
+ cyg_handle_t *handle, /* returned thread handle */
+ cyg_thread *thread /* put thread here */
+) __THROW;
+
+void cyg_thread_exit(void) __THROW;
+
+/* It may be necessary to arrange for the victim to run for it to disappear */
+cyg_bool_t cyg_thread_delete(cyg_handle_t thread) __THROW; /* false if NOT deleted */
+
+void cyg_thread_suspend(cyg_handle_t thread) __THROW;
+
+void cyg_thread_resume(cyg_handle_t thread) __THROW;
+
+void cyg_thread_kill(cyg_handle_t thread) __THROW;
+
+void cyg_thread_release(cyg_handle_t thread) __THROW;
+
+void cyg_thread_yield(void) __THROW;
+
+cyg_handle_t cyg_thread_self(void) __THROW;
+
+cyg_handle_t cyg_thread_idle_thread(void) __THROW;
+
+/* Priority manipulation */
+
+void cyg_thread_set_priority(cyg_handle_t thread, cyg_priority_t priority ) __THROW;
+
+cyg_priority_t cyg_thread_get_priority(cyg_handle_t thread) __THROW;
+cyg_priority_t cyg_thread_get_current_priority(cyg_handle_t thread) __THROW;
+
+/* Deadline scheduling control (optional) */
+
+void cyg_thread_deadline_wait(
+ cyg_tick_count_t start_time, /* abs earliest start time */
+ cyg_tick_count_t run_time, /* worst case execution time */
+ cyg_tick_count_t deadline /* absolute deadline */
+) __THROW;
+
+void cyg_thread_delay(cyg_tick_count_t delay) __THROW;
+
+/* Stack information */
+cyg_addrword_t cyg_thread_get_stack_base(cyg_handle_t thread) __THROW;
+
+cyg_uint32 cyg_thread_get_stack_size(cyg_handle_t thread) __THROW;
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
+cyg_uint32 cyg_thread_measure_stack_usage(cyg_handle_t thread) __THROW;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Thread enumeration and information */
+
+typedef struct
+{
+ cyg_handle_t handle;
+ cyg_uint16 id;
+ cyg_uint32 state;
+ char *name;
+ cyg_priority_t set_pri;
+ cyg_priority_t cur_pri;
+ cyg_addrword_t stack_base;
+ cyg_uint32 stack_size;
+ cyg_uint32 stack_used;
+} cyg_thread_info;
+
+cyg_bool_t cyg_thread_get_next( cyg_handle_t *thread, cyg_uint16 *id ) __THROW;
+
+cyg_bool_t cyg_thread_get_info( cyg_handle_t thread,
+ cyg_uint16 id,
+ cyg_thread_info *info ) __THROW;
+
+cyg_uint16 cyg_thread_get_id( cyg_handle_t thread ) __THROW;
+
+cyg_handle_t cyg_thread_find( cyg_uint16 id ) __THROW;
+
+/*---------------------------------------------------------------------------*/
+/* Per-thread Data */
+
+#ifdef CYGVAR_KERNEL_THREADS_DATA
+
+cyg_ucount32 cyg_thread_new_data_index(void) __THROW;
+
+void cyg_thread_free_data_index(cyg_ucount32 index) __THROW;
+
+CYG_ADDRWORD cyg_thread_get_data(cyg_ucount32 index) __THROW;
+
+CYG_ADDRWORD *cyg_thread_get_data_ptr(cyg_ucount32 index) __THROW;
+
+void cyg_thread_set_data(cyg_ucount32 index, CYG_ADDRWORD data) __THROW;
+
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Thread destructors */
+
+#ifdef CYGPKG_KERNEL_THREADS_DESTRUCTORS
+
+typedef void (*cyg_thread_destructor_fn)(cyg_addrword_t);
+
+cyg_bool_t cyg_thread_add_destructor( cyg_thread_destructor_fn fn,
+ cyg_addrword_t data ) __THROW;
+cyg_bool_t cyg_thread_rem_destructor( cyg_thread_destructor_fn fn,
+ cyg_addrword_t data ) __THROW;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Exception handling. */
+
+/* Replace current exception handler, this may apply to either the */
+/* current thread, or to a global exception handler. The exception */
+/* number may be ignored, or used to specify a particular handler. */
+
+void cyg_exception_set_handler(
+ cyg_code_t exception_number,
+ cyg_exception_handler_t *new_handler,
+ cyg_addrword_t new_data,
+ cyg_exception_handler_t **old_handler,
+ cyg_addrword_t *old_data
+) __THROW;
+
+/* Clear exception hander to default value */
+void cyg_exception_clear_handler(
+ cyg_code_t exception_number
+) __THROW;
+
+/* Invoke exception handler */
+void cyg_exception_call_handler(
+ cyg_handle_t thread,
+ cyg_code_t exception_number,
+ cyg_addrword_t exception_info
+) __THROW;
+
+
+/*---------------------------------------------------------------------------*/
+/* Interrupt handling */
+typedef void cyg_VSR_t(void);
+typedef cyg_uint32 cyg_ISR_t(cyg_vector_t vector, cyg_addrword_t data);
+typedef void cyg_DSR_t( cyg_vector_t vector,
+ cyg_ucount32 count,
+ cyg_addrword_t data);
+
+
+enum cyg_ISR_results
+{
+ CYG_ISR_HANDLED = 1, /* Interrupt was handled */
+ CYG_ISR_CALL_DSR = 2 /* Schedule DSR */
+};
+
+void cyg_interrupt_create(
+ cyg_vector_t vector, /* Vector to attach to */
+ cyg_priority_t priority, /* Queue priority */
+ cyg_addrword_t data, /* Data pointer */
+ cyg_ISR_t *isr, /* Interrupt Service Routine */
+ cyg_DSR_t *dsr, /* Deferred Service Routine */
+ cyg_handle_t *handle, /* returned handle */
+ cyg_interrupt *intr /* put interrupt here */
+) __THROW;
+
+void cyg_interrupt_delete( cyg_handle_t interrupt ) __THROW;
+
+void cyg_interrupt_attach( cyg_handle_t interrupt ) __THROW;
+
+void cyg_interrupt_detach( cyg_handle_t interrupt ) __THROW;
+
+/* VSR manipulation */
+
+void cyg_interrupt_get_vsr(
+ cyg_vector_t vector, /* vector to get */
+ cyg_VSR_t **vsr /* vsr got */
+) __THROW;
+
+void cyg_interrupt_set_vsr(
+ cyg_vector_t vector, /* vector to set */
+ cyg_VSR_t *vsr /* vsr to set */
+) __THROW;
+
+/* CPU level interrupt mask */
+void cyg_interrupt_disable(void) __THROW;
+
+void cyg_interrupt_enable(void) __THROW;
+
+/* Interrupt controller access */
+void cyg_interrupt_mask(cyg_vector_t vector) __THROW;
+void cyg_interrupt_mask_intunsafe(cyg_vector_t vector) __THROW;
+
+void cyg_interrupt_unmask(cyg_vector_t vector) __THROW;
+void cyg_interrupt_unmask_intunsafe(cyg_vector_t vector) __THROW;
+
+void cyg_interrupt_acknowledge(cyg_vector_t vector) __THROW;
+
+void cyg_interrupt_configure(
+ cyg_vector_t vector, /* vector to configure */
+ cyg_bool_t level, /* level or edge triggered */
+ cyg_bool_t up /* rising/faling edge, high/low level*/
+) __THROW;
+
+void cyg_interrupt_set_cpu(
+ cyg_vector_t vector, /* vector to control */
+ cyg_cpu_t cpu /* CPU to set */
+) __THROW;
+
+cyg_cpu_t cyg_interrupt_get_cpu(
+ cyg_vector_t vector /* vector to control */
+) __THROW;
+
+/*---------------------------------------------------------------------------*/
+/* Counters, Clocks and Alarms */
+
+void cyg_counter_create(
+ cyg_handle_t *handle, /* returned counter handle */
+ cyg_counter *counter /* put counter here */
+) __THROW;
+
+void cyg_counter_delete(cyg_handle_t counter) __THROW;
+
+/* Return current value of counter */
+cyg_tick_count_t cyg_counter_current_value(cyg_handle_t counter) __THROW;
+
+/* Set new current value */
+void cyg_counter_set_value(
+ cyg_handle_t counter,
+ cyg_tick_count_t new_value
+) __THROW;
+
+/* Advance counter by one tick */
+void cyg_counter_tick(cyg_handle_t counter) __THROW;
+
+/* Advance counter by multiple ticks */
+void cyg_counter_multi_tick(cyg_handle_t counter, cyg_tick_count_t _ticks) __THROW;
+
+
+#define CYG_RESOLUTION_T_MEMBERS \
+ cyg_uint32 dividend; \
+ cyg_uint32 divisor;
+
+typedef struct
+{
+ CYG_RESOLUTION_T_MEMBERS
+} cyg_resolution_t;
+
+/* Create a clock object */
+void cyg_clock_create(
+ cyg_resolution_t resolution, /* Initial resolution */
+ cyg_handle_t *handle, /* Returned clock handle */
+ cyg_clock *clock /* put clock here */
+) __THROW;
+
+void cyg_clock_delete(cyg_handle_t clock) __THROW;
+
+/* convert a clock handle to a counter handle so we can use the */
+/* counter API on it. */
+void cyg_clock_to_counter(
+ cyg_handle_t clock,
+ cyg_handle_t *counter
+) __THROW;
+
+void cyg_clock_set_resolution(
+ cyg_handle_t clock,
+ cyg_resolution_t resolution /* New resolution */
+) __THROW;
+
+cyg_resolution_t cyg_clock_get_resolution(cyg_handle_t clock) __THROW;
+
+/* handle of real time clock */
+cyg_handle_t cyg_real_time_clock(void) __THROW;
+
+/* returns value of real time clock's counter.
+ This is the same as:
+ (cyg_clock_to_counter(cyg_real_time_clock(), &h),
+ cyg_counter_current_value(h)) */
+cyg_tick_count_t cyg_current_time(void) __THROW;
+
+/* Alarm handler function */
+typedef void cyg_alarm_t(cyg_handle_t alarm, cyg_addrword_t data);
+
+void cyg_alarm_create(
+ cyg_handle_t counter, /* Attached to this counter */
+ cyg_alarm_t *alarmfn, /* Call-back function */
+ cyg_addrword_t data, /* Call-back data */
+ cyg_handle_t *handle, /* Returned alarm object */
+ cyg_alarm *alarm /* put alarm here */
+) __THROW;
+
+/* Disable alarm, detach from counter and invalidate handles */
+void cyg_alarm_delete( cyg_handle_t alarm) __THROW;
+
+void cyg_alarm_initialize(
+ cyg_handle_t alarm,
+ cyg_tick_count_t trigger, /* Absolute trigger time */
+ cyg_tick_count_t interval /* Relative retrigger interval */
+) __THROW;
+
+void cyg_alarm_get_times(
+ cyg_handle_t alarm,
+ cyg_tick_count_t *trigger, /* Next trigger time */
+ cyg_tick_count_t *interval /* Current interval */
+) __THROW;
+
+void cyg_alarm_enable( cyg_handle_t alarm ) __THROW;
+
+void cyg_alarm_disable( cyg_handle_t alarm ) __THROW;
+
+/*---------------------------------------------------------------------------*/
+/* Mail boxes */
+void cyg_mbox_create(
+ cyg_handle_t *handle,
+ cyg_mbox *mbox
+) __THROW;
+
+void cyg_mbox_delete(cyg_handle_t mbox) __THROW;
+
+void *cyg_mbox_get(cyg_handle_t mbox) __THROW;
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+void *cyg_mbox_timed_get(
+ cyg_handle_t mbox,
+ cyg_tick_count_t abstime
+ ) __THROW;
+#endif
+
+void *cyg_mbox_tryget(cyg_handle_t mbox) __THROW;
+
+void *cyg_mbox_peek_item(cyg_handle_t mbox) __THROW;
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+cyg_bool_t cyg_mbox_put(cyg_handle_t mbox, void *item) __THROW;
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+cyg_bool_t cyg_mbox_timed_put(
+ cyg_handle_t mbox,
+ void *item,
+ cyg_tick_count_t abstime
+ ) __THROW;
+#endif
+#endif
+
+cyg_bool_t cyg_mbox_tryput(cyg_handle_t mbox, void *item) __THROW;
+
+cyg_count32 cyg_mbox_peek(cyg_handle_t mbox) __THROW;
+
+cyg_bool_t cyg_mbox_waiting_to_get(cyg_handle_t mbox) __THROW;
+
+cyg_bool_t cyg_mbox_waiting_to_put(cyg_handle_t mbox) __THROW;
+
+
+/*-----------------------------------------------------------------------*/
+/* Memory pools */
+
+/* These definitions are found in the "memalloc" package as this is */
+/* where the implementation lives. */
+
+#ifdef CYGPKG_MEMALLOC
+# include <cyg/memalloc/kapi.h>
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Semaphores */
+
+void cyg_semaphore_init(
+ cyg_sem_t *sem, /* Semaphore to init */
+ cyg_count32 val /* Initial semaphore value */
+) __THROW;
+
+void cyg_semaphore_destroy( cyg_sem_t *sem ) __THROW;
+
+cyg_bool_t cyg_semaphore_wait( cyg_sem_t *sem ) __THROW;
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+cyg_bool_t cyg_semaphore_timed_wait(
+ cyg_sem_t *sem,
+ cyg_tick_count_t abstime
+ ) __THROW;
+#endif
+
+cyg_bool_t cyg_semaphore_trywait( cyg_sem_t *sem ) __THROW;
+
+void cyg_semaphore_post( cyg_sem_t *sem ) __THROW;
+
+void cyg_semaphore_peek( cyg_sem_t *sem, cyg_count32 *val ) __THROW;
+
+/*---------------------------------------------------------------------------*/
+/* Flags */
+
+typedef cyg_uint32 cyg_flag_value_t;
+typedef cyg_uint8 cyg_flag_mode_t;
+#define CYG_FLAG_WAITMODE_AND ((cyg_flag_mode_t)0) /* all bits must be set */
+#define CYG_FLAG_WAITMODE_OR ((cyg_flag_mode_t)2) /* any bit must be set */
+#define CYG_FLAG_WAITMODE_CLR ((cyg_flag_mode_t)1) /* clear when satisfied */
+
+void cyg_flag_init(
+ cyg_flag_t *flag /* Flag to init */
+) __THROW;
+
+void cyg_flag_destroy( cyg_flag_t *flag ) __THROW;
+
+/* bitwise-or in the bits in value; awaken any waiting tasks whose
+ condition is now satisfied */
+void cyg_flag_setbits( cyg_flag_t *flag, cyg_flag_value_t value) __THROW;
+
+/* bitwise-and with the the bits in value; this clears the bits which
+ are not set in value. No waiting task can be awoken. */
+void cyg_flag_maskbits( cyg_flag_t *flag, cyg_flag_value_t value) __THROW;
+
+/* wait for the flag value to match the pattern, according to the mode.
+ If mode includes CLR, set the flag value to zero when
+ our pattern is matched. The return value is that which matched
+ the request, or zero for an error/timeout return.
+ Value must not itself be zero. */
+cyg_flag_value_t cyg_flag_wait( cyg_flag_t *flag,
+ cyg_flag_value_t pattern,
+ cyg_flag_mode_t mode ) __THROW;
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+cyg_flag_value_t cyg_flag_timed_wait( cyg_flag_t *flag,
+ cyg_flag_value_t pattern,
+ cyg_flag_mode_t mode,
+ cyg_tick_count_t abstime ) __THROW;
+
+#endif
+
+cyg_flag_value_t cyg_flag_poll( cyg_flag_t *flag,
+ cyg_flag_value_t pattern,
+ cyg_flag_mode_t mode ) __THROW;
+
+cyg_flag_value_t cyg_flag_peek( cyg_flag_t *flag ) __THROW;
+
+cyg_bool_t cyg_flag_waiting( cyg_flag_t *flag ) __THROW;
+
+/*---------------------------------------------------------------------------*/
+/* Mutex */
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+enum cyg_mutex_protocol
+{
+ CYG_MUTEX_NONE = 0, // no inversion protocol
+ CYG_MUTEX_INHERIT, // priority inheritance protocol
+ CYG_MUTEX_CEILING // priority ceiling protocol
+};
+#endif
+
+void cyg_mutex_init(
+ cyg_mutex_t *mutex /* Mutex to init */
+) __THROW;
+
+void cyg_mutex_destroy( cyg_mutex_t *mutex ) __THROW;
+
+cyg_bool_t cyg_mutex_lock( cyg_mutex_t *mutex ) __THROW;
+
+cyg_bool_t cyg_mutex_trylock( cyg_mutex_t *mutex ) __THROW;
+
+void cyg_mutex_unlock( cyg_mutex_t *mutex ) __THROW;
+
+void cyg_mutex_release( cyg_mutex_t *mutex ) __THROW;
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+void cyg_mutex_set_ceiling( cyg_mutex_t *mutex, cyg_priority_t priority ) __THROW;
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+void cyg_mutex_set_protocol ( cyg_mutex_t *mutex, enum cyg_mutex_protocol protocol ) __THROW;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Condition Variables */
+
+void cyg_cond_init(
+ cyg_cond_t *cond, /* condition variable to init */
+ cyg_mutex_t *mutex /* associated mutex */
+) __THROW;
+
+void cyg_cond_destroy( cyg_cond_t *cond ) __THROW;
+
+cyg_bool_t cyg_cond_wait( cyg_cond_t *cond ) __THROW;
+
+void cyg_cond_signal( cyg_cond_t *cond ) __THROW;
+
+void cyg_cond_broadcast( cyg_cond_t *cond ) __THROW;
+
+#ifdef CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT
+cyg_bool_t cyg_cond_timed_wait(
+ cyg_cond_t *cond,
+ cyg_tick_count_t abstime
+ ) __THROW;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Spinlocks */
+
+void cyg_spinlock_init(
+ cyg_spinlock_t *lock, /* spinlock to initialize */
+ cyg_bool_t locked /* init locked or unlocked */
+) __THROW;
+
+void cyg_spinlock_destroy( cyg_spinlock_t *lock ) __THROW;
+
+void cyg_spinlock_spin( cyg_spinlock_t *lock ) __THROW;
+
+void cyg_spinlock_clear( cyg_spinlock_t *lock ) __THROW;
+
+cyg_bool_t cyg_spinlock_try( cyg_spinlock_t *lock ) __THROW;
+
+cyg_bool_t cyg_spinlock_test( cyg_spinlock_t *lock ) __THROW;
+
+void cyg_spinlock_spin_intsave( cyg_spinlock_t *lock,
+ cyg_addrword_t *istate ) __THROW;
+
+void cyg_spinlock_clear_intsave( cyg_spinlock_t *lock,
+ cyg_addrword_t istate ) __THROW;
+
+/*---------------------------------------------------------------------------*/
+#ifdef __cplusplus
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+
+#include <cyg/kernel/kapidata.h>
+
+/*---------------------------------------------------------------------------*/
+/* EOF kapi.h */
+#endif /* CYGFUN_KERNEL_API_C */
+#endif /* CYGONCE_KERNEL_KAPI_H */
diff --git a/ecos/packages/kernel/current/include/kapidata.h b/ecos/packages/kernel/current/include/kapidata.h
new file mode 100644
index 0000000000..33efc7723d
--- /dev/null
+++ b/ecos/packages/kernel/current/include/kapidata.h
@@ -0,0 +1,554 @@
+#ifndef CYGONCE_KERNEL_KAPIDATA_H
+#define CYGONCE_KERNEL_KAPIDATA_H
+
+/*=============================================================================
+//
+// kapidata.h
+//
+// Native API data structures
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2002 Bart Veer
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1998-03-13
+// Purpose: Native API data structures
+// Description: This file defines the structures used in the native API. The
+// sizes of these structures are dependent on the system
+// configuration and must be kept in step with their real
+// counterparts in the C++ headers.
+// IMPORTANT: It is NOT guaranteed that the fields of these
+// structures correspond to the equivalent fields in the
+// C++ classes they shadow.
+//
+// One oddity with this file is that the way many of the "mirror"
+// classes are defined with macros. The resulting structures
+// then have a "flat" layout, rather than just declaring a
+// member structure directly in the structure. The reason for
+// this is that as of GCC 3.x, the C++ compiler will optimise
+// classes by removing padding and reusing it for subsequent
+// members defined in a derived class. This affects some targets
+// (including PowerPC and MIPS at least) when a C++ base class
+// includes a long long. By instead arranging for the C structure
+// to just list all the members directly, the compiler will then
+// behave the same for the C structures as the C++ classes.
+//
+// This means that care has to be taken to follow the same
+// methodology if new stuff is added to this file. Even if
+// it doesn't contain long longs for your target, it may for
+// others, depending on HAL definitions.
+//
+// Usage: included by kapi.h
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================*/
+
+#include <pkgconf/system.h>
+#include <pkgconf/kernel.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/hal/hal_intr.h> // exception defines
+
+/*---------------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*---------------------------------------------------------------------------*/
+
+#ifndef CYGNUM_KERNEL_SCHED_BITMAP_SIZE
+#if defined(CYGSEM_KERNEL_SCHED_MLQUEUE)
+#define CYGNUM_KERNEL_SCHED_BITMAP_SIZE 32
+#elif defined(CYGSEM_KERNEL_SCHED_BITMAP)
+#define CYGNUM_KERNEL_SCHED_BITMAP_SIZE 32
+#endif
+#endif
+
+#if CYGNUM_KERNEL_SCHED_BITMAP_SIZE <= 8
+typedef cyg_ucount8 cyg_sched_bitmap;
+#elif CYGNUM_KERNEL_SCHED_BITMAP_SIZE <= 16
+typedef cyg_ucount16 cyg_sched_bitmap;
+#elif CYGNUM_KERNEL_SCHED_BITMAP_SIZE <= 32
+typedef cyg_ucount32 cyg_sched_bitmap;
+#elif CYGNUM_KERNEL_SCHED_BITMAP_SIZE <= 64
+typedef cyg_ucount64 cyg_sched_bitmap;
+#else
+#error Bitmaps greater than 64 bits not currently allowed
+#endif
+
+typedef struct
+{
+#if defined(CYGSEM_KERNEL_SCHED_BITMAP)
+
+ cyg_sched_bitmap map;
+
+#elif defined(CYGSEM_KERNEL_SCHED_MLQUEUE)
+
+ cyg_thread *queue;
+
+#elif defined(CYGSEM_KERNEL_SCHED_LOTTERY)
+
+ cyg_thread *queue;
+
+#else
+
+#error Undefined scheduler type
+
+#endif
+} cyg_threadqueue;
+
+/*---------------------------------------------------------------------------*/
+
+struct cyg_interrupt
+{
+ cyg_vector_t vector;
+ cyg_priority_t priority;
+ cyg_ISR_t *isr;
+ cyg_DSR_t *dsr;
+ CYG_ADDRWORD data;
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
+ cyg_ucount32 dsr_count;
+ cyg_interrupt *next_dsr;
+#endif
+#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
+ cyg_interrupt *next;
+#endif
+};
+
+
+/*---------------------------------------------------------------------------*/
+
+
+#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)
+# define CYG_COUNTER_ALARM_LIST_MEMBER \
+ cyg_alarm *alarm_list;
+#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)
+# define CYG_COUNTER_ALARM_LIST_MEMBER \
+ cyg_alarm *alarm_list[CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE];
+#else
+# define CYG_COUNTER_ALARM_LIST_MEMBER
+#endif
+
+#define CYG_COUNTER_MEMBERS \
+ CYG_COUNTER_ALARM_LIST_MEMBER \
+ cyg_tick_count_t counter; \
+ cyg_uint32 increment;
+
+struct cyg_counter
+{
+ CYG_COUNTER_MEMBERS
+};
+
+/*---------------------------------------------------------------------------*/
+
+struct cyg_clock
+{
+ CYG_COUNTER_MEMBERS
+ CYG_RESOLUTION_T_MEMBERS
+};
+
+/*---------------------------------------------------------------------------*/
+
+
+#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST) || \
+ defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)
+# define CYG_ALARM_LIST_MEMBERS \
+ cyg_alarm *next; \
+ cyg_alarm *prev;
+#else
+# define CYG_ALARM_LIST_MEMBERS
+#endif
+
+#define CYG_ALARM_MEMBERS \
+ CYG_ALARM_LIST_MEMBERS \
+ cyg_counter *counter; \
+ cyg_alarm_t *alarm; \
+ CYG_ADDRWORD data; \
+ cyg_tick_count_t trigger; \
+ cyg_tick_count_t interval; \
+ cyg_bool enabled;
+
+struct cyg_alarm
+{
+ CYG_ALARM_MEMBERS
+};
+
+/*---------------------------------------------------------------------------*/
+/* Exception controller */
+
+#ifdef CYGPKG_KERNEL_EXCEPTIONS
+
+# ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE
+# define CYG_EXCEPTION_CONTROL_MEMBERS \
+ cyg_exception_handler_t *exception_handler[CYGNUM_HAL_EXCEPTION_COUNT]; \
+ CYG_ADDRWORD exception_data[CYGNUM_HAL_EXCEPTION_COUNT];
+# else
+# define CYG_EXCEPTION_CONTROL_MEMBERS \
+ cyg_exception_handler_t *exception_handler; /* Handler function */ \
+ CYG_ADDRWORD exception_data; /* Handler data */
+# endif
+
+typedef struct
+{
+ CYG_EXCEPTION_CONTROL_MEMBERS
+} cyg_exception_control;
+
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Hardware Thread structure */
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
+# define CYG_HARDWARETHREAD_STACK_LIMIT_MEMBER \
+ CYG_ADDRESS stack_limit; /* movable stack limit */
+#else
+# define CYG_HARDWARETHREAD_STACK_LIMIT_MEMBER
+#endif
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+# define CYG_HARDWARETHREAD_SAVED_CONTEXT_MEMBER \
+ void *saved_context; // If non-zero, this points at a more
+ // interesting context than stack_ptr.
+#else
+# define CYG_HARDWARETHREAD_SAVED_CONTEXT_MEMBER
+#endif
+
+typedef void cyg_thread_entry(CYG_ADDRWORD data);
+
+#define CYG_HARDWARETHREAD_MEMBERS \
+ CYG_ADDRESS stack_base; /* pointer to base of stack area */ \
+ cyg_uint32 stack_size; /* size of stack area in bytes */ \
+ CYG_HARDWARETHREAD_STACK_LIMIT_MEMBER \
+ CYG_ADDRESS stack_ptr; /* pointer to saved state on stack */ \
+ cyg_thread_entry *entry_point; /* main entry point (code pointer!) */ \
+ CYG_ADDRWORD entry_data; /* entry point argument */ \
+ CYG_HARDWARETHREAD_SAVED_CONTEXT_MEMBER
+
+typedef struct
+{
+ CYG_HARDWARETHREAD_MEMBERS
+} cyg_hardwarethread;
+
+/*---------------------------------------------------------------------------*/
+/* Scheduler Thread structure */
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+# define CYG_SCHEDTHREAD_CPU_MEMBER \
+ cyg_uint32 cpu; // CPU id of cpu currently running
+#else
+# define CYG_SCHEDTHREAD_CPU_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
+#endif
+
+#if defined(CYGSEM_KERNEL_SCHED_BITMAP)
+# define CYG_SCHEDTHREAD_SCHEDIMP_MEMBERS \
+ cyg_priority_t priority; /* current thread priority */
+#elif defined(CYGSEM_KERNEL_SCHED_MLQUEUE)
+# 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_ENABLED_MEMBER
+#elif defined(CYGSEM_KERNEL_SCHED_LOTTERY)
+# define CYG_SCHEDTHREAD_SCHEDIMP_MEMBERS \
+ cyg_thread *next; \
+ cyg_thread *prev; \
+ cyg_priority_t priority; /* current thread priority */ \
+ cyg_priority_t compensation_tickets; /* sleep compensation */
+#else
+# error Undefined scheduler type
+#endif
+
+#ifndef CYGSEM_KERNEL_SCHED_ASR_GLOBAL
+# define CYG_SCHEDTHREAD_ASR_NONGLOBAL_MEMBER \
+ void (*asr)(CYG_ADDRWORD); // ASR function
+#else
+# define CYG_SCHEDTHREAD_ASR_NONGLOBAL_MEMBER
+#endif
+
+#ifndef CYGSEM_KERNEL_SCHED_ASR_DATA_GLOBAL
+# define CYG_SCHEDTHREAD_ASR_DATA_NONGLOBAL_MEMBER \
+ CYG_ADDRWORD asr_data; // ASR data pointer
+#else
+# define CYG_SCHEDTHREAD_ASR_DATA_NONGLOBAL_MEMBER
+#endif
+
+#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
+# define CYG_SCHEDTHREAD_ASR_MEMBER \
+ volatile cyg_ucount32 asr_inhibit; /* If true, blocks calls to ASRs */ \
+ volatile cyg_bool asr_pending; /* If true, this thread's ASR */ \
+ /* should be called. */ \
+ CYG_SCHEDTHREAD_ASR_NONGLOBAL_MEMBER \
+ CYG_SCHEDTHREAD_ASR_DATA_NONGLOBAL_MEMBER
+#else
+# define CYG_SCHEDTHREAD_ASR_MEMBER
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
+# define CYG_SCHEDTHREAD_MUTEX_INV_PROTO_SIMPLE_MEMBERS \
+ cyg_priority_t original_priority; \
+ cyg_bool priority_inherited;
+#else
+# define CYG_SCHEDTHREAD_MUTEX_INV_PROTO_SIMPLE_MEMBERS
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
+# define CYG_SCHEDTHREAD_MUTEX_INV_PROTO_MEMBERS \
+ cyg_count32 mutex_count; \
+ CYG_SCHEDTHREAD_MUTEX_INV_PROTO_SIMPLE_MEMBERS
+#else
+# define CYG_SCHEDTHREAD_MUTEX_INV_PROTO_MEMBERS
+#endif
+
+#define CYG_SCHEDTHREAD_MEMBERS \
+ CYG_SCHEDTHREAD_SCHEDIMP_MEMBERS \
+ cyg_threadqueue *queue; \
+ CYG_SCHEDTHREAD_ASR_MEMBER \
+ CYG_SCHEDTHREAD_MUTEX_INV_PROTO_MEMBERS
+
+
+typedef struct
+{
+ CYG_SCHEDTHREAD_MEMBERS
+} cyg_schedthread;
+
+/* This compiler version test is required because the C++ ABI changed in
+ GCC v3.x and GCC could now reuse "spare" space from base classes in derived
+ classes, and in C++ land, cyg_alarm is a base class of cyg_threadtimer.
+*/
+#if defined(__GNUC__) && (__GNUC__ < 3)
+#define CYG_THREADTIMER_MEMBERS \
+ cyg_alarm alarm; \
+ cyg_thread *thread;
+#else
+#define CYG_THREADTIMER_MEMBERS \
+ CYG_ALARM_MEMBERS \
+ cyg_thread *thread;
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Thread structure */
+
+typedef struct
+{
+ CYG_THREADTIMER_MEMBERS
+} cyg_threadtimer;
+
+
+typedef enum
+{
+ CYG_REASON_NONE,
+ CYG_REASON_WAIT,
+ CYG_REASON_DELAY,
+ CYG_REASON_TIMEOUT,
+ CYG_REASON_BREAK,
+ CYG_REASON_DESTRUCT,
+ CYG_REASON_EXIT,
+ CYG_REASON_DONE
+} cyg_reason_t;
+
+#if defined(CYGPKG_KERNEL_EXCEPTIONS) && !defined(CYGSEM_KERNEL_EXCEPTIONS_GLOBAL)
+# define CYG_THREAD_EXCEPTION_CONTROL_MEMBER \
+ cyg_exception_control exception_control;
+#else
+# define CYG_THREAD_EXCEPTION_CONTROL_MEMBER
+#endif
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+# define CYG_THREAD_TIMER_MEMBER \
+ cyg_threadtimer timer;
+#else
+# define CYG_THREAD_TIMER_MEMBER
+#endif
+
+#ifdef CYGVAR_KERNEL_THREADS_DATA
+# define CYG_THREAD_THREAD_DATA_MEMBER \
+ CYG_ADDRWORD thread_data[CYGNUM_KERNEL_THREADS_DATA_MAX];
+#else
+# define CYG_THREAD_THREAD_DATA_MEMBER
+#endif
+
+#ifdef CYGVAR_KERNEL_THREADS_NAME
+# define CYG_THREAD_NAME_MEMBER \
+ char *name;
+#else
+# define CYG_THREAD_NAME_MEMBER
+#endif
+
+#ifdef CYGVAR_KERNEL_THREADS_LIST
+# define CYG_THREAD_LIST_NEXT_MEMBER \
+ cyg_thread *list_next;
+#else
+# define CYG_THREAD_LIST_NEXT_MEMBER
+#endif
+
+
+
+#ifdef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+struct Cyg_Destructor_Entry {
+ cyg_thread_destructor_fn fn;
+ cyg_addrword_t data;
+};
+# define CYG_THREAD_DESTRUCTORS_MEMBER \
+ struct Cyg_Destructor_Entry destructors[ CYGNUM_KERNEL_THREADS_DESTRUCTORS ];
+#else
+# define CYG_THREAD_DESTRUCTORS_MEMBER
+#endif
+
+
+#define CYG_THREAD_MEMBERS \
+ CYG_HARDWARETHREAD_MEMBERS \
+ CYG_SCHEDTHREAD_MEMBERS \
+ \
+ cyg_uint32 state; \
+ cyg_ucount32 suspend_count; \
+ cyg_ucount32 wakeup_count; \
+ CYG_ADDRWORD wait_info; \
+ cyg_uint16 unique_id; \
+ \
+ CYG_THREAD_EXCEPTION_CONTROL_MEMBER \
+ CYG_THREAD_TIMER_MEMBER \
+ \
+ cyg_reason_t sleep_reason; \
+ cyg_reason_t wake_reason; \
+ \
+ CYG_THREAD_THREAD_DATA_MEMBER \
+ CYG_THREAD_DESTRUCTORS_MEMBER \
+ CYG_THREAD_NAME_MEMBER \
+ CYG_THREAD_LIST_NEXT_MEMBER
+
+
+struct cyg_thread
+{
+ CYG_THREAD_MEMBERS
+};
+
+/*---------------------------------------------------------------------------*/
+
+struct cyg_mbox
+{
+ cyg_count32 base; /* index of first used slot */
+ cyg_count32 count; /* count of used slots */
+ cyg_threadqueue get_threadq; /* Queue of waiting threads */
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ cyg_threadqueue put_threadq; /* Queue of waiting threads */
+#endif
+ void * itemqueue[ CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE ];
+};
+
+/*---------------------------------------------------------------------------*/
+
+struct cyg_sem_t
+{
+ cyg_count32 count; /* The semaphore count */
+ cyg_threadqueue queue; /* Queue of waiting threads */
+};
+
+/*---------------------------------------------------------------------------*/
+
+struct cyg_flag_t
+{
+ cyg_flag_value_t value; /* The flag value */
+ cyg_threadqueue queue; /* Queue of waiting threads */
+};
+
+/*---------------------------------------------------------------------------*/
+
+typedef enum
+{
+ CYG_MUTEX_PROTOCOL_NONE,
+ CYG_MUTEX_PROTOCOL_INHERIT,
+ CYG_MUTEX_PROTOCOL_CEILING
+} cyg_mutex_protocol_t;
+
+struct cyg_mutex_t
+{
+ cyg_atomic locked; /* true if locked */
+ cyg_thread *owner; /* Current locking thread */
+ cyg_threadqueue queue; /* Queue of waiting threads */
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+ cyg_mutex_protocol_t protocol; /* this mutex's protocol */
+#endif
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+ cyg_priority_t ceiling; /* mutex priority ceiling */
+#endif
+
+};
+
+/*---------------------------------------------------------------------------*/
+
+struct cyg_cond_t
+{
+ cyg_mutex_t *mutex; /* Associated mutex */
+ cyg_threadqueue queue; /* Queue of waiting threads */
+};
+
+/*------------------------------------------------------------------------*/
+
+struct cyg_spinlock_t
+{
+ cyg_uint32 lock; /* lock word */
+};
+
+/*------------------------------------------------------------------------*/
+
+/* Memory allocator types now come from the "memalloc" package which is */
+/* where the implementation lives. */
+
+#ifdef CYGPKG_MEMALLOC
+# include <cyg/memalloc/kapidata.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* EOF kapidata.h */
+#endif /* CYGONCE_KERNEL_KAPIDATA_H */
diff --git a/ecos/packages/kernel/current/include/kernel.hxx b/ecos/packages/kernel/current/include/kernel.hxx
new file mode 100644
index 0000000000..eb5802962e
--- /dev/null
+++ b/ecos/packages/kernel/current/include/kernel.hxx
@@ -0,0 +1,86 @@
+#ifndef CYGONCE_KERNEL_KERNEL_HXX
+#define CYGONCE_KERNEL_KERNEL_HXX
+
+//==========================================================================
+//
+// kernel.hxx
+//
+// Kernel mega-include file
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-09
+// Purpose: Include all kernel files
+// Description: This file contains includes for all the kernel
+// headers. This simplifys things in the sources.
+// Usage: #include <cyg/kernel/kernel.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h>
+
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/infra/cyg_trac.h> // tracing macros
+
+#include <cyg/kernel/errors.h>
+
+#include <cyg/kernel/instrmnt.h>
+
+#include <cyg/kernel/diag.h>
+
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/intr.hxx>
+#include <cyg/kernel/clock.hxx>
+
+#include <cyg/kernel/sema.hxx>
+#include <cyg/kernel/mutex.hxx>
+
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/clock.inl>
+
+// -------------------------------------------------------------------------
+#endif // #ifndef CYGONCE_KERNEL_KERNEL_HXX
+// EOF kernel.hxx
diff --git a/ecos/packages/kernel/current/include/ktypes.h b/ecos/packages/kernel/current/include/ktypes.h
new file mode 100644
index 0000000000..d5d85cc0b7
--- /dev/null
+++ b/ecos/packages/kernel/current/include/ktypes.h
@@ -0,0 +1,129 @@
+#ifndef CYGONCE_KERNEL_KTYPES_H
+#define CYGONCE_KERNEL_KTYPES_H
+
+//==========================================================================
+//
+// ktypes.h
+//
+// Standard types used in the kernel and its interfaces
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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 from an original by hmt
+// Contributors: nickg
+// Date: 1997-09-08
+// Purpose: Define kernel specific types
+// Description: Kernel specific types
+// Usage: #include <cyg/kernel/ktypes.h>
+// ...
+// cyg_priority priority; // etc
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// -------------------------------------------------------------------------
+// Check that a configuration file is present.
+
+#ifndef CYGONCE_PKGCONF_KERNEL_H
+#error "No Configuration file included"
+#endif
+
+// -------------------------------------------------------------------------
+
+#include <cyg/infra/cyg_type.h>
+#include <stddef.h> // for size_t
+
+// -------------------------------------------------------------------------
+// Integer types:
+
+typedef cyg_int32 cyg_code; // General return/error/status code
+
+typedef cyg_count32 cyg_priority; // priority value
+
+typedef cyg_uint32 cyg_vector; // vector number/descriptor
+
+typedef cyg_uint64 cyg_tick_count; // clock tick count value
+
+// -------------------------------------------------------------------------
+// Predefinitions of various kernel classes
+
+#ifdef __cplusplus
+
+class Cyg_Scheduler;
+class Cyg_Scheduler_Implementation;
+
+class Cyg_HardwareThread;
+class Cyg_SchedThread;
+class Cyg_SchedThread_Implementation;
+class Cyg_Thread;
+
+class Cyg_ThreadQueue;
+class Cyg_ThreadQueue_Implementation;
+
+#endif
+
+
+// -------------------------------------------------------------------------
+// Class and structure conversion macros.
+// CYG_CLASSFROMFIELD translates a pointer to a field of a struct or
+// class into a pointer to the class.
+// CYG_OFFSETOFBASE yields the offset of a base class of a derived
+// class.
+// CYG_CLASSFROMBASE translates a pointer to a base class into a pointer
+// to a selected derived class. The base class object _must_ be part of
+// the specified derived class. This is essentially a poor mans version
+// of the RTTI dynamic_cast operator.
+// Caveat: These macros do not work for virtual base classes.
+
+#define CYG_CLASSFROMFIELD(_type_,_member_,_ptr_)\
+ ((_type_ *)((char *)(_ptr_)-((char *)&(((_type_ *)0)->_member_))))
+
+#ifdef __cplusplus
+
+#define CYG_OFFSETOFBASE(_type_,_base_)\
+ ((char *)((_base_ *)((_type_ *)4)) - (char *)4)
+
+# define CYG_CLASSFROMBASE(_class_,_base_,_ptr_)\
+ ((_class_ *)((char *)(_ptr_) - CYG_OFFSETOFBASE(_class_,_base_)))
+
+#endif
+
+// -------------------------------------------------------------------------
+#endif // CYGONCE_KERNEL_KTYPES_H
+// EOF ktypes.h
+
diff --git a/ecos/packages/kernel/current/include/llistt.hxx b/ecos/packages/kernel/current/include/llistt.hxx
new file mode 100644
index 0000000000..3aa45bed8b
--- /dev/null
+++ b/ecos/packages/kernel/current/include/llistt.hxx
@@ -0,0 +1,171 @@
+#ifndef CYGONCE_KERNEL_LLISTT_HXX
+#define CYGONCE_KERNEL_LLISTT_HXX
+
+//==========================================================================
+//
+// llistt.hxx
+//
+// Llistt linked list template class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 1998-02-10
+// Purpose: Define Llistt template class
+// Description: The classes defined here provide the APIs for llistts.
+// Usage: #include <cyg/kernel/llistt.hxx>
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/thread.hxx>
+
+// -------------------------------------------------------------------------
+// A simple linked list template; each item also contains a pointer of type
+// T, and you can search for a particular T* in a list.
+//
+// It is intended that this list be amenable to the trick of using the
+// address of the pointer that is the list head, cast to an item pointer,
+// as the "zeroth" element of the list; prev of the first item is the
+// address of the head pointer, and inserting before the first item works
+// correctly. For this reason, a "getprev" is not provided; iteration may
+// only be forwards, until a NULL is found.
+//
+// It is expected that derived classes will be used to hold other
+// information than just the T* but that is beyond our discussion here;
+// only the T* can be searched for using code provided here.
+//
+// This module is NOT thread-safe; it is expected that all clients will be
+// seeing that that themselves.
+
+template <class T>
+class Cyg_Llistt
+{
+private:
+ Cyg_Llistt<T> *next, *prev;
+ T *tptr;
+
+private:
+ // make initialisation _without_ a T* impossible.
+ Cyg_Llistt<T> &operator=(Cyg_Llistt<T> &);
+ Cyg_Llistt(Cyg_Llistt<T> &);
+ Cyg_Llistt();
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Llistt( T *tvalue ) // Constructor
+ {
+ tptr = tvalue;
+ next = prev = NULL;
+ }
+
+ ~Cyg_Llistt() // Destructor
+ {
+ CYG_ASSERT( NULL == next, "bad item next - still in list" );
+ CYG_ASSERT( NULL == prev, "bad item prev - still in list" );
+ }
+
+ // iterator, basically.
+ Cyg_Llistt<T> * getnext() { return next; }
+
+ // get the value
+ T * getitem() { return tptr; }
+
+ // look up a particular T value in the llist
+ static Cyg_Llistt<T> *
+ find( Cyg_Llistt<T> *list, T *tvalue )
+ {
+ for ( ; list ; list = list->next ) {
+ if ( list->tptr == tvalue )
+ break;
+ }
+ return list;
+ }
+
+ // unlink an item from the list
+ void
+ unlink()
+ {
+ CYG_ASSERT( prev, "not in a list" );
+ prev->next = next;
+ if ( next ) {
+ next->prev = prev;
+ }
+ next = prev = NULL;
+ }
+
+ // insert a new item in the list after "this"
+ void
+ insertafter( Cyg_Llistt<T> *item )
+ {
+ CYG_ASSERT( item, "null item" );
+ CYG_ASSERT( NULL == item->next, "bad item next - already linked" );
+ CYG_ASSERT( NULL == item->prev, "bad item prev - already linked" );
+ item->next = next;
+ item->prev = this;
+ if ( next )
+ next->prev = item;
+ next = item;
+ }
+
+ // insert a new item in the list before "this"
+ void
+ insertbefore( Cyg_Llistt<T> *item )
+ {
+ CYG_ASSERT( prev, "this not in a list" );
+ CYG_ASSERT( item, "null item" );
+ CYG_ASSERT( NULL == item->next, "bad item next - already linked" );
+ CYG_ASSERT( NULL == item->prev, "bad item prev - already linked" );
+ item->prev = prev;
+ item->next = this;
+ prev->next = item;
+ prev = item;
+ }
+};
+
+
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_LLISTT_HXX
+// EOF llistt.hxx
diff --git a/ecos/packages/kernel/current/include/lottery.hxx b/ecos/packages/kernel/current/include/lottery.hxx
new file mode 100644
index 0000000000..38db7a65c9
--- /dev/null
+++ b/ecos/packages/kernel/current/include/lottery.hxx
@@ -0,0 +1,223 @@
+#ifndef CYGONCE_KERNEL_LOTTERY_HXX
+#define CYGONCE_KERNEL_LOTTERY_HXX
+
+//==========================================================================
+//
+// lottery.hxx
+//
+// Lottery scheduler class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-10
+// Purpose: Define lottery scheduler implementation
+// Description: The classes defined here are used as base classes
+// by the common classes that define schedulers and thread
+// things. A lottery scheduler provides each thread with a
+// share of the processor based on the number of tickets that
+// it owns.
+// Usage: Included according to configuration by
+// <cyg/kernel/sched.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+
+// -------------------------------------------------------------------------
+// Customize the scheduler
+
+#define CYGIMP_THREAD_PRIORITY 1 // Threads have changable priorities
+
+#define CYG_THREAD_MIN_PRIORITY 1
+#define CYG_THREAD_MAX_PRIORITY 0x7FFFFFFF
+
+// set default scheduling info value for thread constructors.
+#define CYG_SCHED_DEFAULT_INFO CYG_THREAD_MAX_PRIORITY
+
+#error Lottery Scheduler not yet complete, do not use!!!
+
+// -------------------------------------------------------------------------
+// Thread queue implementation.
+// This class provides the (scheduler specific) implementation of the
+// thread queue class.
+
+class Cyg_ThreadQueue_Implementation
+{
+ friend class Cyg_Scheduler_Implementation;
+ friend class Cyg_SchedThread_Implementation;
+
+ Cyg_Thread *queue;
+
+protected:
+
+ // API used by Cyg_ThreadQueue
+
+ // Add thread to queue
+ void enqueue(Cyg_Thread *thread);
+
+ // return first thread on queue
+ Cyg_Thread *highpri();
+
+ // remove first thread on queue
+ Cyg_Thread *dequeue();
+
+ // remove specified thread from queue
+ void remove(Cyg_Thread *thread);
+
+ // test if queue is empty
+ cyg_bool empty();
+
+ void rotate(); // Rotate the queue
+};
+
+inline cyg_bool Cyg_ThreadQueue_Implementation::empty()
+{
+ return queue == NULL;
+}
+
+// -------------------------------------------------------------------------
+// This class contains the implementation details of the scheduler, and
+// provides a standard API for accessing it.
+
+class Cyg_Scheduler_Implementation
+ : public Cyg_Scheduler_Base
+{
+ friend class Cyg_ThreadQueue_Implementation;
+ friend class Cyg_SchedThread_Implementation;
+
+ // All runnable threads are kept on a single run queue
+ // in MRU order.
+ Cyg_ThreadQueue_Implementation run_queue;
+
+ cyg_uint32 rand_seed;
+
+ cyg_int32 total_tickets;
+
+protected:
+
+ Cyg_Scheduler_Implementation(); // Constructor
+
+ // The following functions provide the scheduler implementation
+ // interface to the Cyg_Scheduler class. These are protected
+ // so that only the scheduler can call them.
+
+ // choose a new thread
+ Cyg_Thread *schedule();
+
+ // make thread schedulable
+ void add_thread(Cyg_Thread *thread);
+
+ // make thread un-schedulable
+ void rem_thread(Cyg_Thread *thread);
+
+ // register thread with scheduler
+ void register_thread(Cyg_Thread *thread);
+
+ // deregister thread
+ void deregister_thread(Cyg_Thread *thread);
+
+ // Test the given priority for uniqueness
+ cyg_bool unique( cyg_priority priority);
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+ // If timeslicing is enbled, define a scheduler
+ // entry point to do timeslicing. This will be
+ // called from the RTC DSR.
+
+protected:
+
+ static cyg_count32 timeslice_count;
+
+public:
+ void timeslice();
+
+ static void reset_timeslice_count();
+
+#endif
+
+
+};
+
+// -------------------------------------------------------------------------
+// Cyg_Scheduler_Implementation inlines
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+inline void Cyg_Scheduler_Implementation::reset_timeslice_count()
+{
+ timeslice_count = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Scheduler thread implementation.
+// This class provides the implementation of the scheduler specific parts
+// of each thread.
+
+class Cyg_SchedThread_Implementation
+{
+ friend class Cyg_Scheduler_Implementation;
+ friend class Cyg_ThreadQueue_Implementation;
+
+ Cyg_Thread *next; // next thread in queue
+ Cyg_Thread *prev; // previous thread in queue
+
+ void insert( Cyg_Thread *thread ); // Insert thread in front of this
+
+ void remove(); // remove this from queue
+
+protected:
+
+ cyg_priority priority; // current thread priority == tickets held
+
+ cyg_priority compensation_tickets; // sleep compensation
+
+ Cyg_SchedThread_Implementation(CYG_ADDRWORD sched_info);
+
+ void yield(); // Yield CPU to next thread
+
+};
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_LOTTERY_HXX
+// EOF lottery.hxx
diff --git a/ecos/packages/kernel/current/include/mbox.hxx b/ecos/packages/kernel/current/include/mbox.hxx
new file mode 100644
index 0000000000..2c41729d7a
--- /dev/null
+++ b/ecos/packages/kernel/current/include/mbox.hxx
@@ -0,0 +1,136 @@
+#ifndef CYGONCE_KERNEL_MBOX_HXX
+#define CYGONCE_KERNEL_MBOX_HXX
+
+//==========================================================================
+//
+// mbox.hxx
+//
+// Plain (void *) Mbox (Message Box/Mailbox) class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 1998-02-10
+// Purpose: Define Mbox class interfaces
+// Description: The classes defined here provide the APIs for mboxes.
+// Usage: #include <cyg/kernel/mbox.hxx>
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/thread.hxx>
+
+#ifdef CYGIMP_MBOX_USE_MBOXT_PLAIN
+#include <cyg/kernel/mboxt.hxx>
+#else
+#include <cyg/kernel/mboxt2.hxx>
+#endif
+
+// -------------------------------------------------------------------------
+// Message/Mail Box. This class implements a queue of void * items using
+// the Cyg_Mbox<Type, QSize> template class.
+
+#ifndef CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE
+// default is 10 elements
+#define CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE (10)
+#endif
+
+// Cyg_Mbox has a fixed size array of (void *)s; one size fits all.
+// Because of this, we can simplify the API by returning a NULL for
+// "failed" conditions. Ergo a NULL message is illegal. BFD.
+
+class Cyg_Mbox
+{
+private:
+#ifdef CYGIMP_MBOX_USE_MBOXT_PLAIN
+ Cyg_Mboxt<void *, CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE> m;
+#else
+ Cyg_Mboxt2<void *, CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE> m;
+#endif
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Mbox(); // Constructor
+ ~Cyg_Mbox(); // Destructor
+
+ void * get(); // get an item; wait if none
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ void * get( cyg_tick_count timeout );
+#endif
+ void * tryget(); // just one attempt
+
+ void * peek_item(); // Get next item to be returned
+ // without removing it
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT // then we support it too
+ cyg_bool put( void *item ); // put an item; wait if full
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_bool put( void *item, cyg_tick_count timeout );
+#endif
+#endif
+ cyg_bool tryput( void *item ); // fails if Q full
+
+ inline
+ cyg_count32 peek() // Get current count value
+ {
+ return m.peek();
+ }
+
+ inline
+ cyg_bool waiting_to_get() // Any threads waiting to get?
+ {
+ return m.waiting_to_get();
+ }
+ inline
+ cyg_bool waiting_to_put() // Any threads waiting to put?
+ {
+ return m.waiting_to_put();
+ }
+};
+
+
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_MBOX_HXX
+// End of mbox.hxx
diff --git a/ecos/packages/kernel/current/include/mboxt.hxx b/ecos/packages/kernel/current/include/mboxt.hxx
new file mode 100644
index 0000000000..a2f1a71d71
--- /dev/null
+++ b/ecos/packages/kernel/current/include/mboxt.hxx
@@ -0,0 +1,138 @@
+#ifndef CYGONCE_KERNEL_MBOXT_HXX
+#define CYGONCE_KERNEL_MBOXT_HXX
+
+//==========================================================================
+//
+// mboxt.hxx
+//
+// Mboxt (Message Box/Mailbox) class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 1998-02-10
+// Purpose: Define Mboxt class interfaces
+// Description: The classes defined here provide the APIs for mboxtes.
+// Usage: #include <cyg/kernel/mboxt.hxx>
+// #include <cyg/kernel/mboxt.inl>
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/thread.hxx>
+
+// -------------------------------------------------------------------------
+// Message/Mail Box. This template implements a queue of T's.
+// Implemented as a template for maximal flexibility; one would hope
+// that only one, with T==(void *) and the same number of them,
+// is ever used without very good reason.
+
+// Cyg_Mboxt has a fixed size array of T's; one size fits all.
+
+template <class T, cyg_count32 QUEUE_SIZE>
+class Cyg_Mboxt
+{
+private:
+ cyg_count32 base; // index of first used slot
+ cyg_count32 count; // count of used slots
+ Cyg_ThreadQueue get_threadq; // Queue of waiting threads
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ Cyg_ThreadQueue put_threadq; // Queue of waiting threads
+#endif
+ static const
+ cyg_count32 size = QUEUE_SIZE;
+ T itemqueue[ QUEUE_SIZE ];
+ // queue of items
+ // private utility functions
+ // wake up a thread from some queue
+ inline void wakeup_waiter( Cyg_ThreadQueue &q );
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Mboxt(); // Constructor
+ ~Cyg_Mboxt(); // Destructor
+
+ cyg_bool get( T &ritem ); // get an item; wait if none
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_bool get( T &ritem, cyg_tick_count abs_timeout );
+#endif
+ cyg_bool tryget( T &ritem ); // just one attempt
+
+ cyg_bool peek_item( T &ritem ); // get next item without
+ // removing it
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ cyg_bool put( const T item ); // put an item; wait if full
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_bool put( const T item, cyg_tick_count abs_timeout );
+#endif
+#endif
+ cyg_bool tryput( const T item ); // fails if Q full
+
+ inline
+ cyg_count32 peek() // Get current count value
+ {
+ return count;
+ }
+
+ inline
+ cyg_bool waiting_to_get() // Any threads waiting?
+ {
+ return ! get_threadq.empty();
+ }
+
+ inline
+ cyg_bool waiting_to_put() // Any threads waiting?
+ {
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ return ! put_threadq.empty();
+#else
+ return false;
+#endif
+ }
+};
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_MBOXT_HXX
+// EOF mboxt.hxx
diff --git a/ecos/packages/kernel/current/include/mboxt.inl b/ecos/packages/kernel/current/include/mboxt.inl
new file mode 100644
index 0000000000..e6e4f2554d
--- /dev/null
+++ b/ecos/packages/kernel/current/include/mboxt.inl
@@ -0,0 +1,634 @@
+#ifndef CYGONCE_KERNEL_MBOXT_INL
+#define CYGONCE_KERNEL_MBOXT_INL
+//==========================================================================
+//
+// mboxt.inl
+//
+// Mboxt mbox template class implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 1998-02-10
+// Purpose: Mboxt template implementation
+// Description: This file contains the implementations of the mboxt
+// template classes.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/mboxt.hxx> // our header
+
+#include <cyg/kernel/thread.inl> // thread inlines
+#include <cyg/kernel/sched.inl> // scheduler inlines
+#include <cyg/kernel/clock.inl> // clock inlines
+
+// -------------------------------------------------------------------------
+// inline function for awakening waiting threads
+
+template <class T, cyg_count32 QUEUE_SIZE>
+inline void
+Cyg_Mboxt<T,QUEUE_SIZE>::wakeup_waiter( Cyg_ThreadQueue &q )
+{
+ if( !q.empty() ) {
+ // The queue is non-empty, so grab the next thread and wake it up.
+ Cyg_Thread *thread = q.dequeue();
+
+ CYG_ASSERTCLASS( thread, "Bad thread pointer");
+
+ thread->set_wake_reason( Cyg_Thread::DONE );
+ thread->wake();
+ CYG_INSTRUMENT_MBOXT(WAKE, this, thread);
+ }
+}
+
+// -------------------------------------------------------------------------
+// Constructor
+
+template <class T, cyg_count32 QUEUE_SIZE>
+Cyg_Mboxt<T,QUEUE_SIZE>::Cyg_Mboxt()
+{
+ CYG_REPORT_FUNCTION();
+ base = 0;
+ count = 0;
+}
+
+// -------------------------------------------------------------------------
+// Destructor
+
+template <class T, cyg_count32 QUEUE_SIZE>
+Cyg_Mboxt<T,QUEUE_SIZE>::~Cyg_Mboxt()
+{
+ CYG_REPORT_FUNCTION();
+ CYG_ASSERT( 0 == count, "Deleting mboxt with messages");
+ CYG_ASSERT( get_threadq.empty(), "Deleting mboxt with threads waiting to get");
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ CYG_ASSERT( put_threadq.empty(), "Deleting mboxt with threads waiting to put");
+#endif
+}
+
+// -------------------------------------------------------------------------
+// debugging/assert function
+
+#ifdef CYGDBG_USE_ASSERTS
+
+template <class T, cyg_count32 QUEUE_SIZE>
+cyg_bool
+Cyg_Mboxt<T,QUEUE_SIZE>::check_this(cyg_assert_class_zeal zeal) const
+{
+ CYG_REPORT_FUNCTION();
+
+ if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() )
+ // then the whole thing is invalid, and we know it.
+ // so return OK, since this check should NOT make an error.
+ return true;
+
+ // check that we have a non-NULL pointer first
+ if( this == NULL ) return false;
+
+#if 0 // thread queues do not have checking funcs.
+ if ( ! get_threadq.check_this( zeal ) ) return false;
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ if ( ! put_threadq.check_this( zeal ) ) return false;
+#endif
+#endif
+
+ switch( zeal )
+ {
+ case cyg_system_test:
+ case cyg_extreme:
+ case cyg_thorough:
+ case cyg_quick:
+ case cyg_trivial:
+ // plenty of scope for fencepost problems here
+ if ( size < count ) return false;
+ if ( size <= base ) return false;
+ if ( 0 > count ) return false;
+ if ( 0 > base ) return false;
+
+ // there was initially a test of the form
+ // (0 < count && count < size) && ! threadqueue.empty()
+ // here - ie. there should only be people waiting if the Q is full
+ // or empty. This is bogus, anyone else might run between a waiter
+ // being awoken, so there can be a 2nd waiter in the Q and a free
+ // slot (say) simultaneously.
+
+ // Further, we need 2 queues; imagine a 10-slot itemqueue with 25
+ // attempts to put to it, so 15 sleep. 10 other threads get,
+ // awakening 10 of the 15 put-sleepers. Another one gets, and
+ // can't because there is no data there _yet_; it sleeps, and the
+ // 10 awakened threads cycle through the run queue, each putting,
+ // the first awakens the get-sleeper, which in turn awakens a
+ // further put-sleeper.
+
+ // This requirement for 2 queue only holds if Ngetters > 2 * Nslots
+ // or Nputters > 2 * Nslots; if these are both false, one queue
+ // will suffice. This could be an optimisation for the future -
+ // wow, 4 bytes.
+
+ case cyg_none:
+ default:
+ break;
+ };
+
+ return true;
+}
+
+#endif
+
+
+// -------------------------------------------------------------------------
+// From here downwards, these are the major functions of the template; if
+// being genuinely used as a template they should probably not be inlined.
+// If being used to construct a specific class, with explicit functions,
+// then they should be. This is controlled by:
+
+#ifdef CYGIMP_MBOXT_INLINE
+#define CYG_MBOXT_INLINE inline
+#else
+#define CYG_MBOXT_INLINE
+#endif
+
+// -------------------------------------------------------------------------
+// Get an item, or wait for one to arrive
+
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt<T,QUEUE_SIZE>::get( T &ritem )
+{
+ CYG_REPORT_FUNCTION();
+ cyg_bool result = true;
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ CYG_INSTRUMENT_MBOXT(GET, this, count);
+
+ // Loop while the mboxt is empty, sleeping each time around
+ // the loop. This copes with the possibility of a higher priority
+ // thread grabbing the message between the wakeup in unlock() and
+ // this thread actually starting.
+
+ while( result && (0 == count) ) {
+ self->set_sleep_reason( Cyg_Thread::WAIT );
+ self->sleep();
+ get_threadq.enqueue( self );
+
+ CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if ( result ) {
+ CYG_INSTRUMENT_MBOXT(GOT, this, count);
+
+ ritem = itemqueue[ (count--, base++) ];
+ CYG_ASSERT( 0 <= count, "Count went -ve" );
+ CYG_ASSERT( size >= base, "Base overflow" );
+
+ if ( size <= base )
+ base = 0;
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ wakeup_waiter( put_threadq );
+#endif
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+
+
+// -------------------------------------------------------------------------
+// Try to get an item with an absolute timeout and return success.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt<T,QUEUE_SIZE>::get( T &ritem, cyg_tick_count abs_timeout )
+{
+ CYG_REPORT_FUNCTION();
+ cyg_bool result = true;
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ CYG_INSTRUMENT_MBOXT(GET, this, count);
+
+ // Set the timer _once_ outside the loop.
+ self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
+
+ // If the timeout is in the past, the wake reason will have been
+ // set to something other than NONE already. Set the result false
+ // to force an immediate return.
+
+ if( self->get_wake_reason() != Cyg_Thread::NONE )
+ result = false;
+
+ // Loop while the mboxt is empty, sleeping each time around the loop.
+ // This copes with the possibility of a higher priority thread grabbing
+ // the message between the wakeup in put()&c and this thread actually
+ // starting.
+ while ( result && (0 == count) ) {
+ // must reset the sleep reason every time
+ self->set_sleep_reason( Cyg_Thread::TIMEOUT );
+ self->sleep();
+ get_threadq.enqueue( self );
+
+ CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::TIMEOUT:
+ result = false;
+ CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count);
+ break;
+
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // clear the timer; if it actually fired, no worries.
+ self->clear_timer();
+
+ if ( result ) {
+
+ CYG_INSTRUMENT_MBOXT(GOT, this, count);
+
+ ritem = itemqueue[ (count--, base++) ];
+ CYG_ASSERT( 0 <= count, "Count went -ve" );
+ CYG_ASSERT( size >= base, "Base overflow" );
+
+ if ( size <= base )
+ base = 0;
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ wakeup_waiter( put_threadq );
+#endif
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+
+// -------------------------------------------------------------------------
+// Try to get an item and return success.
+
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt<T,QUEUE_SIZE>::tryget( T &ritem )
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MBOXT(TRY, this, count);
+
+ cyg_bool result = ( 0 < count );
+ // If the mboxt is not empty, grab an item and return it.
+ if ( result ) {
+ ritem = itemqueue[ (count--, base++) ];
+ CYG_ASSERT( 0 <= count, "Count went -ve" );
+ CYG_ASSERT( size >= base, "Base overflow" );
+ if ( size <= base )
+ base = 0;
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ wakeup_waiter( put_threadq );
+#endif
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// get next item without removing it
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt<T,QUEUE_SIZE>::peek_item( T &ritem )
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MBOXT(TRY, this, count);
+
+ cyg_bool result = ( 0 < count );
+ // If the mboxt is not empty, grab an item and return it.
+ if ( result )
+ ritem = itemqueue[ base ];
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Put an item in the queue; wait if full.
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt<T,QUEUE_SIZE>::put( const T item )
+{
+ CYG_REPORT_FUNCTION();
+ cyg_bool result = true;
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MBOXT(PUT, this, count);
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ while ( result && (size == count) ) {
+ self->set_sleep_reason( Cyg_Thread::WAIT );
+ self->sleep();
+ put_threadq.enqueue( self );
+
+ CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if ( result ) {
+ cyg_count32 in = base + (count++);
+ if ( size <= in )
+ in -= size;
+
+ CYG_ASSERT( size > in, "in overflow" );
+ CYG_ASSERT( 0 <= in, "in overflow" );
+ CYG_ASSERT( size >= count, "count overflow" );
+
+ itemqueue[ in ] = item;
+
+ wakeup_waiter( get_threadq );
+ }
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Put an item in the queue; wait if full, with an absolute timeout;
+// return success.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt<T,QUEUE_SIZE>::put( const T item, cyg_tick_count abs_timeout )
+{
+ CYG_REPORT_FUNCTION();
+ cyg_bool result = true;
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MBOXT(PUT, this, count);
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Set the timer _once_ outside the loop.
+ self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
+
+ // If the timeout is in the past, the wake reason will have been
+ // set to something other than NONE already. Set the result false
+ // to force an immediate return.
+
+ if( self->get_wake_reason() != Cyg_Thread::NONE )
+ result = false;
+
+ // Loop while the mboxt is full, sleeping each time around the loop.
+ // This copes with the possibility of a higher priority thread filling
+ // the empty slot between the wakeup in get()&c and this thread
+ // actually starting.
+ while ( result && (size == count) ) {
+ // must reset the sleep reason every time
+ self->set_sleep_reason( Cyg_Thread::TIMEOUT );
+ self->sleep();
+ put_threadq.enqueue( self );
+
+ CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::TIMEOUT:
+ result = false;
+ CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count);
+ break;
+
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // clear the timer; if it actually fired, no worries.
+ self->clear_timer();
+
+ if ( result ) {
+ cyg_count32 in = base + (count++);
+ if ( size <= in )
+ in -= size;
+
+ CYG_ASSERT( size > in, "in overflow" );
+ CYG_ASSERT( 0 <= in, "in overflow" );
+ CYG_ASSERT( size >= count, "count overflow" );
+
+ itemqueue[ in ] = item;
+
+ wakeup_waiter( get_threadq );
+ }
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+#endif // CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+
+// -------------------------------------------------------------------------
+// Try to put an item in the queue and return success; queue may be full.
+
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt<T,QUEUE_SIZE>::tryput( const T item )
+{
+ CYG_REPORT_FUNCTION();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MBOXT(PUT, this, count);
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ if ( size == count ) {
+ Cyg_Scheduler::unlock(); // unlock, maybe switch threads
+ return false; // the mboxt is full
+ }
+
+ cyg_count32 in = base + (count++);
+ if ( size <= in )
+ in -= size;
+
+ CYG_ASSERT( size > in, "in overflow" );
+ CYG_ASSERT( 0 <= in, "in overflow" );
+ CYG_ASSERT( size >= count, "count overflow" );
+
+ itemqueue[ in ] = item;
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ wakeup_waiter( get_threadq );
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ return true;
+}
+
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_MBOXT_INL
+// EOF mboxt.inl
diff --git a/ecos/packages/kernel/current/include/mboxt2.hxx b/ecos/packages/kernel/current/include/mboxt2.hxx
new file mode 100644
index 0000000000..7f7058e79c
--- /dev/null
+++ b/ecos/packages/kernel/current/include/mboxt2.hxx
@@ -0,0 +1,142 @@
+#ifndef CYGONCE_KERNEL_MBOXT2_HXX
+#define CYGONCE_KERNEL_MBOXT2_HXX
+
+//==========================================================================
+//
+// mboxt2.hxx
+//
+// Mboxt2 (Message Box/Mailbox) class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 1998-02-10
+// Purpose: Define Mboxt2 class interfaces
+// Description: The classes defined here provide the APIs for mboxt2es.
+// Usage: #include <cyg/kernel/mboxt2.hxx>
+// #include <cyg/kernel/mboxt2.inl>
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+
+// -------------------------------------------------------------------------
+// Message/Mail Box. This template implements a queue of T's.
+// Implemented as a template for maximal flexibility; one would hope
+// that only one, with T==(void *) and the same number of them,
+// is ever used without very good reason.
+
+// Cyg_Mboxt2 has a fixed size array of T's; one size fits all.
+
+template <class T, cyg_count32 QUEUE_SIZE>
+class Cyg_Mboxt2
+{
+private:
+ cyg_count32 base; // index of first used slot
+ cyg_count32 count; // count of used slots
+ Cyg_ThreadQueue get_threadq; // Queue of waiting threads
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ Cyg_ThreadQueue put_threadq; // Queue of waiting threads
+#endif
+ static const
+ cyg_count32 size = QUEUE_SIZE;
+ T itemqueue[ QUEUE_SIZE ];
+ // queue of items
+ // private utility functions
+ // wake up a thread from some queue
+ inline void wakeup_winner( const T &msg );
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ inline void wakeup_putter( void );
+#endif
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Mboxt2(); // Constructor
+ ~Cyg_Mboxt2(); // Destructor
+
+ cyg_bool get( T &ritem ); // get an item; wait if none
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_bool get( T &ritem, cyg_tick_count abs_timeout );
+#endif
+ cyg_bool tryget( T &ritem ); // just one attempt
+
+ cyg_bool peek_item( T &ritem ); // get next item without
+ // removing it
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ cyg_bool put( const T item ); // put an item; wait if full
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_bool put( const T item, cyg_tick_count abs_timeout );
+#endif
+#endif
+ cyg_bool tryput( const T item ); // fails if Q full
+
+ inline
+ cyg_count32 peek() // Get current count value
+ {
+ return count;
+ }
+
+ inline
+ cyg_bool waiting_to_get() // Any threads waiting?
+ {
+ return ! get_threadq.empty();
+ }
+
+ inline
+ cyg_bool waiting_to_put() // Any threads waiting?
+ {
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ return ! put_threadq.empty();
+#else
+ return false;
+#endif
+ }
+};
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_MBOXT2_HXX
+// EOF mboxt2.hxx
diff --git a/ecos/packages/kernel/current/include/mboxt2.inl b/ecos/packages/kernel/current/include/mboxt2.inl
new file mode 100644
index 0000000000..c453155674
--- /dev/null
+++ b/ecos/packages/kernel/current/include/mboxt2.inl
@@ -0,0 +1,683 @@
+#ifndef CYGONCE_KERNEL_MBOXT2_INL
+#define CYGONCE_KERNEL_MBOXT2_INL
+//==========================================================================
+//
+// mboxt2.inl
+//
+// Mboxt2 mbox template class implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 1998-02-10
+// Purpose: Mboxt2 template implementation
+// Description: This file contains the implementations of the mboxt2
+// template classes.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/mboxt2.hxx> // our header
+
+#include <cyg/kernel/thread.inl> // thread inlines
+#include <cyg/kernel/sched.inl> // scheduler inlines
+#include <cyg/kernel/clock.inl> // clock inlines
+
+// -------------------------------------------------------------------------
+// inline function for awakening waiting threads
+
+template <class T, cyg_count32 QUEUE_SIZE>
+inline void
+Cyg_Mboxt2<T,QUEUE_SIZE>::wakeup_winner( const T &msg )
+{
+ CYG_ASSERT( !get_threadq.empty(), "Where did the winner go?" );
+
+ // The queue is non-empty, so grab the next thread and wake it up.
+ Cyg_Thread *thread = get_threadq.dequeue();
+
+ CYG_ASSERTCLASS( thread, "Bad thread pointer");
+
+ T *msg_ret = (T *)(thread->get_wait_info());
+ *msg_ret = msg;
+
+ thread->set_wake_reason( Cyg_Thread::DONE );
+ thread->wake();
+
+ CYG_INSTRUMENT_MBOXT(WAKE, this, thread);
+}
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+template <class T, cyg_count32 QUEUE_SIZE>
+inline void
+Cyg_Mboxt2<T,QUEUE_SIZE>::wakeup_putter( void )
+{
+ if( !put_threadq.empty() ) {
+ // The queue is non-empty, so grab the next thread and wake it up.
+ Cyg_Thread *thread = put_threadq.dequeue();
+
+ CYG_ASSERTCLASS( thread, "Bad thread pointer");
+
+ T *new_msg = (T *)(thread->get_wait_info());
+
+ cyg_count32 in = base + (count++);
+ if ( size <= in )
+ in -= size;
+
+ CYG_ASSERT( size > in, "in overflow" );
+ CYG_ASSERT( 0 <= in, "in overflow" );
+ CYG_ASSERT( size >= count, "count overflow" );
+
+ itemqueue[ in ] = *new_msg;
+
+ thread->set_wake_reason( Cyg_Thread::DONE );
+ thread->wake();
+
+ CYG_INSTRUMENT_MBOXT(WAKE, this, thread);
+ }
+}
+#endif
+
+// -------------------------------------------------------------------------
+// Constructor
+
+template <class T, cyg_count32 QUEUE_SIZE>
+Cyg_Mboxt2<T,QUEUE_SIZE>::Cyg_Mboxt2()
+{
+ CYG_REPORT_FUNCTION();
+ base = 0;
+ count = 0;
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Destructor
+
+template <class T, cyg_count32 QUEUE_SIZE>
+Cyg_Mboxt2<T,QUEUE_SIZE>::~Cyg_Mboxt2()
+{
+ CYG_REPORT_FUNCTION();
+#if 0
+ CYG_ASSERT( 0 == count, "Deleting mboxt2 with messages");
+ CYG_ASSERT( get_threadq.empty(), "Deleting mboxt2 with threads waiting to get");
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ CYG_ASSERT( put_threadq.empty(), "Deleting mboxt2 with threads waiting to put");
+#endif
+#endif
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ while ( ! get_threadq.empty() ) {
+ Cyg_Thread *thread = get_threadq.dequeue();
+ thread->set_wake_reason( Cyg_Thread::DESTRUCT );
+ thread->wake();
+ }
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ while ( ! put_threadq.empty() ) {
+ Cyg_Thread *thread = put_threadq.dequeue();
+ thread->set_wake_reason( Cyg_Thread::DESTRUCT );
+ thread->wake();
+ }
+#endif
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// debugging/assert function
+
+#ifdef CYGDBG_USE_ASSERTS
+
+template <class T, cyg_count32 QUEUE_SIZE>
+cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::check_this(cyg_assert_class_zeal zeal) const
+{
+ if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() )
+ // then the whole thing is invalid, and we know it.
+ // so return OK, since this check should NOT make an error.
+ return true;
+
+ // check that we have a non-NULL pointer first
+ if( this == NULL ) return false;
+
+#if 0 // thread queues do not have checking funcs.
+ if ( ! get_threadq.check_this( zeal ) ) return false;
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ if ( ! put_threadq.check_this( zeal ) ) return false;
+#endif
+#endif
+
+ switch( zeal )
+ {
+ case cyg_system_test:
+ case cyg_extreme:
+ case cyg_thorough:
+ case cyg_quick:
+ case cyg_trivial:
+ // plenty of scope for fencepost problems here
+ if ( size < count ) return false;
+ if ( size <= base ) return false;
+ if ( 0 > count ) return false;
+ if ( 0 > base ) return false;
+
+ // Comments about needing 2 queues elided; they're not true in this
+ // immediate-dispatch model. I think we could get away with only
+ // one queue now, biut is it worth it? 4 bytes of redundant info
+ // buys a lot of correctness.
+
+ case cyg_none:
+ default:
+ break;
+ };
+
+ return true;
+}
+
+#endif
+
+
+// -------------------------------------------------------------------------
+// From here downwards, these are the major functions of the template; if
+// being genuinely used as a template they should probably not be inlined.
+// If being used to construct a specific class, with explicit functions,
+// then they should be. This is controlled by:
+
+#ifdef CYGIMP_MBOXT_INLINE
+#define CYG_MBOXT_INLINE inline
+#else
+#define CYG_MBOXT_INLINE
+#endif
+
+// -------------------------------------------------------------------------
+// Get an item, or wait for one to arrive
+
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::get( T &ritem )
+{
+ CYG_REPORT_FUNCTION();
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ CYG_INSTRUMENT_MBOXT(GET, this, count);
+
+ if ( 0 < count ) {
+ CYG_INSTRUMENT_MBOXT(GOT, this, count);
+
+ ritem = itemqueue[ (count--, base++) ];
+ CYG_ASSERT( 0 <= count, "Count went -ve" );
+ CYG_ASSERT( size >= base, "Base overflow" );
+
+ if ( size <= base )
+ base = 0;
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ wakeup_putter();
+#endif
+
+ // Unlock the scheduler and definitely switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_REPORT_RETVAL( true );
+ return true;
+ }
+
+ self->set_wait_info( (CYG_ADDRWORD)&ritem );
+ self->set_sleep_reason( Cyg_Thread::WAIT );
+ self->sleep();
+ get_threadq.enqueue( self );
+
+ CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+
+ // Unlock scheduler and allow other threads to run
+ Cyg_Scheduler::unlock_reschedule();
+
+ cyg_bool result = true;
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+
+
+// -------------------------------------------------------------------------
+// Try to get an item with an absolute timeout and return success.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::get( T &ritem, cyg_tick_count abs_timeout )
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ CYG_INSTRUMENT_MBOXT(GET, this, count);
+
+ if ( 0 < count ) {
+ CYG_INSTRUMENT_MBOXT(GOT, this, count);
+
+ ritem = itemqueue[ (count--, base++) ];
+ CYG_ASSERT( 0 <= count, "Count went -ve" );
+ CYG_ASSERT( size >= base, "Base overflow" );
+
+ if ( size <= base )
+ base = 0;
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ wakeup_putter();
+#endif
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_REPORT_RETVAL( true );
+ return true;
+ }
+
+ // Set the timer
+ self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
+
+ // If the timeout is in the past, the wake reason will have been set to
+ // something other than NONE already. If so, skip the wait and go
+ // straight to unlock.
+
+ if( Cyg_Thread::NONE == self->get_wake_reason() ) {
+ self->set_wait_info( (CYG_ADDRWORD)&ritem );
+ self->sleep();
+ get_threadq.enqueue( self );
+
+ CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+ }
+
+ // Unlock scheduler and allow other threads to run
+ Cyg_Scheduler::unlock_reschedule();
+
+ // clear the timer; if it actually fired, no worries.
+ self->clear_timer();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ cyg_bool result = true;
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::TIMEOUT:
+ result = false;
+ CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count);
+ break;
+
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+
+// -------------------------------------------------------------------------
+// Try to get an item and return success.
+
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::tryget( T &ritem )
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MBOXT(TRY, this, count);
+
+ cyg_bool result = ( 0 < count );
+ // If the mboxt2 is not empty, grab an item and return it.
+ if ( result ) {
+ ritem = itemqueue[ (count--, base++) ];
+ CYG_ASSERT( 0 <= count, "Count went -ve" );
+ CYG_ASSERT( size >= base, "Base overflow" );
+ if ( size <= base )
+ base = 0;
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ wakeup_putter();
+#endif
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// get next item without removing it
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::peek_item( T &ritem )
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MBOXT(TRY, this, count);
+
+ cyg_bool result = ( 0 < count );
+ // If the mboxt2 is not empty, grab an item and return it.
+ if ( result )
+ ritem = itemqueue[ base ];
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Put an item in the queue; wait if full.
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::put( const T item )
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MBOXT(PUT, this, count);
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ if ( size == count ) {
+ CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" );
+
+ self->set_wait_info( (CYG_ADDRWORD)&item );
+ self->set_sleep_reason( Cyg_Thread::WAIT );
+ self->sleep();
+ put_threadq.enqueue( self );
+
+ CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+
+ // when this returns, our item is in the queue.
+ Cyg_Scheduler::unlock_reschedule(); // unlock, switch threads
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ cyg_bool result = true;
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ CYG_REPORT_RETVAL( result );
+ return result;
+ }
+
+ if ( !get_threadq.empty() ) {
+ wakeup_winner( item );
+ Cyg_Scheduler::unlock(); // unlock, maybe switch threads
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_REPORT_RETVAL( true );
+ return true;
+ }
+
+ cyg_count32 in = base + (count++);
+ if ( size <= in )
+ in -= size;
+
+ CYG_ASSERT( size > in, "in overflow" );
+ CYG_ASSERT( 0 <= in, "in overflow" );
+ CYG_ASSERT( size >= count, "count overflow" );
+
+ itemqueue[ in ] = item;
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETVAL( true );
+ return true;
+}
+
+// -------------------------------------------------------------------------
+// Put an item in the queue; wait if full, with an absolute timeout;
+// return success.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::put( const T item, cyg_tick_count abs_timeout )
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MBOXT(PUT, this, count);
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ if ( size == count ) {
+
+ CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" );
+
+ // Set the timer
+ self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
+
+ // If the timeout is in the past, the wake reason will have been set to
+ // something other than NONE already. If so, skip the wait and go
+ // straight to unlock.
+
+ if( Cyg_Thread::NONE == self->get_wake_reason() ) {
+ self->set_wait_info( (CYG_ADDRWORD)&item );
+ self->sleep();
+ put_threadq.enqueue( self );
+
+ CYG_INSTRUMENT_MBOXT(WAIT, this, count);
+ }
+
+ // when this returns, our item is in the queue.
+ Cyg_Scheduler::unlock_reschedule(); // unlock, switch threads
+
+ // clear the timer; if it actually fired, no worries.
+ self->clear_timer();
+
+ cyg_bool result = true;
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::TIMEOUT:
+ result = false;
+ CYG_INSTRUMENT_MBOXT(TIMEOUT, this, count);
+ break;
+
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_REPORT_RETVAL( result );
+ return result;
+ }
+
+
+ if ( !get_threadq.empty() ) {
+ wakeup_winner( item );
+ Cyg_Scheduler::unlock(); // unlock, maybe switch threads
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_REPORT_RETVAL( true );
+ return true;
+ }
+
+ cyg_count32 in = base + (count++);
+ if ( size <= in )
+ in -= size;
+
+ CYG_ASSERT( size > in, "in overflow" );
+ CYG_ASSERT( 0 <= in, "in overflow" );
+ CYG_ASSERT( size >= count, "count overflow" );
+
+ itemqueue[ in ] = item;
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_REPORT_RETVAL( true );
+ return true;
+}
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+#endif // CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+
+// -------------------------------------------------------------------------
+// Try to put an item in the queue and return success; queue may be full.
+
+template <class T, cyg_count32 QUEUE_SIZE>
+CYG_MBOXT_INLINE cyg_bool
+Cyg_Mboxt2<T,QUEUE_SIZE>::tryput( const T item )
+{
+ CYG_REPORT_FUNCTION();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MBOXT(PUT, this, count);
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ if ( size == count ) {
+ CYG_ASSERT( get_threadq.empty(), "Threads waiting AND queue full?" );
+ Cyg_Scheduler::unlock(); // unlock, maybe switch threads
+ CYG_REPORT_RETVAL( false );
+ return false; // the mboxt2 is full
+ }
+
+ if ( !get_threadq.empty() ) {
+ CYG_ASSERT( 0 == count, "Threads waiting AND queue not empty" );
+ wakeup_winner( item );
+ Cyg_Scheduler::unlock(); // unlock, maybe switch threads
+ CYG_REPORT_RETVAL( true );
+ return true;
+ }
+
+ cyg_count32 in = base + (count++);
+ if ( size <= in )
+ in -= size;
+
+ CYG_ASSERT( size > in, "in overflow" );
+ CYG_ASSERT( 0 <= in, "in overflow" );
+ CYG_ASSERT( size >= count, "count overflow" );
+
+ itemqueue[ in ] = item;
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETVAL( true );
+ return true;
+}
+
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_MBOXT2_INL
+// EOF mboxt2.inl
diff --git a/ecos/packages/kernel/current/include/mlqueue.hxx b/ecos/packages/kernel/current/include/mlqueue.hxx
new file mode 100644
index 0000000000..88d07976cc
--- /dev/null
+++ b/ecos/packages/kernel/current/include/mlqueue.hxx
@@ -0,0 +1,318 @@
+#ifndef CYGONCE_KERNEL_MLQUEUE_HXX
+#define CYGONCE_KERNEL_MLQUEUE_HXX
+
+//==========================================================================
+//
+// mlqueue.hxx
+//
+// Multi-Level Queue scheduler class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: jlarmour
+// Date: 1997-09-10
+// Purpose: Define multilevel queue scheduler implementation
+// Description: The classes defined here are used as base classes
+// by the common classes that define schedulers and thread
+// things. The MLQ scheduler in various configurations
+// provides standard FIFO, round-robin and single priority
+// schedulers.
+// Usage: Included according to configuration by
+// <cyg/kernel/sched.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+
+#include <cyg/infra/clist.hxx> // List implementation
+
+// -------------------------------------------------------------------------
+// The macro CYGNUM_KERNEL_SCHED_PRIORITIES contains the number of priorities
+// supported by the scheduler.
+
+#ifndef CYGNUM_KERNEL_SCHED_PRIORITIES
+#define CYGNUM_KERNEL_SCHED_PRIORITIES 32 // define a default
+#endif
+
+// set bitmap size
+#define CYGNUM_KERNEL_SCHED_BITMAP_SIZE CYGNUM_KERNEL_SCHED_PRIORITIES
+
+// -------------------------------------------------------------------------
+// The macro CYGNUM_KERNEL_SCHED_BITMAP_SIZE contains the number of bits that the
+// scheduler bitmap should contain. It is derived from the number of prioirity
+// levels defined by the configuration.
+
+#if CYGNUM_KERNEL_SCHED_BITMAP_SIZE <= 8
+typedef cyg_ucount8 cyg_sched_bitmap;
+#elif CYGNUM_KERNEL_SCHED_BITMAP_SIZE <= 16
+typedef cyg_ucount16 cyg_sched_bitmap;
+#elif CYGNUM_KERNEL_SCHED_BITMAP_SIZE <= 32
+typedef cyg_ucount32 cyg_sched_bitmap;
+#else
+#error Bitmaps greater than 32 bits not currently allowed
+#endif
+
+// -------------------------------------------------------------------------
+// Customize the scheduler
+
+#define CYGIMP_THREAD_PRIORITY 1 // Threads have changable priorities
+
+#define CYG_THREAD_MIN_PRIORITY (CYGNUM_KERNEL_SCHED_PRIORITIES-1)
+#define CYG_THREAD_MAX_PRIORITY 0
+
+// set default scheduling info value for thread constructors.
+#define CYG_SCHED_DEFAULT_INFO CYG_THREAD_MAX_PRIORITY
+
+// -------------------------------------------------------------------------
+// scheduler Run queue object
+
+typedef Cyg_CList_T<Cyg_Thread> Cyg_RunQueue;
+
+// -------------------------------------------------------------------------
+// Thread queue implementation.
+// This class provides the (scheduler specific) implementation of the
+// thread queue class.
+
+class Cyg_ThreadQueue_Implementation
+ : public Cyg_CList_T<Cyg_Thread>
+{
+ friend class Cyg_Scheduler_Implementation;
+ friend class Cyg_SchedThread_Implementation;
+
+ void set_thread_queue(Cyg_Thread *thread,
+ Cyg_ThreadQueue *tq );
+
+protected:
+
+ // API used by Cyg_ThreadQueue
+
+ Cyg_ThreadQueue_Implementation() {}; // Constructor
+
+ // Add thread to queue
+ void enqueue(Cyg_Thread *thread);
+
+ // return first thread on queue
+ Cyg_Thread *highpri();
+
+ // remove first thread on queue
+ Cyg_Thread *dequeue();
+
+ // Remove thread from queue
+ void remove(Cyg_Thread *thread);
+
+};
+
+// -------------------------------------------------------------------------
+// This class contains the implementation details of the scheduler, and
+// provides a standard API for accessing it.
+
+class Cyg_Scheduler_Implementation
+ : public Cyg_Scheduler_Base
+{
+ friend class Cyg_ThreadQueue_Implementation;
+ friend class Cyg_SchedThread_Implementation;
+ friend class Cyg_HardwareThread;
+ friend void cyg_scheduler_set_need_reschedule();
+
+ // Mask of which run queues have ready threads
+ cyg_sched_bitmap queue_map;
+
+ // Each run queue is a double linked circular list of threads.
+ // These pointers point to the head element of each list.
+ Cyg_RunQueue run_queue[CYGNUM_KERNEL_SCHED_PRIORITIES];
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ // In SMP systems we additionally keep a counter for each priority
+ // of the number of pending but not running threads in each queue.
+
+ cyg_uint32 pending[CYGNUM_KERNEL_SCHED_PRIORITIES];
+
+ cyg_sched_bitmap pending_map;
+
+#endif
+
+protected:
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+ // Timeslice counter. This is decremented on each
+ // clock tick, and a timeslice is performed each
+ // 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
+ // interface to the Cyg_Scheduler class. These are protected
+ // so that only the scheduler can call them.
+
+ // choose a new thread
+ Cyg_Thread *schedule();
+
+ // make thread schedulable
+ void add_thread(Cyg_Thread *thread);
+
+ // make thread un-schedulable
+ void rem_thread(Cyg_Thread *thread);
+
+ // register thread with scheduler
+ void register_thread(Cyg_Thread *thread);
+
+ // deregister thread
+ void deregister_thread(Cyg_Thread *thread);
+
+ // Test the given priority for uniqueness
+ cyg_bool unique( cyg_priority priority);
+
+ // Set need_reschedule if the supplied thread is of lower
+ // priority than any that are currently running.
+ static void set_need_reschedule( Cyg_Thread *thread );
+ static void set_need_reschedule();
+
+public:
+ void set_idle_thread( Cyg_Thread *thread, HAL_SMP_CPU_TYPE cpu );
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+ // If timeslicing is enbled, define a scheduler
+ // entry points to do timeslicing. This will be
+ // called from the RTC DSR.
+public:
+ void timeslice();
+ void timeslice_cpu();
+
+#endif
+
+};
+
+// -------------------------------------------------------------------------
+// Cyg_Scheduler_Implementation inlines
+
+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.
+
+class Cyg_SchedThread_Implementation
+ : public Cyg_DNode_T<Cyg_Thread>
+{
+ friend class Cyg_Scheduler_Implementation;
+ friend class Cyg_ThreadQueue_Implementation;
+
+protected:
+
+ cyg_priority priority; // current thread priority
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+ HAL_SMP_CPU_TYPE cpu; // CPU id of cpu currently running
+ // this thread, or CYG_KERNEL_CPU_NONE
+ // if not running.
+#endif
+
+ Cyg_SchedThread_Implementation(CYG_ADDRWORD sched_info);
+
+ void yield(); // Yield CPU to next thread
+
+ static void rotate_queue( cyg_priority pri );
+ // Rotate that run queue
+
+ void to_queue_head( void ); // Move this thread to the head
+ // of its queue (not necessarily
+ // a scheduler queue)
+
+#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.
+
+ cyg_bool timeslice_enabled;
+
+public:
+
+ void timeslice_enable();
+
+ void timeslice_disable();
+
+#endif
+
+};
+
+// -------------------------------------------------------------------------
+// Cyg_SchedThread_Implementation inlines.
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
+
+inline void Cyg_SchedThread_Implementation::timeslice_enable()
+{
+ timeslice_enabled = true;
+}
+
+inline void Cyg_SchedThread_Implementation::timeslice_disable()
+{
+ timeslice_enabled = false;
+}
+
+#endif
+
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_MLQUEUE_HXX
+// EOF mlqueue.hxx
diff --git a/ecos/packages/kernel/current/include/mqueue.hxx b/ecos/packages/kernel/current/include/mqueue.hxx
new file mode 100644
index 0000000000..5099f47c9a
--- /dev/null
+++ b/ecos/packages/kernel/current/include/mqueue.hxx
@@ -0,0 +1,163 @@
+#ifndef CYGONCE_KERNEL_MQUEUE_HXX
+#define CYGONCE_KERNEL_MQUEUE_HXX
+/*========================================================================
+//
+// mqueue.hxx
+//
+// Message queues
+//
+//========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): jlarmour
+// Contributors:
+// Date: 2000-05-09
+// Purpose: This file provides the interface for eCos message queues
+// Description: This differs from the message boxes also supported by
+// eCos primarily because the requirements of message
+// queues are driven by POSIX semantics. POSIX semantics are
+// more dynamic and therefore heavyweight than Mboxes,
+// including prioritization, and variable sized queues and
+// message lengths
+// Usage: #include <cyg/kernel/mqueue.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//======================================================================
+*/
+
+/* CONFIGURATION */
+
+#include <pkgconf/kernel.h> /* Configuration header */
+
+/* INCLUDES */
+
+#include <stddef.h> /* size_t */
+#include <cyg/infra/cyg_type.h> /* Types */
+#include <cyg/infra/cyg_ass.h> /* CYGDBG_DEFINE_CHECK_THIS,
+ CYGDBG_USE_ASSERTS */
+#include <cyg/kernel/ktypes.h> /* Kernel package types */
+#include <cyg/kernel/sema.hxx> /* Cyg_Counting_Semaphore */
+
+/* CLASSES */
+
+class Cyg_Mqueue {
+public:
+ typedef void (*callback_fn_t)(Cyg_Mqueue &q, CYG_ADDRWORD data);
+ typedef void * (*qalloc_fn_t)(size_t len);
+ typedef void (*qfree_fn_t)(void *ptr, size_t len);
+
+ typedef enum {
+ OK=0,
+ NOMEM,
+ WOULDBLOCK,
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ TIMEOUT,
+#endif
+ INTR
+ } qerr_t;
+
+protected:
+ struct qentry {
+ struct qentry *next;
+ unsigned int priority;
+ size_t buflen;
+ volatile bool busy;
+ // data buffer follows here
+ char *buf() const { return (char *)this + sizeof(*this); }
+ };
+
+ Cyg_Counting_Semaphore putsem, getsem;
+
+ struct qentry *q; // q entries in use
+ struct qentry *freelist; // q entries not in use
+ void *queuespace; // placeholder for the dynamically allocated
+ // area
+
+ size_t queuespacesize;
+
+ qfree_fn_t free_fn; // how to free queuespace when we destruct
+
+ callback_fn_t callback;
+ CYG_ADDRWORD callback_data;
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+#ifdef CYGDBG_USE_ASSERTS
+ long qlen;
+ size_t msgsize;
+#endif
+
+public:
+
+ Cyg_Mqueue( long maxmsgs, long maxmsgsize,
+ qalloc_fn_t qalloc, qfree_fn_t qfree, qerr_t *err );
+ ~Cyg_Mqueue();
+ // put() copies len bytes of *buf into the queue at priority prio
+ qerr_t put( const char *buf, size_t len, unsigned int prio, bool block=true
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ ,cyg_tick_count timeout = 0
+#endif
+ );
+
+ // get() returns the oldest highest priority message in the queue in *buf
+ // and sets *prio to the priority (if prio is non-NULL) and *len to the
+ // actual message size
+ qerr_t get( char *buf, size_t *len, unsigned int *prio, bool block=true
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ ,cyg_tick_count timeout = 0
+#endif
+ );
+
+ // count() returns the number of messages in the queue
+ long count();
+
+ // Supply a callback function to call (with the supplied data argument)
+ // when the queue goes from empty to non-empty (unless someone's already
+ // doing a get()). This returns the old callback_fn, and if olddata is
+ // non-NULL sets it to the old data (yes, really!)
+ callback_fn_t setnotify( callback_fn_t callback_fn, CYG_ADDRWORD data,
+ CYG_ADDRWORD *olddata=NULL);
+
+}; /* class Cyg_Mqueue */
+
+#ifndef CYGIMP_KERNEL_SYNCH_MQUEUE_NOT_INLINE
+# include <cyg/kernel/mqueue.inl>
+#endif
+
+#endif /* CYGONCE_KERNEL_MQUEUE_HXX multiple inclusion protection */
+
+/* EOF mqueue.hxx */
diff --git a/ecos/packages/kernel/current/include/mqueue.inl b/ecos/packages/kernel/current/include/mqueue.inl
new file mode 100644
index 0000000000..da8ce24a4c
--- /dev/null
+++ b/ecos/packages/kernel/current/include/mqueue.inl
@@ -0,0 +1,543 @@
+#ifndef CYGONCE_KERNEL_MQUEUE_INL
+#define CYGONCE_KERNEL_MQUEUE_INL
+/*========================================================================
+//
+// mqueue.inl
+//
+// Message queues implementation
+//
+//========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): jlarmour
+// Contributors:
+// Date: 2000-05-09
+// Purpose: This file provides the implementation for eCos message
+// queues
+// Description: This differs from the message boxes also supported
+// by eCos primarily because the requirements of message
+// queues are driven by POSIX semantics. POSIX semantics are
+// more dynamic and therefore heavyweight than Mboxes,
+// including prioritization, and variable sized queues and
+// message lengths
+// Usage: Do not include this file directly - instead
+// #include <cyg/kernel/mqueue.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//======================================================================
+*/
+
+/* CONFIGURATION */
+
+#include <pkgconf/system.h>
+#include <pkgconf/kernel.h> // Configuration header
+
+/* INCLUDES */
+
+#include <stddef.h> // size_t, NULL
+#include <cyg/infra/cyg_type.h> // Types
+#include <cyg/kernel/mqueue.hxx> // Header for this file, just in case
+#include <cyg/infra/cyg_ass.h> // Assertion support
+#include <cyg/infra/cyg_trac.h> // Tracing support
+#include <cyg/kernel/sched.hxx> // scheduler
+#include <cyg/kernel/sched.inl> // scheduler inlines
+#include <cyg/kernel/sema.hxx> // Cyg_Counting_Semaphore
+
+#ifdef CYGPKG_ISOINFRA
+# include <string.h> // memcpy
+#else
+externC void * memcpy( void *, const void *, size_t );
+#endif
+
+// NOTE:
+// An alternative implementation based on mutexes and condition variables
+// rather than semaphores/scheduler locking was considered. But it was
+// not thought quite as good because it isn't driver safe. You would
+// also have to manage explicitly what counting semaphores do for you
+// intrinsically. Also with the mutex approach, the message queue would
+// be locked the whole time a new entry was being filled in, or copied out
+//
+// It also makes the non-blocking case properly non-blocking rather than
+// still being able to block while waiting for a mutex protecting
+// the message queue internal structures
+
+/* INLINE FUNCTIONS */
+
+#ifndef CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE
+# define CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE inline
+#endif
+
+//------------------------------------------------------------------------
+
+CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE cyg_bool
+Cyg_Mqueue::check_this( cyg_assert_class_zeal zeal ) const
+{
+ if (zeal != cyg_none) {
+ CYG_CHECK_DATA_PTRC(this); // extreme paranoia
+
+#ifdef CYGDBG_USE_ASSERTS
+ if ( qlen <= 0 || msgsize <= 0 )
+ return false;
+#endif
+
+ if ( queuespacesize < sizeof(struct qentry)+1 )
+ return false;
+
+ CYG_CHECK_DATA_PTRC(queuespace);
+ CYG_CHECK_FUNC_PTRC(free_fn);
+
+ // prevent pre-emption through this. Not so bad since
+ // this is only a diagnostic function
+ Cyg_Scheduler::lock();
+
+ if (NULL != q)
+ CYG_CHECK_DATA_PTRC(q);
+ if (NULL != freelist)
+ CYG_CHECK_DATA_PTRC(freelist);
+ if (NULL != callback)
+ CYG_CHECK_FUNC_PTRC(callback);
+
+ // check each queue entry
+ long msgs=0, busymsgs=0;
+ unsigned int oldprio=0;
+ struct qentry *qtmp;
+
+ if ( NULL != q )
+ oldprio = q->priority;
+ for ( qtmp=q; NULL != qtmp; qtmp=qtmp->next ) {
+ if ( NULL != qtmp->next )
+ CYG_CHECK_DATA_PTRC( qtmp->next );
+
+ // queue should be priority ordered
+ if ( qtmp->priority > oldprio )
+ goto fail;
+ oldprio = qtmp->priority;
+
+#ifdef CYGDBG_USE_ASSERTS
+ // valid length
+ if ( !qtmp->busy )
+ if ( qtmp->buflen > msgsize )
+ goto fail;
+#endif
+ if ( qtmp->busy )
+ busymsgs++;
+ else
+ msgs++;
+ } // for
+
+ long freemsgs=0;
+
+ // check that number of used and unused messages == q length
+ for ( qtmp=freelist; NULL != qtmp; qtmp=qtmp->next ) {
+ if ( NULL != qtmp->next )
+ CYG_CHECK_DATA_PTRC( qtmp->next );
+ if ( qtmp->busy )
+ busymsgs++;
+ else
+ freemsgs++;
+ }
+
+#ifdef CYGDBG_USE_ASSERTS
+ // and sum of all messages should be the total q length
+ if ( qlen != (msgs+freemsgs+busymsgs) )
+ goto fail;
+#endif
+
+ Cyg_Scheduler::unlock();
+
+ }
+ return true; // object OK
+ fail:
+ Cyg_Scheduler::unlock();
+ return false; // object fubar'd
+}
+
+//------------------------------------------------------------------------
+
+CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE
+Cyg_Mqueue::Cyg_Mqueue( long maxmsgs, long maxmsgsize,
+ qalloc_fn_t qalloc, qfree_fn_t qfree, qerr_t *err )
+ : putsem(maxmsgs), getsem(0)
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG5( "maxmsgs=%ld, maxmsgsize=%ld, qalloc=%08x, "
+ "qfree=%08x, &err=%08x", maxmsgs, maxmsgsize,
+ qalloc, qfree, err);
+ CYG_PRECONDITIONC( (maxmsgs > 0) && (maxmsgsize > 0) );
+ CYG_CHECK_DATA_PTRC( err );
+ CYG_CHECK_FUNC_PTRC( qalloc );
+ CYG_CHECK_FUNC_PTRC( qfree );
+
+ // mem to allocate for entire queue size. Also wants to be rounded
+ // up so that the structs are aligned.
+ const long addralign = sizeof(void *) - 1;
+ long entrysize = (sizeof(struct qentry) + maxmsgsize + addralign)
+ & ~addralign;
+
+ queuespacesize = entrysize * maxmsgs;
+ queuespace = qalloc( queuespacesize );
+
+ if (NULL == queuespace) {
+ *err=NOMEM;
+ CYG_REPORT_RETURN();
+ return;
+ }
+
+ // link up freelist
+ long i;
+ struct qentry *qtmp;
+ for ( i=0, qtmp=(struct qentry *)queuespace;
+ i<maxmsgs-1;
+ i++, qtmp=qtmp->next ) {
+ qtmp->busy = false;
+ qtmp->next = (struct qentry *)((char *)qtmp + entrysize);
+ } // for
+
+ freelist = (struct qentry *)queuespace;
+
+ // set the last entry in the chain to the start to make the list circular
+ qtmp->next = NULL;
+ qtmp->busy = false;
+ callback = NULL;
+ q = NULL;
+ free_fn = qfree;
+#ifdef CYGDBG_USE_ASSERTS
+ qlen = maxmsgs;
+ msgsize = maxmsgsize;
+#endif
+
+ *err = OK;
+
+ // object should be valid now
+ CYG_ASSERT_THISC();
+
+ CYG_REPORT_RETURN();
+}
+
+//------------------------------------------------------------------------
+
+CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE
+Cyg_Mqueue::~Cyg_Mqueue()
+{
+ CYG_REPORT_FUNCTION();
+
+ if ( NULL != queuespace ) {
+ // object should be valid if queuespace was successfully allocated
+ CYG_ASSERT_THISC();
+ free_fn( queuespace, queuespacesize );
+ }
+
+#ifdef CYGDBG_USE_ASSERTS
+ qlen = msgsize = 0; // deliberately make it fail check_this() if used
+#endif
+
+ CYG_REPORT_RETURN();
+}
+
+//------------------------------------------------------------------------
+
+// put() copies len bytes of *buf into the queue at priority prio
+CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE Cyg_Mqueue::qerr_t
+Cyg_Mqueue::put( const char *buf, size_t len, unsigned int prio, bool block
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ , cyg_tick_count timeout
+#endif
+ )
+{
+ CYG_REPORT_FUNCTYPE( "err=%d");
+ CYG_REPORT_FUNCARG4( "buf=%08x, len=%ld, prio=%ud, block=%d",
+ buf, len, prio, block==true );
+ CYG_CHECK_DATA_PTRC( buf );
+ CYG_ASSERT_THISC();
+ CYG_PRECONDITIONC( len <= (size_t)msgsize );
+
+ qerr_t err;
+ struct qentry *qtmp, *qent;
+
+ // wait till a freelist entry is available
+ if ( true == block ) {
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ if ( timeout != 0) {
+ if ( false == putsem.wait(timeout) ) {
+ err = TIMEOUT;
+ goto exit;
+ }
+ }
+ else
+#endif
+ if ( false == putsem.wait() ) {
+ err = INTR;
+ goto exit;
+ }
+ } else {
+ if ( false == putsem.trywait() ) {
+ err = WOULDBLOCK;
+ goto exit;
+ }
+ }
+
+ // prevent preemption when fiddling with important members
+ Cyg_Scheduler::lock();
+
+ CYG_ASSERT_THISC();
+
+ // get a queue entry from the freelist
+ // don't need to check the freelist - the semaphore tells us there's
+ // definitely a usable non-busy one there. It's just a question of
+ // locating it.
+
+ if (!freelist->busy) { // fast-track common case
+ qent = freelist;
+ freelist = freelist->next;
+ } else {
+ for ( qtmp=freelist; qtmp->next->busy; qtmp=qtmp->next )
+ CYG_EMPTY_STATEMENT; // skip through
+ qent = qtmp->next;
+ qtmp->next = qent->next;
+ }
+
+ // now put it in place in q
+
+ if ( NULL == q ) {
+ q = qent;
+ q->next = NULL;
+ } else {
+ struct qentry **qentp;
+
+ // insert into queue according to prio
+ for ( qentp=&q; NULL != *qentp; qentp = &((*qentp)->next) ) {
+ if ((*qentp)->priority < prio)
+ break;
+ } // for
+
+ qent->next = *qentp;
+ *qentp = qent;
+ } // else
+
+ qent->priority = prio; // have to set this now so when the sched is
+ // unlocked, other qent's can be added in the
+ // right place
+ qent->busy = true; // let things know this entry should be ignored until
+ // it's finished having its data copied
+
+ // unlock the scheduler, and potentially switch threads, but
+ // that's okay now. We don't want it locked for the expensive memcpy
+ Cyg_Scheduler::unlock();
+
+ qent->buflen = len;
+ memcpy( qent->buf(), buf, len );
+
+ // make available now - setting non-atomically is alright if you think
+ // about it - the only thing that matters is that it's completed before
+ // the post()
+ qent->busy = false;
+
+ // if we have to notify someone, we only do it if no-one's already
+ // sitting waiting for a message to appear, AND if it's a transition
+ // from empty to non-empty
+
+ if ( callback != NULL && !getsem.waiting() && (0 == getsem.peek()) ) {
+ getsem.post();
+ callback( *this, callback_data );
+ } else
+ getsem.post();
+
+ err = OK;
+
+ exit:
+ CYG_ASSERT_THISC();
+ CYG_REPORT_RETVAL(err);
+ return err;
+} // Cyg_Mqueue::put()
+
+//------------------------------------------------------------------------
+
+
+// get() returns the oldest highest priority message in the queue in *buf
+// and sets *prio to the priority (if prio is non-NULL) and *len to the
+// actual message size
+
+CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE Cyg_Mqueue::qerr_t
+Cyg_Mqueue::get( char *buf, size_t *len, unsigned int *prio, bool block
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ , cyg_tick_count timeout
+#endif
+ )
+{
+ CYG_REPORT_FUNCTYPE( "err=%d");
+ CYG_REPORT_FUNCARG4( "buf=%08x, len=%08x, prio=%08x, block=%d",
+ buf, len, prio, block==true );
+ CYG_CHECK_DATA_PTRC( buf );
+ CYG_CHECK_DATA_PTRC( len );
+ if ( NULL != prio )
+ CYG_CHECK_DATA_PTRC( prio );
+ CYG_ASSERT_THISC();
+
+ qerr_t err;
+ struct qentry *qent;
+
+ // wait till a q entry is available
+ if ( true == block ) {
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ if ( timeout != 0) {
+ if ( false == getsem.wait(timeout) ) {
+ err = TIMEOUT;
+ goto exit;
+ }
+ }
+ else
+#endif
+ if ( false == getsem.wait() ) {
+ err = INTR;
+ goto exit;
+ }
+ } else {
+ if ( false == getsem.trywait() ) {
+ err = WOULDBLOCK;
+ goto exit;
+ }
+ }
+
+ // prevent preemption when fiddling with important members
+
+ Cyg_Scheduler::lock();
+
+ // don't need to check the q - the semaphore tells us there's
+ // definitely a usable non-busy one there. It's just a question of
+ // locating it.
+
+ if ( !q->busy ) { // fast-track the common case
+ qent = q;
+ q = qent->next;
+ } else {
+ struct qentry *qtmp;
+
+ for ( qtmp=q; qtmp->next->busy; qtmp=qtmp->next )
+ CYG_EMPTY_STATEMENT; // skip through
+
+ qent = qtmp->next;
+ qtmp->next = qent->next;
+ } // else
+
+ // now stick at front of freelist, but marked busy
+ qent->next = freelist;
+ freelist = qent;
+
+ qent->busy = true; // don't let it truly be part of the freelist just yet
+ // till the data is copied out
+
+ // unlock the scheduler, and potentially switch threads, but
+ // that's okay now. We don't want it locked for the expensive memcpy
+ Cyg_Scheduler::unlock();
+
+ *len = qent->buflen;
+ if ( NULL != prio )
+ *prio = qent->priority;
+ memcpy( buf, qent->buf(), *len );
+
+ // make available now - setting non-atomically is alright if you think
+ // about it - the only thing that matters is that it's completed before
+ // the post()
+ qent->busy = false;
+
+ putsem.post();
+
+ err = OK;
+
+ exit:
+ CYG_ASSERT_THISC();
+ CYG_REPORT_RETVAL(err);
+ return err;
+
+} // Cyg_Mqueue::get()
+
+//------------------------------------------------------------------------
+
+// count() returns the number of messages in the queue
+inline long
+Cyg_Mqueue::count()
+{
+ CYG_REPORT_FUNCTYPE("curmsgs=%d");
+
+ long curmsgs = (long)getsem.peek();
+
+ CYG_REPORT_RETVAL(curmsgs);
+ return curmsgs;
+} // Cyg_Mqueue::count()
+
+//------------------------------------------------------------------------
+
+
+// Supply a callback function to call (with the supplied data argument)
+// when the queue goes from empty to non-empty (unless someone's already
+// doing a get()). This returns the old callback_fn, and if olddata is
+// non-NULL sets it to the old data (yes, really!)
+CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE Cyg_Mqueue::callback_fn_t
+Cyg_Mqueue::setnotify( callback_fn_t callback_fn, CYG_ADDRWORD data,
+ CYG_ADDRWORD *olddata)
+{
+ CYG_REPORT_FUNCTYPE("old callback=%08x");
+ CYG_REPORT_FUNCARG3XV( callback_fn, data, olddata );
+ if ( NULL != callback_fn )
+ CYG_CHECK_FUNC_PTRC( callback_fn );
+ if (NULL != olddata)
+ CYG_CHECK_DATA_PTRC( olddata );
+
+ callback_fn_t oldfn;
+
+ // Need to prevent preemption for accessing common structures
+ // Just locking the scheduler has the least overhead
+ Cyg_Scheduler::lock();
+
+ oldfn = callback;
+ if (NULL != olddata)
+ *olddata = callback_data;
+
+ callback_data = data;
+ callback = callback_fn;
+
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETVAL(oldfn);
+ return oldfn;
+}
+
+//------------------------------------------------------------------------
+
+#endif /* CYGONCE_KERNEL_MQUEUE_INL multiple inclusion protection */
+
+/* EOF mqueue.inl */
diff --git a/ecos/packages/kernel/current/include/mutex.hxx b/ecos/packages/kernel/current/include/mutex.hxx
new file mode 100644
index 0000000000..d37e001559
--- /dev/null
+++ b/ecos/packages/kernel/current/include/mutex.hxx
@@ -0,0 +1,217 @@
+#ifndef CYGONCE_KERNEL_MUTEX_HXX
+#define CYGONCE_KERNEL_MUTEX_HXX
+
+//==========================================================================
+//
+// mutex.hxx
+//
+// Mutex class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-09
+// Purpose: Define Mutex class interfaces
+// Description: The classes defined here provide the APIs for mutexes
+// and condition variables.
+// Usage: #include <cyg/kernel/mutex.hxx>
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <cyg/kernel/thread.hxx>
+
+// -------------------------------------------------------------------------
+// Mutex.
+
+class Cyg_Mutex
+{
+ friend class Cyg_Condition_Variable;
+
+ cyg_atomic locked; // true if locked. This may seem
+ // redundant due to "owner" below,
+ // but is intentionally present for
+ // future SMP support.
+
+ Cyg_Thread *owner; // Current locking thread
+
+ Cyg_ThreadQueue queue; // Queue of waiting threads
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+
+public:
+ enum cyg_protcol
+ {
+ NONE = 0, // no inversion protocol
+ INHERIT, // priority inheritance protocol
+ CEILING // priority ceiling protocol
+ };
+
+private:
+ cyg_protcol protocol; // this mutex's protocol
+
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+
+private:
+ cyg_priority ceiling; // mutex priority ceiling
+
+#endif
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Mutex(); // Create in unlocked state
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+
+ Cyg_Mutex( cyg_protcol protocol ); // Create with defined protocol
+
+#endif
+
+ ~Cyg_Mutex(); // Destructor
+
+ cyg_bool lock(); // lock and/or wait
+
+ cyg_bool trylock(); // try to lock and return success
+
+ void unlock(); // unlock
+
+ void release(); // release all waiting threads
+
+ // Get the current owning thread
+ inline Cyg_Thread *get_owner() { return owner; }
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+
+ // set ceiling priority for priority ceiling protocol
+ void set_ceiling( cyg_priority priority );
+
+ cyg_priority get_ceiling(void) { return ceiling; };
+
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+
+ // set inversion protocol
+ void set_protocol( cyg_protcol new_protocol );
+#endif
+
+};
+
+// -------------------------------------------------------------------------
+// Condition variable.
+
+class Cyg_Condition_Variable
+{
+ Cyg_Mutex *mutex; // Associated mutex
+
+ Cyg_ThreadQueue queue; // Queue of waiting threads
+
+ // Private internal implementation function for wait operations
+ cyg_bool wait_inner( Cyg_Mutex *mutex );
+
+#ifdef CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT
+
+ // Private internal implementation function for timed wait operations
+ cyg_bool wait_inner( Cyg_Mutex *mutex, cyg_tick_count timeout );
+
+#endif
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Condition_Variable(); // simple constructor
+
+ Cyg_Condition_Variable(
+ Cyg_Mutex &mutex // linked mutex
+ );
+
+ ~Cyg_Condition_Variable(); // Destructor
+
+
+ void signal(); // Set cond true, wake one thread
+
+ void broadcast(); // Set cond true, wake all threads
+
+ // Wait for condition to be true
+ inline cyg_bool wait() { return wait_inner( mutex ); }
+
+#ifdef CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT
+
+ // Wait until a signal or timeout expiry
+ inline cyg_bool wait( cyg_tick_count timeout )
+ { return wait_inner( mutex, timeout ); }
+
+#endif
+
+#ifdef CYGMFN_KERNEL_SYNCH_CONDVAR_WAIT_MUTEX
+
+ // Wait for condition to be true using the supplied mutex
+ inline cyg_bool wait( Cyg_Mutex &mx ) { return wait_inner( &mx ); }
+
+
+#ifdef CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT
+
+ // Wait until a signal or timeout expiry, using the supplied mutex
+ inline cyg_bool wait( Cyg_Mutex &mx, cyg_tick_count timeout )
+ { return wait_inner( &mx, timeout ); }
+
+#endif
+#endif
+
+ // Return a pointer to this variables thread queue. Used mainly
+ // for testing whether a thread is on the queue for a particular
+ // cv.
+ inline Cyg_ThreadQueue *get_queue() { return &queue; };
+
+};
+
+
+// -------------------------------------------------------------------------
+
+#endif // ifndef CYGONCE_KERNEL_MUTEX_HXX
+// EOF mutex.hxx
diff --git a/ecos/packages/kernel/current/include/sched.hxx b/ecos/packages/kernel/current/include/sched.hxx
new file mode 100644
index 0000000000..241363d10d
--- /dev/null
+++ b/ecos/packages/kernel/current/include/sched.hxx
@@ -0,0 +1,412 @@
+#ifndef CYGONCE_KERNEL_SCHED_HXX
+#define CYGONCE_KERNEL_SCHED_HXX
+
+//==========================================================================
+//
+// sched.hxx
+//
+// Scheduler class declaration(s)
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-09
+// Purpose: Define Scheduler class interfaces
+// Description: These class definitions supply the internal API
+// used to scheduler threads.
+// Usage: #include <cyg/kernel/sched.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <cyg/kernel/smp.hxx> // SMP support
+
+// -------------------------------------------------------------------------
+// Miscellaneous types
+
+#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
+
+typedef void Cyg_ASR( CYG_ADDRWORD data ); // ASR type signature
+
+#endif
+
+__externC void cyg_scheduler_set_need_reschedule();
+
+// -------------------------------------------------------------------------
+// Scheduler base class. This defines stuff that is needed by the
+// specific scheduler implementation. Each scheduler comprises three
+// classes: Cyg_Scheduler_Base, Cyg_Scheduler_Implementation which
+// inherits from it and Cyg_Scheduler which inherits from _it_ in turn.
+
+class Cyg_Scheduler_Base
+ : public Cyg_Scheduler_SchedLock
+{
+ friend class Cyg_HardwareThread;
+ friend class Cyg_SchedThread;
+
+protected:
+ // The following variables are implicit in the API, but are
+ // not publically visible.
+
+ // Current running thread
+ static Cyg_Thread * volatile current_thread[CYGNUM_KERNEL_CPU_MAX]
+ CYGBLD_ANNOTATE_VARIABLE_SCHED;
+
+ // Set when reschedule needed
+ static volatile cyg_bool need_reschedule[CYGNUM_KERNEL_CPU_MAX]
+ CYGBLD_ANNOTATE_VARIABLE_SCHED;
+
+ // Count of number of thread switches
+ static volatile cyg_ucount32 thread_switches[CYGNUM_KERNEL_CPU_MAX]
+ CYGBLD_ANNOTATE_VARIABLE_SCHED;
+
+public:
+
+ // return a pointer to the current thread
+ static Cyg_Thread *get_current_thread();
+
+ // Set current thread pointer
+ static void set_current_thread(Cyg_Thread *thread);
+ static void set_current_thread(Cyg_Thread *thread, HAL_SMP_CPU_TYPE cpu);
+
+ // Set need_reschedule flag
+ static void set_need_reschedule();
+ static void set_need_reschedule(Cyg_Thread *thread);
+
+ // Get need_reschedule flag
+ static cyg_bool get_need_reschedule();
+
+ // Return current value of lock
+ static cyg_ucount32 get_sched_lock();
+
+ // Clear need_reschedule flag
+ static void clear_need_reschedule();
+
+ // Return current number of thread switches
+ static cyg_ucount32 get_thread_switches();
+
+};
+
+// -------------------------------------------------------------------------
+// Include the scheduler implementation header
+
+#include CYGPRI_KERNEL_SCHED_IMPL_HXX
+
+// Do some checking that we have a consistent universe.
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
+# ifndef CYGIMP_THREAD_PRIORITY
+# error Priority inversion protocols will not work without priorities!!!
+# endif
+#endif
+
+// -------------------------------------------------------------------------
+// Scheduler class. This is the public scheduler interface seen by the
+// rest of the kernel.
+
+class Cyg_Scheduler
+ : public Cyg_Scheduler_Implementation
+{
+ friend class Cyg_Thread;
+
+ // This function is the actual implementation of the unlock
+ // function. The unlock() later is an inline shell that deals
+ // with the common case.
+
+ static void unlock_inner(cyg_uint32 new_lock = 0);
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ // The following API functions are common to all scheduler
+ // implementations.
+
+ // claim the preemption lock
+ static void lock();
+
+ // release the preemption lock and possibly reschedule
+ static void unlock();
+
+ // release and reclaim the lock atomically, keeping the old
+ // value on restart
+ static void reschedule();
+
+ // decrement the lock but also look for a reschedule opportunity
+ static void unlock_reschedule();
+
+ // release the preemption lock without rescheduling
+ static void unlock_simple();
+
+ // Start execution of the scheduler
+ static void start() CYGBLD_ATTRIB_NORET;
+
+ // Start execution of the scheduler on the current CPU
+ static void start_cpu() CYGBLD_ATTRIB_NORET;
+
+ // The only scheduler instance should be this one...
+ static Cyg_Scheduler scheduler CYGBLD_ANNOTATE_VARIABLE_SCHED;
+
+};
+
+// -------------------------------------------------------------------------
+// This class encapsulates the scheduling abstractions in a thread.
+// Cyg_SchedThread is included as a base class of Cyg_Thread. The actual
+// implementation of the abstractions is in Cyg_SchedThread_Implementation
+// so this class has little to do.
+
+class Cyg_SchedThread
+ : public Cyg_SchedThread_Implementation
+{
+ friend class Cyg_ThreadQueue_Implementation;
+ friend class Cyg_Scheduler_Implementation;
+ friend class Cyg_Scheduler;
+
+ Cyg_ThreadQueue *queue;
+
+
+public:
+
+ Cyg_SchedThread(Cyg_Thread *thread, CYG_ADDRWORD sched_info);
+
+ // Return current queue pointer
+
+ Cyg_ThreadQueue *get_current_queue();
+
+ // Remove this thread from current queue
+ void remove();
+
+#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
+
+ // ASR support.
+ // An ASR is an Asynchronous Service Routine. When set pending it
+ // is called when the thread exits the scheduler. ASRs are mainly
+ // used by compatibility subsystems, such as POSIX, to implement
+ // such things as thread cancellation and signal delivery.
+
+private:
+
+ volatile cyg_ucount32 asr_inhibit; // If > 0, blocks calls to ASRs
+
+ volatile cyg_bool asr_pending; // If true, this thread's ASR should be called.
+
+#ifdef CYGSEM_KERNEL_SCHED_ASR_GLOBAL
+ static
+#endif
+ Cyg_ASR *asr; // ASR function
+#ifdef CYGSEM_KERNEL_SCHED_ASR_DATA_GLOBAL
+ static
+#endif
+ CYG_ADDRWORD asr_data; // ASR data pointer
+
+ // Default ASR function
+ static void asr_default(CYG_ADDRWORD data);
+
+public:
+
+ // Public interface to ASR mechanism
+
+ // Set, clear and get inhibit flag.
+ inline void set_asr_inhibit() { asr_inhibit++; }
+ inline void clear_asr_inhibit() { asr_inhibit--; }
+ inline cyg_ucount32 get_asr_inhibit() { return asr_inhibit; }
+
+ // Set and get pending flag. The flag is only cleared when the
+ // ASR is called.
+ inline void set_asr_pending() { asr_pending = true; }
+ inline cyg_bool get_asr_pending() { return asr_pending; }
+
+ // Set a new ASR, returning the old one.
+ void set_asr( Cyg_ASR *new_asr, CYG_ADDRWORD new_data,
+ Cyg_ASR **old_asr, CYG_ADDRWORD *old_data);
+
+ // Clear the ASR function back to the default.
+ void clear_asr();
+
+#else
+
+public:
+
+ // Even when we do not have ASRs enabled, we keep these functions
+ // available. This avoids excessive ifdefs in the rest of the
+ // kernel code.
+ inline void set_asr_inhibit() { }
+ inline void clear_asr_inhibit() { }
+
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
+
+private:
+
+ // For all priority inversion protocols we need to keep track of how
+ // many mutexes we have locked, including one which we are waiting to
+ // lock, because we can inherit priority while sleeping just prior to
+ // wakeup.
+
+ cyg_count32 mutex_count;
+
+protected:
+ // These are implementation functions that are common to all protocols.
+
+ // Inherit the given priority. If thread is non-NULL the priority is
+ // being inherited from it, otherwise it has come from the mutex.
+ void set_inherited_priority( cyg_priority pri, Cyg_Thread *thread = 0 );
+
+ // Relay the priority of the ex-owner thread or from the queue if it
+ // has a higher priority than ours.
+ void relay_inherited_priority( Cyg_Thread *ex_owner, Cyg_ThreadQueue *pqueue);
+
+ // Lose priority inheritance
+ void clear_inherited_priority();
+
+public:
+ // Count and uncount the number of mutexes held by
+ // this thread.
+ void count_mutex() { mutex_count++; };
+ void uncount_mutex() { mutex_count--; };
+
+#if defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE)
+
+protected:
+
+ // The simple priority inversion protocols simply needs
+ // somewhere to store the base priority of the current thread.
+
+ cyg_priority original_priority; // our original priority
+
+ cyg_bool priority_inherited; // have we inherited?
+
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+
+public:
+
+ // Inherit the priority of the provided thread if it
+ // has higher priority than this.
+ void inherit_priority( Cyg_Thread *thread);
+
+ // Relay the priority of the ex-owner thread or from the queue if it
+ // has a higher priority than ours.
+ void relay_priority( Cyg_Thread *ex_owner, Cyg_ThreadQueue *pqueue);
+
+ // Lose priority inheritance
+ void disinherit_priority();
+
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+
+public:
+
+ // Set the priority of this thread to the given ceiling.
+ void set_priority_ceiling( cyg_priority pri );
+
+ // Clear the ceiling, if necessary.
+ void clear_priority_ceiling();
+
+#endif
+
+#endif
+
+};
+
+// -------------------------------------------------------------------------
+// Simple inline accessor functions
+
+inline Cyg_Thread *Cyg_Scheduler_Base::get_current_thread()
+{
+ return current_thread[CYG_KERNEL_CPU_THIS()];
+}
+
+inline void Cyg_Scheduler_Base::set_current_thread(Cyg_Thread *thread )
+{
+ current_thread[CYG_KERNEL_CPU_THIS()] = thread;
+}
+
+inline void Cyg_Scheduler_Base::set_current_thread(Cyg_Thread *thread,
+ HAL_SMP_CPU_TYPE cpu)
+{
+ current_thread[cpu] = thread;
+}
+
+inline cyg_bool Cyg_Scheduler_Base::get_need_reschedule()
+{
+ return need_reschedule[CYG_KERNEL_CPU_THIS()];
+}
+
+inline void Cyg_Scheduler_Base::set_need_reschedule()
+{
+ need_reschedule[CYG_KERNEL_CPU_THIS()] = true;
+}
+
+inline void Cyg_Scheduler_Base::set_need_reschedule(Cyg_Thread *thread)
+{
+ need_reschedule[CYG_KERNEL_CPU_THIS()] = true;
+}
+
+inline void Cyg_Scheduler_Base::clear_need_reschedule()
+{
+ need_reschedule[CYG_KERNEL_CPU_THIS()] = false;
+}
+
+inline cyg_ucount32 Cyg_Scheduler_Base::get_sched_lock()
+{
+ return Cyg_Scheduler_SchedLock::get_sched_lock();
+}
+
+// Return current number of thread switches
+inline cyg_ucount32 Cyg_Scheduler_Base::get_thread_switches()
+{
+ return thread_switches[CYG_KERNEL_CPU_THIS()];
+}
+
+// Return current queue pointer
+inline Cyg_ThreadQueue *Cyg_SchedThread::get_current_queue()
+{
+ return queue;
+}
+
+// -------------------------------------------------------------------------
+#endif // ifndef __SCHED_HXX__
+// EOF sched.hxx
diff --git a/ecos/packages/kernel/current/include/sched.inl b/ecos/packages/kernel/current/include/sched.inl
new file mode 100644
index 0000000000..90b92fe0fb
--- /dev/null
+++ b/ecos/packages/kernel/current/include/sched.inl
@@ -0,0 +1,168 @@
+#ifndef CYGONCE_KERNEL_SCHED_INL
+#define CYGONCE_KERNEL_SCHED_INL
+
+//==========================================================================
+//
+// sched.inl
+//
+// Scheduler class inlines
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-09
+// Purpose: Define inlines for scheduler classes
+// Description: Inline functions for the scheduler classes. These are
+// not defined in the header so that we have the option
+// of making them non-inline.
+// Usage:
+// #include <cyg/kernel/sched.hxx>
+// ...
+// #include <cyg/kernel/sched.inl>
+// ...
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/instrmnt.h>
+#include <cyg/hal/hal_arch.h>
+
+// -------------------------------------------------------------------------
+// Inlines for Cyg_Scheduler class
+
+inline void Cyg_Scheduler::lock()
+{
+ // We do not need to do a read-modify-write sequence here because
+ // the scheduler lock is strictly nesting. Even if we are interrupted
+ // partway through the increment, the lock will be returned to the same
+ // value before we are resumed/rescheduled.
+
+ HAL_REORDER_BARRIER();
+
+ inc_sched_lock();
+
+ HAL_REORDER_BARRIER();
+
+ CYG_INSTRUMENT_SCHED(LOCK,get_sched_lock(),0);
+};
+
+inline void Cyg_Scheduler::unlock()
+{
+ // This is an inline wrapper for the real scheduler unlock function in
+ // Cyg_Scheduler::unlock_inner().
+
+ // Only do anything if the lock is about to go zero, otherwise we simply
+ // decrement and return. As with lock() we do not need any special code
+ // to decrement the lock counter.
+
+ CYG_INSTRUMENT_SCHED(UNLOCK,get_sched_lock(),0);
+
+ HAL_REORDER_BARRIER();
+
+ cyg_ucount32 __lock = get_sched_lock() - 1;
+
+ if( __lock == 0 ) unlock_inner(0);
+ else set_sched_lock(__lock);
+
+ HAL_REORDER_BARRIER();
+}
+
+inline void Cyg_Scheduler::reschedule()
+{
+ // This function performs the equivalent of calling unlock() and
+ // lock() is succession. Unlike that pair, however, it does not
+ // leave a brief window between the calls when the lock is unclaimed
+ // by the current thread.
+
+ CYG_INSTRUMENT_SCHED(RESCHEDULE,get_sched_lock(),0);
+
+ unlock_inner( get_sched_lock() );
+}
+
+inline void Cyg_Scheduler:: unlock_reschedule()
+{
+ // This function decrements the scheduler lock and also looks for
+ // a reschedule opportunity. When the lock is being decremented
+ // from 1 to zero this function is equivalent to unlock. When the
+ // lock is being decremented to a non-zero value, it is more or less
+ // equivalent to reschedule() followed by unlock().
+
+ CYG_INSTRUMENT_SCHED(UNLOCK,get_sched_lock(),0);
+
+ unlock_inner( get_sched_lock() - 1 );
+}
+
+inline void Cyg_Scheduler::unlock_simple()
+{
+ // This function decrements the lock, but does not call unlock_inner().
+ // Therefore does not immediately allow another thread to run:
+ // merely makes it possible for some other thread to run at some
+ // indeterminate future time. This is mainly for use by
+ // debuggers, it should not normally be used anywhere else.
+
+ CYG_INSTRUMENT_SCHED(UNLOCK,get_sched_lock(),0);
+
+ HAL_REORDER_BARRIER();
+
+ if (get_sched_lock() > 1)
+ set_sched_lock(get_sched_lock() - 1);
+ else zero_sched_lock();
+
+ HAL_REORDER_BARRIER();
+}
+
+
+// -------------------------------------------------------------------------
+// Inlines for Cyg_SchedThread class
+
+#include <cyg/kernel/thread.inl> // we use some thread inlines here
+
+inline void Cyg_SchedThread::remove()
+{
+ if( queue != NULL )
+ {
+ queue->remove((Cyg_Thread *)this);
+ queue = NULL;
+ }
+}
+
+// -------------------------------------------------------------------------
+
+#endif // ifndef CYGONCE_KERNEL_SCHED_INL
+// EOF sched.inl
diff --git a/ecos/packages/kernel/current/include/sema.hxx b/ecos/packages/kernel/current/include/sema.hxx
new file mode 100644
index 0000000000..d97ff13849
--- /dev/null
+++ b/ecos/packages/kernel/current/include/sema.hxx
@@ -0,0 +1,137 @@
+#ifndef CYGONCE_KERNEL_SEMA_HXX
+#define CYGONCE_KERNEL_SEMA_HXX
+
+//==========================================================================
+//
+// sema.hxx
+//
+// Semaphore class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-09
+// Purpose: Define Semaphore class interfaces
+// Description: The classes defined here provide the APIs for binary
+// and counting semaphores.
+// Usage: #include <cyg/kernel/sema.hxx>
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/thread.inl> // thread inlines
+
+// -------------------------------------------------------------------------
+// Binary semaphore. This has only two states: posted and not-posted.
+
+class Cyg_Binary_Semaphore
+{
+ cyg_bool state; // The binary semaphore state
+
+ Cyg_ThreadQueue queue; // Queue of waiting threads
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Binary_Semaphore( // Constructor
+ cyg_bool init_state = false // Initial state value
+ );
+
+ ~Cyg_Binary_Semaphore(); // Destructor
+
+ cyg_bool wait(); // Wait until state == true
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_bool wait( cyg_tick_count timeout );
+#endif // Wait until state == true or timeout
+
+ cyg_bool trywait(); // Set state false if possible
+
+ void post(); // Increment count
+
+ cyg_bool posted(); // Get current state
+
+};
+
+// -------------------------------------------------------------------------
+// Counting semaphore. This implements the usual counter based semaphore.
+
+class Cyg_Counting_Semaphore
+{
+ cyg_count32 count; // The semaphore count
+
+ Cyg_ThreadQueue queue; // Queue of waiting threads
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Counting_Semaphore( // Constructor
+ cyg_count32 init_count = 0 // Initial count value
+ );
+
+ ~Cyg_Counting_Semaphore(); // Destructor
+
+ cyg_bool wait(); // Wait until decrement
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_bool wait( cyg_tick_count timeout );
+#endif // Wait until decrement or timeout
+
+ cyg_bool trywait(); // Try to decrement
+
+ void post(); // Increment count
+
+ cyg_count32 peek() const; // Get current count value
+
+ inline
+ cyg_bool waiting() // Is anyone waiting?
+ {
+ return !queue.empty();
+ }
+
+};
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_SEMA_HXX
+// EOF sema.hxx
diff --git a/ecos/packages/kernel/current/include/sema2.hxx b/ecos/packages/kernel/current/include/sema2.hxx
new file mode 100644
index 0000000000..807f0cf3c8
--- /dev/null
+++ b/ecos/packages/kernel/current/include/sema2.hxx
@@ -0,0 +1,137 @@
+#ifndef CYGONCE_KERNEL_SEMA2_HXX
+#define CYGONCE_KERNEL_SEMA2_HXX
+
+//==========================================================================
+//
+// sema2.hxx
+//
+// Semaphore class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-09
+// Purpose: Define Semaphore class interfaces
+// Description: The classes defined here provide the APIs for binary
+// and counting semaphores.
+// Usage: #include <cyg/kernel/sema2.hxx>
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/thread.hxx>
+
+#if 0
+// THERE IS NO BINARY-SEMAPHORE-2
+
+// -------------------------------------------------------------------------
+// Binary semaphore. This has only two states: posted and not-posted.
+
+class Cyg_Binary_Semaphore2
+{
+ cyg_bool state; // The binary semaphore state
+
+ Cyg_ThreadQueue queue; // Queue of waiting threads
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Binary_Semaphore2( // Constructor
+ cyg_bool init_state = false // Initial state value
+ );
+
+ ~Cyg_Binary_Semaphore2(); // Destructor
+
+ cyg_bool wait(); // Wait until state == true
+
+ cyg_bool trywait(); // Set state false if possible
+
+ void post(); // Increment count
+
+ cyg_bool posted(); // Get current state
+
+};
+#endif
+
+// -------------------------------------------------------------------------
+// Counting semaphore. This implements the usual counter based semaphore.
+
+class Cyg_Counting_Semaphore2
+{
+ cyg_count32 count; // The semaphore count
+
+ Cyg_ThreadQueue queue; // Queue of waiting threads
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Counting_Semaphore2( // Constructor
+ cyg_count32 init_count = 0 // Initial count value
+ );
+
+ ~Cyg_Counting_Semaphore2(); // Destructor
+
+ cyg_bool wait(); // Wait until decrement
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_bool wait( cyg_tick_count abs_timeout );
+#endif // Wait until decrement or timeout
+
+ cyg_bool trywait(); // Try to decrement
+
+ void post(); // Increment count
+
+ cyg_count32 peek() const; // Get current count value
+
+ inline
+ cyg_bool waiting() // Is anyone waiting?
+ {
+ return !queue.empty();
+ }
+
+};
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_SEMA2_HXX
+// EOF sema2.hxx
diff --git a/ecos/packages/kernel/current/include/smp.hxx b/ecos/packages/kernel/current/include/smp.hxx
new file mode 100644
index 0000000000..ed18b1a1bb
--- /dev/null
+++ b/ecos/packages/kernel/current/include/smp.hxx
@@ -0,0 +1,468 @@
+#ifndef CYGONCE_KERNEL_SMP_HXX
+#define CYGONCE_KERNEL_SMP_HXX
+
+//==========================================================================
+//
+// smp.hxx
+//
+// SMP kernel support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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-02-10
+// Purpose: Kernel SMP support
+// Description: If SMP support is configured into the kernel, then this file
+// translates HAL defined macros into C and C++ classes and methods
+// that can be called from the rest of the kernel. If SMP is not
+// configured in, then the same classes and methods are defined here
+// to operate correctly in a single CPU configuration.
+//
+// Usage: #include <cyg/kernel/smp.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <cyg/hal/hal_intr.h> // HAL_DISABLE_INTERRUPTS() etc.
+
+#include <cyg/kernel/instrmnt.h>
+
+//==========================================================================
+
+#if defined(CYGPKG_KERNEL_SMP_SUPPORT) && (CYGPKG_HAL_SMP_SUPPORT)
+
+//==========================================================================
+// SMP support is included
+
+#define CYG_KERNEL_SMP_ENABLED
+
+// -------------------------------------------------------------------------
+// Get HAL support
+
+#include <cyg/hal/hal_smp.h>
+
+// -------------------------------------------------------------------------
+// Defined values
+// These all just map straight through to the HAL.
+
+#define CYGNUM_KERNEL_CPU_MAX HAL_SMP_CPU_MAX
+
+#define CYG_KERNEL_CPU_COUNT() HAL_SMP_CPU_COUNT()
+
+#define CYG_KERNEL_CPU_START_COUNT() HAL_SMP_CPU_START_COUNT()
+
+#define CYG_KERNEL_CPU_THIS() HAL_SMP_CPU_THIS()
+
+#define CYG_KERNEL_CPU_NONE HAL_SMP_CPU_NONE
+
+// -------------------------------------------------------------------------
+// CPU control
+
+#define CYG_KERNEL_CPU_START( __cpu ) HAL_SMP_CPU_START( __cpu )
+
+#define CYG_KERNEL_CPU_RESCHEDULE_INTERRUPT( __cpu, __wait ) \
+ HAL_SMP_CPU_RESCHEDULE_INTERRUPT( __cpu, __wait )
+
+#define CYG_KERNEL_CPU_TIMESLICE_INTERRUPT( __cpu, __wait ) \
+ HAL_SMP_CPU_TIMESLICE_INTERRUPT( __cpu, __wait )
+
+// -------------------------------------------------------------------------
+// Scheduler lock default implementation.
+
+// This implementation should serve for most targets. However, some
+// targets may have hardware or other features that make simple
+// spinlocks impossible, or allow us to implement the scheduler lock
+// in a more efficient manner. If that is the case then the HAL will
+// implement these macros itself.
+
+#ifndef HAL_SMP_SCHEDLOCK_DATA_TYPE
+
+#define HAL_SMP_SCHEDLOCK_DATA_TYPE struct hal_smp_schedlock_data_type
+
+struct hal_smp_schedlock_data_type {
+ HAL_SPINLOCK_TYPE spinlock;
+ volatile HAL_SMP_CPU_TYPE holder;
+};
+
+#define HAL_SMP_SCHEDLOCK_INIT( __lock, __data ) \
+CYG_MACRO_START \
+{ \
+ __lock = 1; \
+ HAL_SPINLOCK_CLEAR(__data.spinlock); \
+ HAL_SPINLOCK_SPIN(__data.spinlock); \
+ __data.holder = HAL_SMP_CPU_THIS(); \
+} \
+CYG_MACRO_END
+
+
+#define HAL_SMP_SCHEDLOCK_INC( __lock, __data ) \
+CYG_MACRO_START \
+{ \
+ CYG_INTERRUPT_STATE __state; \
+ HAL_DISABLE_INTERRUPTS(__state); \
+ if( __data.holder == HAL_SMP_CPU_THIS() ) \
+ __lock++; \
+ else \
+ { \
+ CYG_INSTRUMENT_SMP(LOCK_WAIT,CYG_KERNEL_CPU_THIS(),0); \
+ HAL_SPINLOCK_SPIN(__data.spinlock); \
+ __data.holder = HAL_SMP_CPU_THIS(); \
+ __lock++; \
+ CYG_INSTRUMENT_SMP(LOCK_GOT,CYG_KERNEL_CPU_THIS(),0); \
+ } \
+ HAL_RESTORE_INTERRUPTS(__state); \
+} \
+CYG_MACRO_END
+
+#define HAL_SMP_SCHEDLOCK_ZERO( __lock, __data ) \
+CYG_MACRO_START \
+{ \
+ CYG_INTERRUPT_STATE __state; \
+ HAL_DISABLE_INTERRUPTS(__state); \
+ CYG_ASSERT( __data.holder == HAL_SMP_CPU_THIS(), "Zeroing schedlock not owned by me!"); \
+ __lock = 0; \
+ __data.holder = HAL_SMP_CPU_NONE; \
+ HAL_SPINLOCK_CLEAR(__data.spinlock); \
+ HAL_RESTORE_INTERRUPTS(__state); \
+} \
+CYG_MACRO_END
+
+#define HAL_SMP_SCHEDLOCK_SET( __lock, __data, __new ) \
+CYG_MACRO_START \
+{ \
+ CYG_ASSERT( __data.holder == HAL_SMP_CPU_THIS(), "Setting schedlock not owned by me!"); \
+ __lock = __new; \
+} \
+CYG_MACRO_END
+
+#endif
+
+// -------------------------------------------------------------------------
+// SpinLock class
+// This class supplies a C++ wrapper for the HAL spinlock API.
+
+#ifdef __cplusplus
+
+#ifdef HAL_SPINLOCK_SPIN
+
+class Cyg_SpinLock
+{
+ HAL_SPINLOCK_TYPE lock;
+
+public:
+
+ // Constructor, initialize the lock to clear
+ Cyg_SpinLock() { lock = HAL_SPINLOCK_INIT_CLEAR; };
+
+ ~Cyg_SpinLock()
+ {
+// CYG_ASSERT( !test(), "spinlock still claimed");
+ };
+
+ // Spin on the lock.
+ void spin()
+ {
+ HAL_SPINLOCK_SPIN(lock);
+ };
+
+ // Clear the lock.
+ void clear()
+ {
+ HAL_SPINLOCK_CLEAR(lock);
+ };
+
+ // Try to claim the lock. Return true if successful, false if not.
+ cyg_bool trylock()
+ {
+ cyg_bool testval;
+ HAL_SPINLOCK_TRY(lock,testval);
+ return testval;
+ };
+
+ // Test the current value of the lock
+ cyg_bool test()
+ {
+ cyg_bool testval;
+ HAL_SPINLOCK_TEST(lock, testval);
+ return testval;
+ };
+
+
+ // The following two member functions are only necessary if the
+ // spinlock is to be used in an ISR.
+
+ // Claim the spinlock, but also mask this CPU's interrupts while
+ // we have it.
+ void spin_intsave(CYG_INTERRUPT_STATE *state)
+ {
+ CYG_INTERRUPT_STATE s;
+ HAL_DISABLE_INTERRUPTS(s);
+ *state = s;
+ spin();
+ };
+
+ // Clear the lock, and restore the interrupt state saved in
+ // spin_intsave().
+ void clear_intsave(CYG_INTERRUPT_STATE state)
+ {
+ clear();
+ HAL_RESTORE_INTERRUPTS(state);
+ };
+};
+
+#endif
+
+// -------------------------------------------------------------------------
+// Scheduler lock class
+// This uses the scheduler lock API defined by the HAL, or the defaults
+// defined above.
+
+class Cyg_Scheduler_SchedLock
+{
+ static volatile cyg_ucount32 sched_lock // lock counter
+ CYGBLD_ATTRIB_ASM_ALIAS( cyg_scheduler_sched_lock )
+ CYGBLD_ANNOTATE_VARIABLE_SCHED
+ ;
+
+ static HAL_SMP_SCHEDLOCK_DATA_TYPE lock_data
+ CYGBLD_ANNOTATE_VARIABLE_SCHED;
+
+protected:
+
+ Cyg_Scheduler_SchedLock()
+ {
+ HAL_SMP_SCHEDLOCK_INIT( sched_lock, lock_data );
+ };
+
+ // Increment the scheduler lock. If this takes the lock from zero
+ // to one then this code must also do whatever is necessary to
+ // serialize CPUs through the scheduler.
+ static void inc_sched_lock()
+ {
+ CYG_INSTRUMENT_SMP(LOCK_INC,CYG_KERNEL_CPU_THIS(),0);
+ HAL_SMP_SCHEDLOCK_INC( sched_lock, lock_data );
+ };
+
+ // Zero the scheduler lock. This will release the CPU serializing
+ // lock and allow another CPU in.
+ static void zero_sched_lock()
+ {
+ CYG_INSTRUMENT_SMP(LOCK_ZERO,CYG_KERNEL_CPU_THIS(),0);
+ CYG_ASSERT( sched_lock != 0, "Scheduler lock already zero");
+ HAL_SMP_SCHEDLOCK_ZERO( sched_lock, lock_data );
+ };
+
+ // Set the scheduler lock to a non-zero value. Both the scheduler
+ // lock and the new value must be non-zero.
+ static void set_sched_lock(cyg_uint32 new_lock)
+ {
+ CYG_INSTRUMENT_SMP(LOCK_SET,CYG_KERNEL_CPU_THIS(),new_lock);
+ CYG_ASSERT( new_lock > 0, "New scheduler lock value == 0");
+ CYG_ASSERT( sched_lock > 0, "Scheduler lock == 0");
+ HAL_SMP_SCHEDLOCK_SET( sched_lock, lock_data, new_lock );
+ };
+
+ static cyg_ucount32 get_sched_lock()
+ {
+ return sched_lock;
+ };
+};
+
+#define CYGIMP_KERNEL_SCHED_LOCK_DEFINITIONS \
+volatile cyg_ucount32 Cyg_Scheduler_SchedLock::sched_lock = 1; \
+HAL_SMP_SCHEDLOCK_DATA_TYPE Cyg_Scheduler_SchedLock::lock_data;
+
+#endif // __cplusplus
+
+// -------------------------------------------------------------------------
+
+#else // defined(CYGSEM_KERNEL_SMP_SUPPORT) && (CYGSEM_HAL_SMP_SUPPORT)
+
+//==========================================================================
+// SMP support is NOT included.
+
+#undef CYG_KERNEL_SMP_ENABLED
+
+// -------------------------------------------------------------------------
+// Defined values
+// Supply a set of values that describe a single CPU system.
+
+#ifndef HAL_SMP_CPU_TYPE
+#define HAL_SMP_CPU_TYPE cyg_uint32
+#endif
+
+#define CYGNUM_KERNEL_CPU_MAX 1
+
+#define CYG_KERNEL_CPU_COUNT() 1
+
+#define CYG_KERNEL_CPU_THIS() 0
+
+#define CYG_KERNEL_CPU_NONE -1
+
+#define CYG_KERNEL_CPU_LOWPRI() CYG_KERNEL_CPU_THIS()
+
+// -------------------------------------------------------------------------
+// SpinLock class
+// This single CPU version simply goes through the motions of setting
+// and clearing the lock variable for debugging purposes.
+
+#ifdef __cplusplus
+
+class Cyg_SpinLock
+{
+ volatile cyg_uint32 lock;
+
+public:
+
+ // Constructor, initialize the lock to clear
+ Cyg_SpinLock() { lock = 0; };
+
+ ~Cyg_SpinLock()
+ {
+ CYG_ASSERT( lock == 0, "spinlock still claimed");
+ };
+
+ // Spin on the lock. In this case we just set it to 1 and proceed.
+ void spin()
+ {
+ CYG_ASSERT( lock == 0, "spinlock already claimed!");
+ lock = 1;
+ };
+
+ // Clear the lock. Again, just set the value.
+ void clear()
+ {
+ CYG_ASSERT( lock != 0, "spinlock already cleared!");
+ lock = 0;
+ };
+
+ // Try to claim the lock. Return true if successful, false if not.
+ cyg_bool trylock()
+ {
+ if( lock ) return false;
+ else { lock = 1; return true; }
+ };
+
+ // Test the current value of the lock
+ cyg_bool test() { return lock; };
+
+
+ // The following two member functions are only necessary if the
+ // spinlock is to be used in an ISR.
+
+ // Claim the spinlock, but also mask this CPU's interrupts while
+ // we have it.
+ void spin_intsave(CYG_INTERRUPT_STATE *state)
+ {
+ CYG_INTERRUPT_STATE s;
+ HAL_DISABLE_INTERRUPTS(s);
+ *state = s;
+ spin();
+ };
+
+ // Clear the lock, and restore the interrupt state saved in
+ // spin_intsave().
+ void clear_intsave(CYG_INTERRUPT_STATE state)
+ {
+ clear();
+ HAL_RESTORE_INTERRUPTS(state);
+ };
+
+};
+
+// -------------------------------------------------------------------------
+// Scheduler lock class
+
+class Cyg_Scheduler_SchedLock
+{
+ static volatile cyg_ucount32 sched_lock // lock counter
+ CYGBLD_ATTRIB_ASM_ALIAS( cyg_scheduler_sched_lock )
+ CYGBLD_ANNOTATE_VARIABLE_SCHED
+ ;
+
+ // For non-SMP versions, the code here does the basic and obvious things.
+protected:
+
+ Cyg_Scheduler_SchedLock()
+ {
+ sched_lock = 1;
+ };
+
+ // Increment the scheduler lock, possibly taking it from zero to
+ // one.
+ static void inc_sched_lock()
+ {
+ sched_lock++;
+ };
+
+ static void zero_sched_lock()
+ {
+ CYG_ASSERT( sched_lock != 0, "Scheduler lock already zero");
+ sched_lock = 0;
+ };
+
+ // Set the scheduler lock to a non-zero value. Both the scheduler
+ // lock and the new value must be non-zero.
+ static void set_sched_lock(cyg_uint32 new_lock)
+ {
+ CYG_ASSERT( new_lock > 0, "New scheduler lock value == 0");
+ CYG_ASSERT( sched_lock > 0, "Scheduler lock == 0");
+ sched_lock = new_lock;
+ };
+
+ static cyg_ucount32 get_sched_lock()
+ {
+ return sched_lock;
+ };
+};
+
+#define CYGIMP_KERNEL_SCHED_LOCK_DEFINITIONS \
+volatile cyg_ucount32 Cyg_Scheduler_SchedLock::sched_lock = 1;
+
+#endif // __cplusplus
+
+#endif // defined(CYGSEM_KERNEL_SMP_SUPPORT) && (CYGSEM_HAL_SMP_SUPPORT)
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_SMP_HXX
+
+// EOF smp.hxx
diff --git a/ecos/packages/kernel/current/include/test/stackmon.h b/ecos/packages/kernel/current/include/test/stackmon.h
new file mode 100644
index 0000000000..6a7bd3df08
--- /dev/null
+++ b/ecos/packages/kernel/current/include/test/stackmon.h
@@ -0,0 +1,239 @@
+#ifndef CYGONCE_KERNEL_TEST_STACKMON_H
+#define CYGONCE_KERNEL_TEST_STACKMON_H
+
+/*=================================================================
+//
+// stackmon.h
+//
+// Auxiliary test header file
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 1999-05-20
+// Description:
+// Defines some convenience functions for stack use output.
+// Note:
+// The functions are defined for both C and C++ usage - with different
+// argument types.
+//
+//####DESCRIPTIONEND####
+*/
+
+#include <pkgconf/system.h>
+#include <pkgconf/hal.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/infra/cyg_type.h>
+#ifdef CYGPKG_KERNEL
+#include <pkgconf/kernel.h>
+# if defined(CYGFUN_KERNEL_API_C)
+# include <cyg/kernel/kapi.h>
+# endif
+# if defined(__cplusplus)
+# include <cyg/kernel/sched.hxx>
+# include <cyg/kernel/thread.hxx>
+# include <cyg/kernel/thread.inl>
+# endif
+# include <cyg/kernel/smp.hxx>
+#endif
+
+#ifndef STACKMON_PRINTF
+#include <cyg/infra/diag.h>
+#define STACKMON_PRINTF diag_printf
+#endif
+
+// ------------------------------------------------------------------------
+// Utility function for actually counting a stack
+
+inline void cyg_test_size_a_stack( char *comment, char *format,
+ char *base, char *top )
+{
+#ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
+ cyg_uint32* cur32 = (cyg_uint32*) ((((CYG_ADDRWORD)&(base[CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE])) + 3) & ~3);
+ cyg_uint32* top32 = (cyg_uint32*) ((((CYG_ADDRWORD)top) + 3) & ~3);
+ for ( ; cur32 < top32; cur32++) {
+ if (*cur32 != 0xDEADBEEF) {
+ break;
+ }
+ }
+ STACKMON_PRINTF( format, comment, (CYG_ADDRWORD)top32 - (CYG_ADDRWORD)cur32, top - base );
+#else
+ register char *p;
+ for ( p = base; p < top; p++ )
+ if ( *p )
+ break;
+ STACKMON_PRINTF( format, comment, top - p, top - base );
+#endif
+}
+
+// ------------------------------------------------------------------------
+
+inline void cyg_test_dump_stack_stats( char *comment,
+ char *base, char *top )
+{
+ cyg_test_size_a_stack( comment, "%31s : stack used %5d size %5d\n",
+ base, top );
+}
+
+// ------------------------------------------------------------------------
+
+#ifdef __cplusplus
+
+inline void cyg_test_dump_thread_stack_stats( char *comment,
+ Cyg_Thread *p )
+{
+#if defined(CYGPKG_KERNEL)
+ char *base, *top;
+ base = (char *)p->get_stack_base();
+ top = base + p->get_stack_size();
+ cyg_test_dump_stack_stats( comment, base, top );
+#endif
+}
+
+#else // __cplusplus
+
+inline void cyg_test_dump_thread_stack_stats( char *comment,
+ cyg_handle_t p )
+{
+#if defined(CYGPKG_KERNEL) && defined(CYGFUN_KERNEL_API_C)
+ char *base, *top;
+ base = (char *) cyg_thread_get_stack_base( p );
+ top = base + cyg_thread_get_stack_size( p );
+ cyg_test_dump_stack_stats( comment, base, top );
+#endif
+}
+
+#endif // __cplusplus
+
+// ------------------------------------------------------------------------
+// Print out size of idle thread stack usage since start-of-time. Only
+// meaningful if there is a scheduler.
+
+#ifdef __cplusplus
+
+inline void cyg_test_dump_idlethread_stack_stats( char *comment )
+{
+#if defined(CYGPKG_KERNEL)
+ int i;
+ extern Cyg_Thread idle_thread[CYGNUM_KERNEL_CPU_MAX];
+ for( i = 0; i < CYGNUM_KERNEL_CPU_MAX; i++ )
+ {
+ // idle thread is not really a plain CygThread; danger.
+ char *ibase = (char *)idle_thread[i].get_stack_base();
+ char *istack = ibase + idle_thread[i].get_stack_size();
+ cyg_test_size_a_stack( comment,
+ "%20s : Idlethread stack used %5d size %5d\n",
+ ibase, istack );
+ }
+#endif
+}
+
+#else // __cplusplus
+
+inline void cyg_test_dump_idlethread_stack_stats( char *comment )
+{
+#if defined(CYGPKG_KERNEL) && defined(CYGFUN_KERNEL_API_C)
+ cyg_handle_t idle_thread = cyg_thread_idle_thread();
+
+ char *ibase = (char *)cyg_thread_get_stack_base( idle_thread );
+ char *istack = ibase + cyg_thread_get_stack_size( idle_thread );
+ cyg_test_size_a_stack( comment,
+ "%20s : Idlethread stack used %5d size %5d\n",
+ ibase, istack );
+#endif
+}
+
+#endif // __cplusplus
+
+// ------------------------------------------------------------------------
+// Print out size of interrupt stack usage since start-of-time or since it
+// was last cleared. NB on some architectures and configurations, the
+// interrupt stack is the same as the bootup stack, so clear it in the
+// first first thread to execute. Clearing it before scheduler start would
+// be fatal!
+
+#if defined(HAL_INTERRUPT_STACK_BASE) && defined(HAL_INTERRUPT_STACK_TOP)
+externC char HAL_INTERRUPT_STACK_BASE[];
+externC char HAL_INTERRUPT_STACK_TOP[];
+#endif
+
+inline void cyg_test_dump_interrupt_stack_stats( char *comment )
+{
+#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
+#if defined(HAL_INTERRUPT_STACK_BASE) && defined(HAL_INTERRUPT_STACK_TOP)
+ cyg_test_size_a_stack( comment,
+ "%20s : Interrupt stack used %5d size %5d\n",
+ HAL_INTERRUPT_STACK_BASE, HAL_INTERRUPT_STACK_TOP );
+#endif
+#endif
+}
+
+// Clear interrupt stack to reset stats - only after sched has started.
+
+inline void cyg_test_clear_interrupt_stack( void )
+{
+#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
+#if defined(HAL_INTERRUPT_STACK_BASE) && defined(HAL_INTERRUPT_STACK_TOP)
+ cyg_uint32 old_intr;
+ HAL_DISABLE_INTERRUPTS(old_intr);
+# ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
+ {
+ cyg_uint32* cur32 = (cyg_uint32*) ((((CYG_ADDRWORD)HAL_INTERRUPT_STACK_BASE) + 3) & ~3);
+ cyg_uint32* top32 = (cyg_uint32*) ((((CYG_ADDRWORD)HAL_INTERRUPT_STACK_TOP) + 3) & ~3);
+ for ( ; cur32 < top32; cur32++) {
+ *cur32 = 0xDEADBEEF;
+ }
+ }
+# else
+ {
+ register char *p;
+ for ( p = HAL_INTERRUPT_STACK_BASE; p < HAL_INTERRUPT_STACK_TOP; p++ )
+ *p = 0; // zero it for checking later
+ }
+# endif
+ HAL_RESTORE_INTERRUPTS(old_intr);
+#endif
+#endif
+}
+
+// ------------------------------------------------------------------------
+
+#endif // ifndef CYGONCE_KERNEL_TEST_STACKMON_H
+
+// EOF stackmon.h
diff --git a/ecos/packages/kernel/current/include/thread.hxx b/ecos/packages/kernel/current/include/thread.hxx
new file mode 100644
index 0000000000..9a62ecd0d5
--- /dev/null
+++ b/ecos/packages/kernel/current/include/thread.hxx
@@ -0,0 +1,590 @@
+#ifndef CYGONCE_KERNEL_THREAD_HXX
+#define CYGONCE_KERNEL_THREAD_HXX
+
+//==========================================================================
+//
+// thread.hxx
+//
+// Thread class declarations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-09
+// Purpose: Define Thread class interfaces
+// Description: The classes defined here collectively implement the
+// internal API used to create, configure and manage threads.
+// Usage: #include <cyg/kernel/thread.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/clock.hxx>
+#include <cyg/kernel/except.hxx>
+
+#include <cyg/hal/hal_arch.h>
+
+// -------------------------------------------------------------------------
+// Miscellaneous types
+
+typedef void cyg_thread_entry(CYG_ADDRWORD data);// Thread entry point function
+
+// -------------------------------------------------------------------------
+// Hardware thread interface.
+// The implementation of this class is provided by the HAL.
+
+class Cyg_HardwareThread
+{
+ friend class Cyg_Scheduler;
+
+protected:
+
+ CYG_ADDRESS stack_base; // pointer to base of stack area
+
+ cyg_uint32 stack_size; // size of stack area in bytes
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
+ CYG_ADDRESS stack_limit; // movable stack limit
+#endif
+
+ CYG_ADDRESS stack_ptr; // pointer to saved state on stack
+
+ cyg_thread_entry *entry_point; // main entry point (code pointer!)
+
+ CYG_ADDRWORD entry_data; // entry point argument
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+
+ HAL_SavedRegisters *saved_context; // If non-zero, this points at a more
+ // interesting context than stack_ptr.
+#endif
+
+ Cyg_HardwareThread(
+ cyg_thread_entry *entry_point, // entry point function
+ CYG_ADDRWORD entry_data, // entry data
+ cyg_ucount32 stack_size = 0, // stack size, 0 = use default
+ CYG_ADDRESS stack_base = 0 // stack base, NULL = allocate
+ );
+
+ // Thread entry point. This is where all threads begin execution.
+ // This routine does a little housekeeping and then call the main
+ // entry_point specified above.
+ static void thread_entry(Cyg_Thread *thread);
+
+ // Initialize the context of the thread to start execution at thread_entry
+ void init_context( Cyg_Thread *thread );
+
+ // Save current thread's context and load that of the given next thread.
+ void switch_context(Cyg_HardwareThread *next);
+
+ // attach a stack to this thread
+ void attach_stack(CYG_ADDRESS stack, cyg_uint32 stack_size);
+
+ // detach the stack from this thread
+ CYG_ADDRESS detach_stack();
+
+ // Adjust the thread's saved state to call the exception
+ // handler when next executed.
+ void prepare_exception (
+ cyg_exception_handler *exception_handler,
+ CYG_ADDRWORD exception_data,
+ cyg_code exception_number,
+ CYG_ADDRWORD exception_info
+ );
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ // Get and set entry_data.
+
+ void set_entry_data( CYG_ADDRWORD data );
+
+ CYG_ADDRWORD get_entry_data();
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+ // Return the current saved state for this thread.
+ HAL_SavedRegisters *get_saved_context();
+
+ // Set the saved context pointer.
+ void set_saved_context(HAL_SavedRegisters *ctx);
+#endif
+
+ // get the size/base of this thread's stack
+ CYG_ADDRESS get_stack_base();
+
+ cyg_uint32 get_stack_size();
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
+ // Allocate some memory at the lower end of the stack
+ // by moving the stack limit pointer.
+
+ void *increment_stack_limit( cyg_ucount32 size);
+
+ CYG_ADDRESS get_stack_limit();
+#endif
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
+
+ inline void check_stack(void);
+
+#endif
+#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
+
+ inline cyg_uint32 measure_stack_usage(void);
+
+#endif
+};
+
+// -------------------------------------------------------------------------
+// Per-thread timer support class.
+// This is only included when required.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+class Cyg_ThreadTimer
+ : public Cyg_Alarm
+{
+ friend class Cyg_Thread;
+
+ // Pointer to current thread
+ Cyg_Thread *thread;
+
+ // Constructor
+ Cyg_ThreadTimer(
+ Cyg_Thread *thread
+ );
+
+ // Alarm function
+ static void alarm( Cyg_Alarm *alarm, CYG_ADDRWORD data);
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+};
+
+#endif
+
+// -------------------------------------------------------------------------
+// Main Thread class.
+// This provides the public API for controlling threads.
+
+class Cyg_Thread
+ : public Cyg_HardwareThread, // provides hardware abstractions
+ public Cyg_SchedThread // provides scheduling abstractions
+{
+ friend class Cyg_Scheduler;
+ friend void deliver_exception( CYG_WORD code, CYG_ADDRWORD data );
+
+ // The following definitions are used by all variants of the
+ // basic thread object.
+
+public:
+ enum { // Thread state values
+
+ RUNNING = 0, // Thread is runnable or running
+ SLEEPING = 1, // Thread is waiting for something to happen
+ COUNTSLEEP = 2, // Sleep in counted manner
+ SUSPENDED = 4, // Suspend count is non-zero
+ CREATING = 8, // Thread is being created
+ EXITED = 16, // Thread has exited
+
+ // This is the set of bits that must be cleared by a generic
+ // wake() or release().
+ SLEEPSET = (SLEEPING | COUNTSLEEP)
+ };
+
+private:
+ // Current thread state, a logical OR of the above values.
+ // Only if this word is zero can the thread execute.
+ cyg_uint32 state;
+
+ // Suspension counter, if > 0, the thread is suspended
+ cyg_ucount32 suspend_count;
+
+ // Wakeup counter, if > 0, sleep will not sleep, just decrement
+ cyg_ucount32 wakeup_count;
+
+ // A word of data used in syncronization object to communicate
+ // information between sleepers and wakers.
+ CYG_ADDRWORD wait_info;
+
+ // Unique thread id assigned on creation
+ cyg_uint16 unique_id;
+
+#ifdef CYGPKG_KERNEL_EXCEPTIONS
+
+ // If exceptions are supported, define an exception control
+ // object that will be used to manage and deliver them. If
+ // exceptions are global there is a single static instance
+ // of this object, if they are per-thread then there is one
+ // for each thread.
+private:
+
+#ifdef CYGSEM_KERNEL_EXCEPTIONS_GLOBAL
+ static
+#endif
+ Cyg_Exception_Control exception_control;
+
+public:
+
+ static void register_exception(
+ cyg_code exception_number, // exception number
+ cyg_exception_handler handler, // handler function
+ CYG_ADDRWORD data, // data argument
+ cyg_exception_handler **old_handler, // handler function
+ CYG_ADDRWORD *old_data // data argument
+ );
+
+ static void deregister_exception(
+ cyg_code exception_number // exception number
+ );
+
+ void deliver_exception(
+ cyg_code exception_number, // exception being raised
+ CYG_ADDRWORD exception_info // exception specific info
+ );
+
+#endif
+
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ // Constructor, Initialize the thread structure. The thread is
+ // created in suspended state, and needs to be resumed to execute.
+ // It is also started at some (configurable) default priority, which
+ // may need to be changed before calling resume.
+
+ Cyg_Thread (
+ cyg_thread_entry *entry, // entry point function
+ CYG_ADDRWORD entry_data, // entry data
+ cyg_ucount32 stack_size = 0, // stack size, 0 = use default
+ CYG_ADDRESS stack_base = 0 // stack base, NULL = allocate
+ );
+
+ Cyg_Thread (
+ CYG_ADDRWORD sched_info, // Scheduling parameter(s)
+ cyg_thread_entry *entry, // entry point function
+ CYG_ADDRWORD entry_data, // entry data
+ char *name, // thread name
+ CYG_ADDRESS stack_base = 0, // stack base, NULL = allocate
+ cyg_ucount32 stack_size = 0 // stack size, 0 = use default
+ );
+
+ // Re-initialize the thread back to it's initial state.
+ void Cyg_Thread::reinitialize();
+
+ ~Cyg_Thread();
+
+ // The following are invoked implicitly on the current thread,
+ // hence they are static member functions.
+
+ static void sleep(); // Put thread to sleep
+
+ static void counted_sleep();// Decrement counter or put
+ // thread to sleep
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ static void counted_sleep( cyg_tick_count delay );
+ // ...for delay ticks
+#endif
+
+ static void exit(); // Terminate thread
+
+ static void yield(); // Yield CPU to another thread
+
+ static void rotate_queue( cyg_priority pri );
+ // Rotate that run queue
+
+ void to_queue_head( void );
+ // Move to the head of its queue
+ // (not necessarily a scheduler q)
+
+ static Cyg_Thread *self(); // Return current thread
+
+
+ // The following are called on threads other than the current one.
+
+ void wake(); // Wake this thread from sleep.
+
+ void counted_wake(); // Increment counter or wake thread
+ cyg_uint32 cancel_counted_wake();
+ // Cancel counted wakeups for this
+ // thread and return how many were
+ // pending
+
+ void suspend(); // Suspend this thread: increment counter and
+ // deschedule.
+
+ void resume(); // Resume this thread: decrement counter and
+ // reschedule if counter is zero.
+
+ void release(); // Release thread from sleep with BREAK
+ // wake_reason.
+
+ void kill(); // Kill this thread
+
+ void force_resume(); // Resume this thread: set counter to zero.
+
+ cyg_uint32 get_state(); // Return current thread state.
+
+
+ // Accessor functions to set and get wait_info.
+
+ void set_wait_info(CYG_ADDRWORD data);
+
+ CYG_ADDRWORD get_wait_info();
+
+ // This part of the API is used if we have a clock and want
+ // per-thread timers for doing delays and timeouts.
+
+ // delay the given number of ticks
+ void delay( cyg_tick_count delay );
+
+
+ enum cyg_reason // sleep/wakeup reason codes
+ {
+ NONE, // No recorded reason
+ WAIT, // Wait with no timeout
+ DELAY, // Simple time delay
+ TIMEOUT, // Wait with timeout/timeout expired
+ BREAK, // forced break out of sleep
+ DESTRUCT, // wait object destroyed[note]
+ EXIT, // forced termination
+ DONE // Wait/delay complete
+ };
+ // [note] NOT the thread, some object it was waiting on.
+ // Thread destruction would first involve EXITing it.
+
+private:
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ Cyg_ThreadTimer timer; // per-thread timer
+#endif
+
+ cyg_reason sleep_reason; // reason for sleeping
+
+ cyg_reason wake_reason; // reason for waking
+
+#ifdef CYGIMP_THREAD_PRIORITY
+
+public:
+
+ // If the scheduler implements priorities, provide
+ // functions to set and get it.
+
+ void set_priority( cyg_priority pri );
+
+ cyg_priority get_priority();
+
+ // This returns the current dispatching priority of the
+ // thread. This may differ from the result of get_priority()
+ // in the presence of priority inheritance or certain
+ // scheduling algorithms.
+ cyg_priority get_current_priority();
+
+#endif
+
+#ifdef CYGVAR_KERNEL_THREADS_DATA
+
+private:
+ // Array of single word entries for each index.
+ CYG_ADDRWORD thread_data[CYGNUM_KERNEL_THREADS_DATA_MAX];
+
+ // Map of free thread_data indexes. Each bit represents an index
+ // and is 1 if that index is free, and 0 if it is in use.
+ static cyg_ucount32 thread_data_map;
+
+public:
+
+ typedef cyg_count32 cyg_data_index;
+
+ static CYG_ADDRWORD get_data( cyg_data_index index );
+
+ static CYG_ADDRWORD *get_data_ptr( cyg_data_index index );
+
+ void set_data( cyg_data_index index, CYG_ADDRWORD data );
+
+ // returns -1 if no more indexes available
+ static cyg_data_index new_data_index();
+
+ static void free_data_index( cyg_data_index index );
+
+#endif
+
+#ifdef CYGPKG_KERNEL_THREADS_DESTRUCTORS
+
+ // thread destructors, called on thread exit.
+private:
+ typedef void (*destructor_fn)(CYG_ADDRWORD);
+ struct Cyg_Destructor_Entry {
+ destructor_fn fn;
+ CYG_ADDRWORD data;
+ };
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+ static
+#endif
+ Cyg_Destructor_Entry destructors[ CYGNUM_KERNEL_THREADS_DESTRUCTORS ];
+public:
+
+ // Add and remove destructors. Returns true on success, false on failure.
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+ static
+#endif
+ cyg_bool add_destructor( destructor_fn fn, CYG_ADDRWORD data );
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+ static
+#endif
+ cyg_bool rem_destructor( destructor_fn fn, CYG_ADDRWORD data );
+#endif
+
+#ifdef CYGVAR_KERNEL_THREADS_NAME
+
+private:
+ // An optional thread name string, for humans to read
+ char *name;
+
+public:
+ // function to get the name string
+ char *get_name();
+
+#endif
+
+
+#ifdef CYGVAR_KERNEL_THREADS_LIST
+
+ // Housekeeping list that tracks all threads
+private:
+ Cyg_Thread *list_next;
+ static Cyg_Thread *thread_list;
+
+ void add_to_list( void );
+ void remove_from_list( void );
+public:
+
+ static Cyg_Thread *get_list_head();
+
+ Cyg_Thread *get_list_next();
+
+#endif
+
+public:
+
+ // Set sleep reason to reason and wake reason to NONE
+ static void set_sleep_reason( cyg_reason reason = WAIT);
+
+ cyg_reason get_sleep_reason();
+
+ // Set the wakeup reason to the given value
+ void set_wake_reason( cyg_reason reason = DONE);
+
+ // Get current wake reason
+ cyg_reason get_wake_reason();
+
+ static void set_timer( // Set timeout and sleep reason
+ cyg_tick_count trigger, // Absolute wakeup time
+ cyg_reason sleep_reason // reason for sleeping
+ );
+
+ static void clear_timer(); // disable thread timer
+
+ // Get a 16 bit unique id for this thread. This is
+ // used in tracing and instrumentation to identify the
+ // current thread.
+
+ cyg_uint16 get_unique_id();
+
+};
+
+// -------------------------------------------------------------------------
+// Thread Queue class.
+// This defines the main API for manipulating queues of threads.
+
+class Cyg_ThreadQueue
+ : public Cyg_ThreadQueue_Implementation
+{
+
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ // API used by rest of kernel.
+
+ // Add thread to queue
+ void enqueue(Cyg_Thread *thread);
+
+ // return first thread on queue
+ Cyg_Thread *highpri();
+
+ // remove first thread on queue
+ Cyg_Thread *dequeue();
+
+ // remove specified thread from queue
+ void remove(Cyg_Thread *thread);
+
+ // test if queue is empty
+ inline cyg_bool empty();
+
+};
+
+// -------------------------------------------------------------------------
+// Thread inlines
+
+// Return current thread state.
+inline cyg_uint32 Cyg_Thread::get_state()
+{
+ return state;
+}
+
+inline void Cyg_Thread::set_wait_info(CYG_ADDRWORD data)
+{
+ wait_info = data;
+}
+
+inline CYG_ADDRWORD Cyg_Thread::get_wait_info()
+{
+ return wait_info;
+}
+
+// -------------------------------------------------------------------------
+#endif // ifndef CYGONCE_KERNEL_THREAD_HXX
+// EOF thread.hxx
diff --git a/ecos/packages/kernel/current/include/thread.inl b/ecos/packages/kernel/current/include/thread.inl
new file mode 100644
index 0000000000..da2523a5e5
--- /dev/null
+++ b/ecos/packages/kernel/current/include/thread.inl
@@ -0,0 +1,693 @@
+#ifndef CYGONCE_KERNEL_THREAD_INL
+#define CYGONCE_KERNEL_THREAD_INL
+
+//==========================================================================
+//
+// thread.inl
+//
+// Thread class inlines
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+//
+// 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: 1997-09-09
+// Purpose: Define inlines for thread classes
+// Description: Inline implementations of various member functions defined
+// in various Thread classes.
+// Usage:
+// #include <cyg/kernel/thread.hxx>
+// ...
+// #include <cyg/kernel/thread.inl>
+// ...
+
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/thread.hxx>
+#include <cyg/hal/hal_arch.h>
+
+#include <cyg/kernel/clock.inl>
+#include <cyg/infra/diag.h>
+
+#ifndef CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE
+#define CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE (0)
+#endif
+
+//==========================================================================
+// Inlines for Cyg_HardwareThread
+
+// -------------------------------------------------------------------------
+// get the size/base of this thread's stack
+
+inline CYG_ADDRESS
+Cyg_HardwareThread::get_stack_base()
+{
+ return stack_base - CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE;
+}
+
+inline cyg_uint32
+Cyg_HardwareThread::get_stack_size()
+{
+ return stack_size + 2 * CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE;
+}
+
+// -------------------------------------------------------------------------
+// Check the stack bounds of this thread:
+#ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
+inline void Cyg_HardwareThread::check_stack(void)
+{
+ cyg_uint32 sig = (cyg_uint32)this;
+ cyg_uint32 *base = (cyg_uint32 *)get_stack_base();
+ cyg_uint32 *top = (cyg_uint32 *)(stack_base + stack_size);
+ cyg_ucount32 i;
+
+ CYG_INSTRUMENT_THREAD(CHECK_STACK, base, top );
+
+ CYG_ASSERT( 0 == ((sizeof(CYG_WORD)-1) & (cyg_uint32)base), "stack base not word aligned" );
+ CYG_ASSERT( 0 == ((sizeof(CYG_WORD)-1) & (cyg_uint32)top), "stack top not word aligned" );
+
+ CYG_ASSERT( (cyg_uint32)stack_ptr > (cyg_uint32)stack_base,
+ "Stack_ptr below base" );
+ CYG_ASSERT( (cyg_uint32)stack_ptr <= ((cyg_uint32)stack_base + stack_size),
+ "Stack_ptr above top" );
+
+ for ( i = 0;
+ i < CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE/sizeof(cyg_uint32);
+ i++ ) {
+ if ((sig ^ (i * 0x01010101)) != base[i]) {
+ char *reason = "Stack base corrupt";
+ diag_printf("%s - i: %d\n", reason, i);
+ diag_dump_buf(base, CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE);
+ CYG_FAIL(reason);
+ }
+ if ((sig ^ (i * 0x10101010)) != top[i]) {
+ char *reason = "Stack top corrupt";
+ diag_printf("%s - i: %d\n", reason, i);
+ diag_dump_buf(top, CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE);
+ CYG_FAIL(reason);
+ }
+ }
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
+ // we won't have added check data above the stack limit if it hasn't
+ // been incremented
+ if (stack_limit != stack_base) {
+ CYG_ADDRESS limit = stack_limit;
+ // the limit will be off by the check data size, so lets correct it
+ limit -= CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE;
+
+ // determine base of check data by rounding up to nearest word aligned
+ // address if not already aligned
+ cyg_uint32 *p = (cyg_uint32 *)((limit + 3) & ~3);
+ // i.e. + sizeof(cyg_uint32)-1) & ~(sizeof(cyg_uint32)-1);
+
+ for ( i = 0;
+ i < CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE/sizeof(cyg_uint32);
+ i++ ) {
+ if ((sig ^ (i * 0x01010101)) != p[i]) {
+ char *reason = "Gap between stack limit and base corrupt";
+ diag_printf("%s - i: %d\n", reason, i);
+ diag_dump_buf(p, CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE);
+ CYG_FAIL(reason);
+ }
+ }
+ }
+#endif
+}
+#endif
+
+// -------------------------------------------------------------------------
+// Measure the stack usage of the thread
+#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
+inline cyg_uint32 Cyg_HardwareThread::measure_stack_usage(void)
+{
+#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
+ CYG_WORD *base = (CYG_WORD *)stack_limit;
+ cyg_uint32 size = (stack_size - (stack_limit-stack_base))/sizeof(CYG_WORD);
+#else
+ CYG_WORD *base = (CYG_WORD *)stack_base;
+ cyg_uint32 size = stack_size/sizeof(CYG_WORD);
+#endif
+ cyg_ucount32 i;
+
+ // Work up the stack comparing with the preset value
+ // We assume the stack grows downwards, hmm...
+ for (i=0; i<size; i++) {
+ if (base[i] != 0xDEADBEEF)
+ break;
+ }
+ return (size - i)*sizeof(CYG_WORD);
+}
+#endif
+
+// -------------------------------------------------------------------------
+// Attach a stack to this thread. If there is a HAL defined macro to
+// do this, then we use that, otherwise assume a falling stack.
+inline void Cyg_HardwareThread::attach_stack(CYG_ADDRESS s_base, cyg_uint32 s_size)
+{
+#ifdef CYGNUM_HAL_STACK_SIZE_MINIMUM
+ CYG_ASSERT( s_size >= CYGNUM_HAL_STACK_SIZE_MINIMUM,
+ "Stack size too small");
+#endif
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
+ {
+ cyg_uint32 sig = (cyg_uint32)this;
+ cyg_uint32 *base = (cyg_uint32 *)s_base;
+ cyg_uint32 *top = (cyg_uint32 *)(s_base + s_size -
+ CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE);
+
+ unsigned int i;
+
+ CYG_INSTRUMENT_THREAD(ATTACH_STACK, base, top );
+
+ CYG_ASSERT( NULL != base, "stack base non-NULL" );
+ CYG_ASSERT( 0 == ((sizeof(CYG_WORD)-1) & (cyg_uint32)base), "stack base alignment" );
+ CYG_ASSERT( 0 == ((sizeof(CYG_WORD)-1) & (cyg_uint32)top), "stack top alignment" );
+
+ for ( i = 0;
+ i < CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE/sizeof(cyg_uint32);
+ i++ ) {
+ base[i] = (sig ^ (i * 0x01010101));
+ top[i] = (sig ^ (i * 0x10101010));
+ }
+ // This check for overlap of the two signature areas also detects
+ // wrap round zero of the size in the unsigned subtraction below.
+ CYG_ASSERT( &base[i] < &top[0], "Stack is so small size wrapped" );
+ // Use this 'i' expression to round correctly to whole words.
+ s_base += i * sizeof(cyg_uint32);
+ s_size -= i * sizeof(cyg_uint32) * 2;
+ // This is a complete guess, the 256; the point is to assert early that
+ // this might go badly wrong. It would not detect wrap of unsigned size.
+ CYG_ASSERT( s_size >= 256,
+ "Stack size too small after allocating checking buffer");
+ }
+#endif
+#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
+ {
+ CYG_WORD *base = (CYG_WORD *)s_base;
+ cyg_uint32 size = s_size/sizeof(CYG_WORD);
+ cyg_ucount32 i;
+
+ // initialize all of stack with known value - don't choose 0
+ // could do with pseudo value as above, but this way, checking
+ // is faster
+ for (i=0; i<size; i++) {
+ base[i] = 0xDEADBEEF;
+ }
+ // Don't bother about the case when the stack isn't a multiple of
+ // CYG_WORD in size. Since it's at the top of the stack, it will
+ // almost certainly be overwritten the instant the thread starts
+ // anyway.
+ }
+#endif
+ stack_base = s_base;
+ stack_size = s_size;
+#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
+ stack_limit = s_base;
+#endif
+
+#ifdef HAL_THREAD_ATTACH_STACK
+
+ HAL_THREAD_ATTACH_STACK(stack_ptr, stack_base, stack_size);
+
+#else
+
+ stack_ptr = stack_base + stack_size;
+
+#endif
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
+ check_stack();
+#endif
+}
+
+// -------------------------------------------------------------------------
+
+inline Cyg_HardwareThread::Cyg_HardwareThread(
+ cyg_thread_entry *e_point, // entry point function
+ CYG_ADDRWORD e_data, // entry data
+ cyg_ucount32 s_size, // stack size, 0 = use default
+ CYG_ADDRESS s_base // stack base, NULL = allocate
+)
+{
+ entry_point = e_point;
+ entry_data = e_data;
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+ saved_context = 0;
+#endif
+
+ attach_stack( s_base, s_size );
+};
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+
+// Return the current saved state for this thread.
+inline HAL_SavedRegisters *Cyg_HardwareThread::get_saved_context()
+{
+ HAL_SavedRegisters *regs;
+ if( saved_context != 0 ) regs = saved_context;
+ else HAL_THREAD_GET_SAVED_REGISTERS( stack_ptr, regs );
+ return regs;
+}
+
+inline void Cyg_HardwareThread::set_saved_context(HAL_SavedRegisters *ctx)
+{
+ saved_context = ctx;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// (declare this inline before its first use)
+
+inline cyg_uint16 Cyg_Thread::get_unique_id()
+{
+ return unique_id;
+}
+
+// -------------------------------------------------------------------------
+// Initialize the context of this thread.
+
+inline void Cyg_HardwareThread::init_context(Cyg_Thread *thread)
+{
+#ifdef CYGPKG_INFRA_DEBUG
+ cyg_uint32 threadid = thread->get_unique_id()*0x01010000;
+#else
+ cyg_uint32 threadid = 0x11110000;
+#endif
+ HAL_THREAD_INIT_CONTEXT( stack_ptr, thread, thread_entry, threadid );
+}
+
+
+
+// -------------------------------------------------------------------------
+// Save current thread's context and load that of the given next thread.
+// This function is only really here for completeness, the
+// kernel generally calls the HAL macros directly.
+
+inline void Cyg_HardwareThread::switch_context(Cyg_HardwareThread *next)
+{
+ HAL_THREAD_SWITCH_CONTEXT( &stack_ptr, &next->stack_ptr );
+}
+
+// -------------------------------------------------------------------------
+// Get and set entry_data.
+
+inline void Cyg_HardwareThread::set_entry_data( CYG_ADDRWORD data )
+{
+ entry_data = data;
+}
+
+inline CYG_ADDRWORD Cyg_HardwareThread::get_entry_data()
+{
+ return entry_data;
+}
+
+// -------------------------------------------------------------------------
+// Allocate some memory at the lower end of the stack
+// by moving the stack limit pointer.
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
+
+#ifndef CYGFUN_KERNEL_THREADS_STACK_CHECKING
+// if stack checking, implementation is in thread.cxx
+inline void *Cyg_HardwareThread::increment_stack_limit( cyg_ucount32 size )
+{
+ void *ret = (void *)stack_limit;
+ stack_limit += size;
+ return ret;
+}
+#endif
+
+inline CYG_ADDRESS
+Cyg_HardwareThread::get_stack_limit()
+{
+ return stack_limit;
+}
+
+#endif
+
+//==========================================================================
+// Inlines for Cyg_Thread class
+
+inline Cyg_Thread *Cyg_Thread::self()
+{
+ return Cyg_Scheduler::get_current_thread();
+}
+
+// -------------------------------------------------------------------------
+
+inline void Cyg_Thread::yield()
+{
+ self()->Cyg_SchedThread::yield();
+}
+
+// -------------------------------------------------------------------------
+
+inline void
+Cyg_Thread::rotate_queue( cyg_priority pri )
+{
+ self()->Cyg_SchedThread::rotate_queue( pri );
+}
+
+// -------------------------------------------------------------------------
+
+inline void
+Cyg_Thread::to_queue_head( void )
+{
+ this->Cyg_SchedThread::to_queue_head();
+}
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGIMP_THREAD_PRIORITY
+
+inline cyg_priority Cyg_Thread::get_priority()
+{
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
+
+ // If we have an inherited priority, return our original
+ // priority rather than the current one.
+
+ if( priority_inherited ) return original_priority;
+
+#endif
+
+ return priority;
+}
+
+// Return the actual dispatching priority of the thread
+// regardless of inheritance or scheduling concerns.
+inline cyg_priority Cyg_Thread::get_current_priority()
+{
+ return priority;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+
+inline void Cyg_Thread::set_sleep_reason( cyg_reason reason)
+{
+ self()->sleep_reason = reason;
+ self()->wake_reason = NONE;
+}
+
+// -------------------------------------------------------------------------
+
+inline Cyg_Thread::cyg_reason Cyg_Thread::get_sleep_reason()
+{
+ return sleep_reason;
+}
+
+// -------------------------------------------------------------------------
+
+inline void Cyg_Thread::set_wake_reason( cyg_reason reason )
+{
+ sleep_reason = NONE;
+ wake_reason = reason;
+}
+
+// -------------------------------------------------------------------------
+
+inline Cyg_Thread::cyg_reason Cyg_Thread::get_wake_reason()
+{
+ return wake_reason;
+}
+
+// -------------------------------------------------------------------------
+
+inline void Cyg_Thread::set_timer(
+ cyg_tick_count trigger,
+ cyg_reason reason
+)
+{
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ self()->sleep_reason = reason;
+ self()->wake_reason = NONE;
+ self()->timer.initialize( trigger);
+#endif
+}
+
+// -------------------------------------------------------------------------
+
+inline void Cyg_Thread::clear_timer()
+{
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ self()->timer.disable();
+#endif
+}
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGVAR_KERNEL_THREADS_DATA
+
+inline CYG_ADDRWORD Cyg_Thread::get_data( Cyg_Thread::cyg_data_index index )
+{
+ CYG_ASSERT( index < CYGNUM_KERNEL_THREADS_DATA_MAX,
+ "Per thread data index out of bounds");
+ CYG_ASSERT( (thread_data_map & (1<<index)) == 0,
+ "Unallocated index used");
+
+ return self()->thread_data[index];
+}
+
+inline CYG_ADDRWORD *Cyg_Thread::get_data_ptr( Cyg_Thread::cyg_data_index index )
+{
+ CYG_ASSERT( index < CYGNUM_KERNEL_THREADS_DATA_MAX,
+ "Per thread data index out of bounds");
+ CYG_ASSERT( (thread_data_map & (1<<index)) == 0,
+ "Unallocated index used");
+
+ return &(self()->thread_data[index]);
+}
+
+inline void Cyg_Thread::set_data( Cyg_Thread::cyg_data_index index,
+ CYG_ADDRWORD data )
+{
+ CYG_ASSERT( index < CYGNUM_KERNEL_THREADS_DATA_MAX,
+ "Per thread data index out of bounds");
+ CYG_ASSERT( (thread_data_map & (1<<index)) == 0,
+ "Unallocated index used");
+
+ thread_data[index] = data;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGVAR_KERNEL_THREADS_NAME
+
+inline char *Cyg_Thread::get_name()
+{
+ return name;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGVAR_KERNEL_THREADS_LIST
+
+inline Cyg_Thread *Cyg_Thread::get_list_head()
+{
+ return thread_list?thread_list->list_next:0;
+}
+
+inline Cyg_Thread *Cyg_Thread::get_list_next()
+{
+ return (this==thread_list)?0:list_next;
+}
+
+#endif
+
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGPKG_KERNEL_EXCEPTIONS
+
+inline void Cyg_Thread::register_exception(
+ cyg_code exception_number, // exception number
+ cyg_exception_handler handler, // handler function
+ CYG_ADDRWORD data, // data argument
+ cyg_exception_handler **old_handler, // handler function
+ CYG_ADDRWORD *old_data // data argument
+ )
+{
+ self()->exception_control.register_exception(
+ exception_number,
+ handler,
+ data,
+ old_handler,
+ old_data
+ );
+}
+
+inline void Cyg_Thread::deregister_exception(
+ cyg_code exception_number // exception number
+ )
+{
+ self()->exception_control.deregister_exception(
+ exception_number
+ );
+}
+
+#endif
+
+//==========================================================================
+// Inlines for Cyg_ThreadTimer class
+
+// -------------------------------------------------------------------------
+#if defined(CYGFUN_KERNEL_THREADS_TIMER) && defined(CYGVAR_KERNEL_COUNTERS_CLOCK)
+
+inline Cyg_ThreadTimer::Cyg_ThreadTimer(
+ Cyg_Thread *th
+ )
+ : Cyg_Alarm(Cyg_Clock::real_time_clock,
+ &alarm,
+ CYG_ADDRWORD(this)
+ )
+{
+ thread = th;
+}
+
+#endif
+
+//==========================================================================
+// Inlines for Cyg_ThreadQueue class
+
+
+inline void Cyg_ThreadQueue::enqueue(Cyg_Thread *thread)
+{
+ Cyg_ThreadQueue_Implementation::enqueue(thread);
+}
+
+// -------------------------------------------------------------------------
+
+inline Cyg_Thread *Cyg_ThreadQueue::highpri()
+{
+ return Cyg_ThreadQueue_Implementation::highpri();
+}
+
+// -------------------------------------------------------------------------
+
+inline Cyg_Thread *Cyg_ThreadQueue::dequeue()
+{
+ return Cyg_ThreadQueue_Implementation::dequeue();
+}
+
+// -------------------------------------------------------------------------
+
+inline void Cyg_ThreadQueue::remove(Cyg_Thread *thread)
+{
+ Cyg_ThreadQueue_Implementation::remove(thread);
+}
+
+// -------------------------------------------------------------------------
+
+inline cyg_bool Cyg_ThreadQueue::empty()
+{
+ return Cyg_ThreadQueue_Implementation::empty();
+}
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGPKG_KERNEL_THREADS_DESTRUCTORS
+
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+# include <cyg/kernel/sched.inl>
+#endif
+
+// Add and remove destructors. Returns true on success, false on failure.
+inline cyg_bool
+Cyg_Thread::add_destructor( destructor_fn fn, CYG_ADDRWORD data )
+{
+ cyg_ucount16 i;
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+ Cyg_Scheduler::lock();
+#endif
+ for (i=0; i<CYGNUM_KERNEL_THREADS_DESTRUCTORS; i++) {
+ if (NULL == destructors[i].fn) {
+ destructors[i].data = data;
+ destructors[i].fn = fn;
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+ Cyg_Scheduler::unlock();
+#endif
+ return true;
+ }
+ }
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+ Cyg_Scheduler::unlock();
+#endif
+ return false;
+}
+
+inline cyg_bool
+Cyg_Thread::rem_destructor( destructor_fn fn, CYG_ADDRWORD data )
+{
+ cyg_ucount16 i;
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+ Cyg_Scheduler::lock();
+#endif
+ for (i=0; i<CYGNUM_KERNEL_THREADS_DESTRUCTORS; i++) {
+ if (destructors[i].fn == fn && destructors[i].data == data) {
+ destructors[i].fn = NULL;
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+ Cyg_Scheduler::unlock();
+#endif
+ return true;
+ }
+ }
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+ Cyg_Scheduler::unlock();
+#endif
+ return false;
+}
+#endif
+
+// -------------------------------------------------------------------------
+
+#endif // ifndef CYGONCE_KERNEL_THREAD_INL
+// EOF thread.inl
diff --git a/ecos/packages/kernel/current/include/timer.hxx b/ecos/packages/kernel/current/include/timer.hxx
new file mode 100644
index 0000000000..5ef94c8fa7
--- /dev/null
+++ b/ecos/packages/kernel/current/include/timer.hxx
@@ -0,0 +1,127 @@
+#ifndef CYGONCE_KERNEL_TIMER_HXX
+#define CYGONCE_KERNEL_TIMER_HXX
+
+//==========================================================================
+//
+// timer.hxx
+//
+// Timer handler class declaration(s)
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-06-10
+// Purpose: Define Timer class interfaces
+// Description: This file defines the Timer class which is derived from
+// the Alarm class to support uITRON type functionality
+// Usage: #include <cyg/kernel/timer.hxx>
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/ktypes.h>
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/clock.hxx> // Cyg_Alarm
+
+// -------------------------------------------------------------------------
+// Timer handler class
+
+class Cyg_Timer
+ : public Cyg_Alarm
+{
+public:
+
+ CYGDBG_DEFINE_CHECK_THIS
+
+ Cyg_Timer();
+
+ ~Cyg_Timer();
+
+ enum {
+ DISABLE = 0,
+ ENABLE = 1,
+ RESET = 2,
+ };
+
+ void initialize(
+ Cyg_Counter *counter,
+ cyg_alarm_fn alarm_fn,
+ CYG_ADDRWORD data,
+ cyg_tick_count trigger, // absolute time
+ cyg_tick_count interval, // 0 => one shot, else repeating
+ cyg_uint32 action // (DISABLE | ENABLE)
+ );
+
+ void activate(cyg_uint32 action); // (DISABLE | ENABLE) [|RESET]
+
+ cyg_tick_count get_trigger();
+ cyg_bool is_enabled();
+ cyg_bool is_initialized();
+ CYG_ADDRWORD get_data();
+};
+
+// -------------------------------------------------------------------------
+// Timer inlines
+
+inline cyg_tick_count
+Cyg_Timer::get_trigger()
+{
+ return trigger;
+}
+
+inline cyg_bool
+Cyg_Timer::is_initialized()
+{
+ return NULL != counter;
+}
+
+inline cyg_bool
+Cyg_Timer::is_enabled()
+{
+ return enabled;
+}
+
+inline CYG_ADDRWORD
+Cyg_Timer::get_data()
+{
+ return data;
+}
+
+#endif // ifndef CYGONCE_KERNEL_TIMER_HXX
+// EOF timer.hxx
diff --git a/ecos/packages/kernel/current/src/common/clock.cxx b/ecos/packages/kernel/current/src/common/clock.cxx
new file mode 100644
index 0000000000..917b588a39
--- /dev/null
+++ b/ecos/packages/kernel/current/src/common/clock.cxx
@@ -0,0 +1,946 @@
+//==========================================================================
+//
+// common/clock.cxx
+//
+// Clock class implementations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Jonathan Larmour
+//
+// 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: 1997-09-15
+// Purpose: Clock class implementation
+// Description: This file contains the definitions of the counter,
+// clock and alarm class member functions that are common
+// to all clock implementations.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <cyg/kernel/clock.hxx> // our header
+
+#include <cyg/kernel/sched.hxx> // scheduler definitions
+#include <cyg/kernel/thread.hxx> // thread definitions
+#include <cyg/kernel/intr.hxx> // interrupt definitions
+
+#include <cyg/kernel/sched.inl> // scheduler inlines
+#include <cyg/kernel/clock.inl> // Clock inlines
+
+// -------------------------------------------------------------------------
+// Static variables
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+
+Cyg_Clock *Cyg_Clock::real_time_clock = NULL; // System real time clock
+
+#endif
+
+//==========================================================================
+// Constructor for counter object
+
+Cyg_Counter::Cyg_Counter(
+ cyg_uint32 incr
+ )
+{
+ CYG_REPORT_FUNCTION();
+
+ counter = 0;
+ increment = incr;
+
+}
+
+// -------------------------------------------------------------------------
+// Destructor for Counter object
+
+Cyg_Counter::~Cyg_Counter()
+{
+ CYG_REPORT_FUNCTION();
+
+
+}
+
+// -------------------------------------------------------------------------
+//
+
+#ifdef CYGDBG_USE_ASSERTS
+
+cyg_bool Cyg_Counter::check_this( cyg_assert_class_zeal zeal) const
+{
+ // check that we have a non-NULL pointer first
+ if( this == NULL ) return false;
+
+ switch( zeal )
+ {
+ case cyg_system_test:
+ case cyg_extreme:
+ case cyg_thorough:
+ case cyg_quick:
+ case cyg_trivial:
+ case cyg_none:
+ default:
+ break;
+ };
+
+ return true;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Counter tick function
+
+void Cyg_Counter::tick( cyg_uint32 ticks )
+{
+// CYG_REPORT_FUNCTION();
+
+ CYG_ASSERTCLASS( this, "Bad counter object" );
+
+ // Increment the counter in a loop so we process
+ // each tick separately. This is easier than trying
+ // to cope with a range of increments.
+
+ while( ticks-- )
+ {
+ Cyg_Scheduler::lock();
+
+ // increment the counter, note that it is
+ // allowed to wrap.
+ counter += increment;
+
+ // now check for any expired alarms
+
+ Cyg_Alarm_List *alarm_list_ptr; // pointer to list
+
+#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)
+
+ alarm_list_ptr = &alarm_list;
+
+#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)
+
+ // With multiple lists, each one contains only the alarms
+ // that will expire at a given tick modulo the list number.
+ // So we only have a fraction of the alarms to check here.
+
+ alarm_list_ptr = &(alarm_list[
+ (counter/increment) % CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] );
+
+#else
+#error "No CYGIMP_KERNEL_COUNTERS_x_LIST config"
+#endif
+
+ // Now that we have the list pointer, we can use common code for
+ // both list organizations.
+
+#ifdef CYGIMP_KERNEL_COUNTERS_SORT_LIST
+
+ // With a sorted alarm list, we can simply pick alarms off the
+ // front of the list until we find one that is in the future.
+
+ while( !alarm_list_ptr->empty() )
+ {
+ Cyg_Alarm *alarm = alarm_list_ptr->get_head();
+
+ CYG_ASSERTCLASS(alarm, "Bad alarm in counter list" );
+
+ if( alarm->trigger <= counter )
+ {
+ // remove alarm from list
+ alarm_list_ptr->rem_head();
+
+ if( alarm->interval != 0 )
+ {
+ // The alarm has a retrigger interval.
+ // Reset the trigger time and requeue
+ // the alarm.
+ alarm->trigger += alarm->interval;
+ add_alarm( alarm );
+ }
+ else alarm->enabled = false;
+
+ CYG_INSTRUMENT_ALARM( CALL, this, alarm );
+
+ // call alarm function
+ alarm->alarm(alarm, alarm->data);
+
+ // all done, loop
+ }
+ else break;
+
+ }
+#else
+
+ // With unsorted lists we must scan the whole list for
+ // candidates. However, we must be careful here since it is
+ // possible for the function of one alarm to add or remove
+ // other alarms to/from this list. Having the list shift under
+ // our feet in this way could be disasterous. We solve this by
+ // restarting the scan from the beginning whenever we call an
+ // alarm function.
+
+ cyg_bool rescan = true;
+
+ while( rescan )
+ {
+ Cyg_DNode_T<Cyg_Alarm> *node = alarm_list_ptr->get_head();
+
+ rescan = false;
+
+ while( node != NULL )
+ {
+ Cyg_Alarm *alarm = CYG_CLASSFROMBASE( Cyg_Alarm, Cyg_DNode, node );
+ Cyg_DNode_T<Cyg_Alarm> *next = alarm->get_next();
+
+ CYG_ASSERTCLASS(alarm, "Bad alarm in counter list" );
+
+ if( alarm->trigger <= counter )
+ {
+ alarm_list_ptr->remove(alarm);
+
+ if( alarm->interval != 0 )
+ {
+ // The alarm has a retrigger interval.
+ // Reset the trigger time and requeue
+ // the alarm.
+ alarm->trigger += alarm->interval;
+ add_alarm( alarm );
+ }
+ else alarm->enabled = false;
+
+ CYG_INSTRUMENT_ALARM( CALL, this, alarm );
+
+ // Call alarm function
+ alarm->alarm(alarm, alarm->data);
+
+ rescan = true;
+
+ break;
+ }
+
+ // If the next node is the head of the list, then we have
+ // looped all the way around. The node == next test
+ // catches the case where we only had one element to start
+ // with.
+ if( next == alarm_list_ptr->get_head() || node == next )
+ node = NULL;
+ else
+ node = next;
+ }
+
+ }
+
+#endif
+ Cyg_Scheduler::unlock();
+
+ }
+
+}
+
+// -------------------------------------------------------------------------
+// Add an alarm to this counter
+
+void Cyg_Counter::add_alarm( Cyg_Alarm *alarm )
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERTCLASS( this, "Bad counter object" );
+ CYG_ASSERTCLASS( alarm, "Bad alarm passed" );
+ CYG_ASSERT( Cyg_Scheduler::get_sched_lock() > 0, "Scheduler not locked");
+
+ // set this now to allow an immediate handler call to manipulate
+ // this alarm sensibly.
+ alarm->enabled = true;
+
+ // Check here for an alarm that triggers now or in the past and
+ // call its alarm function immediately.
+ if( alarm->trigger <= counter )
+ {
+ CYG_INSTRUMENT_ALARM( CALL, this, alarm );
+
+ // call alarm function. Note that this is being
+ // called here before the add_alarm has returned.
+ // Note that this function may disable the alarm.
+
+ alarm->alarm(alarm, alarm->data);
+
+ // Note that this extra check on alarm->enabled is in case the
+ // handler function disables this alarm!
+ if( alarm->interval != 0 && alarm->enabled )
+ {
+ // The alarm has a retrigger interval.
+ // Reset the trigger interval and drop
+ // through to queue it.
+ alarm->trigger += alarm->interval;
+ // ensure the next alarm time is in our future, and in phase
+ // with the original time requested.
+ alarm->synchronize();
+ }
+ else
+ {
+ // The alarm is all done with, disable it
+ // unlock and return.
+ alarm->enabled = false;
+ return;
+ }
+ }
+
+ CYG_INSTRUMENT_ALARM( ADD, this, alarm );
+
+ // Find the pointer to the relevant list _after_ a retrigger
+ // alarm has been given its new trigger time.
+
+ Cyg_Alarm_List *alarm_list_ptr; // pointer to list
+
+#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)
+
+ alarm_list_ptr = &alarm_list;
+
+#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)
+
+ // Each alarm must go into the list that covers the tick that is
+ // going to happen _after_ the trigger time (or at it if trigger
+ // happens to fall on a tick.
+
+ alarm_list_ptr = &(alarm_list[
+ ((alarm->trigger+increment-1)/increment) %
+ CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] );
+
+#else
+#error "No CYGIMP_KERNEL_COUNTERS_x_LIST config"
+#endif
+
+#ifdef CYGIMP_KERNEL_COUNTERS_SORT_LIST
+
+ // Now that we have the list pointer, we can use common code for
+ // both list organizations.
+
+ Cyg_Alarm *list_alarm = alarm_list_ptr->get_head();
+
+ if( list_alarm != NULL )
+ {
+ do
+ {
+ CYG_ASSERTCLASS(list_alarm, "Bad alarm in counter list" );
+
+ // The alarms are in ascending trigger order. If we
+ // find an alarm that triggers later than us, we go
+ // in front of it.
+
+ if( list_alarm->trigger > alarm->trigger )
+ {
+ alarm_list_ptr->insert( list_alarm, alarm );
+ return;
+ }
+
+ list_alarm = list_alarm->get_next();
+
+ } while( list_alarm != alarm_list_ptr->get_head() );
+ // a lower or equal alarm time was not found, so drop through
+ // so it is added to the list tail
+ }
+#endif
+
+ alarm_list_ptr->add_tail( alarm );
+}
+
+// -------------------------------------------------------------------------
+// Remove an alarm from this counter
+
+void Cyg_Counter::rem_alarm( Cyg_Alarm *alarm )
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERTCLASS( this, "Bad counter object" );
+ CYG_ASSERTCLASS( alarm, "Bad alarm passed" );
+ CYG_ASSERT( Cyg_Scheduler::get_sched_lock() > 0, "Scheduler not locked");
+
+ Cyg_Alarm_List *alarm_list_ptr; // pointer to list
+
+#if defined(CYGIMP_KERNEL_COUNTERS_SINGLE_LIST)
+
+ alarm_list_ptr = &alarm_list;
+
+#elif defined(CYGIMP_KERNEL_COUNTERS_MULTI_LIST)
+
+ alarm_list_ptr = &(alarm_list[
+ ((alarm->trigger+increment-1)/increment) %
+ CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE ] );
+
+#else
+#error "No CYGIMP_KERNEL_COUNTERS_x_LIST config"
+#endif
+
+ // Now that we have the list pointer, we can use common code for
+ // both list organizations.
+
+ CYG_INSTRUMENT_ALARM( REM, this, alarm );
+
+ alarm_list_ptr->remove( alarm );
+
+ alarm->enabled = false;
+
+}
+
+//==========================================================================
+// Constructor for clock object
+
+Cyg_Clock::Cyg_Clock(
+ cyg_resolution res
+ )
+{
+ CYG_REPORT_FUNCTION();
+
+ resolution = res;
+}
+
+// -------------------------------------------------------------------------
+// Destructor for Clock objects
+
+Cyg_Clock::~Cyg_Clock()
+{
+ CYG_REPORT_FUNCTION();
+
+}
+
+// -------------------------------------------------------------------------
+//
+
+#ifdef CYGDBG_USE_ASSERTS
+
+cyg_bool Cyg_Clock::check_this( cyg_assert_class_zeal zeal) const
+{
+ // check that we have a non-NULL pointer first
+ if( this == NULL ) return false;
+
+ switch( zeal )
+ {
+ case cyg_system_test:
+ case cyg_extreme:
+ case cyg_thorough:
+ case cyg_quick:
+ case cyg_trivial:
+ case cyg_none:
+ default:
+ break;
+ };
+
+ return true;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+//
+// Clock Converters: split a rational into 4 factors to try to prevent
+// overflow whilst retaining reasonable accuracy.
+//
+// typically we get numbers like 1,000,000 for ns_per and
+// 100 and 1,000,000,000 for the dividend and divisor.
+// So we want answers like 1/10 and 10/1 out of these routines.
+
+static void construct_converter( Cyg_Clock::converter *pcc,
+ cyg_uint64 m1, cyg_uint64 d1,
+ cyg_uint64 m2, cyg_uint64 d2 )
+{
+ cyg_uint64 upper, lower;
+ unsigned int i;
+ static cyg_uint16 primes[] = {
+ 3,5,7,11,13,17,19,23,29,31,37,41,43,47,
+ 53,59,61,67,71,73,79,83,89,97,
+ 101,103,107,109,113,127,131,137,139,149,
+ 151,157,163,167,173,179,181,191,193,197,199,
+ 239, // for 1,111,111
+ 541, // for 10,101,011
+ 1667, // for 8,333,333
+ };
+
+ int rounding = 0;
+
+ // Here we assume that our workings will fit in a 64; the point is to
+ // allow calculations with a number of ticks that may be large.
+ upper = m1 * m2;
+ lower = d1 * d2;
+#ifdef CYGDBG_USE_ASSERTS
+ cyg_uint64 save_upper = upper;
+ cyg_uint64 save_lower = lower;
+#endif
+
+ retry_rounding:
+ // First strip out common powers of 2
+ while ( (0 == (1 & upper)) && ( 0 == (1 & lower)) ) {
+ upper >>= 1;
+ lower >>= 1;
+ }
+
+ // then common factors - use lazy table above
+ for ( i = 0 ; i < (sizeof( primes )/sizeof( primes[0] )); i++ ) {
+ cyg_uint64 j, k, p = (cyg_uint64)(primes[i]);
+ j = upper / p;
+ while ( j * p == upper ) {
+ k = lower / p;
+ if ( k * p != lower )
+ break;
+ upper = j;
+ lower = k;
+ j = upper / p;
+ }
+ }
+
+ m1 = upper;
+ d1 = lower;
+ m2 = 1;
+ d2 = 1;
+
+ if ( m1 > 0x10000 ) {
+ // only bother if there are more than 16 bits consumed here
+
+ // now move powers of 2 from d1 to d2
+ // keeping them the same order of magnitude
+ while ( (0 == (1 & d1)) && (d2 < d1) ) {
+ d1 >>= 1;
+ d2 <<= 1;
+ }
+
+ // and factors from the table - go too far, if anything
+ int cont = (d2 < d1);
+ for ( i = 0 ; cont && (i < (sizeof( primes )/sizeof( primes[0] ))); i++ ) {
+ cyg_uint64 k, p = (cyg_uint64)(primes[i]);
+ k = d1 / p;
+ while ( cont && ((k * p) == d1) ) {
+ // we can extract a prime
+ d1 = k;
+ d2 *= p;
+ k = d1 / p;
+ cont = (d2 < d1);
+ }
+ }
+
+ // move powers of 2 from m1 to m2 so long as we do not go less than d1
+ while ( (0 == (1 & m1)) && (m2 < m1) && (m1 > (d1 << 5)) ) {
+ m1 >>= 1;
+ m2 <<= 1;
+ if ( m1 < 0x10000 )
+ break;
+ }
+
+ // and factors from the table - ensure m1 stays well larger than d1
+ cont = ((m2 < m1) && (m1 > (d1 << 4)) && (m1 > 0x10000));
+ for ( i = 0 ; cont && (i < (sizeof( primes )/sizeof( primes[0] ))); i++ ) {
+ cyg_uint64 k, p = (cyg_uint64)(primes[i]);
+ k = m1 / p;
+ cont = cont && (k > (d1 << 4) && (k > 0x10000));
+ while ( cont && ((k * p) == m1) ) {
+ // we can extract a prime
+ m1 = k;
+ m2 *= p;
+ k = m1 / p; // examine k for getting too small
+ cont = ((m2 < m1) && (k > (d1 << 4)) && (k > 0x10000));
+ }
+ }
+
+ // if, after all that, m1 odd and unchanged, and too large,
+ // decrement it just the once and try again: then try it
+ // incremented once.
+ if ( (m1 & 1) && (m1 == upper) && (m1 > 0x10000) && (rounding < 2) ) {
+ CYG_ASSERT( 1 == m2, "m2 should be 1 to try rounding" );
+ m1--;
+ upper = m1;
+ rounding++;
+ goto retry_rounding;
+ }
+ // likewise for d1 - each of the pair can be odd only once each
+ if ( (d1 & 1) && (d1 == lower) && (d1 > 0x10000) && (rounding < 2) ) {
+ CYG_ASSERT( 1 == d2, "d2 should be 1 to try rounding" );
+ d1--;
+ lower = d1;
+ rounding++;
+ goto retry_rounding;
+ }
+ }
+
+ CYG_ASSERT( 0 != m1, "m1 zero" );
+ CYG_ASSERT( 0 != m2, "m2 zero" );
+ CYG_ASSERT( 0 != d1, "d1 zero" );
+ CYG_ASSERT( 0 != d2, "d2 zero" );
+ CYG_ASSERT( rounding || save_upper/save_lower == (m1 * m2)/(d1 * d2),
+ "Unequal in forwards direction" );
+ CYG_ASSERT( rounding || save_lower/save_upper == (d1 * d2)/(m1 * m2),
+ "Unequal in reverse direction" );
+
+ pcc->mul1 = m1;
+ pcc->div1 = d1;
+ pcc->mul2 = m2;
+ pcc->div2 = d2;
+}
+
+// other to clocks is (other * ns_per * dividend / divisor)
+void Cyg_Clock::get_other_to_clock_converter(
+ cyg_uint64 ns_per_other_tick,
+ struct converter *pcc )
+{
+ construct_converter( pcc,
+ ns_per_other_tick, 1,
+ resolution.divisor, resolution.dividend );
+}
+
+// clocks to other is (ticks * divisor / dividend / ns_per)
+void Cyg_Clock::get_clock_to_other_converter(
+ cyg_uint64 ns_per_other_tick,
+ struct converter *pcc )
+{
+ construct_converter( pcc,
+ 1, ns_per_other_tick,
+ resolution.dividend, resolution.divisor );
+}
+
+
+//==========================================================================
+// Constructor for alarm object
+
+Cyg_Alarm::Cyg_Alarm(
+ Cyg_Counter *c, // Attached to this counter
+ cyg_alarm_fn *a, // Call-back function
+ CYG_ADDRWORD d // Call-back data
+ )
+{
+ CYG_REPORT_FUNCTION();
+
+ counter = c;
+ alarm = a;
+ data = d;
+ trigger = 0;
+ interval = 0;
+ enabled = false;
+
+}
+
+Cyg_Alarm::Cyg_Alarm(){}
+
+// -------------------------------------------------------------------------
+// Destructor
+
+Cyg_Alarm::~Cyg_Alarm()
+{
+ CYG_REPORT_FUNCTION();
+
+ disable();
+}
+
+// -------------------------------------------------------------------------
+//
+
+#ifdef CYGDBG_USE_ASSERTS
+
+cyg_bool Cyg_Alarm::check_this( cyg_assert_class_zeal zeal) const
+{
+ // check that we have a non-NULL pointer first
+ if( this == NULL ) return false;
+
+ switch( zeal )
+ {
+ case cyg_system_test:
+ case cyg_extreme:
+ case cyg_thorough:
+ if( trigger != 0 && !enabled ) return false;
+ case cyg_quick:
+ case cyg_trivial:
+ case cyg_none:
+ default:
+ break;
+ };
+
+ return true;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Initialize Alarm and enable
+
+void Cyg_Alarm::initialize(
+ cyg_tick_count t, // Absolute trigger time
+ cyg_tick_count i // Relative retrigger interval
+ )
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_Scheduler::lock();
+
+ // If already enabled, remove from counter
+
+ if( enabled ) counter->rem_alarm(this);
+
+ CYG_INSTRUMENT_ALARM( INIT, this, 0 );
+ CYG_INSTRUMENT_ALARM( TRIGGER,
+ ((cyg_uint32 *)&t)[0],
+ ((cyg_uint32 *)&t)[1] );
+ CYG_INSTRUMENT_ALARM( INTERVAL,
+ ((cyg_uint32 *)&i)[0],
+ ((cyg_uint32 *)&i)[1] );
+
+ trigger = t;
+ interval = i;
+
+ counter->add_alarm(this);
+
+ Cyg_Scheduler::unlock();
+}
+
+// -------------------------------------------------------------------------
+// Synchronize with a past alarm stream that had been disabled,
+// bring past times into synch, and the like.
+
+void
+Cyg_Alarm::synchronize( void )
+{
+ if( interval != 0 ) {
+ // This expression sets the trigger to the next whole interval
+ // at or after the current time. This means that alarms will
+ // continue at the same intervals as if they had never been
+ // disabled. The alternative would be to just set trigger to
+ // (counter->counter + interval), but this is less satisfying
+ // than preserving the original intervals. That behaviour can
+ // always be obtained by using initialize() rather than
+ // enable(), while the current behaviour would be more
+ // difficult to achieve that way.
+ cyg_tick_count d;
+ d = counter->current_value() + interval - trigger;
+ if ( d > interval ) {
+ // then trigger was in the past, so resynchronize
+ trigger += interval * ((d - 1) / interval );
+ }
+ // otherwise, we were just set up, so no worries.
+ }
+}
+
+// -------------------------------------------------------------------------
+// Ensure alarm enabled
+
+void Cyg_Alarm::enable()
+{
+ Cyg_Scheduler::lock();
+
+ if( !enabled )
+ {
+ // ensure the alarm time is in our future:
+ synchronize();
+ enabled = true;
+ counter->add_alarm(this);
+ }
+
+ Cyg_Scheduler::unlock();
+}
+
+// -------------------------------------------------------------------------
+// Ensure alarm disabled
+
+void Cyg_Alarm::disable()
+{
+ Cyg_Scheduler::lock();
+
+ if( enabled ) counter->rem_alarm(this);
+
+ Cyg_Scheduler::unlock();
+}
+
+// -------------------------------------------------------------------------
+// Get the current time values from the alarm
+
+void Cyg_Alarm::get_times(
+ cyg_tick_count *t, // Next trigger time
+ cyg_tick_count *i // Current interval
+ )
+{
+ // Lock the scheduler while we do this to avoid
+ // race conditions.
+ Cyg_Scheduler::lock();
+
+ if( t != NULL ) *t = trigger;
+ if( i != NULL ) *i = interval;
+
+ Cyg_Scheduler::unlock();
+}
+
+//==========================================================================
+// System clock object
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+
+class Cyg_RealTimeClock
+ : public Cyg_Clock
+{
+ Cyg_Interrupt interrupt;
+
+ static cyg_uint32 isr(cyg_vector vector, CYG_ADDRWORD data);
+
+ static void dsr(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data);
+
+ Cyg_RealTimeClock();
+
+ static Cyg_RealTimeClock rtc;
+};
+
+Cyg_Clock::cyg_resolution rtc_resolution = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
+
+//Cyg_RealTimeClock Cyg_RealTimeClock::rtc __attribute__((init_priority (1)));
+
+Cyg_RealTimeClock Cyg_RealTimeClock::rtc CYG_INIT_PRIORITY( CLOCK );
+
+// -------------------------------------------------------------------------
+
+Cyg_RealTimeClock::Cyg_RealTimeClock()
+ : Cyg_Clock(rtc_resolution),
+ interrupt(CYGNUM_HAL_INTERRUPT_RTC,
+ CYGNUM_KERNEL_COUNTERS_CLOCK_ISR_PRIORITY,
+ (CYG_ADDRWORD)this, isr, dsr)
+{
+ CYG_REPORT_FUNCTION();
+
+ HAL_CLOCK_INITIALIZE( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD );
+
+ interrupt.attach();
+
+ interrupt.unmask_interrupt(CYGNUM_HAL_INTERRUPT_RTC);
+
+ Cyg_Clock::real_time_clock = this;
+}
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
+cyg_tick_count total_clock_latency, total_clock_interrupts;
+cyg_int32 min_clock_latency = 0x7FFFFFFF;
+cyg_int32 max_clock_latency = 0;
+bool measure_clock_latency = false;
+#endif
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)
+cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls;
+cyg_int32 min_clock_dsr_latency = 0x7FFFFFFF;
+cyg_int32 max_clock_dsr_latency = 0;
+cyg_uint32 clock_dsr_start = 0;
+#endif
+
+// -------------------------------------------------------------------------
+
+cyg_uint32 Cyg_RealTimeClock::isr(cyg_vector vector, CYG_ADDRWORD data)
+{
+// CYG_REPORT_FUNCTION();
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
+ if (measure_clock_latency) {
+ cyg_int32 delta;
+ HAL_CLOCK_LATENCY(&delta);
+ // Note: Ignore a latency of 0 when finding min_clock_latency.
+ if (delta > 0) {
+ // Valid delta measured
+ total_clock_latency += delta;
+ total_clock_interrupts++;
+ if (min_clock_latency > delta) min_clock_latency = delta;
+ if (max_clock_latency < delta) max_clock_latency = delta;
+ }
+ }
+#endif
+
+ CYG_INSTRUMENT_CLOCK( ISR, 0, 0);
+
+ HAL_CLOCK_RESET( CYGNUM_HAL_INTERRUPT_RTC, CYGNUM_KERNEL_COUNTERS_RTC_PERIOD );
+
+ Cyg_Interrupt::acknowledge_interrupt(CYGNUM_HAL_INTERRUPT_RTC);
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY)
+ HAL_CLOCK_READ(&clock_dsr_start);
+#endif
+ return Cyg_Interrupt::CALL_DSR|Cyg_Interrupt::HANDLED;
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_RealTimeClock::dsr(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data)
+{
+// CYG_REPORT_FUNCTION();
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) && defined(HAL_CLOCK_LATENCY)
+ if (measure_clock_latency) {
+ cyg_int32 delta;
+ HAL_CLOCK_READ((cyg_uint32 *)&delta);
+ delta -= clock_dsr_start;
+ // Note: Ignore a latency of <= 0 when finding min_clock_latency.
+ if (delta > 0 ) {
+ // Valid delta measured
+ total_clock_dsr_latency += delta;
+ total_clock_dsr_calls++;
+ if (min_clock_dsr_latency > delta) min_clock_dsr_latency = delta;
+ if (max_clock_dsr_latency < delta) max_clock_dsr_latency = delta;
+ }
+ }
+#endif
+
+ Cyg_RealTimeClock *rtc = (Cyg_RealTimeClock *)data;
+
+ CYG_INSTRUMENT_CLOCK( TICK_START,
+ rtc->current_value_lo(),
+ rtc->current_value_hi());
+
+ rtc->tick( count );
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+#if 0 == CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES
+
+ // If timeslicing is enabled, call the scheduler to
+ // handle it. But not if we have unique priorities.
+
+ Cyg_Scheduler::scheduler.timeslice();
+
+#endif
+#endif
+
+ CYG_INSTRUMENT_CLOCK( TICK_END,
+ rtc->current_value_lo(),
+ rtc->current_value_hi());
+
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// EOF common/clock.cxx
diff --git a/ecos/packages/kernel/current/src/common/except.cxx b/ecos/packages/kernel/current/src/common/except.cxx
new file mode 100644
index 0000000000..fac3847df8
--- /dev/null
+++ b/ecos/packages/kernel/current/src/common/except.cxx
@@ -0,0 +1,268 @@
+//==========================================================================
+//
+// common/except.cxx
+//
+// Exception handling implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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, jlarmour
+// Date: 1999-02-16
+// Purpose: Exception handling implementation
+// Description: This file contains the code that registers and delivers
+// exceptions.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/except.hxx> // our header
+
+#include <cyg/hal/hal_arch.h> // architecture definitions
+#include <cyg/hal/hal_intr.h> // vector definitions
+
+#include <cyg/kernel/thread.hxx> // thread interface
+
+#include <cyg/kernel/thread.inl> // thread inlines
+
+#ifdef CYGPKG_KERNEL_EXCEPTIONS
+
+// -------------------------------------------------------------------------
+// Null exception handler. This is used to capture exceptions that are
+// not caught by user supplied handlers.
+
+void
+cyg_null_exception_handler(
+ CYG_ADDRWORD data, // user supplied data
+ cyg_code exception_number, // exception being raised
+ CYG_ADDRWORD exception_info // any exception specific info
+ )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG3("data=%08x, exception=%d, info=%08x", data,
+ exception_number, exception_info);
+ CYG_TRACE1( 1, "Uncaught exception: %d", exception_number);
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Exception Controller constructor.
+
+Cyg_Exception_Control::Cyg_Exception_Control()
+{
+ CYG_REPORT_FUNCTION();
+#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE
+
+ for( int i = 0; i < CYGNUM_HAL_EXCEPTION_COUNT ; i++ )
+ exception_handler[i] = cyg_null_exception_handler,
+ exception_data[i] = 0;
+#else
+
+ exception_handler = cyg_null_exception_handler;
+ exception_data = 0;
+
+#endif
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Exception registation. Stores the handler function and data to be used
+// for handling the given exception number. Where exceptions are not decoded
+// only a single handler may be registered for all exceptions. This function
+// also returns the old values of the exception handler and data to allow
+// chaining to be implemented.
+
+void
+Cyg_Exception_Control::register_exception(
+ cyg_code exception_number, // exception number
+ cyg_exception_handler handler, // handler function
+ CYG_ADDRWORD data, // data argument
+ cyg_exception_handler **old_handler, // handler function
+ CYG_ADDRWORD *old_data // data argument
+ )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG5("exception=%d, handler func=%08x, data=%08x, "
+ "space for old handler=%08x,space for old data=%08x",
+ exception_number, handler, data, old_handler,
+ old_data);
+
+ CYG_ASSERT( exception_number <= CYGNUM_HAL_EXCEPTION_MAX,
+ "Out of range exception number");
+ CYG_ASSERT( exception_number >= CYGNUM_HAL_EXCEPTION_MIN,
+ "Out of range exception number");
+
+
+ // Should we complain if there is already a registered
+ // handler, or should we just replace is silently?
+
+#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE
+
+ if( old_handler != NULL )
+ *old_handler = exception_handler[exception_number -
+ CYGNUM_HAL_EXCEPTION_MIN];
+ if( old_data != NULL )
+ *old_data = exception_data[exception_number -
+ CYGNUM_HAL_EXCEPTION_MIN];
+ exception_handler[exception_number - CYGNUM_HAL_EXCEPTION_MIN] = handler;
+ exception_data[exception_number - CYGNUM_HAL_EXCEPTION_MIN] = data;
+
+#else
+
+ if( old_handler != NULL )
+ *old_handler = exception_handler;
+ if( old_data != NULL )
+ *old_data = exception_data;
+ exception_handler = handler;
+ exception_data = data;
+
+#endif
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Exception deregistation. Revert the handler for the exception number
+// to the default.
+
+void
+Cyg_Exception_Control::deregister_exception(
+ cyg_code exception_number // exception number
+ )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("exception number=%d", exception_number);
+
+ CYG_ASSERT( exception_number <= CYGNUM_HAL_EXCEPTION_MAX,
+ "Out of range exception number");
+ CYG_ASSERT( exception_number >= CYGNUM_HAL_EXCEPTION_MIN,
+ "Out of range exception number");
+
+#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE
+
+ exception_handler[exception_number - CYGNUM_HAL_EXCEPTION_MIN] =
+ cyg_null_exception_handler;
+ exception_data[exception_number - CYGNUM_HAL_EXCEPTION_MIN] = 0;
+
+#else
+
+ exception_handler = cyg_null_exception_handler;
+ exception_data = 0;
+
+#endif
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Exception delivery. Call the appropriate exception handler.
+
+void
+Cyg_Exception_Control::deliver_exception(
+ cyg_code exception_number, // exception being raised
+ CYG_ADDRWORD exception_info // exception specific info
+ )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG2("exception number=%d, exception info=%08x",
+ exception_number, exception_info);
+
+ cyg_exception_handler *handler = NULL;
+ CYG_ADDRWORD data = 0;
+
+ CYG_ASSERT( exception_number <= CYGNUM_HAL_EXCEPTION_MAX,
+ "Out of range exception number");
+ CYG_ASSERT( exception_number >= CYGNUM_HAL_EXCEPTION_MIN,
+ "Out of range exception number");
+
+#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE
+
+ handler = exception_handler[exception_number - CYGNUM_HAL_EXCEPTION_MIN];
+ data = exception_data[exception_number - CYGNUM_HAL_EXCEPTION_MIN];
+
+#else
+
+ handler = exception_handler;
+ data = exception_data;
+
+#endif
+
+ // The handler will always be a callable function: either the user's
+ // registered function or the null handler. So it is always safe to
+ // just go ahead and call it.
+
+ handler( data, exception_number, exception_info );
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Exception delivery function called from the HAL as a result of a
+// hardware exception being raised.
+
+externC void
+cyg_hal_deliver_exception( CYG_WORD code, CYG_ADDRWORD data )
+{
+ CYG_REPORT_FUNCTION();
+ Cyg_Thread::self()->deliver_exception( (cyg_code)code, data );
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Where exceptions are global, there is a single static instance of the
+// exception control object. Define it here.
+
+#ifdef CYGSEM_KERNEL_EXCEPTIONS_GLOBAL
+
+Cyg_Exception_Control Cyg_Thread::exception_control
+ CYG_INIT_PRIORITY(INTERRUPTS);
+
+#endif
+
+// -------------------------------------------------------------------------
+
+#endif // ifdef CYGPKG_KERNEL_EXCEPTIONS
+
+// -------------------------------------------------------------------------
+// EOF common/except.cxx
diff --git a/ecos/packages/kernel/current/src/common/kapi.cxx b/ecos/packages/kernel/current/src/common/kapi.cxx
new file mode 100644
index 0000000000..3801e94912
--- /dev/null
+++ b/ecos/packages/kernel/current/src/common/kapi.cxx
@@ -0,0 +1,1264 @@
+//==========================================================================
+//
+// common/kapi.cxx
+//
+// C API Implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Nick Garnett
+// Copyright (C) 2003 Jonathan Larmour
+//
+// 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, dsm
+// Contributors: nickg
+// Date: 1998-03-02
+// Purpose: C API Implementation
+// Description: C++ implementation of the C API
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+#include <cyg/kernel/diag.h>
+
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl> // thread inlines
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/intr.hxx>
+#include <cyg/kernel/clock.hxx>
+
+#include <cyg/kernel/sema.hxx>
+#include <cyg/kernel/flag.hxx>
+#include <cyg/kernel/mutex.hxx>
+#include <cyg/kernel/mbox.hxx>
+
+#include <cyg/kernel/sched.inl> // scheduler inlines
+#include <cyg/kernel/clock.inl> // clock inlines
+
+#include <cyg/kernel/kapi.h> // C API
+
+// -------------------------------------------------------------------------
+// Magic new function
+
+inline void *operator new(size_t size, void *ptr)
+{
+ CYG_CHECK_DATA_PTR( ptr, "Bad pointer" );
+ return ptr;
+}
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGDBG_USE_ASSERTS
+
+#define CYG_ASSERT_SIZES(cstruct, cxxstruct) \
+CYG_MACRO_START \
+ char *msg = "Size of C struct " #cstruct \
+ " != size of C++ struct " #cxxstruct ; \
+ CYG_ASSERT( sizeof(cstruct) == sizeof(cxxstruct) , msg ); \
+CYG_MACRO_END
+
+#else
+
+#define CYG_ASSERT_SIZES(cstruct, cxxstruct)
+
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Scheduler operations */
+
+/* Starts scheduler with created threads. Never returns. */
+externC void cyg_scheduler_start(void) __THROW
+{
+ Cyg_Scheduler::start();
+}
+
+/* Lock the scheduler. */
+externC void cyg_scheduler_lock(void) __THROW
+{
+ Cyg_Scheduler::lock();
+ // get_sched_lock() is unsigned, see below "cyg_ucount32 lock"
+ CYG_ASSERT( (0xff000000 & (Cyg_Scheduler::get_sched_lock())) == 0,
+ "Scheduler overlocked" );
+}
+
+/* Lock the scheduler, but never more than level=1. */
+externC void cyg_scheduler_safe_lock(void) __THROW
+{
+ Cyg_Scheduler::lock();
+ cyg_ucount32 slock = Cyg_Scheduler::get_sched_lock();
+ if (slock > 1)
+ Cyg_Scheduler::unlock();
+ // get_sched_lock() is unsigned, see below "cyg_ucount32 lock"
+ CYG_ASSERT( (0xff000000 & (Cyg_Scheduler::get_sched_lock())) == 0,
+ "Scheduler overlocked" );
+}
+
+/* Unlock the scheduler. */
+externC void cyg_scheduler_unlock(void) __THROW
+{
+ cyg_ucount32 slock = Cyg_Scheduler::get_sched_lock();
+ CYG_ASSERT( 0 < slock, "Scheduler not locked" );
+ // And program defensively too:
+ if ( 0 < slock )
+ Cyg_Scheduler::unlock();
+}
+
+/* Read the scheduler lock value. */
+externC cyg_ucount32 cyg_scheduler_read_lock(void) __THROW
+{
+ cyg_ucount32 slock = Cyg_Scheduler::get_sched_lock();
+ return slock;
+}
+
+/*---------------------------------------------------------------------------*/
+/* Thread operations */
+
+externC void cyg_thread_create(
+ cyg_addrword_t sched_info, /* scheduling info (eg pri) */
+ cyg_thread_entry_t *entry, /* entry point function */
+ cyg_addrword_t entry_data, /* entry data */
+ char *name, /* optional thread name */
+ void *stack_base, /* stack base, NULL = alloc */
+ cyg_ucount32 stack_size, /* stack size, 0 = default */
+ cyg_handle_t *handle, /* returned thread handle */
+ cyg_thread *thread /* put thread here */
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_thread, Cyg_Thread );
+
+ Cyg_Thread *t = new((void *)thread) Cyg_Thread (
+ (CYG_ADDRWORD) sched_info,
+ (cyg_thread_entry *)entry,
+ (CYG_ADDRWORD) entry_data,
+ name,
+ (CYG_ADDRWORD) stack_base,
+ stack_size
+ );
+ t=t;
+
+ CYG_CHECK_DATA_PTR( handle, "Bad handle pointer" );
+ *handle = (cyg_handle_t)thread;
+}
+
+externC void cyg_thread_exit() __THROW
+{
+ Cyg_Thread::exit();
+}
+
+externC cyg_bool_t cyg_thread_delete( cyg_handle_t thread ) __THROW
+{
+ Cyg_Thread *th = (Cyg_Thread *)thread;
+ if( th->get_state() != Cyg_Thread::EXITED )
+ th->kill(); // encourage it to terminate
+ if( th->get_state() != Cyg_Thread::EXITED )
+ return false; // it didn't run yet, leave it up to the app to fix
+ th->~Cyg_Thread();
+ return true;
+}
+
+externC void cyg_thread_suspend(cyg_handle_t thread) __THROW
+{
+ ((Cyg_Thread *)thread)->suspend();
+}
+
+externC void cyg_thread_resume(cyg_handle_t thread) __THROW
+{
+ Cyg_Thread *th = (Cyg_Thread *)thread;
+
+ // If we are resuming an exited thread then
+ // reinitialize it.
+
+ if( th->get_state() == Cyg_Thread::EXITED )
+ th->reinitialize();
+
+ th->resume();
+}
+
+externC void cyg_thread_kill( cyg_handle_t thread) __THROW
+{
+ ((Cyg_Thread *)thread)->kill();
+}
+
+externC void cyg_thread_release( cyg_handle_t thread) __THROW
+{
+ ((Cyg_Thread *)thread)->release();
+}
+
+externC void cyg_thread_yield() __THROW
+{
+ Cyg_Thread::yield();
+}
+
+externC cyg_handle_t cyg_thread_self() __THROW
+{
+ return (cyg_handle_t)Cyg_Thread::self();
+}
+
+externC cyg_uint16 cyg_thread_get_id( cyg_handle_t thread) __THROW
+{
+ return ((Cyg_Thread *)thread)->get_unique_id();
+}
+
+// idle thread is not really a plain CygThread; danger.
+externC cyg_handle_t cyg_thread_idle_thread() __THROW
+{
+ extern Cyg_Thread idle_thread;
+ return (cyg_handle_t)&idle_thread;
+}
+
+/* Priority manipulation */
+externC void cyg_thread_set_priority(
+ cyg_handle_t thread, cyg_priority_t priority ) __THROW
+{
+#ifdef CYGIMP_THREAD_PRIORITY
+ ((Cyg_Thread *)thread)->set_priority(priority);
+#endif
+}
+
+
+/* Get the normal priority, ie without any applied mutex inheritance or
+ * ceiling protocol. */
+externC cyg_priority_t cyg_thread_get_priority(cyg_handle_t thread) __THROW
+{
+#ifdef CYGIMP_THREAD_PRIORITY
+ return ((Cyg_Thread *)thread)->get_priority();
+#else
+ return 0;
+#endif
+}
+
+
+/* Get the current priority, ie any applied mutex inheritance or
+ * ceiling protocol. */
+externC cyg_priority_t cyg_thread_get_current_priority(cyg_handle_t thread) __THROW
+{
+#ifdef CYGIMP_THREAD_PRIORITY
+ return ((Cyg_Thread *)thread)->get_current_priority();
+#else
+ return 0;
+#endif
+}
+
+/* Deadline scheduling control (optional) */
+
+externC void cyg_thread_deadline_wait(
+ cyg_tick_count_t start_time, /* abs earliest start time */
+ cyg_tick_count_t run_time, /* worst case execution time */
+ cyg_tick_count_t deadline /* absolute deadline */
+) __THROW
+{
+ CYG_ASSERT(0,"Not implemented");
+}
+
+externC void cyg_thread_delay(cyg_tick_count_t delay) __THROW
+{
+ Cyg_Thread::self()->delay(delay);
+}
+
+/* Stack information */
+externC cyg_addrword_t cyg_thread_get_stack_base(cyg_handle_t thread) __THROW
+{
+ return ((Cyg_Thread *)thread)->get_stack_base();
+}
+
+externC cyg_uint32 cyg_thread_get_stack_size(cyg_handle_t thread) __THROW
+{
+ return ((Cyg_Thread *)thread)->get_stack_size();
+}
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
+externC cyg_uint32 cyg_thread_measure_stack_usage(cyg_handle_t thread) __THROW
+{
+ return ((Cyg_Thread *)thread)->measure_stack_usage();
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Thread enumeration and information */
+
+#ifdef CYGVAR_KERNEL_THREADS_LIST
+
+cyg_bool_t cyg_thread_get_next( cyg_handle_t *current, cyg_uint16 *id ) __THROW
+{
+ cyg_bool_t result = true;
+
+ // There is a minute but finite chance that the thread could have
+ // exitted since the previous cyg_thread_get_next() call, and we can't
+ // detect the ID mismatch further down. So be quite zealous with checking.
+
+ CYG_CHECK_DATA_PTRC( current );
+ CYG_CHECK_DATA_PTRC( id );
+ if ( *current != 0 )
+ CYG_CHECK_DATA_PTRC( *current );
+
+ Cyg_Scheduler::lock();
+
+ Cyg_Thread *thread = (Cyg_Thread *)*current;
+ CYG_ASSERT_ZERO_OR_CLASSC( thread );
+ if( *current == 0 )
+ {
+ thread = Cyg_Thread::get_list_head();
+ *current = (cyg_handle_t)thread;
+ *id = thread->get_unique_id();
+ }
+ else if( (thread->get_unique_id() == *id) &&
+ (thread = thread->get_list_next()) != NULL )
+ {
+ CYG_CHECK_DATA_PTRC( thread );
+ CYG_ASSERT_CLASSC( thread );
+ *current = (cyg_handle_t)thread;
+ *id = thread->get_unique_id();
+ }
+ else
+ {
+ *current = 0;
+ *id = 0;
+ result = false;
+ }
+
+ Cyg_Scheduler::unlock();
+
+ return result;
+}
+
+cyg_handle_t cyg_thread_find( cyg_uint16 id ) __THROW
+{
+ Cyg_Scheduler::lock();
+
+ Cyg_Thread *thread = Cyg_Thread::get_list_head();
+
+ while( thread != NULL )
+ {
+ if( thread->get_unique_id() == id )
+ break;
+
+ thread = thread->get_list_next();
+ }
+
+ Cyg_Scheduler::unlock();
+
+ return (cyg_handle_t)thread;
+}
+
+#endif
+
+cyg_bool_t cyg_thread_get_info( cyg_handle_t threadh,
+ cyg_uint16 id,
+ cyg_thread_info *info ) __THROW
+{
+ cyg_bool_t result = true;
+ Cyg_Thread *thread = (Cyg_Thread *)threadh;
+ CYG_CHECK_DATA_PTRC( thread );
+ if ( NULL != info )
+ CYG_CHECK_DATA_PTRC( info );
+
+ Cyg_Scheduler::lock();
+
+ if( thread->get_unique_id() == id && info != NULL )
+ {
+ CYG_ASSERT_CLASSC( thread );
+ info->handle = threadh;
+ info->id = id;
+ info->state = thread->get_state();
+#ifdef CYGVAR_KERNEL_THREADS_NAME
+ info->name = thread->get_name();
+#else
+ info->name = NULL;
+#endif
+ info->set_pri = thread->get_priority();
+ info->cur_pri = thread->get_current_priority();
+ info->stack_base = thread->get_stack_base();
+ info->stack_size = thread->get_stack_size();
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_MEASUREMENT
+ info->stack_used = thread->measure_stack_usage();
+#else
+ info->stack_used = 0;
+#endif
+ }
+ else result = false;
+
+ Cyg_Scheduler::unlock();
+
+ return result;
+}
+
+/*---------------------------------------------------------------------------*/
+/* Per-thread data */
+
+#ifdef CYGVAR_KERNEL_THREADS_DATA
+
+externC cyg_ucount32 cyg_thread_new_data_index() __THROW
+{
+ Cyg_Thread::cyg_data_index index = Cyg_Thread::new_data_index();
+ CYG_ASSERT(index >= 0, "failed to allocate data index" );
+ return index;
+}
+
+externC void cyg_thread_free_data_index(cyg_ucount32 index) __THROW
+{
+ Cyg_Thread::free_data_index(index);
+}
+
+externC CYG_ADDRWORD cyg_thread_get_data(cyg_ucount32 index) __THROW
+{
+ return Cyg_Thread::get_data(index);
+}
+
+externC CYG_ADDRWORD *cyg_thread_get_data_ptr(cyg_ucount32 index) __THROW
+{
+ return Cyg_Thread::get_data_ptr(index);
+}
+
+externC void cyg_thread_set_data(cyg_ucount32 index, CYG_ADDRWORD
+data) __THROW
+{
+ Cyg_Thread::self()->set_data(index, data);
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Thread destructors */
+
+#ifdef CYGPKG_KERNEL_THREADS_DESTRUCTORS
+__externC cyg_bool_t
+cyg_thread_add_destructor( cyg_thread_destructor_fn fn,
+ cyg_addrword_t data ) __THROW
+{
+ return Cyg_Thread::self()->add_destructor( fn, data );
+}
+
+__externC cyg_bool_t
+cyg_thread_rem_destructor( cyg_thread_destructor_fn fn,
+ cyg_addrword_t data ) __THROW
+{
+ return Cyg_Thread::self()->rem_destructor( fn, data );
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Exception handling. */
+
+#ifdef CYGPKG_KERNEL_EXCEPTIONS
+externC void cyg_exception_set_handler(
+ cyg_code_t exception_number,
+ cyg_exception_handler_t *new_handler,
+ cyg_addrword_t new_data,
+ cyg_exception_handler_t **old_handler,
+ cyg_addrword_t *old_data
+) __THROW
+{
+ Cyg_Thread::register_exception(
+ exception_number,
+ (cyg_exception_handler *)new_handler,
+ (CYG_ADDRWORD)new_data,
+ (cyg_exception_handler **)old_handler,
+ (CYG_ADDRWORD *)old_data
+ );
+}
+
+/* Clear exception handler to default */
+externC void cyg_exception_clear_handler(
+ cyg_code_t exception_number
+) __THROW
+{
+ Cyg_Thread::deregister_exception( exception_number );
+}
+
+/* Invoke exception handler */
+externC void cyg_exception_call_handler(
+ cyg_handle_t thread,
+ cyg_code_t exception_number,
+ cyg_addrword_t error_code
+) __THROW
+{
+ Cyg_Thread *t = (Cyg_Thread *)thread;
+
+ t->deliver_exception( exception_number, error_code );
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Interrupt handling */
+
+externC void cyg_interrupt_create(
+ cyg_vector_t vector, /* Vector to attach to */
+ cyg_priority_t priority, /* Queue priority */
+ cyg_addrword_t data, /* Data pointer */
+ cyg_ISR_t *isr, /* Interrupt Service Routine */
+ cyg_DSR_t *dsr, /* Deferred Service Routine */
+ cyg_handle_t *handle, /* returned handle */
+ cyg_interrupt *intr /* put interrupt here */
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_interrupt, Cyg_Interrupt );
+
+ Cyg_Interrupt *t = new((void *)intr) Cyg_Interrupt (
+ (cyg_vector)vector,
+ (cyg_priority)priority,
+ (CYG_ADDRWORD)data,
+ (cyg_ISR *)isr,
+ (cyg_DSR *)dsr );
+ t=t;
+
+ CYG_CHECK_DATA_PTR( handle, "Bad handle pointer" );
+ *handle = (cyg_handle_t)intr;
+}
+
+externC void cyg_interrupt_delete( cyg_handle_t interrupt) __THROW
+{
+ ((Cyg_Interrupt *)interrupt)->~Cyg_Interrupt();
+}
+
+void cyg_interrupt_attach( cyg_handle_t interrupt ) __THROW
+{
+ ((Cyg_Interrupt *)interrupt)->attach();
+}
+
+void cyg_interrupt_detach( cyg_handle_t interrupt ) __THROW
+{
+ ((Cyg_Interrupt *)interrupt)->detach();
+}
+
+/* VSR manipulation */
+
+externC void cyg_interrupt_get_vsr(
+ cyg_vector_t vector, /* vector to get */
+ cyg_VSR_t **vsr /* vsr got */
+) __THROW
+{
+ Cyg_Interrupt::get_vsr( (cyg_vector)vector, (cyg_VSR **)vsr);
+}
+
+externC void cyg_interrupt_set_vsr(
+ cyg_vector_t vector, /* vector to set */
+ cyg_VSR_t *vsr /* vsr to set */
+) __THROW
+{
+ Cyg_Interrupt::set_vsr( (cyg_vector)vector, (cyg_VSR *)vsr);
+}
+
+/* CPU level interrupt mask */
+externC void cyg_interrupt_disable() __THROW
+{
+ Cyg_Interrupt::disable_interrupts();
+}
+
+externC void cyg_interrupt_enable() __THROW
+{
+ Cyg_Interrupt::enable_interrupts();
+}
+
+/* Interrupt controller access */
+externC void cyg_interrupt_mask(cyg_vector_t vector) __THROW
+{
+ Cyg_Interrupt::mask_interrupt( (cyg_vector)vector);
+}
+
+externC void cyg_interrupt_mask_intunsafe(cyg_vector_t vector) __THROW
+{
+ Cyg_Interrupt::mask_interrupt_intunsafe( (cyg_vector)vector);
+}
+
+externC void cyg_interrupt_unmask(cyg_vector_t vector) __THROW
+{
+ Cyg_Interrupt::unmask_interrupt( (cyg_vector)vector);
+}
+
+externC void cyg_interrupt_unmask_intunsafe(cyg_vector_t vector) __THROW
+{
+ Cyg_Interrupt::unmask_interrupt_intunsafe( (cyg_vector)vector);
+}
+
+externC void cyg_interrupt_acknowledge(cyg_vector_t vector) __THROW
+{
+ Cyg_Interrupt::acknowledge_interrupt( (cyg_vector)vector);
+}
+
+
+externC void cyg_interrupt_configure(
+ cyg_vector_t vector, /* vector to configure */
+ cyg_bool_t level, /* level or edge triggered */
+ cyg_bool_t up /* rising/faling edge, high/low level*/
+) __THROW
+{
+ Cyg_Interrupt::configure_interrupt( (cyg_vector)vector, level, up );
+}
+
+externC void cyg_interrupt_set_cpu(
+ cyg_vector_t vector, /* vector to control */
+ cyg_cpu_t cpu /* CPU to set */
+) __THROW
+{
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+ Cyg_Interrupt::set_cpu( vector, cpu );
+#endif
+}
+
+externC cyg_cpu_t cyg_interrupt_get_cpu(
+ cyg_vector_t vector /* vector to control */
+) __THROW
+{
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+ return Cyg_Interrupt::get_cpu( vector );
+#else
+ return CYG_KERNEL_CPU_THIS();
+#endif
+
+}
+
+/*---------------------------------------------------------------------------*/
+/* Counters, Clocks and Alarms */
+
+externC void cyg_counter_create(
+ cyg_handle_t *handle, /* returned counter handle */
+ cyg_counter *counter /* put counter here */
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_counter, Cyg_Counter );
+
+ Cyg_Counter *t = new((void *)counter) Cyg_Counter ();
+ t=t;
+
+ CYG_CHECK_DATA_PTR( handle, "Bad handle pointer" );
+ *handle = (cyg_handle_t)counter;
+}
+
+externC void cyg_counter_delete(cyg_handle_t counter) __THROW
+{
+ ((Cyg_Counter *)counter)->~Cyg_Counter();
+}
+
+/* Return current value of counter */
+externC cyg_tick_count_t cyg_counter_current_value(cyg_handle_t counter) __THROW
+{
+ return ((Cyg_Counter *)counter)->current_value();
+}
+
+/* Set new current value */
+externC void cyg_counter_set_value(
+ cyg_handle_t counter,
+ cyg_tick_count_t new_value
+) __THROW
+{
+ ((Cyg_Counter *)counter)->set_value( new_value );
+}
+
+/* Advance counter by one tick */
+externC void cyg_counter_tick(cyg_handle_t counter) __THROW
+{
+ ((Cyg_Counter *)counter)->tick();
+}
+
+/* Advance counter by multiple ticks */
+externC void cyg_counter_multi_tick(cyg_handle_t counter, cyg_tick_count_t ticks) __THROW
+{
+ ((Cyg_Counter *)counter)->tick(ticks);
+}
+
+/* Create a clock object */
+externC void cyg_clock_create(
+ cyg_resolution_t resolution, /* Initial resolution */
+ cyg_handle_t *handle, /* Returned clock handle */
+ cyg_clock *clock /* put clock here */
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_clock, Cyg_Clock );
+
+ Cyg_Clock::cyg_resolution res;
+
+ res.dividend = resolution.dividend;
+ res.divisor = resolution.divisor;
+
+ Cyg_Clock *t = new((void *)clock) Cyg_Clock ( res );
+ t=t;
+
+ CYG_CHECK_DATA_PTR( handle, "Bad handle pointer" );
+ *handle = (cyg_handle_t)clock;
+}
+
+externC void cyg_clock_delete(cyg_handle_t clock) __THROW
+{
+ ((Cyg_Clock *)clock)->~Cyg_Clock();
+}
+
+/* convert a clock handle to a counter handle so we can use the */
+/* counter API on it. */
+externC void cyg_clock_to_counter(
+ cyg_handle_t clock,
+ cyg_handle_t *counter
+) __THROW
+{
+ CYG_CHECK_DATA_PTR( counter, "Bad counter handle pointer" );
+ *counter = (cyg_handle_t)(Cyg_Counter *)clock;
+}
+
+externC void cyg_clock_set_resolution(
+ cyg_handle_t clock,
+ cyg_resolution_t resolution /* New resolution */
+) __THROW
+{
+ Cyg_Clock::cyg_resolution res;
+
+ res.dividend = resolution.dividend;
+ res.divisor = resolution.divisor;
+
+ ((Cyg_Clock *)clock)->set_resolution( res );
+}
+
+externC cyg_resolution_t cyg_clock_get_resolution(cyg_handle_t clock) __THROW
+{
+ Cyg_Clock::cyg_resolution res =
+ ((Cyg_Clock *)clock)->get_resolution();
+
+ cyg_resolution_t resolution;
+
+ resolution.dividend = res.dividend;
+ resolution.divisor = res.divisor;
+
+ return resolution;
+}
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+externC cyg_handle_t cyg_real_time_clock(void) __THROW
+{
+ return (cyg_handle_t)Cyg_Clock::real_time_clock;
+}
+
+externC cyg_tick_count_t cyg_current_time(void) __THROW
+{
+ return Cyg_Clock::real_time_clock->current_value();
+}
+#endif
+
+externC void cyg_alarm_create(
+ cyg_handle_t counter, /* Attached to this counter */
+ cyg_alarm_t *alarmfn, /* Call-back function */
+ cyg_addrword_t data, /* Call-back data */
+ cyg_handle_t *handle, /* Returned alarm object */
+ cyg_alarm *alarm /* put alarm here */
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_alarm, Cyg_Alarm );
+
+ Cyg_Alarm *t = new((void *)alarm) Cyg_Alarm (
+ (Cyg_Counter *)counter,
+ (cyg_alarm_fn *)alarmfn,
+ (CYG_ADDRWORD)data
+ );
+ t=t;
+
+ CYG_CHECK_DATA_PTR( handle, "Bad handle pointer" );
+ *handle = (cyg_handle_t)alarm;
+}
+
+/* Disable alarm, detach from counter and invalidate handles */
+externC void cyg_alarm_delete( cyg_handle_t alarm) __THROW
+{
+ ((Cyg_Alarm *)alarm)->~Cyg_Alarm();
+}
+
+externC void cyg_alarm_initialize(
+ cyg_handle_t alarm,
+ cyg_tick_count_t trigger, /* Absolute trigger time */
+ cyg_tick_count_t interval /* Relative retrigger interval */
+) __THROW
+{
+ ((Cyg_Alarm *)alarm)->initialize(
+ (cyg_tick_count)trigger,
+ (cyg_tick_count)interval);
+}
+
+externC void cyg_alarm_get_times(
+ cyg_handle_t alarm,
+ cyg_tick_count_t *trigger, /* Next trigger time */
+ cyg_tick_count_t *interval /* Current interval */
+) __THROW
+{
+ ((Cyg_Alarm *)alarm)->get_times(
+ (cyg_tick_count*)trigger,
+ (cyg_tick_count*)interval);
+}
+
+externC void cyg_alarm_enable( cyg_handle_t alarm ) __THROW
+{
+ ((Cyg_Alarm *)alarm)->enable();
+}
+
+externC void cyg_alarm_disable( cyg_handle_t alarm ) __THROW
+{
+ ((Cyg_Alarm *)alarm)->disable();
+}
+
+/*---------------------------------------------------------------------------*/
+/* Mail boxes */
+
+externC void cyg_mbox_create(
+ cyg_handle_t *handle,
+ cyg_mbox *mbox
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_mbox, Cyg_Mbox );
+
+ Cyg_Mbox *t = new((void *)mbox) Cyg_Mbox();
+ t=t;
+
+ CYG_CHECK_DATA_PTR( handle, "Bad handle pointer" );
+ *handle = (cyg_handle_t)mbox;
+}
+
+externC void cyg_mbox_delete(cyg_handle_t mbox) __THROW
+{
+ ((Cyg_Mbox *)mbox)->~Cyg_Mbox();
+}
+
+externC void *cyg_mbox_get(cyg_handle_t mbox) __THROW
+{
+ return ((Cyg_Mbox *)mbox)->get();
+}
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+void *cyg_mbox_timed_get(
+ cyg_handle_t mbox,
+ cyg_tick_count_t abstime
+ ) __THROW
+{
+ return ((Cyg_Mbox *)mbox)->get(abstime);
+}
+#endif
+
+externC void *cyg_mbox_tryget(cyg_handle_t mbox) __THROW
+{
+ return ((Cyg_Mbox *)mbox)->tryget();
+}
+
+externC void *cyg_mbox_peek_item(cyg_handle_t mbox) __THROW
+{
+ return ((Cyg_Mbox *)mbox)->peek_item();
+}
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+externC cyg_bool_t cyg_mbox_put(cyg_handle_t mbox, void *item) __THROW
+{
+ return ((Cyg_Mbox *)mbox)->put(item);
+}
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+externC cyg_bool_t cyg_mbox_timed_put(
+ cyg_handle_t mbox,
+ void *item,
+ cyg_tick_count_t abstime
+ ) __THROW
+{
+ return ((Cyg_Mbox *)mbox)->put(item, abstime);
+}
+#endif
+#endif
+
+externC cyg_bool_t cyg_mbox_tryput(cyg_handle_t mbox, void *item) __THROW
+{
+ return ((Cyg_Mbox *)mbox)->tryput(item);
+}
+
+externC cyg_count32 cyg_mbox_peek(cyg_handle_t mbox) __THROW
+{
+ return ((Cyg_Mbox *)mbox)->peek();
+}
+
+externC cyg_bool_t cyg_mbox_waiting_to_get(cyg_handle_t mbox) __THROW
+{
+ return ((Cyg_Mbox *)mbox)->waiting_to_get();
+}
+
+externC cyg_bool_t cyg_mbox_waiting_to_put(cyg_handle_t mbox) __THROW
+{
+ return ((Cyg_Mbox *)mbox)->waiting_to_put();
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* Semaphores */
+
+externC void cyg_semaphore_init(
+ cyg_sem_t *sem, /* Semaphore to init */
+ cyg_count32 val /* Initial semaphore value */
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_sem_t, Cyg_Counting_Semaphore );
+
+ Cyg_Counting_Semaphore *t = new((void *)sem) Cyg_Counting_Semaphore(val);
+ t=t;
+}
+
+externC void cyg_semaphore_destroy( cyg_sem_t *sem ) __THROW
+{
+ ((Cyg_Counting_Semaphore *)sem)->~Cyg_Counting_Semaphore();
+}
+
+externC cyg_bool_t cyg_semaphore_wait( cyg_sem_t *sem ) __THROW
+{
+ return ((Cyg_Counting_Semaphore *)sem)->wait();
+}
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+externC cyg_bool_t cyg_semaphore_timed_wait(
+ cyg_sem_t *sem,
+ cyg_tick_count_t abstime
+ ) __THROW
+{
+ return ((Cyg_Counting_Semaphore *)sem)->wait(abstime);
+}
+#endif
+
+
+externC int cyg_semaphore_trywait( cyg_sem_t *sem ) __THROW
+{
+ return ((Cyg_Counting_Semaphore *)sem)->trywait();
+}
+
+externC void cyg_semaphore_post( cyg_sem_t *sem ) __THROW
+{
+ ((Cyg_Counting_Semaphore *)sem)->post();
+}
+
+externC void cyg_semaphore_peek( cyg_sem_t *sem, cyg_count32 *val ) __THROW
+{
+ CYG_CHECK_DATA_PTR( val, "Bad val parameter" );
+
+ *val = ((Cyg_Counting_Semaphore *)sem)->peek();
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* Flags */
+
+void cyg_flag_init(
+ cyg_flag_t *flag /* Flag to init */
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_flag_t, Cyg_Flag );
+ CYG_ASSERT(
+ ( Cyg_Flag::AND == CYG_FLAG_WAITMODE_AND ) &&
+ ( Cyg_Flag::OR == CYG_FLAG_WAITMODE_OR ) &&
+ ( Cyg_Flag::CLR == CYG_FLAG_WAITMODE_CLR ),
+ "CYG_FLAG_WAITMODE_xxx definition != C++ Cyg_Flag::xxx" );
+
+ Cyg_Flag *t = new((void *)flag) Cyg_Flag();
+ t=t;
+}
+
+void cyg_flag_destroy( cyg_flag_t *flag ) __THROW
+{
+ ((Cyg_Flag *)flag)->~Cyg_Flag();
+}
+
+void cyg_flag_setbits( cyg_flag_t *flag, cyg_flag_value_t value) __THROW
+{
+ ((Cyg_Flag *)flag)->setbits( value );
+}
+
+void cyg_flag_maskbits( cyg_flag_t *flag, cyg_flag_value_t value) __THROW
+{
+ ((Cyg_Flag *)flag)->maskbits( value );
+}
+
+cyg_flag_value_t cyg_flag_wait( cyg_flag_t *flag,
+ cyg_flag_value_t pattern,
+ cyg_flag_mode_t mode ) __THROW
+{
+ if ( 0 == pattern || 0 != (mode & ~3) )
+ return 0;
+ return ((Cyg_Flag *)flag)->wait( pattern, mode );
+
+}
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+cyg_flag_value_t cyg_flag_timed_wait( cyg_flag_t *flag,
+ cyg_flag_value_t pattern,
+ cyg_flag_mode_t mode,
+ cyg_tick_count_t abstime ) __THROW
+{
+ if ( 0 == pattern || 0 != (mode & ~3) )
+ return 0;
+ return ((Cyg_Flag *)flag)->wait( pattern, mode, abstime );
+
+}
+#endif
+
+cyg_flag_value_t cyg_flag_poll( cyg_flag_t *flag,
+ cyg_flag_value_t pattern,
+ cyg_flag_mode_t mode ) __THROW
+{
+ if ( 0 == pattern || 0 != (mode & ~3) )
+ return 0;
+ return ((Cyg_Flag *)flag)->poll( pattern, mode );
+
+}
+
+cyg_flag_value_t cyg_flag_peek( cyg_flag_t *flag ) __THROW
+{
+ return ((Cyg_Flag *)flag)->peek();
+}
+
+cyg_bool_t cyg_flag_waiting( cyg_flag_t *flag ) __THROW
+{
+ return ((Cyg_Flag *)flag)->waiting();
+}
+
+/*---------------------------------------------------------------------------*/
+/* Mutex */
+
+externC void cyg_mutex_init(
+ cyg_mutex_t *mutex /* Mutex to init */
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_mutex_t, Cyg_Mutex );
+
+ Cyg_Mutex *m = new((void *)mutex) Cyg_Mutex;
+
+ m=m;
+}
+
+externC void cyg_mutex_destroy( cyg_mutex_t *mutex ) __THROW
+{
+ ((Cyg_Mutex *)mutex)->~Cyg_Mutex();
+}
+
+externC cyg_bool_t cyg_mutex_lock( cyg_mutex_t *mutex ) __THROW
+{
+ return ((Cyg_Mutex *)mutex)->lock();
+}
+
+externC cyg_bool_t cyg_mutex_trylock( cyg_mutex_t *mutex ) __THROW
+{
+ return ((Cyg_Mutex *)mutex)->trylock();
+}
+
+externC void cyg_mutex_unlock( cyg_mutex_t *mutex ) __THROW
+{
+ ((Cyg_Mutex *)mutex)->unlock();
+}
+
+externC void cyg_mutex_release( cyg_mutex_t *mutex ) __THROW
+{
+ ((Cyg_Mutex *)mutex)->release();
+}
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+externC void cyg_mutex_set_ceiling(
+ cyg_mutex_t *mutex,
+ cyg_priority_t priority ) __THROW
+{
+ ((Cyg_Mutex *)mutex)->set_ceiling(priority);
+}
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+externC void cyg_mutex_set_protocol(
+ cyg_mutex_t *mutex,
+ enum cyg_mutex_protocol protocol ) __THROW
+{
+ ((Cyg_Mutex *)mutex)->set_protocol((Cyg_Mutex::cyg_protcol)protocol);
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Condition Variables */
+
+externC void cyg_cond_init(
+ cyg_cond_t *cond, /* condition variable to init */
+ cyg_mutex_t *mutex /* associated mutex */
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_cond_t, Cyg_Condition_Variable );
+
+ Cyg_Condition_Variable *t = new((void *)cond) Cyg_Condition_Variable(
+ *(Cyg_Mutex *)mutex);
+ t=t;
+}
+
+externC void cyg_cond_destroy( cyg_cond_t *cond ) __THROW
+{
+ ((Cyg_Condition_Variable *)cond)->~Cyg_Condition_Variable();
+}
+
+externC cyg_bool_t cyg_cond_wait( cyg_cond_t *cond ) __THROW
+{
+ return ((Cyg_Condition_Variable *)cond)->wait();
+}
+
+externC void cyg_cond_signal( cyg_cond_t *cond ) __THROW
+{
+ ((Cyg_Condition_Variable *)cond)->signal();
+}
+
+externC void cyg_cond_broadcast( cyg_cond_t *cond ) __THROW
+{
+ ((Cyg_Condition_Variable *)cond)->broadcast();
+}
+
+#ifdef CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT
+externC cyg_bool_t cyg_cond_timed_wait(
+ cyg_cond_t *cond,
+ cyg_tick_count_t abstime
+ ) __THROW
+{
+ return ((Cyg_Condition_Variable *)cond)->wait(abstime);
+}
+
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Spinlocks */
+
+externC void cyg_spinlock_init(
+ cyg_spinlock_t *lock, /* spinlock to initialize */
+ cyg_bool_t locked /* init locked or unlocked */
+) __THROW
+{
+ CYG_ASSERT_SIZES( cyg_spinlock_t, Cyg_SpinLock );
+
+ // Create the spinlock in cleared state
+ Cyg_SpinLock *t = new((void *)lock) Cyg_SpinLock();
+
+ // If the lock is to start locked, then lock it now.
+ if( locked )
+ t->spin();
+}
+
+externC void cyg_spinlock_destroy( cyg_spinlock_t *lock ) __THROW
+{
+ ((Cyg_SpinLock *)lock)->~Cyg_SpinLock();
+}
+
+externC void cyg_spinlock_spin( cyg_spinlock_t *lock ) __THROW
+{
+ ((Cyg_SpinLock *)lock)->spin();
+}
+
+externC void cyg_spinlock_clear( cyg_spinlock_t *lock ) __THROW
+{
+ ((Cyg_SpinLock *)lock)->clear();
+}
+
+externC cyg_bool_t cyg_spinlock_try( cyg_spinlock_t *lock ) __THROW
+{
+ return ((Cyg_SpinLock *)lock)->trylock();
+}
+
+externC cyg_bool_t cyg_spinlock_test( cyg_spinlock_t *lock ) __THROW
+{
+ return ((Cyg_SpinLock *)lock)->test();
+}
+
+externC void cyg_spinlock_spin_intsave( cyg_spinlock_t *lock,
+ cyg_addrword_t *istate ) __THROW
+{
+ ((Cyg_SpinLock *)lock)->spin_intsave((CYG_INTERRUPT_STATE *)istate);
+}
+
+externC void cyg_spinlock_clear_intsave( cyg_spinlock_t *lock,
+ cyg_addrword_t istate ) __THROW
+{
+ ((Cyg_SpinLock *)lock)->clear_intsave((CYG_INTERRUPT_STATE)istate);
+}
+
+
+// -------------------------------------------------------------------------
+// Check structure sizes.
+// This class and constructor get run automatically in debug versions
+// of the kernel and check that the structures configured in the C
+// code are the same size as the C++ classes they should match.
+
+#ifdef CYGPKG_INFRA_DEBUG
+
+class Cyg_Check_Structure_Sizes
+{
+ int dummy;
+public:
+ Cyg_Check_Structure_Sizes( int x ) __THROW;
+
+};
+
+#define CYG_CHECK_SIZES(cstruct, cxxstruct) \
+if( sizeof(cstruct) != sizeof(cxxstruct) ) \
+{ \
+ char *fmt = "Size of C struct " #cstruct \
+ " != size of C++ struct " #cxxstruct ; \
+ CYG_TRACE2(1, fmt, sizeof(cstruct) , sizeof(cxxstruct) ); \
+ fail = true; \
+ fmt = fmt; \
+}
+
+Cyg_Check_Structure_Sizes::Cyg_Check_Structure_Sizes(int x) __THROW
+{
+ cyg_bool fail = false;
+
+ dummy = x+1;
+
+ CYG_CHECK_SIZES( cyg_thread, Cyg_Thread );
+ CYG_CHECK_SIZES( cyg_interrupt, Cyg_Interrupt );
+ CYG_CHECK_SIZES( cyg_counter, Cyg_Counter );
+ CYG_CHECK_SIZES( cyg_clock, Cyg_Clock );
+ CYG_CHECK_SIZES( cyg_alarm, Cyg_Alarm );
+ CYG_CHECK_SIZES( cyg_mbox, Cyg_Mbox );
+ CYG_CHECK_SIZES( cyg_sem_t, Cyg_Counting_Semaphore );
+ CYG_CHECK_SIZES( cyg_flag_t, Cyg_Flag );
+ CYG_CHECK_SIZES( cyg_mutex_t, Cyg_Mutex );
+ CYG_CHECK_SIZES( cyg_cond_t, Cyg_Condition_Variable );
+ CYG_CHECK_SIZES( cyg_spinlock_t, Cyg_SpinLock );
+
+ CYG_ASSERT( !fail, "Size checks failed");
+}
+
+static Cyg_Check_Structure_Sizes cyg_kapi_check_structure_sizes(1);
+
+#endif
+
+
+// -------------------------------------------------------------------------
+
+#endif
+// EOF common/kapi.cxx
diff --git a/ecos/packages/kernel/current/src/common/thread.cxx b/ecos/packages/kernel/current/src/common/thread.cxx
new file mode 100644
index 0000000000..7888c66307
--- /dev/null
+++ b/ecos/packages/kernel/current/src/common/thread.cxx
@@ -0,0 +1,1299 @@
+//==========================================================================
+//
+// common/thread.cxx
+//
+// Thread class implementations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-15
+// Purpose: Thread class implementation
+// Description: This file contains the definitions of the thread class
+// member functions that are common to all thread implementations.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h> // kernel configuration file
+
+#include <cyg/hal/hal_arch.h> // HAL_REORDER_BARRIER &
+ // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/thread.hxx> // our header
+
+#include <cyg/kernel/intr.hxx> // Interrupt support
+
+#include <cyg/kernel/thread.inl> // thread inlines
+#include <cyg/kernel/sched.inl> // scheduler inlines
+#include <cyg/kernel/clock.inl> // clock inlines
+
+#ifdef CYGDBG_KERNEL_THREADS_STACK_MEASUREMENT_VERBOSE_EXIT
+#include <cyg/infra/diag.h>
+#endif
+
+// =========================================================================
+// Cyg_HardwareThread members
+
+// -------------------------------------------------------------------------
+// Thread entry point.
+// This is inserted as the PC value in all initial thread contexts.
+// It does some housekeeping and then calls the real entry point.
+
+void
+Cyg_HardwareThread::thread_entry( Cyg_Thread *thread )
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_Scheduler::scheduler.clear_need_reschedule(); // finished rescheduling
+ Cyg_Scheduler::scheduler.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.
+ Cyg_Scheduler::reset_timeslice_count();
+#endif
+
+ // Zero the lock
+ HAL_REORDER_BARRIER (); // Prevent the compiler from moving
+ Cyg_Scheduler::zero_sched_lock(); // the assignment into the code above.
+ HAL_REORDER_BARRIER();
+
+ // Call entry point in a loop.
+
+ for(;;)
+ {
+ thread->entry_point(thread->entry_data);
+ thread->exit();
+ }
+}
+
+// =========================================================================
+// Cyg_Thread members
+
+// -------------------------------------------------------------------------
+// Statics and thread list functions
+
+#ifdef CYGVAR_KERNEL_THREADS_LIST
+
+// List of all extant threads
+Cyg_Thread *Cyg_Thread::thread_list = 0;
+
+inline void
+Cyg_Thread::add_to_list( void )
+{
+ // Add thread to housekeeping list
+ Cyg_Scheduler::lock();
+
+ if( thread_list == 0 )
+ list_next = this;
+ else {
+ Cyg_Thread *prev = thread_list;
+ do {
+ if ( this == prev )
+ break; // found it already!
+ prev = prev->list_next;
+ } while ( prev != thread_list );
+ if ( this != prev ) {
+ // insert it in the list:
+ list_next = thread_list->list_next;
+ thread_list->list_next = this;
+ }
+ }
+ thread_list = this;
+
+ Cyg_Scheduler::unlock();
+}
+
+inline void
+Cyg_Thread::remove_from_list( void )
+{
+ // remove thread from housekeeping list
+ Cyg_Scheduler::lock();
+
+ Cyg_Thread *prev = thread_list;
+
+ do {
+ if( prev->list_next == this ) {
+ prev->list_next = list_next;
+ if( thread_list == this )
+ thread_list = list_next;
+ break;
+ }
+ prev = prev->list_next;
+ } while ( prev != thread_list );
+
+ Cyg_Scheduler::unlock();
+}
+
+#endif
+
+static cyg_uint16 next_unique_id = 1;
+
+// -------------------------------------------------------------------------
+// Magic new operator to allow the thread constructor to be
+// recalled.
+
+inline void *
+operator new(size_t size, Cyg_Thread *ptr)
+{ return (void *)ptr; };
+
+// Constructor
+
+Cyg_Thread::Cyg_Thread(
+ CYG_ADDRWORD sched_info, // Scheduling parameter(s)
+ cyg_thread_entry *entry, // entry point function
+ CYG_ADDRWORD entry_data, // entry data
+ char *name_arg, // thread name cookie
+ CYG_ADDRESS stack_base, // stack base, NULL = allocate
+ cyg_ucount32 stack_size // stack size, 0 = use default
+ )
+: Cyg_HardwareThread(entry, entry_data, stack_size, stack_base),
+ Cyg_SchedThread(this, sched_info)
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ ,timer(this)
+#endif
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_INSTRUMENT_THREAD(CREATE,this,0);
+
+ // Start the thread in suspended state.
+ state = SUSPENDED;
+ suspend_count = 1;
+ wakeup_count = 0;
+
+ // Initialize sleep_reason which is used by kill, release
+ sleep_reason = NONE;
+ wake_reason = NONE;
+
+ // Assign a 16 bit id to the thread.
+ unique_id = next_unique_id++;
+
+#ifdef CYGVAR_KERNEL_THREADS_DATA
+ // Zero all per-thread data entries.
+ for( int i = 0; i < CYGNUM_KERNEL_THREADS_DATA_MAX; i++ )
+ thread_data[i] = 0;
+#endif
+#ifdef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+ for (int j=0; j<CYGNUM_KERNEL_THREADS_DESTRUCTORS; j++) {
+ destructors[j].fn = NULL;
+ }
+#endif
+#ifdef CYGVAR_KERNEL_THREADS_NAME
+ name = name_arg;
+#endif
+#ifdef CYGVAR_KERNEL_THREADS_LIST
+ // Add thread to housekeeping list
+ add_to_list();
+#endif
+
+ Cyg_Scheduler::scheduler.register_thread(this);
+
+ init_context(this);
+
+ CYG_REPORT_RETURN();
+}
+
+
+// -------------------------------------------------------------------------
+// Re-initialize this thread.
+// We do this by re-invoking the constructor with the original
+// arguments, which are still available in the object.
+
+void
+Cyg_Thread::reinitialize()
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERTCLASS( this, "Bad thread");
+ CYG_ASSERT( this != Cyg_Scheduler::get_current_thread(),
+ "Attempt to reinitialize current thread");
+ CYG_ASSERT( get_current_queue() == NULL , "Thread is still on a queue");
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ // Clear the timeout. It is irrelevant whether there was
+ // actually a timeout pending.
+ timer.disable();
+#endif
+
+ // Ensure the scheduler has let go of us.
+ Cyg_Scheduler::scheduler.deregister_thread(this);
+
+ cyg_priority pri = get_priority();
+#ifdef CYGVAR_KERNEL_THREADS_NAME
+ char * name_arg = name;
+#else
+ char * name_arg = NULL;
+#endif
+
+ new(this) Cyg_Thread( pri,
+ entry_point, entry_data,
+ name_arg,
+ get_stack_base(), get_stack_size() );
+ // the constructor re-registers the thread with the scheduler.
+
+ CYG_ASSERTCLASS( this, "Thread corrupted by reinitialize");
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Destructor.
+
+Cyg_Thread::~Cyg_Thread()
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_Scheduler::scheduler.deregister_thread(this);
+
+#ifdef CYGVAR_KERNEL_THREADS_LIST
+ // Remove thread from housekeeping list.
+ remove_from_list();
+#endif
+
+ // Zero the unique_id to render this thread inconsistent.
+ unique_id = 0;
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Thread consistency checker.
+
+#ifdef CYGDBG_USE_ASSERTS
+
+cyg_bool
+Cyg_Thread::check_this( cyg_assert_class_zeal zeal) const
+{
+// CYG_REPORT_FUNCTION();
+
+ // check that we have a non-NULL pointer first
+ if( this == NULL ) return false;
+
+ switch( zeal )
+ {
+ case cyg_system_test:
+ case cyg_extreme:
+ case cyg_thorough:
+ if( (state & SUSPENDED) && (suspend_count == 0) ) return false;
+ case cyg_quick:
+ // Check that the stackpointer is within its limits.
+ // Note: This does not check the current stackpointer value
+ // of the executing thread.
+ if( (stack_ptr > (stack_base + stack_size)) ||
+ (stack_ptr < stack_base) ) return false;
+#ifdef CYGFUN_KERNEL_THREADS_STACK_LIMIT
+ if( stack_ptr < stack_limit ) return false;
+#endif
+ case cyg_trivial:
+ case cyg_none:
+ default:
+ break;
+ };
+
+ return true;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Put the thread to sleep.
+// This can only be called by the current thread on itself, hence
+// it is a static function.
+
+void
+Cyg_Thread::sleep()
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_Thread *current = Cyg_Scheduler::get_current_thread();
+
+ CYG_ASSERTCLASS( current, "Bad current thread" );
+
+ CYG_INSTRUMENT_THREAD(SLEEP,current,0);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ // If running, remove from run qs
+ if ( current->state == RUNNING )
+ Cyg_Scheduler::scheduler.rem_thread(current);
+
+ // Set the state
+ current->state |= SLEEPING;
+
+ // Unlock the scheduler and switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Awaken the thread from sleep.
+
+void
+Cyg_Thread::wake()
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_INSTRUMENT_THREAD(WAKE,this,Cyg_Scheduler::current_thread);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ if( 0 != (state & SLEEPSET) )
+ {
+ // Set the state
+ state &= ~SLEEPSET;
+
+ // remove from any queue we were on
+ remove();
+
+ // If the thread is now runnable, return it to run queue
+ if( state == RUNNING )
+ Cyg_Scheduler::scheduler.add_thread(this);
+
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Put the thread to sleep, with wakeup count.
+// This can only be called by the current thread on itself, hence
+// it is a static function.
+
+void
+Cyg_Thread::counted_sleep()
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_Thread *current = Cyg_Scheduler::get_current_thread();
+
+ CYG_ASSERTCLASS( current, "Bad current thread" );
+
+ CYG_INSTRUMENT_THREAD(SLEEP,current,0);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ if ( 0 == current->wakeup_count ) {
+ set_sleep_reason( Cyg_Thread::WAIT );
+ current->sleep(); // prepare to sleep
+ current->state |= COUNTSLEEP; // Set the state
+ }
+ else
+ // there is a queued wakeup, do not sleep
+ current->wakeup_count--;
+
+ // Unlock the scheduler and switch threads
+ Cyg_Scheduler::unlock();
+
+ // and deal with anything we must do when we return
+ switch( current->wake_reason ) {
+ case DESTRUCT:
+ case EXIT:
+ current->exit();
+ break;
+
+ default:
+ break;
+ }
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Put the thread to sleep for a delay, with wakeup count.
+// This can only be called by the current thread on itself, hence
+// it is a static function.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+void
+Cyg_Thread::counted_sleep( cyg_tick_count delay )
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_Thread *current = Cyg_Scheduler::get_current_thread();
+
+ CYG_ASSERTCLASS( current, "Bad current thread" );
+
+ CYG_INSTRUMENT_THREAD(SLEEP,current,0);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ if ( 0 == current->wakeup_count ) {
+
+ // Set the timer (once outside any waiting loop.)
+ set_timer( Cyg_Clock::real_time_clock->current_value()+delay,
+ Cyg_Thread::TIMEOUT );
+
+ // If the timeout is in the past, the wake reason will have been
+ // set to something other than NONE already.
+
+ if( current->get_wake_reason() == Cyg_Thread::NONE )
+ {
+ set_sleep_reason( Cyg_Thread::TIMEOUT );
+ current->sleep(); // prepare to sleep
+ current->state |= COUNTSLEEP; // Set the state
+
+ Cyg_Scheduler::reschedule();
+
+ // clear the timer; if it actually fired, no worries.
+ clear_timer();
+ }
+ }
+ else
+ // there is a queued wakeup, do not sleep
+ current->wakeup_count--;
+
+ // Unlock the scheduler and switch threads
+ Cyg_Scheduler::unlock();
+
+ // and deal with anything we must do when we return
+ switch( current->wake_reason ) {
+ case DESTRUCT:
+ case EXIT:
+ current->exit();
+ break;
+
+ default:
+ break;
+ }
+
+ CYG_REPORT_RETURN();
+}
+#endif
+
+// -------------------------------------------------------------------------
+// Awaken the thread from sleep.
+
+void
+Cyg_Thread::counted_wake()
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_INSTRUMENT_THREAD(WAKE,this,Cyg_Scheduler::current_thread);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ if ( 0 == (state & COUNTSLEEP) ) // already awake, or waiting:
+ wakeup_count++; // not in a counted sleep anyway.
+ else {
+ sleep_reason = NONE;
+ wake_reason = DONE;
+ wake(); // and awaken the thread
+ }
+
+#ifdef CYGNUM_KERNEL_MAX_COUNTED_WAKE_COUNT_ASSERT
+ CYG_ASSERT( CYGNUM_KERNEL_MAX_COUNTED_WAKE_COUNT_ASSERT > wakeup_count,
+ "wakeup_count overflow" );
+#endif
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Cancel wakeups for this thread and return how many were pending
+cyg_uint32
+Cyg_Thread::cancel_counted_wake()
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_INSTRUMENT_THREAD(WAKE,this,Cyg_Scheduler::current_thread);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ cyg_uint32 result = wakeup_count;
+ wakeup_count = 0;
+
+ // Unlock the scheduler
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Suspend thread. Increment suspend count and deschedule thread
+// if still running.
+
+void
+Cyg_Thread::suspend()
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_INSTRUMENT_THREAD(SUSPEND,this,Cyg_Scheduler::current_thread);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ suspend_count++;
+
+#ifdef CYGNUM_KERNEL_MAX_SUSPEND_COUNT_ASSERT
+ CYG_ASSERT( CYGNUM_KERNEL_MAX_SUSPEND_COUNT_ASSERT > suspend_count,
+ "suspend_count overflow" );
+#endif
+
+ // If running, remove from run qs
+ if( state == RUNNING )
+ Cyg_Scheduler::scheduler.rem_thread(this);
+
+ // Set the state
+ state |= SUSPENDED;
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Resume thread. Decrement suspend count and reschedule if it
+// is zero.
+
+void
+Cyg_Thread::resume()
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_INSTRUMENT_THREAD(RESUME,this,Cyg_Scheduler::current_thread);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ // If we are about to zero the count, clear the state bit and
+ // reschedule the thread if possible.
+
+ if( suspend_count == 1 )
+ {
+ suspend_count = 0;
+
+ CYG_ASSERT( (state & SUSPENDED) != 0, "SUSPENDED bit not set" );
+
+ // Set the state
+ state &= ~SUSPENDED;
+
+ // Return thread to scheduler if runnable
+ if( state == RUNNING )
+ Cyg_Scheduler::scheduler.add_thread(this);
+ }
+ else
+ if( suspend_count > 0 )
+ suspend_count--;
+ // else ignore attempt to resume
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Forced Resume thread. Zero suspend count and reschedule...
+
+void
+Cyg_Thread::force_resume()
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_INSTRUMENT_THREAD(RESUME,this,Cyg_Scheduler::current_thread);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ // If we are about to zero the count, clear the state bit and
+ // reschedule the thread if possible.
+
+ if ( 0 < suspend_count ) {
+ suspend_count = 0;
+
+ CYG_ASSERT( (state & SUSPENDED) != 0, "SUSPENDED bit not set" );
+
+ // Set the state
+ state &= ~SUSPENDED;
+
+ // Return thread to scheduler if runnable
+ if( state == RUNNING )
+ Cyg_Scheduler::scheduler.add_thread(this);
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Force thread to wake up from a sleep with a wake_reason of
+// BREAK. It is the responsibility of the woken thread to detect
+// the release() and do the right thing.
+
+void
+Cyg_Thread::release()
+{
+ CYG_REPORT_FUNCTION();
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ // If the thread is in any of the sleep states, set the
+ // wake reason and wake it up.
+
+ switch( sleep_reason )
+ {
+
+ case NONE:
+ // The thread is not sleeping for any reason, do nothing.
+ // drop through...
+
+ case DESTRUCT:
+ case BREAK:
+ case EXIT:
+ case DONE:
+ // Do nothing in any of these cases. They are here to
+ // keep the compiler happy.
+
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+ return;
+
+ case WAIT:
+ // The thread was waiting for some sync object to do
+ // something.
+ // drop through...
+
+ case TIMEOUT:
+ // The thread was waiting on a sync object with a timeout.
+ // drop through...
+
+ case DELAY:
+ // The thread was simply delaying, unless it has been
+ // woken up for some other reason, wake it now.
+ sleep_reason = NONE;
+ wake_reason = BREAK;
+ break;
+ }
+
+ wake();
+
+ // Allow preemption
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Exit thread. This puts the thread into EXITED state.
+
+#ifdef CYGPKG_KERNEL_THREADS_DESTRUCTORS
+#ifndef CYGSEM_KERNEL_THREADS_DESTRUCTORS_PER_THREAD
+Cyg_Thread::Cyg_Destructor_Entry
+Cyg_Thread::destructors[ CYGNUM_KERNEL_THREADS_DESTRUCTORS ];
+#endif
+#endif
+
+void
+Cyg_Thread::exit()
+{
+ CYG_REPORT_FUNCTION();
+
+ // The thread should never return from this function.
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+#ifdef CYGPKG_KERNEL_THREADS_DESTRUCTORS
+ cyg_ucount16 i;
+ for (i=0; i<CYGNUM_KERNEL_THREADS_DESTRUCTORS; i++) {
+ if (NULL != self->destructors[i].fn) {
+ destructor_fn fn = self->destructors[i].fn;
+ CYG_ADDRWORD data = self->destructors[i].data;
+ fn(data);
+ }
+ }
+#endif
+#ifdef CYGDBG_KERNEL_THREADS_STACK_MEASUREMENT_VERBOSE_EXIT
+ diag_printf( "Stack usage for thread %08x: %d\n", self,
+ self->measure_stack_usage() );
+#endif
+
+ Cyg_Scheduler::lock();
+
+ // clear the timer; if there was none, no worries.
+ clear_timer();
+
+ // It is possible that we have already been killed by another
+ // thread, in which case we do not want to try and take ourself
+ // out of the scheduler again.
+ if( self->state != EXITED )
+ {
+ self->state = EXITED;
+
+ Cyg_Scheduler::scheduler.rem_thread(self);
+ }
+
+ Cyg_Scheduler::reschedule();
+}
+
+// -------------------------------------------------------------------------
+// Kill thread. Force the thread into EXITED state externally, or
+// make it wake up and call exit().
+
+void
+Cyg_Thread::kill()
+{
+ CYG_REPORT_FUNCTION();
+ // If this is called by the current thread on itself,
+ // just call exit(), which is what he should have done
+ // in the first place.
+ if( this == Cyg_Scheduler::get_current_thread() )
+ exit();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ // We are killing someone else. Find out what state he is
+ // in and force him to wakeup and call exit().
+
+ force_resume(); // this is necessary for when
+ // he is asleep AND suspended.
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ timer.disable(); // and make sure the timer
+ // does not persist.
+#endif
+
+ if ( EXIT != wake_reason ) switch( sleep_reason ) {
+ // Only do any of this if the thread is not in pending death already:
+
+ case NONE:
+ // The thread is not sleeping for any reason, it must be
+ // on a run queue.
+ // We can safely deschedule and set its state.
+ if( state == RUNNING ) Cyg_Scheduler::scheduler.rem_thread(this);
+ state = EXITED;
+ break;
+
+ case DESTRUCT:
+ case BREAK:
+ case EXIT:
+ case DONE:
+ // Do nothing in any of these cases. They are here to
+ // keep the compiler happy.
+
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+ return;
+
+ case WAIT:
+ // The thread was waiting for some sync object to do
+ // something.
+ // drop through...
+
+ case TIMEOUT:
+ // The thread was waiting on a sync object with a timeout.
+ // drop through...
+
+ case DELAY:
+ // The thread was simply delaying, unless it has been
+ // woken up for some other reason, wake it now.
+ sleep_reason = NONE;
+ wake_reason = EXIT;
+ break;
+ }
+
+ wake();
+
+ // Allow preemption
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Set thread priority
+
+#ifdef CYGIMP_THREAD_PRIORITY
+
+void
+Cyg_Thread::set_priority( cyg_priority new_priority )
+{
+ CYG_REPORT_FUNCTION();
+
+// CYG_ASSERT( new_priority >= CYG_THREAD_MAX_PRIORITY, "Priority out of range");
+// CYG_ASSERT( new_priority <= CYG_THREAD_MIN_PRIORITY, "Priority out of range");
+
+ CYG_INSTRUMENT_THREAD(PRIORITY,this,new_priority);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ Cyg_ThreadQueue *queue = NULL;
+
+ // If running, remove from run qs
+ if( state == RUNNING )
+ Cyg_Scheduler::scheduler.rem_thread(this);
+ else if( state & SLEEPING )
+ {
+ // Remove thread from current queue.
+ queue = get_current_queue();
+ // if indeed we are on a queue
+ if ( NULL != queue ) {
+ CYG_CHECK_DATA_PTR(queue, "Bad queue pointer");
+ remove();
+ }
+ }
+
+ Cyg_Scheduler::scheduler.deregister_thread(this);
+
+#if CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES
+
+ // Check that there are no other threads at this priority.
+ // If so, leave is as it is.
+
+ CYG_ASSERT( Cyg_Scheduler::scheduler.unique(new_priority), "Priority not unique");
+
+ if( Cyg_Scheduler::scheduler.unique(new_priority) )
+ priority = new_priority;
+
+#else // !CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
+
+ // When we have priority inheritance, we must update the original
+ // priority and not the inherited one. If the new priority is
+ // better than the current inherited one, then use that
+ // immediately. We remain in inherited state to avoid problems
+ // with multiple mutex inheritances.
+
+ if( priority_inherited )
+ {
+ original_priority = new_priority;
+ if( priority > new_priority ) priority = new_priority;
+ }
+ else priority = new_priority;
+
+#else
+
+ priority = new_priority;
+
+#endif
+
+#endif // CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES
+
+ Cyg_Scheduler::scheduler.register_thread(this);
+
+ // Return thread to scheduler if runnable
+ if( state == RUNNING )
+ Cyg_Scheduler::scheduler.add_thread(this);
+ else if ( state & SLEEPING )
+ {
+ // return to current queue
+ // if indeed we are on a queue
+ if ( NULL != queue ) {
+ CYG_CHECK_DATA_PTR(queue, "Bad queue pointer");
+ queue->enqueue(this);
+ }
+ }
+
+ // If the current thread is being reprioritized, set the
+ // reschedule flag to ensure that it gets rescheduled if
+ // necessary. (Strictly we only need to do this if the new
+ // priority is less than that of some other runnable thread, in
+ // practice checking that is as expensive as what the scheduler
+ // will do anyway).
+ // If it is not the current thread then we need to see whether
+ // it is more worthy of execution than any current thread and
+ // rescheduled if necessary.
+
+ if( this == Cyg_Scheduler::get_current_thread() )
+ Cyg_Scheduler::set_need_reschedule();
+ else Cyg_Scheduler::set_need_reschedule(this);
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+}
+
+#endif
+
+
+// -------------------------------------------------------------------------
+// Thread delay function
+
+void
+Cyg_Thread::delay( cyg_tick_count delay)
+{
+ CYG_REPORT_FUNCTION();
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+ CYG_INSTRUMENT_THREAD(DELAY,this,delay);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ sleep();
+
+ set_timer( Cyg_Clock::real_time_clock->current_value()+delay, DELAY );
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ // Clear the timeout. It is irrelevant whether the alarm has
+ // actually gone off or not.
+ clear_timer();
+
+ // and deal with anything else we must do when we return
+ switch( wake_reason ) {
+ case DESTRUCT:
+ case EXIT:
+ exit();
+ break;
+
+ default:
+ break;
+ }
+#endif
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+//
+
+#ifdef CYGPKG_KERNEL_EXCEPTIONS
+
+void
+Cyg_Thread::deliver_exception(
+ cyg_code exception_number, // exception being raised
+ CYG_ADDRWORD exception_info // exception specific info
+ )
+{
+ if( this == Cyg_Scheduler::get_current_thread() )
+ {
+ // Delivering to current thread, probably as a result
+ // of a real hardware exception. Simply invoke the appropriate
+ // handler.
+
+ exception_control.deliver_exception( exception_number, exception_info );
+ }
+#ifdef CYGIMP_EXCEPTION_ASYNC
+ else
+ {
+ // Delivering to another thread, probably as a result of one thread
+ // invoking this function on another thread. Adjust the other thread's
+ // state to make it execute the exception routine when it next runs.
+
+ // At present there is an unresolved problem here. We do not know what
+ // state the destination thread is in. It may not be a suitable point at
+ // which to invoke an exception routine. In most cases the exception
+ // routine will be run in the scheduler thread switch code, where the world is
+ // in an inconsistent state. We really need to run the routine at the
+ // end of unlock_inner(). However this would add extra code to the scheduler,
+ // and require a way of storing pending exceptions. So for now this option is
+ // disabled and not yet implemented, it may never be.
+
+ }
+#endif
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Per-thread data support
+
+#ifdef CYGVAR_KERNEL_THREADS_DATA
+
+// Set the data map bits for each free slot in the data array.
+cyg_ucount32 Cyg_Thread::thread_data_map = (~CYGNUM_KERNEL_THREADS_DATA_ALL) &
+ (1+(((cyg_ucount32)(1<<(CYGNUM_KERNEL_THREADS_DATA_MAX-1))-1)<<1));
+// the second expression is equivalent to ((1<<CYGNUM_KERNEL_THREADS_DATA_MAX)-1);
+// but avoids overflow. The compiler will compile to a constant just fine.
+
+Cyg_Thread::cyg_data_index
+Cyg_Thread::new_data_index()
+{
+ Cyg_Scheduler::lock();
+
+ Cyg_Thread::cyg_data_index index;
+
+ if (0 == thread_data_map)
+ return -1;
+
+ // find ls set bit
+ HAL_LSBIT_INDEX( index, thread_data_map );
+
+ // clear the bit
+ thread_data_map &= ~(1<<index);
+
+ Cyg_Scheduler::unlock();
+
+ return index;
+}
+
+void Cyg_Thread::free_data_index( Cyg_Thread::cyg_data_index index )
+{
+ Cyg_Scheduler::lock();
+
+ thread_data_map |= (1<<index);
+
+ Cyg_Scheduler::unlock();
+}
+
+
+#endif
+
+// -------------------------------------------------------------------------
+// Allocate some memory at the lower end of the stack
+// by moving the stack limit pointer.
+
+#if defined(CYGFUN_KERNEL_THREADS_STACK_LIMIT) && \
+ defined(CYGFUN_KERNEL_THREADS_STACK_CHECKING)
+// if not doing stack checking, implementation can be found in thread.inl
+// This implementation puts the magic buffer area (to watch for overruns
+// *above* the stack limit, i.e. there is no official demarcation between
+// the stack and the buffer. But that's okay if you think about it... having
+// a demarcation would not accomplish anything more.
+void *Cyg_HardwareThread::increment_stack_limit( cyg_ucount32 size )
+{
+ void *ret = (void *)stack_limit;
+
+ // First lock the scheduler because we're going to be tinkering with
+ // the check data
+ Cyg_Scheduler::lock();
+
+ // if we've inc'd the limit before, it will be off by the check data
+ // size, so lets correct it
+ if (stack_limit != stack_base)
+ stack_limit -= CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE;
+ stack_limit += size;
+
+ // determine base of check data by rounding up to nearest word aligned
+ // address if not already aligned
+ cyg_uint32 *p = (cyg_uint32 *)((stack_limit + 3) & ~3);
+ // i.e. + sizeof(cyg_uint32)-1) & ~(sizeof(cyg_uint32)-1);
+ cyg_ucount32 i;
+ cyg_uint32 sig = (cyg_uint32)this;
+
+ for ( i = 0;
+ i < CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE/sizeof(cyg_uint32);
+ i++ ) {
+ p[i] = (sig ^ (i * 0x01010101));
+ }
+
+ // increment limit by the check size. Note this will not necessarily
+ // reach the end of the check data. But that doesn't really matter.
+ // Doing this allows better checking of the saved stack pointer in
+ // Cyg_Thread::check_this()
+ stack_limit += CYGNUM_KERNEL_THREADS_STACK_CHECK_DATA_SIZE;
+
+ Cyg_Scheduler::unlock();
+
+ return ret;
+}
+#endif
+
+// =========================================================================
+// Cyg_ThreadTimer member functions
+
+// -------------------------------------------------------------------------
+// Timer alarm function. Inspect the sleep_reason and if necessary wake
+// up the thread with an appropriate wake_reason.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+void
+Cyg_ThreadTimer::alarm(
+ Cyg_Alarm *alarm,
+ CYG_ADDRWORD data
+)
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_ThreadTimer *self = (Cyg_ThreadTimer *)data;
+ Cyg_Thread *thread = self->thread;
+
+ CYG_INSTRUMENT_THREAD(ALARM, 0, 0);
+
+ Cyg_Scheduler::lock();
+
+ Cyg_Thread::cyg_reason sleep_reason = thread->get_sleep_reason();
+
+ switch( sleep_reason ) {
+
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ case Cyg_Thread::EXIT:
+ case Cyg_Thread::NONE:
+ case Cyg_Thread::WAIT:
+ case Cyg_Thread::DONE:
+ // Do nothing in any of these cases. Most are here to
+ // keep the compiler happy.
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+ return;
+
+ case Cyg_Thread::DELAY:
+ // The thread was simply delaying, unless it has been
+ // woken up for some other reason, wake it now.
+ thread->set_wake_reason(Cyg_Thread::DONE);
+ break;
+
+ case Cyg_Thread::TIMEOUT:
+ // The thread has timed out, set the wake reason to
+ // TIMEOUT and restart.
+ thread->set_wake_reason(Cyg_Thread::TIMEOUT);
+ break;
+ }
+
+ thread->wake();
+
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+}
+
+#endif
+
+// =========================================================================
+// The Idle thread
+// The idle thread is implemented as a single instance of the
+// Cyg_IdleThread class. This is so that it can be initialized before
+// main in a static constructor.
+
+// -------------------------------------------------------------------------
+// Data definitions
+
+// stack
+#ifdef CYGNUM_HAL_STACK_SIZE_MINIMUM
+# ifdef CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE
+# if CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE < CYGNUM_HAL_STACK_SIZE_MINIMUM
+
+// then override the configured stack size
+# undef CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE
+# define CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM
+
+# endif // CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE < CYGNUM_HAL_STACK_SIZE_MINIMUM
+# endif // CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE
+#endif // CYGNUM_HAL_STACK_SIZE_MINIMUM
+
+static char idle_thread_stack[CYGNUM_KERNEL_CPU_MAX][CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE];
+
+// Loop counter for debugging/housekeeping
+cyg_uint32 idle_thread_loops[CYGNUM_KERNEL_CPU_MAX];
+
+// -------------------------------------------------------------------------
+// Idle thread code.
+
+void
+idle_thread_main( CYG_ADDRESS data )
+{
+ CYG_REPORT_FUNCTION();
+
+ for(;;)
+ {
+ idle_thread_loops[CYG_KERNEL_CPU_THIS()]++;
+
+ HAL_IDLE_THREAD_ACTION(idle_thread_loops[CYG_KERNEL_CPU_THIS()]);
+
+#if 0
+ // For testing, it is useful to be able to fake
+ // clock interrupts in the idle thread.
+
+ Cyg_Clock::real_time_clock->tick();
+#endif
+#ifdef CYGIMP_IDLE_THREAD_YIELD
+ // In single priority and non-preemptive systems,
+ // the idle thread should yield repeatedly to
+ // other threads.
+ Cyg_Thread::yield();
+#endif
+ }
+}
+
+// -------------------------------------------------------------------------
+// Idle thread class
+
+class Cyg_IdleThread : public Cyg_Thread
+{
+public:
+ Cyg_IdleThread();
+
+};
+
+// -------------------------------------------------------------------------
+// Instantiate the idle thread
+
+Cyg_IdleThread idle_thread[CYGNUM_KERNEL_CPU_MAX] CYG_INIT_PRIORITY( IDLE_THREAD );
+
+// -------------------------------------------------------------------------
+// Idle threads constructor
+
+Cyg_IdleThread::Cyg_IdleThread()
+ : Cyg_Thread( CYG_THREAD_MIN_PRIORITY,
+ idle_thread_main,
+ 0,
+ "Idle Thread",
+ (CYG_ADDRESS)idle_thread_stack[this-&idle_thread[0]],
+ CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE)
+{
+ CYG_REPORT_FUNCTION();
+
+ // Call into scheduler to set up this thread as the default
+ // current thread for its CPU.
+
+ Cyg_Scheduler::scheduler.set_idle_thread( this, this-&idle_thread[0] );
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// EOF common/thread.cxx
diff --git a/ecos/packages/kernel/current/src/common/timer.cxx b/ecos/packages/kernel/current/src/common/timer.cxx
new file mode 100644
index 0000000000..07caf3fc5f
--- /dev/null
+++ b/ecos/packages/kernel/current/src/common/timer.cxx
@@ -0,0 +1,129 @@
+//==========================================================================
+//
+// common/timer.cxx
+//
+// Timer class implementations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-06-11
+// Purpose: Clock class implementation
+// Description: This file implements the Timer class which is derived from
+// the Alarm class to support uITRON type functionality
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <cyg/kernel/clock.hxx>
+#include <cyg/kernel/timer.hxx>
+
+#include <cyg/kernel/clock.inl> // Clock inlines
+
+// -------------------------------------------------------------------------
+
+Cyg_Timer::Cyg_Timer()
+{
+}
+
+Cyg_Timer::~Cyg_Timer()
+{
+ CYG_REPORT_FUNCTION();
+
+ disable();
+ counter = NULL;
+}
+
+// -------------------------------------------------------------------------
+
+void
+Cyg_Timer::initialize(
+ Cyg_Counter *c,
+ cyg_alarm_fn a,
+ CYG_ADDRWORD d,
+ cyg_tick_count t, // absolute time
+ cyg_tick_count i, // 0 => one shot, else repeating
+ cyg_uint32 action // (DISABLE | ENABLE)
+ )
+{
+ CYG_REPORT_FUNCTION();
+
+ counter = c;
+ alarm = a;
+ data = d;
+ trigger = t;
+ interval = i;
+ enabled = false;
+
+ CYG_ASSERT(0 == (action & ~ENABLE), "unknown action");
+
+ if(action & ENABLE)
+ enable();
+}
+
+void
+Cyg_Timer::activate(cyg_uint32 action) // (DISABLE | ENABLE) [|RESET]
+{
+ // we must also disable the alarm when resetting it so as to remove it
+ // from its queue, so that the enable afterwards places it on the right
+ // queue instead of assuming that, being enabled, it's already there.
+ // (if not enabling, the behaviour is unchanged and correct)
+ if(!(action & ENABLE) || (action & RESET) )
+ disable(); // otherwise, the enable below does nothing...
+
+ if((action & RESET))
+ {
+ cyg_tick_count t;
+ t = counter->current_value();
+ trigger = t + interval;
+ }
+
+ if((action & ENABLE)) {
+ enable(); // ...when it should put the timer on a new queue.
+ }
+}
+
+// -------------------------------------------------------------------------
+// EOF common/timer.cxx
diff --git a/ecos/packages/kernel/current/src/debug/dbg-thread-demux.c b/ecos/packages/kernel/current/src/debug/dbg-thread-demux.c
new file mode 100644
index 0000000000..285dae2c32
--- /dev/null
+++ b/ecos/packages/kernel/current/src/debug/dbg-thread-demux.c
@@ -0,0 +1,181 @@
+/*==========================================================================
+//
+// dbg-thread-demux.c
+//
+// GDB Stub ROM system calls
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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:
+// Date: 1998-09-03
+// Purpose: GDB Stub ROM system calls
+// Description:
+//
+//####DESCRIPTIONEND####
+//
+//========================================================================*/
+
+#include <cyg/hal/hal_arch.h>
+
+/* This file implements system calls out from the ROM debug stub into
+ the operating environment.
+ We assume they exist in the same address space.
+ This file should be linked into your operating environment, your O.S.
+ or whatever is managing multiple saved process contexts.
+ Your O.S. needs to implement and provide
+ dbg_thread_capabilities
+ dbg_currthread
+ dbg_threadlist
+ dbg_threadinfo
+ dbg_getthreadreg
+ dbg_setthreadreg
+
+ The debug stub will call this function by calling it indirectly
+ vis a pre-assigned location possably somthing like a virtual vector table.
+ Where this is exactly is platform specific.
+
+ The O.S. should call patch_dbg_syscalls() and pass the address of the
+ location to be patched with the dbg_thread_syscall_rmt function.
+ Nothing really calls this by name.
+
+ This scheme would also work if we wanted to use a real trapped system call.
+ */
+
+// -------------------------------------------------------------------------
+
+#include <pkgconf/system.h> // for CYGPKG... and STARTUP
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/infra/cyg_type.h>
+
+#include "cyg/hal/dbg-threads-api.h"
+#include "cyg/hal/dbg-thread-syscall.h"
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+static int dbg_thread_syscall_rmt(
+ enum dbg_syscall_ids id,
+ union dbg_thread_syscall_parms * p
+ )
+{
+ int ret;
+ CYGARC_HAL_SAVE_GP();
+ switch (id)
+ {
+ case dbg_null_func :
+ ret = 1 ; /* test the syscall apparatus */
+ break;
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+ case dbg_capabilities_func :
+ ret = dbg_thread_capabilities(p->cap_parms.abilities) ;
+ break ;
+ case dbg_currthread_func :
+ ret = dbg_currthread(p->currthread_parms.ref) ;
+ break ;
+ case dbg_threadlist_func :
+ ret = dbg_threadlist(p->threadlist_parms.startflag,
+ p->threadlist_parms.lastid,
+ p->threadlist_parms.nextthreadid) ;
+ break ;
+ case dbg_threadinfo_func :
+ ret = dbg_threadinfo(p->info_parms.ref,
+ p->info_parms.info ) ;
+ break ;
+ case dbg_getthreadreg_func :
+ ret = dbg_getthreadreg(p->reg_parms.thread,
+ p->reg_parms.regcount,
+ p->reg_parms.registers) ;
+ break ;
+ case dbg_setthreadreg_func :
+ ret = dbg_setthreadreg(p->reg_parms.thread,
+ p->reg_parms.regcount,
+ p->reg_parms.registers) ;
+ break ;
+ case dbg_scheduler_func :
+ ret = dbg_scheduler(p->scheduler_parms.thread,
+ p->scheduler_parms.lock,
+ p->scheduler_parms.mode) ;
+ break ;
+#endif /* CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT */
+ default :
+ ret = 0 ; /* failure due to non-implementation */
+ }
+ CYGARC_HAL_RESTORE_GP();
+ return ret;
+}
+#endif /* CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT */
+
+// Note: This constant is the same as the one defined in hal_if.h:
+// #define CYGNUM_CALL_IF_DBG_SYSCALL 15
+// But we don't have the hal_if on all the platforms we support this
+// intercalling on. Maintaining backwards compatibility is so much fun!
+
+#define DBG_SYSCALL_THREAD_VEC_NUM 15
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+
+#ifdef CYGPKG_HAL_SPARCLITE_SLEB
+# include <cyg/hal/hal_cygm.h>
+# ifdef CYG_HAL_USE_ROM_MONITOR_CYGMON
+// then we support talking to CygMon...
+# undef DBG_SYSCALL_THREAD_VEC_NUM
+# define DBG_SYSCALL_THREAD_VEC_NUM BSP_VEC_MT_DEBUG
+# endif
+// otherwise this code is wrong for SPARClite but also not used.
+#endif
+
+#endif
+
+void patch_dbg_syscalls(void * vector)
+{
+ dbg_syscall_func * f ;
+ f = vector ;
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+
+ f[DBG_SYSCALL_THREAD_VEC_NUM] = dbg_thread_syscall_rmt ;
+
+#endif
+
+}
+
+// -------------------------------------------------------------------------
+// End of dbg-thread-demux.c
diff --git a/ecos/packages/kernel/current/src/debug/dbg_gdb.cxx b/ecos/packages/kernel/current/src/debug/dbg_gdb.cxx
new file mode 100644
index 0000000000..935eb31d50
--- /dev/null
+++ b/ecos/packages/kernel/current/src/debug/dbg_gdb.cxx
@@ -0,0 +1,469 @@
+/*==========================================================================
+//
+// dbg_gdb.c
+//
+// GDB Debugging Interface
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1998-08-22
+// Purpose: GDB Debugging Interface
+// Description: Interface for calls from GDB stubs into the OS. These
+// currently mostly support thread awareness.
+//
+//####DESCRIPTIONEND####
+//
+//========================================================================*/
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/hal.h> // CYG_HAL_USE_ROM_MONITOR_CYGMON
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+
+#include <cyg/kernel/ktypes.h>
+
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/sched.hxx>
+
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/sched.inl>
+
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_stub.h>
+
+extern "C"
+{
+#include <cyg/hal/dbg-threads-api.h>
+};
+
+#define USE_ID 1
+
+#if (CYG_BYTEORDER == CYG_LSBFIRST)
+
+unsigned long swap32(unsigned long x)
+{
+ unsigned long r = 0;
+
+ r |= (x>>24)&0xFF;
+ r |= ((x>>16)&0xFF)<<8;
+ r |= ((x>>8)&0xFF)<<16;
+ r |= ((x)&0xFF)<<24;
+
+ return r;
+}
+
+#else
+
+#define swap32(x) ((unsigned long)(x))
+
+#endif
+
+//--------------------------------------------------------------------------
+
+externC int dbg_thread_capabilities(struct dbg_capabilities * cpb)
+{
+ cpb->mask1 = has_thread_current |
+ has_thread_registers |
+ has_thread_reg_change |
+ has_thread_list |
+ has_thread_info ;
+ return 1 ;
+}
+
+//--------------------------------------------------------------------------
+
+static void dbg_make_threadref(Cyg_Thread *thread, threadref *ref )
+{
+ // The following test tries to avoid accessing uninitialized pointers.
+ // This can happen if we take a breakpoint before the data is copied
+ // or the BSS zeroed. We currently assume that RAM will reset to zero
+ // or 0xff. If it is random, we have no hope.
+
+ if( (CYG_ADDRWORD)thread == 0 || (CYG_ADDRWORD)thread == 0xffffffff )
+ {
+ ((unsigned long *)ref)[0] = 0;
+ ((unsigned long *)ref)[1] = 0;
+ }
+ else
+ {
+ cyg_uint16 id = thread->get_unique_id();
+
+#if USE_ID
+ ((unsigned long *)ref)[0] = (unsigned long)thread;
+ ((unsigned long *)ref)[1] = (unsigned long)swap32(id);
+#else
+ ((unsigned long *)ref)[1] = (unsigned long)thread;
+ ((unsigned long *)ref)[0] = (unsigned long)id;
+#endif
+ }
+}
+
+static Cyg_Thread *dbg_get_thread( threadref *ref)
+{
+#if USE_ID
+
+ cyg_uint16 id = 0;
+
+ id = (cyg_uint16)swap32(((unsigned long *)ref)[1]);
+
+ Cyg_Thread *th = Cyg_Thread::get_list_head();
+ while( th != 0 )
+ {
+ if( th->get_unique_id() == id ) break;
+ th = th->get_list_next();
+ }
+
+// if( thread->get_unique_id() != id ) th = 0;
+
+#else
+
+ cyg_uint16 id = 0;
+
+ Cyg_Thread *thread = (Cyg_Thread *)(((unsigned long *)ref)[1]);
+ id = (cyg_uint16)(((unsigned long *)ref)[0]);
+
+ // Validate the thread.
+ Cyg_Thread *th = Cyg_Thread::get_list_head();
+ while( th != 0 )
+ {
+ if( th == thread ) break;
+ th = th->get_list_next();
+ }
+
+// if( thread->get_unique_id() != id ) th = 0;
+
+#endif
+
+ return th;
+}
+
+//--------------------------------------------------------------------------
+
+externC int dbg_currthread(threadref * varparm)
+{
+ Cyg_Thread *thread = Cyg_Scheduler::get_current_thread();
+
+ dbg_make_threadref(thread, varparm );
+
+ return 1 ;
+}
+
+//--------------------------------------------------------------------------
+
+externC int dbg_thread_id(threadref *threadid)
+{
+ Cyg_Thread *thread = dbg_get_thread(threadid);
+ if( thread == 0 ) return 0;
+ return thread->get_unique_id ();
+}
+
+//--------------------------------------------------------------------------
+
+externC int dbg_currthread_id(void)
+{
+ Cyg_Thread *thread = Cyg_Scheduler::get_current_thread();
+ return thread->get_unique_id ();
+}
+
+//--------------------------------------------------------------------------
+
+externC int dbg_threadlist(int startflag,
+ threadref * lastthreadid,
+ threadref * next_thread)
+{
+ Cyg_Thread *thread;
+ if( startflag )
+ {
+ thread = Cyg_Thread::get_list_head();
+ dbg_make_threadref(thread, next_thread);
+ }
+ else
+ {
+ thread = dbg_get_thread(lastthreadid);
+
+ if( thread == 0 ) return 0;
+ thread = thread->get_list_next();
+
+ if( thread == 0 ) return 0;
+ dbg_make_threadref(thread, next_thread);
+ }
+ return 1 ;
+}
+
+//--------------------------------------------------------------------------
+// Some support routines for manufacturing thread info strings
+
+static char *dbg_addstr(char *s, char *t)
+{
+ while( (*s++ = *t++) != 0 );
+
+ return s-1;
+}
+
+static char *dbg_addint(char *s, int n, int base)
+{
+ char buf[16];
+ char sign = '+';
+ cyg_count8 bpos;
+ char *digits = "0123456789ABCDEF";
+
+ if( n < 0 ) n = -n, sign = '-';
+
+ /* Set pos to start */
+ bpos = 0;
+
+ /* construct digits into buffer in reverse order */
+ if( n == 0 ) buf[bpos++] = '0';
+ else while( n != 0 )
+ {
+ cyg_ucount8 d = n % base;
+ buf[bpos++] = digits[d];
+ n /= base;
+ }
+
+ /* set sign if negative. */
+ if( sign == '-' )
+ {
+ buf[bpos] = sign;
+ }
+ else bpos--;
+
+ /* Now write it out in correct order. */
+ while( bpos >= 0 )
+ *s++ = buf[bpos--];
+
+ *s = 0;
+
+ return s;
+}
+
+static char *dbg_adddec(char *s, int x)
+{
+ return dbg_addint(s, x, 10);
+}
+
+//--------------------------------------------------------------------------
+
+externC int dbg_threadinfo(
+ threadref * threadid,
+ struct cygmon_thread_debug_info * info)
+{
+ static char statebuf[60];
+
+ Cyg_Thread *thread = dbg_get_thread(threadid);
+ if( thread == 0 ) return 0;
+
+ info->context_exists = 1;
+
+ char *sbp = statebuf;
+ char *s;
+
+ if( thread->get_state() & Cyg_Thread::SUSPENDED )
+ {
+ sbp = dbg_addstr( sbp, "suspended+");
+ }
+
+ switch( thread->get_state() & ~Cyg_Thread::SUSPENDED )
+ {
+ case Cyg_Thread::RUNNING:
+ if ( Cyg_Scheduler::get_current_thread() == thread ) {
+ s = "running"; break;
+ }
+ else if ( thread->get_state() & Cyg_Thread::SUSPENDED ) {
+ s = ""; sbp--; /*kill '+'*/ break;
+ }
+ else {
+ s = "ready"; break;
+ }
+ case Cyg_Thread::SLEEPING:
+ s = "sleeping"; break;
+ case Cyg_Thread::COUNTSLEEP | Cyg_Thread::SLEEPING:
+ case Cyg_Thread::COUNTSLEEP:
+ s = "counted sleep"; break;
+ case Cyg_Thread::CREATING:
+ s = "creating"; sbp = statebuf; break;
+ case Cyg_Thread::EXITED:
+ s = "exited"; sbp = statebuf; break;
+ default:
+ s = "unknown state"; break;
+ }
+
+ sbp = dbg_addstr( sbp, s );
+ sbp = dbg_addstr( sbp, ", Priority: " );
+ sbp = dbg_adddec( sbp, thread->get_priority() );
+
+ info->thread_display = statebuf;
+
+#ifdef CYGVAR_KERNEL_THREADS_NAME
+ info->unique_thread_name = thread->get_name();
+#else
+ info->unique_thread_name = 0;
+#endif
+
+ info->more_display = 0;
+
+ return 1 ;
+}
+
+//--------------------------------------------------------------------------
+
+externC int dbg_getthreadreg(
+ threadref * osthreadid,
+ int regcount, /* count of registers in the array */
+ void * regval) /* fillin this array */
+{
+ Cyg_Thread *thread = dbg_get_thread(osthreadid);
+
+ if( thread == 0 ) return 0;
+
+ if( thread == Cyg_Scheduler::get_current_thread() )
+ {
+#if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON)
+ // We have no state for the current thread, Cygmon has
+ // got that and we cannot get at it.
+ return 0;
+#elif defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
+ // registers hold the state of the current thread.
+ __stub_copy_registers ((target_register_t *)regval, registers);
+#else
+ return 0;
+#endif
+ }
+ else
+ {
+ HAL_SavedRegisters *regs = thread->get_saved_context();
+ if( regs == 0 ) return 0;
+
+ HAL_GET_GDB_REGISTERS (regval, regs);
+ }
+
+ return 1 ;
+}
+
+//--------------------------------------------------------------------------
+
+externC int dbg_setthreadreg(
+ threadref * osthreadid,
+ int regcount , /* number of registers */
+ void * regval)
+{
+ Cyg_Thread *thread = dbg_get_thread(osthreadid);
+
+ if( thread == 0 ) return 0;
+
+ if( thread == Cyg_Scheduler::get_current_thread() )
+ {
+#if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON)
+ // We have no state for the current thread, Cygmon has
+ // got that and we cannot get at it.
+ return 0;
+#elif defined(CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS)
+ // registers hold the state of the current thread.
+ __stub_copy_registers (registers, (target_register_t *)regval);
+#else
+ return 0;
+#endif
+ }
+ else
+ {
+ HAL_SavedRegisters *regs = thread->get_saved_context();
+ if( regs == 0 ) return 0;
+
+ HAL_SET_GDB_REGISTERS (regs, regval);
+ }
+
+ return 1;
+}
+
+//--------------------------------------------------------------------------
+// Thread scheduler control for debugger.
+// Arguments:
+// osthreadid : must match currently executing thread.
+// Future use: change the currently executing thread.
+// lock : 0 == unlock scheduler, 1 == lock scheduler
+// mode : 0 == single-instruction step, 1 == free running
+//
+// Return values:
+// 1 == success
+// 0 == failure
+// -1 == request that the caller handle this itself
+// (eg.by disabling interrupts)
+//
+
+externC int dbg_scheduler(
+ threadref * osthreadid,
+ int lock, /* 0 == unlock, 1 == lock */
+ int mode) /* 0 == step, 1 == continue */
+{
+#if 0
+ /* Minimal implementation: let stub do the work. */
+ return -1; // Stub will disable interrupts
+#else
+ Cyg_Thread *thread = dbg_get_thread(osthreadid);
+
+ if( thread == 0 ) return 0; // fail
+
+ if( thread == Cyg_Scheduler::get_current_thread() )
+ {
+ // OK to proceed
+
+ if (lock)
+ {
+ Cyg_Scheduler::lock();
+ }
+ else
+ {
+ if (Cyg_Scheduler::get_sched_lock() >= 1)
+ Cyg_Scheduler::unlock_simple();
+ }
+ return 1; // success
+ }
+ else
+ {
+ // Cannot accept any thread other than current one
+ return 0; // fail
+ }
+#endif
+}
+
+
+#endif // CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+
+//--------------------------------------------------------------------------
+// End of dbg_gdb.cxx
diff --git a/ecos/packages/kernel/current/src/instrmnt/meminst.cxx b/ecos/packages/kernel/current/src/instrmnt/meminst.cxx
new file mode 100644
index 0000000000..dd86748bd4
--- /dev/null
+++ b/ecos/packages/kernel/current/src/instrmnt/meminst.cxx
@@ -0,0 +1,261 @@
+//==========================================================================
+//
+// instrmnt/meminst.cxx
+//
+// Memory buffer instrumentation functions
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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, andrew.lunn@ascom.ch
+// Date: 1997-10-27
+// Purpose: Instrumentation functions
+// Description: The functions in this file are implementations of the
+// standard instrumentation functions that place records
+// into a memory buffer.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/intr.hxx> // interrupt control
+#include <cyg/kernel/sched.hxx> // scheduler defines
+
+#include <cyg/kernel/sched.inl> // scheduler inlines
+#include <cyg/kernel/clock.inl> // clock inlines
+
+#ifdef CYGPKG_KERNEL_INSTRUMENT
+
+// -------------------------------------------------------------------------
+// Instrumentation record.
+
+struct Instrument_Record
+{
+ CYG_WORD16 type; // record type
+ CYG_WORD16 thread; // current thread id
+ CYG_WORD timestamp; // 32 bit timestamp
+ CYG_WORD arg1; // first arg
+ CYG_WORD arg2; // second arg
+};
+
+// -------------------------------------------------------------------------
+// Buffer base and end. This buffer must be a whole number of
+
+#ifdef CYGVAR_KERNEL_INSTRUMENT_EXTERNAL_BUFFER
+
+externC Instrument_Record instrument_buffer[];
+externC cyg_uint32 instrument_buffer_size;
+
+#else
+
+extern "C"
+{
+
+Instrument_Record instrument_buffer[CYGNUM_KERNEL_INSTRUMENT_BUFFER_SIZE];
+
+cyg_uint32 instrument_buffer_size = CYGNUM_KERNEL_INSTRUMENT_BUFFER_SIZE;
+
+};
+
+#endif
+
+extern "C"
+{
+
+#define instrument_buffer_start instrument_buffer[0]
+#define instrument_buffer_end instrument_buffer[instrument_buffer_size]
+
+extern "C"
+{
+Instrument_Record *instrument_buffer_pointer = &instrument_buffer_start;
+};
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_FLAGS
+
+// This array contains a 32 bit word for each event class. The
+// bits in the word correspond to events. By setting or clearing
+// the appropriate bit, the selected instrumentation event may
+// be enabled or disabled dynamically.
+
+cyg_uint32 instrument_flags[(CYG_INSTRUMENT_CLASS_MAX>>8)+1];
+
+#endif
+
+};
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+HAL_SPINLOCK_TYPE instrument_lock = HAL_SPINLOCK_INIT_CLEAR;
+
+#else
+
+#define HAL_SPINLOCK_SPIN( __lock )
+
+#define HAL_SPINLOCK_CLEAR( __lock )
+
+#endif
+
+// -------------------------------------------------------------------------
+
+void cyg_instrument( cyg_uint32 type, CYG_ADDRWORD arg1, CYG_ADDRWORD arg2 )
+{
+
+ cyg_uint32 old_ints;
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_FLAGS
+
+ cyg_ucount8 cl = (type>>8)&0xff;
+ cyg_ucount8 event = type&0xff;
+
+ if( instrument_flags[cl] & (1<<event) )
+#endif
+ {
+ HAL_DISABLE_INTERRUPTS(old_ints);
+ HAL_SPINLOCK_SPIN( instrument_lock );
+
+ Instrument_Record *p = instrument_buffer_pointer;
+ Cyg_Thread *t = Cyg_Scheduler::get_current_thread();
+ p->type = type;
+ p->thread = (t==0)?0x0FFF:t->get_unique_id();
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+ // Add CPU id to in top 4 bytes of thread id
+ p->thread = (p->thread&0x0FFF)|(CYG_KERNEL_CPU_THIS()<<12);
+#endif
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+// p->timestamp = Cyg_Clock::real_time_clock->current_value_lo();
+ HAL_CLOCK_READ( &p->timestamp );
+#else
+ p->timestamp = 0;
+#endif
+ p->arg1 = arg1;
+ p->arg2 = arg2;
+
+ p++;
+#ifdef CYGDBG_KERNEL_INSTRUMENT_BUFFER_WRAP
+ if( p == &instrument_buffer_end )
+ instrument_buffer_pointer = &instrument_buffer_start;
+ else instrument_buffer_pointer = p;
+#else
+ // when not wrapping, just continue to put further entries
+ // in the last slot.
+ if( p != &instrument_buffer_end )
+ instrument_buffer_pointer = p;
+#endif
+ HAL_SPINLOCK_CLEAR( instrument_lock );
+ HAL_RESTORE_INTERRUPTS(old_ints);
+ }
+
+ return;
+}
+
+// -------------------------------------------------------------------------
+// Functions to enable and disable selected instrumentation events
+// when the flags are enabled.
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_FLAGS
+
+externC void cyg_instrument_enable( cyg_uint32 cl, cyg_uint32 event)
+{
+ if( 0 != event )
+ instrument_flags[cl>>8] |= 1<<event;
+ else
+ instrument_flags[cl>>8] = ~0;
+}
+
+externC void cyg_instrument_disable( cyg_uint32 cl, cyg_uint32 event)
+{
+ if( 0 != event )
+ instrument_flags[cl>>8] &= ~(1<<event);
+ else
+ instrument_flags[cl>>8] = 0;
+
+}
+
+externC cyg_bool cyg_instrument_state( cyg_uint32 cl, cyg_uint32 event)
+{
+ return (instrument_flags[cl>>8] & (1<<event)) != 0;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGDBG_KERNEL_INSTRUMENT_MSGS
+#define CYGDBG_KERNEL_INSTRUMENT_MSGS_DEFINE_TABLE
+#include <cyg/kernel/instrument_desc.h>
+#define NELEM(x) (sizeof(x)/sizeof*(x))
+externC char * cyg_instrument_msg(CYG_WORD16 type) {
+
+ struct instrument_desc_s *record;
+ struct instrument_desc_s *end_record;
+ CYG_WORD cl, event;
+
+ record = instrument_desc;
+ end_record = &instrument_desc[NELEM(instrument_desc)-1];
+ cl = type & 0xff00;
+ event = type & 0x00ff;
+
+ while ((record != end_record) && (record->num != cl)) {
+ record++;
+ }
+
+ if (record->num == cl) {
+ record++;
+ while ((record != end_record) && (record->num != event) &&
+ (record->num < 0xff)) {
+ record++;
+ }
+
+ if (record->num == event) {
+ return (record->msg);
+ }
+ }
+ return("Unknown event");
+}
+#endif // CYGDBG_KERNEL_INSTRUMENT_MSGS
+#endif // CYGPKG_KERNEL_INSTRUMENT
+
+// EOF instrmnt/meminst.cxx
diff --git a/ecos/packages/kernel/current/src/intr/intr.cxx b/ecos/packages/kernel/current/src/intr/intr.cxx
new file mode 100644
index 0000000000..6443ed00c9
--- /dev/null
+++ b/ecos/packages/kernel/current/src/intr/intr.cxx
@@ -0,0 +1,784 @@
+//==========================================================================
+//
+// intr/intr.cxx
+//
+// Interrupt class implementations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1999-02-17
+// Purpose: Interrupt class implementation
+// Description: This file contains the definitions of the interrupt
+// class.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/intr.hxx> // our header
+
+#include <cyg/kernel/sched.hxx> // scheduler
+
+#include <cyg/kernel/sched.inl>
+
+// -------------------------------------------------------------------------
+// Statics
+
+volatile cyg_int32 Cyg_Interrupt::disable_counter[CYGNUM_KERNEL_CPU_MAX];
+
+Cyg_SpinLock Cyg_Interrupt::interrupt_disable_spinlock CYG_INIT_PRIORITY( INTERRUPTS );
+
+CYG_INTERRUPT_STATE Cyg_Interrupt::interrupt_disable_state[CYGNUM_KERNEL_CPU_MAX];
+
+// -------------------------------------------------------------------------
+
+Cyg_Interrupt::Cyg_Interrupt(
+ cyg_vector vec, // Vector to attach to
+ cyg_priority pri, // Queue priority
+ CYG_ADDRWORD d, // Data pointer
+ cyg_ISR *ir, // Interrupt Service Routine
+ cyg_DSR *dr // Deferred Service Routine
+ )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG5("vector=%d, priority=%d, data=%08x, isr=%08x, "
+ "dsr=%08x", vec, pri, d, ir, dr);
+
+ vector = vec;
+ priority = pri;
+ isr = ir;
+ dsr = dr;
+ data = d;
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
+
+ dsr_count = 0;
+ next_dsr = NULL;
+
+#endif
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
+
+ next = NULL;
+
+#endif
+
+ CYG_REPORT_RETURN();
+
+};
+
+// -------------------------------------------------------------------------
+
+Cyg_Interrupt::~Cyg_Interrupt()
+{
+ CYG_REPORT_FUNCTION();
+ detach();
+ CYG_REPORT_RETURN();
+};
+
+// -------------------------------------------------------------------------
+// DSR handling statics:
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
+
+Cyg_Interrupt *
+Cyg_Interrupt::dsr_table[CYGNUM_KERNEL_CPU_MAX][CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE];
+
+cyg_ucount32 Cyg_Interrupt::dsr_table_head[CYGNUM_KERNEL_CPU_MAX];
+
+volatile cyg_ucount32 Cyg_Interrupt::dsr_table_tail[CYGNUM_KERNEL_CPU_MAX];
+
+#endif
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
+
+Cyg_Interrupt* volatile Cyg_Interrupt::dsr_list[CYGNUM_KERNEL_CPU_MAX];
+
+#endif
+
+// -------------------------------------------------------------------------
+// Call any pending DSRs
+
+void
+Cyg_Interrupt::call_pending_DSRs_inner(void)
+{
+// CYG_REPORT_FUNCTION();
+
+ HAL_SMP_CPU_TYPE cpu = CYG_KERNEL_CPU_THIS();
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
+
+ while( dsr_table_head[cpu] != dsr_table_tail[cpu] )
+ {
+ Cyg_Interrupt *intr = dsr_table[cpu][dsr_table_head[cpu]];
+
+ dsr_table_head[cpu]++;
+ if( dsr_table_head[cpu] >= CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE )
+ dsr_table_head[cpu] = 0;
+
+ CYG_INSTRUMENT_INTR(CALL_DSR, intr->vector, 0);
+
+ CYG_ASSERT( intr->dsr != NULL , "No DSR defined");
+
+ intr->dsr( intr->vector, 1, (CYG_ADDRWORD)intr->data );
+ }
+
+#endif
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
+
+ while( dsr_list[cpu] != NULL )
+ {
+ Cyg_Interrupt* intr;
+ cyg_uint32 old_intr;
+ cyg_count32 count;
+
+ HAL_DISABLE_INTERRUPTS(old_intr);
+
+ intr = dsr_list[cpu];
+ dsr_list[cpu] = intr->next_dsr;
+ count = intr->dsr_count;
+ intr->dsr_count = 0;
+
+ HAL_RESTORE_INTERRUPTS(old_intr);
+
+ CYG_ASSERT( intr->dsr != NULL , "No DSR defined");
+
+ intr->dsr( intr->vector, count, (CYG_ADDRWORD)intr->data );
+
+ }
+
+#endif
+
+};
+
+externC void
+cyg_interrupt_call_pending_DSRs(void)
+{
+ Cyg_Interrupt::call_pending_DSRs_inner();
+}
+
+//
+// Use HAL supported function to run through the DSRs, but executing using
+// the separate interrupt stack if available. This function calls back
+// into this module via 'cyg_interrupt_call_pending_DSRs' above, to keep
+// the whole process as general as possible.
+
+void
+Cyg_Interrupt::call_pending_DSRs(void)
+{
+ CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1,
+ "DSRs being called with sched_lock not equal to 1");
+ HAL_INTERRUPT_STACK_CALL_PENDING_DSRS();
+}
+
+
+// -------------------------------------------------------------------------
+
+void
+Cyg_Interrupt::post_dsr(void)
+{
+// CYG_REPORT_FUNCTION();
+ HAL_SMP_CPU_TYPE cpu = CYG_KERNEL_CPU_THIS();
+
+ CYG_INSTRUMENT_INTR(POST_DSR, vector, 0);
+
+ cyg_uint32 old_intr;
+
+ // We need to disable interrupts during this part to
+ // guard against nested interrupts.
+
+ HAL_DISABLE_INTERRUPTS(old_intr);
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
+
+ dsr_table[cpu][dsr_table_tail[cpu]++] = this;
+ if( dsr_table_tail[cpu] >= CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE )
+ dsr_table_tail[cpu] = 0;
+
+#endif
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
+
+ // Only add the interrupt to the dsr list if this is
+ // the first DSR call.
+ // At present DSRs are pushed onto the list and will be
+ // called in reverse order. We do not define the order
+ // in which DSRs are called, so this is acceptable.
+
+ if( dsr_count++ == 0 )
+ {
+ next_dsr = dsr_list[cpu];
+ dsr_list[cpu] = this;
+ }
+
+#endif
+
+ HAL_RESTORE_INTERRUPTS(old_intr);
+};
+
+// -------------------------------------------------------------------------
+// A C callable interface to Cyg_Interrupt::post_dsr() that can be used from
+// the HAL.
+
+externC void
+cyg_interrupt_post_dsr( CYG_ADDRWORD intr_obj )
+{
+ Cyg_Interrupt* intr = (Cyg_Interrupt*) intr_obj;
+ intr->post_dsr ();
+}
+
+// -------------------------------------------------------------------------
+
+// FIXME: should have better name - Jifl
+externC void
+interrupt_end(
+ cyg_uint32 isr_ret,
+ Cyg_Interrupt *intr,
+ HAL_SavedRegisters *regs
+ )
+{
+// CYG_REPORT_FUNCTION();
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+ Cyg_Scheduler::lock();
+#endif
+
+ // Sometimes we have a NULL intr object pointer.
+ cyg_vector vector = (intr!=NULL)?intr->vector:0;
+
+ CYG_INSTRUMENT_INTR(END, vector, isr_ret);
+
+ CYG_UNUSED_PARAM( cyg_vector, vector ); // prevent compiler warning
+
+#ifndef CYGIMP_KERNEL_INTERRUPTS_CHAIN
+
+ // Only do this if we are in a non-chained configuration.
+ // If we are chained, then chain_isr below will do the DSR
+ // posting.
+
+ if( isr_ret & Cyg_Interrupt::CALL_DSR && intr != NULL ) intr->post_dsr();
+
+#endif
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+
+ // If we have GDB support enabled, and there is the possibility
+ // that this thread will be context switched as a result of this
+ // interrupt, then save the pointer to the saved thread context in
+ // the thread object so that GDB can get a meaningful context to
+ // look at.
+
+ Cyg_Scheduler::get_current_thread()->set_saved_context(regs);
+
+#endif
+
+ // Now unlock the scheduler, which may also call DSRs
+ // and cause a thread switch to happen.
+
+ Cyg_Scheduler::unlock();
+
+#ifdef CYGDBG_KERNEL_DEBUG_GDB_THREAD_SUPPORT
+
+ Cyg_Scheduler::get_current_thread()->set_saved_context(0);
+
+#endif
+
+ CYG_INSTRUMENT_INTR(RESTORE, vector, 0);
+}
+
+// -------------------------------------------------------------------------
+// Interrupt chaining statics.
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
+
+Cyg_Interrupt *Cyg_Interrupt::chain_list[CYGNUM_HAL_ISR_TABLE_SIZE];
+
+#endif
+
+// -------------------------------------------------------------------------
+// Chaining ISR inserted in HAL vector
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
+
+cyg_uint32
+Cyg_Interrupt::chain_isr(cyg_vector vector, CYG_ADDRWORD data)
+{
+ Cyg_Interrupt *p = *(Cyg_Interrupt **)data;
+ register cyg_uint32 isr_ret = 0;
+ register cyg_uint32 isr_chain_ret = 0;
+
+ CYG_INSTRUMENT_INTR(CHAIN_ISR, vector, 0);
+
+ while( p != NULL )
+ {
+ if( p->vector == vector )
+ {
+ isr_ret = p->isr(vector, p->data);
+
+ isr_chain_ret |= isr_ret;
+
+ if( isr_ret & Cyg_Interrupt::CALL_DSR ) p->post_dsr();
+
+ if( isr_ret & Cyg_Interrupt::HANDLED ) break;
+ }
+
+ p = p->next;
+ }
+
+#ifdef HAL_DEFAULT_ISR
+ if( (isr_chain_ret & (Cyg_Interrupt::HANDLED|Cyg_Interrupt::CALL_DSR)) == 0 )
+ {
+ // If we finished the loop for some reason other than that an
+ // ISR has handled the interrupt, call any default ISR to either
+ // report the spurious interrupt, or do some other HAL level processing
+ // such as GDB interrupt detection etc.
+
+ HAL_DEFAULT_ISR( vector, 0 );
+ }
+#endif
+
+ return isr_ret & ~Cyg_Interrupt::CALL_DSR;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Attach an ISR to an interrupt vector.
+
+void
+Cyg_Interrupt::attach(void)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+ CYG_INSTRUMENT_INTR(ATTACH, vector, 0);
+
+ HAL_INTERRUPT_SET_LEVEL( vector, priority );
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
+
+ CYG_ASSERT( next == NULL , "Cyg_Interrupt already on a list");
+
+ cyg_uint32 index;
+
+ HAL_TRANSLATE_VECTOR( vector, index );
+
+ if( chain_list[index] == NULL )
+ {
+ int in_use;
+ // First Interrupt on this chain, just assign it and register
+ // the chain_isr with the HAL.
+
+ chain_list[index] = this;
+
+ HAL_INTERRUPT_IN_USE( vector, in_use );
+ CYG_ASSERT( 0 == in_use, "Interrupt vector not free.");
+ HAL_INTERRUPT_ATTACH( vector, chain_isr, &chain_list[index], NULL );
+ }
+ else
+ {
+ // There are already interrupts chained, add this one into the
+ // chain in priority order.
+
+ Cyg_Interrupt **p = &chain_list[index];
+
+ while( *p != NULL )
+ {
+ Cyg_Interrupt *n = *p;
+
+ if( n->priority < priority ) break;
+
+ p = &n->next;
+ }
+ next = *p;
+ *p = this;
+ }
+
+#else
+
+ {
+ int in_use;
+
+
+ HAL_INTERRUPT_IN_USE( vector, in_use );
+ CYG_ASSERT( 0 == in_use, "Interrupt vector not free.");
+
+ HAL_INTERRUPT_ATTACH( vector, isr, data, this );
+ }
+
+#endif
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Detach the ISR from the vector
+
+void
+Cyg_Interrupt::detach(void)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+ CYG_INSTRUMENT_INTR(DETACH, vector, 0);
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
+
+ // Remove the interrupt object from the vector chain.
+
+ cyg_uint32 index;
+
+ HAL_TRANSLATE_VECTOR( vector, index );
+
+ Cyg_Interrupt **p = &chain_list[index];
+
+ while( *p != NULL )
+ {
+ Cyg_Interrupt *n = *p;
+
+ if( n == this )
+ {
+ *p = next;
+ break;
+ }
+
+ p = &n->next;
+ }
+
+ // If this was the last one, detach the vector.
+
+ if( chain_list[index] == NULL )
+ HAL_INTERRUPT_DETACH( vector, chain_isr );
+
+#else
+
+ HAL_INTERRUPT_DETACH( vector, isr );
+
+#endif
+
+ CYG_REPORT_RETURN();
+
+}
+
+// -------------------------------------------------------------------------
+// Get the current service routine
+
+void
+Cyg_Interrupt::get_vsr(cyg_vector vector, cyg_VSR **vsr)
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG2("vector = %d, mem to put VSR in is at %08x", vector,
+ vsr);
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_VSR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_VSR_MAX, "Invalid vector");
+
+ HAL_VSR_GET( vector, vsr );
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Install a vector service routine
+
+void
+Cyg_Interrupt::set_vsr(cyg_vector vector, cyg_VSR *vsr, cyg_VSR **old)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_REPORT_FUNCARG3( "vector = %d, new vsr is at %08x, mem to put "
+ "old VSR in is at %08x", vector, vsr, old);
+
+ CYG_INSTRUMENT_INTR(SET_VSR, vector, vsr);
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_VSR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_VSR_MAX, "Invalid vector");
+
+ CYG_INTERRUPT_STATE old_ints;
+
+ HAL_DISABLE_INTERRUPTS(old_ints);
+
+ HAL_VSR_SET( vector, vsr, old );
+
+ HAL_RESTORE_INTERRUPTS(old_ints);
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Disable interrupts at the CPU
+
+
+void
+Cyg_Interrupt::disable_interrupts(void)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_INSTRUMENT_INTR(DISABLE, disable_counter[CYG_KERNEL_CPU_THIS()]+1, 0);
+
+ HAL_SMP_CPU_TYPE cpu_this = CYG_KERNEL_CPU_THIS();
+
+ // If the disable_counter is zero, disable interrupts and claim the spinlock.
+
+ if( 0 == disable_counter[cpu_this] )
+ {
+ // Claim the spinlock and disable interrupts. We save the original interrupt
+ // enable state to restore later.
+ interrupt_disable_spinlock.spin_intsave(&interrupt_disable_state[cpu_this]);
+ }
+
+ // Now increment our disable counter.
+
+ disable_counter[cpu_this]++;
+
+ CYG_REPORT_RETURN();
+}
+
+
+// -------------------------------------------------------------------------
+// Re-enable CPU interrupts
+
+void
+Cyg_Interrupt::enable_interrupts(void)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_INSTRUMENT_INTR(ENABLE, disable_counter[CYG_KERNEL_CPU_THIS()], 0);
+
+ HAL_SMP_CPU_TYPE cpu_this = CYG_KERNEL_CPU_THIS();
+
+ CYG_ASSERT( disable_counter[cpu_this] > 0 , "Disable counter not greater than zero");
+
+ // If the disable counter goes to zero, then release the spinlock and restore
+ // the previous interrupt state.
+
+ if( --disable_counter[cpu_this] == 0 )
+ {
+ interrupt_disable_spinlock.clear_intsave(interrupt_disable_state[cpu_this]);
+ }
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Mask a specific interrupt in a PIC
+
+void
+Cyg_Interrupt::mask_interrupt(cyg_vector vector)
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("vector=%d", vector);
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+ CYG_INSTRUMENT_INTR(MASK, vector, 0);
+
+ CYG_INTERRUPT_STATE old_ints;
+
+ HAL_DISABLE_INTERRUPTS(old_ints);
+ HAL_INTERRUPT_MASK( vector );
+ HAL_RESTORE_INTERRUPTS(old_ints);
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Mask a specific interrupt in a PIC (but not interrupt safe)
+
+void
+Cyg_Interrupt::mask_interrupt_intunsafe(cyg_vector vector)
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("vector=%d", vector);
+
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+ CYG_INSTRUMENT_INTR(MASK, vector, 0);
+
+ HAL_INTERRUPT_MASK( vector );
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Clear PIC mask
+
+void
+Cyg_Interrupt::unmask_interrupt(cyg_vector vector)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+ CYG_INSTRUMENT_INTR(UNMASK, vector, 0);
+
+ CYG_INTERRUPT_STATE old_ints;
+
+ HAL_DISABLE_INTERRUPTS(old_ints);
+ HAL_INTERRUPT_UNMASK( vector );
+ HAL_RESTORE_INTERRUPTS(old_ints);
+
+ CYG_REPORT_RETURN();
+}
+
+
+// -------------------------------------------------------------------------
+// Clear PIC mask (but not interrupt safe)
+
+void
+Cyg_Interrupt::unmask_interrupt_intunsafe(cyg_vector vector)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+ CYG_INSTRUMENT_INTR(UNMASK, vector, 0);
+
+ HAL_INTERRUPT_UNMASK( vector );
+
+ CYG_REPORT_RETURN();
+}
+
+
+// -------------------------------------------------------------------------
+// Acknowledge interrupt at PIC
+
+void
+Cyg_Interrupt::acknowledge_interrupt(cyg_vector vector)
+{
+// CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+ CYG_INSTRUMENT_INTR(ACK, vector, 0);
+
+ HAL_INTERRUPT_ACKNOWLEDGE( vector );
+}
+
+// -------------------------------------------------------------------------
+// Change interrupt detection at PIC
+
+void
+Cyg_Interrupt::configure_interrupt(
+ cyg_vector vector, // vector to control
+ cyg_bool level, // level or edge triggered
+ cyg_bool up // hi/lo level, rising/falling edge
+ )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG3("vector = %d, level = %d, up = %d", vector, level,
+ up);
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+ CYG_INSTRUMENT_INTR(CONFIGURE, vector, (level<<1)|up);
+
+ HAL_INTERRUPT_CONFIGURE( vector, level, up );
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// SMP support for setting/getting interrupt CPU
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+void
+Cyg_Interrupt::set_cpu(
+ cyg_vector vector, // vector to control
+ HAL_SMP_CPU_TYPE cpu // CPU to set
+ )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG2("vector = %d, cpu = %d", vector, cpu );
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+ CYG_INSTRUMENT_INTR(SET_CPU, vector, cpu);
+
+ HAL_INTERRUPT_SET_CPU( vector, cpu );
+
+ CYG_REPORT_RETURN();
+}
+
+HAL_SMP_CPU_TYPE
+Cyg_Interrupt::get_cpu(
+ cyg_vector vector // vector to control
+ )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("vector = %d", vector);
+
+ CYG_ASSERT( vector >= CYGNUM_HAL_ISR_MIN, "Invalid vector");
+ CYG_ASSERT( vector <= CYGNUM_HAL_ISR_MAX, "Invalid vector");
+
+ HAL_SMP_CPU_TYPE cpu = 0;
+
+ HAL_INTERRUPT_GET_CPU( vector, cpu );
+
+ CYG_INSTRUMENT_INTR(GET_CPU, vector, cpu);
+
+ CYG_REPORT_RETURN();
+
+ return cpu;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// EOF intr/intr.cxx
diff --git a/ecos/packages/kernel/current/src/sched/bitmap.cxx b/ecos/packages/kernel/current/src/sched/bitmap.cxx
new file mode 100644
index 0000000000..5800e50ded
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sched/bitmap.cxx
@@ -0,0 +1,323 @@
+//==========================================================================
+//
+// sched/bitmap.cxx
+//
+// Bitmap scheduler class implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-16
+// Purpose: Bitmap scheduler class implementation
+// Description: This file contains the implementations of
+// Cyg_Scheduler_Implementation and Cyg_SchedThread_Implementation.
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <cyg/kernel/sched.hxx> // our header
+
+#include <cyg/hal/hal_arch.h> // Architecture specific definitions
+
+#include <cyg/kernel/thread.inl> // thread inlines
+#include <cyg/kernel/sched.inl> // scheduler inlines
+
+#ifdef CYGSEM_KERNEL_SCHED_BITMAP
+
+//==========================================================================
+// Cyg_Scheduler_Implementation class members
+
+// -------------------------------------------------------------------------
+// Constructor.
+
+Cyg_Scheduler_Implementation::Cyg_Scheduler_Implementation()
+{
+ CYG_REPORT_FUNCTION();
+
+ // At present we cannot init run_queue here because the absence of
+ // ordering of static constructors means that we could do this
+ // after the static idle thread has been created. (Guess how I
+ // found this out!)
+// run_queue = 0;
+
+}
+
+// -------------------------------------------------------------------------
+// Choose the best thread to run next
+
+Cyg_Thread *Cyg_Scheduler_Implementation::schedule()
+{
+ CYG_REPORT_FUNCTION();
+
+ // The run queue may _never_ be empty, there is always
+ // an idle thread at the lowest priority.
+
+ CYG_ASSERT(run_queue != 0, "Run queue empty");
+
+ cyg_uint32 index;
+
+ HAL_LSBIT_INDEX(index, run_queue);
+
+ return thread_table[index];
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_Scheduler_Implementation::add_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT((CYG_THREAD_MIN_PRIORITY >= thread->priority)
+ && (CYG_THREAD_MAX_PRIORITY <= thread->priority),
+ "Priority out of range!");
+
+ CYG_ASSERT( thread_table[thread->priority] == NULL ||
+ thread_table[thread->priority] == thread,
+ "Duplicate thread priorities" );
+
+ CYG_ASSERT( (run_queue & (1<<thread->priority)) == 0,
+ "Run queue bit already set" );
+
+ // If the thread is on some other queue, remove it
+ // here.
+ if( thread->queue != NULL )
+ {
+ thread->queue->remove(thread);
+ thread->queue = NULL;
+ }
+
+ run_queue |= 1<<thread->priority;
+
+ // If the new thread is higher priority than the
+ // current thread, request a reschedule.
+
+ if( thread->priority < Cyg_Scheduler::get_current_thread()->priority )
+ set_need_reschedule();
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_Scheduler_Implementation::rem_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( thread_table[thread->priority] == thread,
+ "Invalid thread priority" );
+
+ CYG_ASSERT( (run_queue & (1<<thread->priority)) != 0,
+ "Run queue bit not set" );
+
+ run_queue &= ~(1<<thread->priority);
+
+ if( thread == Cyg_Scheduler::get_current_thread() )
+ set_need_reschedule();
+}
+
+// -------------------------------------------------------------------------
+// Set up initial idle thread
+
+void Cyg_Scheduler_Implementation::set_idle_thread( Cyg_Thread *thread, HAL_SMP_CPU_TYPE cpu )
+{
+ CYG_REPORT_FUNCTION();
+
+ // Make the thread the current thread for this CPU.
+
+ current_thread[cpu] = thread;
+
+ // This will insert the thread in the run queues and make it
+ // available to execute.
+ thread->resume();
+}
+
+// -------------------------------------------------------------------------
+// register thread with scheduler
+
+void Cyg_Scheduler_Implementation::register_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ thread_table[thread->priority] = thread;
+}
+
+// -------------------------------------------------------------------------
+
+// deregister thread
+void Cyg_Scheduler_Implementation::deregister_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ thread_table[thread->priority] = NULL;
+}
+
+// -------------------------------------------------------------------------
+// Test the given priority for uniqueness
+
+cyg_bool Cyg_Scheduler_Implementation::unique( cyg_priority priority)
+{
+ CYG_REPORT_FUNCTION();
+
+ return thread_table[priority] == NULL;
+}
+
+
+//==========================================================================
+// Cyg_Cyg_SchedThread_Implementation class members
+
+Cyg_SchedThread_Implementation::Cyg_SchedThread_Implementation
+(
+ CYG_ADDRWORD sched_info
+)
+{
+ CYG_REPORT_FUNCTION();
+
+#if 1
+ // Assign this thread's priority to the supplied sched_info
+ // or the next highest priority available.
+
+ priority = cyg_priority(sched_info);
+
+ while( !Cyg_Scheduler::scheduler.unique(priority) )
+ priority++;
+
+#else
+ // Assign initial priorities to threads in descending order of
+ // creation.
+
+ static cyg_priority init_priority = 0;
+
+ priority = init_priority++;
+#endif
+
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_SchedThread_Implementation::yield()
+{
+ CYG_REPORT_FUNCTION();
+
+ // We cannot yield in this scheduler
+}
+
+//==========================================================================
+// Cyg_ThreadQueue_Implementation class members
+
+Cyg_ThreadQueue_Implementation::Cyg_ThreadQueue_Implementation()
+{
+ CYG_REPORT_FUNCTION();
+
+ wait_queue = 0; // empty queue
+
+ CYG_REPORT_RETURN();
+}
+
+
+void Cyg_ThreadQueue_Implementation::enqueue(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ wait_queue |= 1<<thread->priority;
+ thread->queue = CYG_CLASSFROMBASE(Cyg_ThreadQueue,
+ Cyg_ThreadQueue_Implementation,
+ this);
+}
+
+// -------------------------------------------------------------------------
+
+Cyg_Thread *Cyg_ThreadQueue_Implementation::dequeue()
+{
+ CYG_REPORT_FUNCTION();
+
+ // Isolate ls bit in run_queue.
+ cyg_sched_bitmap next_thread = wait_queue & -wait_queue;
+
+ if( next_thread == 0 ) return NULL;
+
+ wait_queue &= ~next_thread;
+
+ cyg_uint32 index;
+
+ HAL_LSBIT_INDEX(index, next_thread);
+
+ Cyg_Thread *thread = Cyg_Scheduler::scheduler.thread_table[index];
+
+ thread->queue = NULL;
+
+ return thread;
+}
+
+// -------------------------------------------------------------------------
+
+Cyg_Thread *Cyg_ThreadQueue_Implementation::highpri()
+{
+ CYG_REPORT_FUNCTION();
+
+ // Isolate ls bit in run_queue.
+ cyg_sched_bitmap next_thread = wait_queue & -wait_queue;
+
+ if( next_thread == 0 ) return NULL;
+
+ cyg_uint32 index;
+
+ HAL_LSBIT_INDEX(index, next_thread);
+
+ return Cyg_Scheduler::scheduler.thread_table[index];
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_ThreadQueue_Implementation::remove(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ wait_queue &= ~(1<<thread->priority);
+ thread->queue = NULL;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// EOF sched/bitmap.cxx
diff --git a/ecos/packages/kernel/current/src/sched/lottery.cxx b/ecos/packages/kernel/current/src/sched/lottery.cxx
new file mode 100644
index 0000000000..128f189e47
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sched/lottery.cxx
@@ -0,0 +1,456 @@
+//==========================================================================
+//
+// sched/lottery.cxx
+//
+// Lottery scheduler class implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-16
+// Purpose: Lottery scheduler class implementation
+// Description: This file contains the implementations of
+// Cyg_Scheduler_Implementation and
+// Cyg_SchedThread_Implementation.
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <cyg/kernel/sched.hxx> // our header
+#include <cyg/kernel/intr.hxx> // interrupt defines, for Cyg_HAL_Clock
+
+#include <cyg/hal/hal_arch.h> // Architecture specific definitions
+
+
+#include <cyg/kernel/thread.inl> // thread inlines
+#include <cyg/kernel/sched.inl> // scheduler inlines
+
+#ifdef CYGSEM_KERNEL_SCHED_LOTTERY
+
+#define CYG_ENABLE_TRACE 1
+
+//==========================================================================
+// Cyg_Scheduler_Implementation class static members
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+cyg_count32 Cyg_Scheduler_Implementation::timeslice_count =
+ CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
+
+#endif
+
+//==========================================================================
+// Cyg_Scheduler_Implementation class members
+
+// -------------------------------------------------------------------------
+// Constructor.
+
+Cyg_Scheduler_Implementation::Cyg_Scheduler_Implementation()
+{
+ CYG_REPORT_FUNCTION();
+
+ total_tickets = 0;
+ rand_seed = 1;
+}
+
+// -------------------------------------------------------------------------
+// Choose the best thread to run next
+
+Cyg_Thread *Cyg_Scheduler_Implementation::schedule()
+{
+ CYG_REPORT_FUNCTION();
+
+#ifdef CYGPKG_HAL_POWERPC
+
+ // PowerPc specific version of random number generator.
+ register cyg_int32 r1 asm("r4");
+ r1 = rand_seed;
+ asm(
+ "li 7,0;"
+ "ori 7,7,33614;"
+ "mulhwu 5,7,%0;"
+ "mullw 6,7,%0;"
+ "srawi 6,6,1;"
+ "add %0,5,6;"
+ "cmpwi %0,0;"
+ "bge 1f;"
+ "slwi %0,%0,1;"
+ "srwi %0,%0,1;"
+ "addi %0,%0,1;"
+ "1:;"
+ : "=r"(r1)
+ : "0"(r1)
+ : "r5", "r6", "r7"
+ );
+ rand_seed = r1;
+
+#else
+#if 1
+ rand_seed = (rand_seed * 1103515245) + 1234;
+ cyg_int32 r1 = rand_seed & 0x7FFFFFFF;
+#else
+ // Generic implementation of RNG.
+#if( CYG_BYTEORDER == CYG_MSBFIRST )
+#define _LO 1
+#define _HI 0
+#else
+#define _LO 0
+#define _HI 1
+#endif
+ union { cyg_int64 r64; cyg_int32 r32[2]; } u;
+ u.r64 = (cyg_int64)rand_seed * 33614LL;
+ cyg_int32 r1 = u.r32[_HI] + (u.r32[_LO]>>1);
+ if( r1 < 0 )
+ r1 = (r1 & 0x7FFFFFFF) + 1;
+ rand_seed = r1;
+#undef _LO
+#undef _HI
+#endif
+#endif
+
+ cyg_int32 ticket = r1 % total_tickets;
+ cyg_int32 tick = ticket;
+ Cyg_Thread *thread = run_queue.highpri();
+
+ // Search the run queue for the thread with the
+ // given ticket.
+ while( ticket > 0 )
+ {
+ ticket -= thread->priority;
+ if( ticket <= 0 ) break;
+ thread = thread->next;
+
+ CYG_ASSERT( thread != run_queue.highpri(), "Looping in scheduler");
+ }
+
+ CYG_TRACE3( CYG_ENABLE_TRACE,
+ "seed %08x ticket %d thread %08x",
+ rand_seed, tick, thread);
+
+ // If the thread has any compensation tickets, take them away since
+ // it has just won.
+
+ if( thread->compensation_tickets > 0 )
+ {
+ thread->priority -= thread->compensation_tickets;
+ total_tickets -= thread->compensation_tickets;
+ thread->compensation_tickets = 0;
+ }
+
+ // Re-insert thread at head of list. This reduces runtime by
+ // putting the large ticket holders at the front of the list.
+
+// run_queue.remove(thread);
+// run_queue.enqueue(thread);
+
+ CYG_CHECK_DATA_PTR( thread, "Invalid next thread pointer");
+ CYG_ASSERTCLASS( thread, "Bad next thread" );
+
+ return thread;
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_Scheduler_Implementation::add_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ // If the thread is on some other queue, remove it
+ // here.
+ if( thread->queue != NULL )
+ {
+ thread->queue->remove(thread);
+ thread->queue = NULL;
+ }
+
+ total_tickets += thread->priority;
+
+ run_queue.enqueue(thread);
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_Scheduler_Implementation::rem_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ run_queue.remove(thread);
+
+ total_tickets -= thread->priority;
+
+ // Compensate the thread for the segment of the quantum that
+ // it used. This makes it more likely to win the lottery next time
+ // it is scheduled. We only do this for threads that have voluntarily
+ // given up the CPU.
+
+// if( thread->get_state() != Cyg_Thread::RUNNING )
+ {
+#if 0
+ cyg_uint32 hal_ticks;
+ HAL_CLOCK_READ( &hal_ticks );
+ thread->compensation_tickets = thread->priority *
+ CYGNUM_KERNEL_COUNTERS_RTC_PERIOD / hal_ticks;
+#else
+ thread->compensation_tickets = (thread->priority *
+ CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS) / timeslice_count;
+
+#endif
+ thread->priority += thread->compensation_tickets;
+ }
+}
+
+// -------------------------------------------------------------------------
+// register thread with scheduler
+
+void Cyg_Scheduler_Implementation::register_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ // No registration necessary in this scheduler
+}
+
+// -------------------------------------------------------------------------
+
+// deregister thread
+void Cyg_Scheduler_Implementation::deregister_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ // No registration necessary in this scheduler
+}
+
+// -------------------------------------------------------------------------
+// Test the given priority for uniqueness
+
+cyg_bool Cyg_Scheduler_Implementation::unique( cyg_priority priority)
+{
+ CYG_REPORT_FUNCTION();
+
+ // Priorities are not unique
+ return true;
+}
+
+//==========================================================================
+// Support for timeslicing option
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+void Cyg_Scheduler_Implementation::timeslice()
+{
+ CYG_REPORT_FUNCTION();
+
+ if( --timeslice_count <= 0 )
+ {
+ CYG_INSTRUMENT_SCHED(TIMESLICE,0,0);
+
+ // Force a reschedule on each timeslice
+ need_reschedule = true;
+ timeslice_count = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
+ }
+}
+
+#endif
+
+//==========================================================================
+// Cyg_Cyg_SchedThread_Implementation class members
+
+Cyg_SchedThread_Implementation::Cyg_SchedThread_Implementation
+(
+ CYG_ADDRWORD sched_info
+)
+{
+ CYG_REPORT_FUNCTION();
+
+ priority = cyg_priority(sched_info);
+
+ // point the next and prev field at this thread.
+
+ next = prev = CYG_CLASSFROMBASE(Cyg_Thread,
+ Cyg_SchedThread_Implementation,
+ this);
+}
+
+// -------------------------------------------------------------------------
+// Insert thread in front of this
+
+void Cyg_SchedThread_Implementation::insert( Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ thread->next = CYG_CLASSFROMBASE(Cyg_Thread,
+ Cyg_SchedThread_Implementation,
+ this);
+ thread->prev = prev;
+ prev->next = thread;
+ prev = thread;
+}
+
+// -------------------------------------------------------------------------
+// remove this from queue
+
+void Cyg_SchedThread_Implementation::remove()
+{
+ CYG_REPORT_FUNCTION();
+
+ next->prev = prev;
+ prev->next = next;
+ next = prev = CYG_CLASSFROMBASE(Cyg_Thread,
+ Cyg_SchedThread_Implementation,
+ this);
+}
+
+// -------------------------------------------------------------------------
+// Yield the processor to another thread
+
+void Cyg_SchedThread_Implementation::yield()
+{
+ CYG_REPORT_FUNCTION();
+
+
+}
+
+//==========================================================================
+// Cyg_ThreadQueue_Implementation class members
+
+void Cyg_ThreadQueue_Implementation::enqueue(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ // Always put thread at head of queue
+ if( queue == NULL ) queue = thread;
+ else
+ {
+ queue->insert(thread);
+// queue->next->insert(thread);
+// queue = thread;
+ }
+
+ thread->queue = CYG_CLASSFROMBASE(Cyg_ThreadQueue,
+ Cyg_ThreadQueue_Implementation,
+ this);
+}
+
+// -------------------------------------------------------------------------
+
+Cyg_Thread *Cyg_ThreadQueue_Implementation::dequeue()
+{
+ CYG_REPORT_FUNCTION();
+
+ if( queue == NULL ) return NULL;
+
+ Cyg_Thread *thread = queue;
+
+ if( thread->next == thread )
+ {
+ // sole thread on list, NULL out ptr
+ queue = NULL;
+ }
+ else
+ {
+ // advance to next and remove thread
+ queue = thread->next;
+ thread->remove();
+ }
+
+ thread->queue = NULL;
+
+ return thread;
+}
+
+// -------------------------------------------------------------------------
+
+Cyg_Thread *Cyg_ThreadQueue_Implementation::highpri()
+{
+ CYG_REPORT_FUNCTION();
+
+ return queue;
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_ThreadQueue_Implementation::remove(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ // If the thread we want is the at the head
+ // of the list, and is on its own, clear the
+ // list and return. Otherwise advance to the
+ // next thread and remove ours. If the thread
+ // is not at the head of the list, just dequeue
+ // it.
+
+ thread->queue = NULL;
+
+ if( queue == thread )
+ {
+ if( thread->next == thread )
+ {
+ queue = NULL;
+ return;
+ }
+ else queue = thread->next;
+ }
+
+ thread->Cyg_SchedThread_Implementation::remove();
+
+}
+
+// -------------------------------------------------------------------------
+// Rotate the front thread on the queue to the back.
+
+void Cyg_ThreadQueue_Implementation::rotate()
+{
+ CYG_REPORT_FUNCTION();
+
+ queue = queue->next;
+}
+
+// -------------------------------------------------------------------------
+
+#endif
+
+// -------------------------------------------------------------------------
+// EOF sched/lottery.cxx
diff --git a/ecos/packages/kernel/current/src/sched/mlqueue.cxx b/ecos/packages/kernel/current/src/sched/mlqueue.cxx
new file mode 100644
index 0000000000..8acadf76a3
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sched/mlqueue.cxx
@@ -0,0 +1,885 @@
+//==========================================================================
+//
+// sched/mlqueue.cxx
+//
+// Multi-level queue scheduler class implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: jlarmour
+// Date: 1999-02-17
+// Purpose: Multilevel queue scheduler class implementation
+// Description: This file contains the implementations of
+// Cyg_Scheduler_Implementation and
+// Cyg_SchedThread_Implementation.
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <cyg/kernel/sched.hxx> // our header
+
+#include <cyg/hal/hal_arch.h> // Architecture specific definitions
+
+#include <cyg/kernel/thread.inl> // thread inlines
+#include <cyg/kernel/sched.inl> // scheduler inlines
+
+#ifdef CYGSEM_KERNEL_SCHED_MLQUEUE
+
+//==========================================================================
+// Cyg_Scheduler_Implementation class static members
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+cyg_ucount32 Cyg_Scheduler_Implementation::timeslice_count[CYGNUM_KERNEL_CPU_MAX];
+
+#endif
+
+
+//==========================================================================
+// Cyg_Scheduler_Implementation class members
+
+// -------------------------------------------------------------------------
+// Constructor.
+
+Cyg_Scheduler_Implementation::Cyg_Scheduler_Implementation()
+{
+ CYG_REPORT_FUNCTION();
+
+ queue_map = 0;
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ pending_map = 0;
+
+ for( int i = 0; i < CYGNUM_KERNEL_SCHED_PRIORITIES; i++ )
+ pending[i] = 0;
+
+#endif
+
+ for( int i = 0; i < CYGNUM_KERNEL_CPU_MAX; i++ )
+ {
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+ timeslice_count[i] = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
+#endif
+ need_reschedule[i] = true;
+ }
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Choose the best thread to run next
+
+Cyg_Thread *
+Cyg_Scheduler_Implementation::schedule(void)
+{
+ CYG_REPORT_FUNCTYPE("returning thread %08x");
+
+ // The run queue may _never_ be empty, there is always
+ // an idle thread at the lowest priority.
+
+ CYG_ASSERT( queue_map != 0, "Run queue empty");
+ CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
+ CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ Cyg_Thread *current = get_current_thread();
+ register cyg_uint32 index;
+
+ CYG_ASSERT( current->cpu != CYG_KERNEL_CPU_NONE, "Current thread does not have CPU set!");
+
+ // If the current thread is still runnable, return it to pending
+ // state so that it can be considered alongside any other threads
+ // for execution.
+ if( current->get_state() == Cyg_Thread::RUNNING )
+ {
+ current->cpu = CYG_KERNEL_CPU_NONE;
+ pending[current->priority]++;
+ pending_map |= (1<<current->priority);
+ }
+ else
+ {
+ // Otherwise, ensure that the thread is no longer marked as
+ // running.
+ current->cpu = CYG_KERNEL_CPU_NONE;
+ }
+
+
+ HAL_LSBIT_INDEX(index, pending_map);
+
+ Cyg_RunQueue *queue = &run_queue[index];
+
+ CYG_ASSERT( !queue->empty(), "Queue for index empty");
+ CYG_ASSERT( pending[index] > 0, "Pending array and map disagree");
+
+ Cyg_Thread *thread = queue->get_head();
+
+ // We know there is a runnable thread in this queue, If the thread
+ // we got is not it, scan until we find it. While not constant time,
+ // this search has an upper bound of the number of CPUs in the system.
+
+ while( thread->cpu != CYG_KERNEL_CPU_NONE )
+ thread = thread->get_next();
+
+ // Take newly scheduled thread out of pending map
+ thread->cpu = CYG_KERNEL_CPU_THIS();
+ if( --pending[index] == 0 )
+ pending_map &= ~(1<<index);
+
+#else
+
+ register cyg_uint32 index;
+
+ HAL_LSBIT_INDEX(index, queue_map);
+
+ Cyg_RunQueue *queue = &run_queue[index];
+
+ CYG_ASSERT( !queue->empty(), "Queue for index empty");
+
+ Cyg_Thread *thread = queue->get_head();
+
+#endif
+
+ CYG_INSTRUMENT_MLQ( SCHEDULE, thread, index);
+
+ CYG_ASSERT( thread != NULL , "No threads in run queue");
+ CYG_ASSERT( thread->queue == NULL , "Runnable thread on a queue!");
+
+ CYG_REPORT_RETVAL(thread);
+
+ return thread;
+}
+
+// -------------------------------------------------------------------------
+
+void
+Cyg_Scheduler_Implementation::add_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("thread=%08x", thread);
+
+ cyg_priority pri = thread->priority;
+ Cyg_RunQueue *queue = &run_queue[pri];
+
+ CYG_INSTRUMENT_MLQ( ADD, thread, pri);
+
+ CYG_ASSERT((CYG_THREAD_MIN_PRIORITY >= pri)
+ && (CYG_THREAD_MAX_PRIORITY <= pri),
+ "Priority out of range!");
+
+ CYG_ASSERT( ((queue_map & (1<<pri))!=0) == ((!run_queue[pri].empty())!=0), "Map and queue disagree");
+
+ // If the thread is on some other queue, remove it
+ // here.
+ if( thread->queue != NULL )
+ {
+ thread->queue->remove(thread);
+ }
+
+ if( queue->empty() )
+ {
+ // set the map bit and ask for a reschedule if this is a
+ // new highest priority thread.
+
+ queue_map |= (1<<pri);
+
+ }
+ // else the queue already has an occupant, queue behind him
+
+ queue->add_tail(thread);
+
+ // If the new thread is higher priority than any
+ // current thread, request a reschedule.
+
+ set_need_reschedule(thread);
+
+#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
+ // pending map.
+
+ if( thread->cpu == CYG_KERNEL_CPU_NONE )
+ {
+ if( pending[pri]++ == 0 )
+ pending_map |= (1<<pri);
+ }
+ // Otherwise the pending count will be dealt with in schedule().
+
+#endif
+
+ CYG_ASSERT( thread->queue == NULL , "Runnable thread on a queue!");
+ CYG_ASSERT( queue_map != 0, "Run queue empty");
+ CYG_ASSERT( queue_map & (1<<pri), "Queue map bit not set for pri");
+ CYG_ASSERT( !run_queue[pri].empty(), "Queue for pri empty");
+ CYG_ASSERT( ((queue_map & (1<<pri))!=0) == ((!run_queue[pri].empty())!=0), "Map and queue disagree");
+ CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
+ CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+
+void
+Cyg_Scheduler_Implementation::rem_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("thread=%08x", thread);
+
+ CYG_ASSERT( queue_map != 0, "Run queue empty");
+
+ cyg_priority pri = thread->priority;
+ Cyg_RunQueue *queue = &run_queue[pri];
+
+ CYG_INSTRUMENT_MLQ( REM, thread, pri);
+
+ CYG_ASSERT( pri != CYG_THREAD_MIN_PRIORITY, "Idle thread trying to sleep!");
+ CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ if( thread->cpu == CYG_KERNEL_CPU_NONE )
+ {
+ // If the thread is not running, then we need to adjust the
+ // pending count array and map if necessary.
+
+ if( --pending[pri] == 0 )
+ pending_map &= ~(1<<pri);
+ }
+ else
+ {
+ // If the target thread is currently running on a different
+ // CPU, send a reschedule interrupt there to deschedule it.
+ if( thread->cpu != CYG_KERNEL_CPU_THIS() )
+ CYG_KERNEL_CPU_RESCHEDULE_INTERRUPT( thread->cpu, 0 );
+ }
+ // If the thread is current running on this CPU, then the pending
+ // count will be dealt with in schedule().
+
+#endif
+
+ CYG_ASSERT( queue_map & (1<<pri), "Queue map bit not set for pri");
+ CYG_ASSERT( !run_queue[pri].empty(), "Queue for pri empty");
+
+ // remove thread from queue
+ queue->remove(thread);
+
+ if( queue->empty() )
+ {
+ // If this was only thread in
+ // queue, clear map.
+
+ queue_map &= ~(1<<pri);
+ }
+
+ CYG_ASSERT( queue_map != 0, "Run queue empty");
+ CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
+ CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
+ CYG_ASSERT( ((queue_map & (1<<pri))!=0) == ((!run_queue[pri].empty())!=0), "Map and queue disagree");
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Set the need_reschedule flag
+// This function overrides the definition in Cyg_Scheduler_Base and tests
+// for a reschedule condition based on the priorities of the given thread
+// and the current thread(s).
+
+void Cyg_Scheduler_Implementation::set_need_reschedule(Cyg_Thread *thread)
+{
+#ifndef CYGPKG_KERNEL_SMP_SUPPORT
+
+ if( current_thread[0]->priority > thread->priority ||
+ current_thread[0]->get_state() != Cyg_Thread::RUNNING )
+ need_reschedule[0] = true;
+
+#else
+
+ HAL_SMP_CPU_TYPE cpu_this = CYG_KERNEL_CPU_THIS();
+ HAL_SMP_CPU_TYPE cpu_count = CYG_KERNEL_CPU_COUNT();
+
+ // Start with current CPU. If we can do the job locally then
+ // that is most efficient. Only go on to other CPUs if that is
+ // not possible.
+
+ for(int i = 0; i < cpu_count; i++)
+ {
+ HAL_SMP_CPU_TYPE cpu =
+ HAL_SMP_CPU_COUNT2IDX ( (i + HAL_SMP_CPU_IDX2COUNT( cpu_this ) ) % cpu_count );
+
+ // If a CPU is not already marked for rescheduling, and its
+ // current thread is of lower priority than _thread_, then
+ // set its need_reschedule flag.
+
+ Cyg_Thread *cur = current_thread[cpu];
+
+ if( (!need_reschedule[cpu]) &&
+ (cur->priority > thread->priority)
+ )
+ {
+ need_reschedule[cpu] = true;
+
+ if( cpu != cpu_this )
+ {
+ // All processors other than this one need to be sent
+ // a reschedule interrupt.
+
+ CYG_INSTRUMENT_SMP( RESCHED_SEND, cpu, 0 );
+ CYG_KERNEL_CPU_RESCHEDULE_INTERRUPT( cpu, 0 );
+ }
+
+ // Having notionally rescheduled _thread_ onto the cpu, we
+ // now see if we can reschedule the former current thread of
+ // that CPU onto another.
+
+ thread = cur;
+ }
+ }
+
+#endif
+}
+
+// -------------------------------------------------------------------------
+// Set up initial idle thread
+
+void Cyg_Scheduler_Implementation::set_idle_thread( Cyg_Thread *thread, HAL_SMP_CPU_TYPE cpu )
+{
+ // Make the thread the current thread for this CPU.
+
+ current_thread[cpu] = thread;
+
+ // This will insert the thread in the run queues and make it
+ // available to execute.
+ thread->resume();
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ thread->cpu = cpu;
+
+ // In SMP, we need to take this thread out of the pending array
+ // and map.
+
+ cyg_priority pri = thread->priority;
+ if( --pending[pri] == 0 )
+ pending_map &= ~(1<<pri);
+#endif
+
+}
+
+// -------------------------------------------------------------------------
+// register thread with scheduler
+
+void
+Cyg_Scheduler_Implementation::register_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("thread=%08x", thread);
+ // No registration necessary in this scheduler
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+
+// deregister thread
+void
+Cyg_Scheduler_Implementation::deregister_thread(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("thread=%08x", thread);
+ // No registration necessary in this scheduler
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Test the given priority for uniqueness
+
+cyg_bool
+Cyg_Scheduler_Implementation::unique( cyg_priority priority)
+{
+ CYG_REPORT_FUNCTYPE("returning %d");
+ CYG_REPORT_FUNCARG1("priority=%d", priority);
+ // Priorities are not unique
+ CYG_REPORT_RETVAL(true);
+ return true;
+}
+
+//==========================================================================
+// Support for timeslicing option
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE
+
+// -------------------------------------------------------------------------
+
+void
+Cyg_Scheduler_Implementation::timeslice(void)
+{
+#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
+ CYG_REPORT_FUNCTION();
+#endif
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ int c;
+ HAL_SMP_CPU_TYPE cpu;
+ HAL_SMP_CPU_TYPE cpu_count = CYG_KERNEL_CPU_COUNT();
+ HAL_SMP_CPU_TYPE cpu_this = CYG_KERNEL_CPU_THIS();
+
+ for( c = 0; c < cpu_count; c++ )
+ {
+ cpu = HAL_SMP_CPU_COUNT2IDX(c);
+
+ if( --timeslice_count[cpu] == 0 )
+ if( cpu == cpu_this )
+ timeslice_cpu();
+ else CYG_KERNEL_CPU_TIMESLICE_INTERRUPT( cpu, 0 );
+ }
+
+#else
+
+ if( --timeslice_count[CYG_KERNEL_CPU_THIS()] == 0 )
+ timeslice_cpu();
+
+#endif
+
+#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
+ CYG_REPORT_RETURN();
+#endif
+}
+
+// -------------------------------------------------------------------------
+
+void
+Cyg_Scheduler_Implementation::timeslice_cpu(void)
+{
+#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
+ CYG_REPORT_FUNCTION();
+#endif
+
+ Cyg_Thread *thread = get_current_thread();
+ HAL_SMP_CPU_TYPE cpu_this = CYG_KERNEL_CPU_THIS();
+
+ CYG_ASSERT( queue_map != 0, "Run queue empty");
+ CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
+ if( thread->timeslice_enabled &&
+ timeslice_count[cpu_this] == 0 )
+#else
+ if( timeslice_count[cpu_this] == 0 )
+#endif
+ {
+ CYG_INSTRUMENT_SCHED(TIMESLICE,0,0);
+#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
+ CYG_TRACE0( true, "quantum consumed, time to reschedule" );
+#endif
+
+ CYG_ASSERT( get_sched_lock() > 0 , "Timeslice called with zero sched_lock");
+
+ // Only try to rotate the run queue if the current thread is running.
+ // Otherwise we are going to reschedule anyway.
+ if( thread->get_state() == Cyg_Thread::RUNNING )
+ {
+ Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
+
+ CYG_INSTRUMENT_MLQ( TIMESLICE, thread, 0);
+
+ CYG_ASSERTCLASS( thread, "Bad current thread");
+ CYG_ASSERTCLASS( sched, "Bad scheduler");
+
+ cyg_priority pri = thread->priority;
+ Cyg_RunQueue *queue = &sched->run_queue[pri];
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ // In SMP systems we set the head of the queue to point to
+ // the thread immediately after the current
+ // thread. schedule() will then pick that thread, or one
+ // after it to run next.
+
+ queue->to_head( thread->get_next() );
+#else
+ queue->rotate();
+#endif
+
+ if( queue->get_head() != thread )
+ sched->set_need_reschedule();
+
+ timeslice_count[cpu_this] = CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS;
+ }
+ }
+
+
+ CYG_ASSERT( queue_map & (1<<CYG_THREAD_MIN_PRIORITY), "Idle thread vanished!!!");
+ CYG_ASSERT( !run_queue[CYG_THREAD_MIN_PRIORITY].empty(), "Idle thread vanished!!!");
+#ifdef CYGDBG_KERNEL_TRACE_TIMESLICE
+ CYG_REPORT_RETURN();
+#endif
+}
+
+// -------------------------------------------------------------------------
+
+__externC void cyg_scheduler_timeslice_cpu(void)
+{
+ Cyg_Scheduler::scheduler.timeslice_cpu();
+}
+
+#endif
+
+//==========================================================================
+// Cyg_SchedThread_Implementation class members
+
+Cyg_SchedThread_Implementation::Cyg_SchedThread_Implementation
+(
+ CYG_ADDRWORD sched_info
+)
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("sched_info=%08x", sched_info);
+
+ // Set priority to the supplied value.
+ priority = (cyg_priority)sched_info;
+
+#ifdef CYGSEM_KERNEL_SCHED_TIMESLICE_ENABLE
+ // If timeslice_enabled exists, set it true by default
+ timeslice_enabled = true;
+#endif
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+ cpu = CYG_KERNEL_CPU_NONE;
+#endif
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Yield the processor to another thread
+
+void
+Cyg_SchedThread_Implementation::yield(void)
+{
+ CYG_REPORT_FUNCTION();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ Cyg_Thread *thread = CYG_CLASSFROMBASE(Cyg_Thread,
+ Cyg_SchedThread_Implementation,
+ this);
+
+ // Only do this if this thread is running. If it is not, there
+ // is no point.
+
+ if( thread->get_state() == Cyg_Thread::RUNNING )
+ {
+ // To yield we simply rotate the appropriate
+ // run queue to the next thread and reschedule.
+
+ CYG_INSTRUMENT_MLQ( YIELD, thread, 0);
+
+ CYG_ASSERTCLASS( thread, "Bad current thread");
+
+ Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
+
+ CYG_ASSERTCLASS( sched, "Bad scheduler");
+
+ cyg_priority pri = thread->priority;
+ Cyg_RunQueue *queue = &sched->run_queue[pri];
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ // In SMP systems we set the head of the queue to point to
+ // the thread immediately after the current
+ // thread. schedule() will then pick that thread, or one
+ // after it to run next.
+
+ queue->to_head( thread->get_next() );
+#else
+ queue->rotate();
+#endif
+
+ if( queue->get_head() != thread )
+ sched->set_need_reschedule();
+
+#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
+ // need_reschedule was not set above.
+ if( !Cyg_Scheduler::get_need_reschedule() )
+ Cyg_Scheduler::unlock();
+ else
+#endif
+ Cyg_Scheduler::unlock_reschedule();
+
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Rotate the run queue at a specified priority.
+// (pri is the decider, not this, so the routine is static)
+
+void
+Cyg_SchedThread_Implementation::rotate_queue( cyg_priority pri )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("priority=%d", pri);
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
+
+ CYG_ASSERTCLASS( sched, "Bad scheduler");
+
+ Cyg_RunQueue *queue = &sched->run_queue[pri];
+
+ if ( !queue->empty() ) {
+ queue->rotate();
+ sched->set_need_reschedule();
+ }
+
+ // Unlock the scheduler and switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Move this thread to the head of its queue
+// (not necessarily a scheduler queue)
+
+void
+Cyg_SchedThread_Implementation::to_queue_head( void )
+{
+ CYG_REPORT_FUNCTION();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ Cyg_Thread *thread = CYG_CLASSFROMBASE(Cyg_Thread,
+ Cyg_SchedThread_Implementation,
+ this);
+
+ CYG_ASSERTCLASS( thread, "Bad current thread");
+
+ Cyg_ThreadQueue *q = thread->get_current_queue();
+ if( q != NULL )
+ q->to_head( thread );
+ else if( thread->in_list() )
+ {
+ // If the queue pointer is NULL then it is on a run
+ // queue. Move the thread to the head of it's priority list
+ // and force a reschedule.
+
+ Cyg_Scheduler *sched = &Cyg_Scheduler::scheduler;
+ sched->run_queue[thread->priority].to_head( thread );
+ sched->set_need_reschedule( thread );
+ }
+
+ // Unlock the scheduler and switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+//==========================================================================
+// Cyg_ThreadQueue_Implementation class members
+
+// -------------------------------------------------------------------------
+
+void
+Cyg_ThreadQueue_Implementation::enqueue(Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("thread=%08x", thread);
+
+ CYG_INSTRUMENT_MLQ( ENQUEUE, this, thread );
+
+#ifdef CYGIMP_KERNEL_SCHED_SORTED_QUEUES
+
+ // Insert the thread into the queue in priority order.
+
+ Cyg_Thread *qhead = get_head();
+
+ if( qhead == NULL ) add_tail( thread );
+ else if( qhead == qhead->get_next() )
+ {
+ // There is currently only one thread in the queue, join it
+ // and adjust the queue pointer to point to the highest
+ // priority of the two. If they are the same priority,
+ // leave the pointer pointing to the oldest.
+
+ qhead->insert( thread );
+
+ if( thread->priority < qhead->priority )
+ to_head(thread);
+ }
+ else
+ {
+ // There is more than one thread in the queue. First check
+ // whether we are of higher priority than the head and if
+ // so just jump in at the front. Also check whether we are
+ // lower priority than the tail and jump onto the end.
+ // Otherwise we really have to search the queue to find
+ // our place.
+
+ if( thread->priority < qhead->priority )
+ {
+ qhead->insert( thread );
+ to_head(thread);
+ }
+ else if( thread->priority > get_tail()->priority )
+ {
+ // We are lower priority than any thread in the queue,
+ // go in at the end.
+
+ add_tail( thread );
+ }
+ else
+ {
+ // Search the queue. We do this backwards so that we
+ // always add new threads after any that have the same
+ // priority.
+
+ // Because of the previous tests we know that this
+ // search will terminate before we hit the head of the
+ // queue, hence we do not need to check for that
+ // condition.
+
+ Cyg_Thread *qtmp = get_tail();
+
+ // Scan the queue until we find a higher or equal
+ // priority thread.
+
+ while( qtmp->priority > thread->priority )
+ qtmp = qtmp->get_prev();
+
+ // Append ourself after the node pointed to by qtmp.
+
+ qtmp->append( thread );
+ }
+ }
+#else
+ // Just add the thread to the tail of the list
+ add_tail( thread );
+#endif
+
+ thread->queue = CYG_CLASSFROMBASE(Cyg_ThreadQueue,
+ Cyg_ThreadQueue_Implementation,
+ this);
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+
+Cyg_Thread *
+Cyg_ThreadQueue_Implementation::dequeue(void)
+{
+ CYG_REPORT_FUNCTYPE("returning thread %08x");
+
+ Cyg_Thread *thread = rem_head();
+
+ CYG_INSTRUMENT_MLQ( DEQUEUE, this, thread );
+
+ if( thread != NULL )
+ thread->queue = NULL;
+
+ CYG_REPORT_RETVAL(thread);
+ return thread;
+}
+
+// -------------------------------------------------------------------------
+
+void
+Cyg_ThreadQueue_Implementation::remove( Cyg_Thread *thread )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_REPORT_FUNCARG1("thread=%08x", thread);
+
+ CYG_INSTRUMENT_MLQ( REMOVE, this, thread );
+
+ thread->queue = NULL;
+
+ Cyg_CList_T<Cyg_Thread>::remove( thread );
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+
+Cyg_Thread *
+Cyg_ThreadQueue_Implementation::highpri(void)
+{
+ CYG_REPORT_FUNCTYPE("returning thread %08x");
+ CYG_REPORT_RETVAL(get_head());
+ return get_head();
+}
+
+// -------------------------------------------------------------------------
+
+inline void
+Cyg_ThreadQueue_Implementation::set_thread_queue(Cyg_Thread *thread,
+ Cyg_ThreadQueue *tq )
+
+{
+ thread->queue = tq;
+}
+
+// -------------------------------------------------------------------------
+
+#endif
+
+// -------------------------------------------------------------------------
+// EOF sched/mlqueue.cxx
diff --git a/ecos/packages/kernel/current/src/sched/sched.cxx b/ecos/packages/kernel/current/src/sched/sched.cxx
new file mode 100644
index 0000000000..cf8249f941
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sched/sched.cxx
@@ -0,0 +1,741 @@
+//==========================================================================
+//
+// sched/sched.cxx
+//
+// Scheduler class implementations
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-15
+// Purpose: Scheduler class implementation
+// Description: This file contains the definitions of the scheduler class
+// member functions that are common to all scheduler
+// implementations.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/sched.hxx> // our header
+
+#include <cyg/kernel/thread.hxx> // thread classes
+#include <cyg/kernel/intr.hxx> // Interrupt interface
+
+#include <cyg/hal/hal_arch.h> // Architecture specific definitions
+
+#include <cyg/kernel/thread.inl> // thread inlines
+#include <cyg/kernel/sched.inl> // scheduler inlines
+
+//-------------------------------------------------------------------------
+// Some local tracing control - a default.
+#ifdef CYGDBG_USE_TRACING
+# if !defined( CYGDBG_INFRA_DEBUG_TRACE_ASSERT_SIMPLE ) && \
+ !defined( CYGDBG_INFRA_DEBUG_TRACE_ASSERT_FANCY )
+ // ie. not a tracing implementation that takes a long time to output
+
+# ifndef CYGDBG_KERNEL_TRACE_UNLOCK_INNER
+# define CYGDBG_KERNEL_TRACE_UNLOCK_INNER
+# endif // control not already defined
+
+# endif // trace implementation not ..._SIMPLE && not ..._FANCY
+#endif // CYGDBG_USE_TRACING
+
+// -------------------------------------------------------------------------
+// Static Cyg_Scheduler class members
+
+// We start with sched_lock at 1 so that any kernel code we
+// call during initialization will not try to reschedule.
+
+CYGIMP_KERNEL_SCHED_LOCK_DEFINITIONS;
+
+Cyg_Thread *volatile Cyg_Scheduler_Base::current_thread[CYGNUM_KERNEL_CPU_MAX];
+
+volatile cyg_bool Cyg_Scheduler_Base::need_reschedule[CYGNUM_KERNEL_CPU_MAX];
+
+Cyg_Scheduler Cyg_Scheduler::scheduler CYG_INIT_PRIORITY( SCHEDULER );
+
+volatile cyg_ucount32 Cyg_Scheduler_Base::thread_switches[CYGNUM_KERNEL_CPU_MAX];
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+CYG_BYTE cyg_sched_cpu_interrupt[CYGNUM_KERNEL_CPU_MAX][sizeof(Cyg_Interrupt)]
+ CYGBLD_ANNOTATE_VARIABLE_SCHED;
+
+__externC cyg_ISR cyg_hal_cpu_message_isr;
+__externC cyg_DSR cyg_hal_cpu_message_dsr;
+
+inline void *operator new(size_t size, void *ptr) { return ptr; };
+
+#endif
+
+// -------------------------------------------------------------------------
+// Scheduler unlock function.
+
+// This is only called when there is the potential for real work to be
+// done. Other cases are handled in Cyg_Scheduler::unlock() which is
+// an inline; _or_ this function may have been called from
+// Cyg_Scheduler::reschedule(), or Cyg_Scheduler::unlock_reschedule. The
+// new_lock argument contains the value that the scheduler lock should
+// have after this function has completed. If it is zero then the lock is
+// being released and some extra work (running ASRs, checking for DSRs) is
+// done before returning. If it is non-zero then it must equal the
+// current value of the lock, and is used to indicate that we want to
+// reacquire the scheduler lock before returning. This latter option
+// only makes any sense if the current thread is no longer runnable,
+// e.g. sleeping, otherwise this function will do nothing.
+// This approach of passing in the lock value at the end effectively
+// makes the scheduler lock a form of per-thread variable. Each call
+// to unlock_inner() carries with it the value the scheduler should
+// have when it reschedules this thread back, and leaves this function.
+// When it is non-zero, and the thread is rescheduled, no ASRS are run,
+// or DSRs processed. By doing this, it makes it possible for threads
+// that want to go to sleep to wake up with the scheduler lock in the
+// same state it was in before.
+
+void Cyg_Scheduler::unlock_inner( cyg_ucount32 new_lock )
+{
+#ifdef CYGDBG_KERNEL_TRACE_UNLOCK_INNER
+ CYG_REPORT_FUNCTION();
+#endif
+
+ do {
+
+ CYG_PRECONDITION( new_lock==0 ? get_sched_lock() == 1 :
+ ((get_sched_lock() == new_lock) || (get_sched_lock() == new_lock+1)),
+ "sched_lock not at expected value" );
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS
+
+ // Call any pending DSRs. Do this here to ensure that any
+ // threads that get awakened are properly scheduled.
+
+ if( new_lock == 0 && Cyg_Interrupt::DSRs_pending() )
+ Cyg_Interrupt::call_pending_DSRs();
+#endif
+
+ Cyg_Thread *current = get_current_thread();
+
+ CYG_ASSERTCLASS( current, "Bad current thread" );
+
+#ifdef CYGFUN_KERNEL_ALL_THREADS_STACK_CHECKING
+ // should have CYGVAR_KERNEL_THREADS_LIST
+ current = Cyg_Thread::get_list_head();
+ while ( current ) {
+ current->check_stack();
+ current = current->get_list_next();
+ }
+ current = get_current_thread();
+#endif
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
+ current->check_stack();
+#endif
+
+ // If the current thread is going to sleep, or someone
+ // wants a reschedule, choose another thread to run
+
+ if( current->state != Cyg_Thread::RUNNING || get_need_reschedule() ) {
+
+ CYG_INSTRUMENT_SCHED(RESCHEDULE,0,0);
+
+ // Get the next thread to run from scheduler
+ Cyg_Thread *next = scheduler.schedule();
+
+ CYG_CHECK_DATA_PTR( next, "Invalid next thread pointer");
+ CYG_ASSERTCLASS( next, "Bad next thread" );
+
+ if( current != next )
+ {
+
+ CYG_INSTRUMENT_THREAD(SWITCH,current,next);
+
+ // Count this thread switch
+ thread_switches[CYG_KERNEL_CPU_THIS()]++;
+
+#ifdef CYGFUN_KERNEL_THREADS_STACK_CHECKING
+ next->check_stack(); // before running it
+#endif
+
+ // Switch contexts
+ HAL_THREAD_SWITCH_CONTEXT( &current->stack_ptr,
+ &next->stack_ptr );
+
+ // Worry here about possible compiler
+ // optimizations across the above call that may try to
+ // propogate common subexpresions. We would end up
+ // with the expression from one thread in its
+ // successor. This is only a worry if we do not save
+ // and restore the complete register set. We need a
+ // way of marking functions that return into a
+ // different context. A temporary fix would be to
+ // disable CSE (-fdisable-cse) in the compiler.
+
+ // We return here only when the current thread is
+ // rescheduled. There is a bit of housekeeping to do
+ // here before we are allowed to go on our way.
+
+ 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
+
+ clear_need_reschedule(); // finished rescheduling
+ }
+
+ if( new_lock == 0 )
+ {
+
+#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
+
+ // Check whether the ASR is pending and not inhibited. If
+ // we can call it, then transfer this info to a local
+ // variable (call_asr) and clear the pending flag. Note
+ // that we only do this if the scheduler lock is about to
+ // be zeroed. In any other circumstance we are not
+ // unlocking.
+
+ cyg_bool call_asr = false;
+
+ if( (current->asr_inhibit == 0) && current->asr_pending )
+ {
+ call_asr = true;
+ current->asr_pending = false;
+ }
+#endif
+
+ HAL_REORDER_BARRIER(); // Make sure everything above has happened
+ // by this point
+ zero_sched_lock(); // Clear the lock
+ HAL_REORDER_BARRIER();
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS
+
+ // Now check whether any DSRs got posted during the thread
+ // switch and if so, go around again. Making this test after
+ // the lock has been zeroed avoids a race condition in which
+ // a DSR could have been posted during a reschedule, but would
+ // not be run until the _next_ time we release the sched lock.
+
+ if( Cyg_Interrupt::DSRs_pending() ) {
+ inc_sched_lock(); // reclaim the lock
+ continue; // go back to head of loop
+ }
+
+#endif
+ // Otherwise the lock is zero, we can return.
+
+// CYG_POSTCONDITION( get_sched_lock() == 0, "sched_lock not zero" );
+
+#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
+ // If the test within the sched_lock indicating that the ASR
+ // be called was true, call it here. Calling the ASR must be
+ // the very last thing we do here, since it must run as close
+ // to "user" state as possible.
+
+ if( call_asr ) current->asr(current->asr_data);
+#endif
+
+ }
+ else
+ {
+ // If new_lock is non-zero then we restore the sched_lock to
+ // the value given.
+
+ HAL_REORDER_BARRIER();
+
+ set_sched_lock(new_lock);
+
+ HAL_REORDER_BARRIER();
+ }
+
+#ifdef CYGDBG_KERNEL_TRACE_UNLOCK_INNER
+ CYG_REPORT_RETURN();
+#endif
+ return;
+
+ } while( 1 );
+
+ CYG_FAIL( "Should not be executed" );
+}
+
+// -------------------------------------------------------------------------
+// Start the scheduler. This is called after the initial threads have been
+// created to start scheduling. It gets any other CPUs running, and then
+// enters the scheduler.
+
+void Cyg_Scheduler::start()
+{
+ CYG_REPORT_FUNCTION();
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ HAL_SMP_CPU_TYPE cpu;
+
+ for( cpu = 0; cpu < CYG_KERNEL_CPU_START_COUNT(); cpu++ )
+ {
+ // Don't start this CPU, it is running already!
+ if( cpu == CYG_KERNEL_CPU_THIS() )
+ continue;
+
+ CYG_KERNEL_CPU_START( cpu );
+ }
+
+#endif
+
+ start_cpu();
+}
+
+// -------------------------------------------------------------------------
+// Start scheduling on this CPU. This is called on each CPU in the system
+// when it is started.
+
+void Cyg_Scheduler::start_cpu()
+{
+ CYG_REPORT_FUNCTION();
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+ // Set up the inter-CPU interrupt for this CPU
+
+ Cyg_Interrupt * intr = new( (void *)&cyg_sched_cpu_interrupt[HAL_SMP_CPU_THIS()] )
+ Cyg_Interrupt( CYGNUM_HAL_SMP_CPU_INTERRUPT_VECTOR( HAL_SMP_CPU_THIS() ),
+ 0,
+ 0,
+ cyg_hal_cpu_message_isr,
+ cyg_hal_cpu_message_dsr
+ );
+
+ intr->set_cpu( intr->get_vector(), HAL_SMP_CPU_THIS() );
+
+ intr->attach();
+
+ intr->unmask_interrupt( intr->get_vector() );
+
+#endif
+
+ // Get the first thread to run from scheduler
+ register Cyg_Thread *next = scheduler.schedule();
+
+ CYG_ASSERTCLASS( next, "Bad initial thread" );
+
+ clear_need_reschedule(); // finished rescheduling
+ set_current_thread(next); // restore current thread pointer
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+ // Reference the real time clock. This ensures that at least one
+ // reference to the kernel_clock.o object exists, without which
+ // the object will not be included while linking.
+ CYG_REFERENCE_OBJECT( Cyg_Clock::real_time_clock );
+#endif
+
+ // Load the first thread. This will also enable interrupts since
+ // the initial state of all threads is to have interrupts enabled.
+
+ HAL_THREAD_LOAD_CONTEXT( &next->stack_ptr );
+
+}
+
+// -------------------------------------------------------------------------
+// SMP support functions
+
+#ifdef CYGPKG_KERNEL_SMP_SUPPORT
+
+// This is called on each secondary CPU on its interrupt stack after
+// the initial CPU has initialized the world.
+
+externC void cyg_kernel_smp_startup()
+{
+ CYG_INSTRUMENT_SMP( CPU_START, CYG_KERNEL_CPU_THIS(), 0 );
+ Cyg_Scheduler::lock();
+ Cyg_Scheduler::start_cpu();
+}
+
+// This is called from the DSR of the inter-CPU interrupt to cause a
+// reschedule when the scheduler lock is zeroed.
+
+__externC void cyg_scheduler_set_need_reschedule()
+{
+ CYG_INSTRUMENT_SMP( RESCHED_RECV, 0, 0 );
+ Cyg_Scheduler::need_reschedule[HAL_SMP_CPU_THIS()] = true;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Consistency checker
+
+#ifdef CYGDBG_USE_ASSERTS
+
+cyg_bool Cyg_Scheduler::check_this( cyg_assert_class_zeal zeal) const
+{
+ CYG_REPORT_FUNCTION();
+
+ // check that we have a non-NULL pointer first
+ if( this == NULL ) return false;
+
+ switch( zeal )
+ {
+ case cyg_system_test:
+ case cyg_extreme:
+ case cyg_thorough:
+ if( !get_current_thread()->check_this(zeal) ) return false;
+ case cyg_quick:
+ case cyg_trivial:
+ case cyg_none:
+ default:
+ break;
+ };
+
+ return true;
+}
+
+#endif
+
+//==========================================================================
+// SchedThread members
+
+// -------------------------------------------------------------------------
+// Static data members
+
+#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
+
+# ifdef CYGSEM_KERNEL_SCHED_ASR_GLOBAL
+Cyg_ASR *Cyg_SchedThread::asr = &Cyg_SchedThread::asr_default;
+# endif
+
+# ifdef CYGSEM_KERNEL_SCHED_ASR_DATA_GLOBAL
+CYG_ADDRWORD Cyg_SchedThread::asr_data = 0;
+# endif
+
+#endif // CYGSEM_KERNEL_SCHED_ASR_SUPPORT
+
+// -------------------------------------------------------------------------
+// Constructor
+
+Cyg_SchedThread::Cyg_SchedThread(Cyg_Thread *thread, CYG_ADDRWORD sched_info)
+: Cyg_SchedThread_Implementation(sched_info)
+{
+ CYG_REPORT_FUNCTION();
+
+ queue = NULL;
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
+
+ mutex_count = 0;
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
+
+ priority_inherited = false;
+
+#endif
+#endif
+
+#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
+
+ asr_inhibit = 0;
+ asr_pending = false;
+
+#ifndef CYGSEM_KERNEL_SCHED_ASR_GLOBAL
+ asr = asr_default;
+#endif
+#ifdef CYGSEM_KERNEL_SCHED_ASR_DATA_GLOBAL
+ asr_data = NULL
+#endif
+
+#endif
+}
+
+// -------------------------------------------------------------------------
+// ASR support functions
+
+#ifdef CYGSEM_KERNEL_SCHED_ASR_SUPPORT
+
+// -------------------------------------------------------------------------
+// Set ASR
+// Install a new ASR, returning the old one.
+
+void Cyg_SchedThread::set_asr( Cyg_ASR *new_asr, CYG_ADDRWORD new_data,
+ Cyg_ASR **old_asr, CYG_ADDRWORD *old_data)
+{
+ CYG_REPORT_FUNCTION();
+
+ // Do this with the scheduler locked...
+ Cyg_Scheduler::lock();
+
+ if( old_asr != NULL ) *old_asr = asr;
+ if( old_data != NULL ) *old_data = asr_data;
+
+ // If new_asr is NULL, do not change the ASR,
+ // but only change the data.
+ if( new_asr != NULL ) asr = new_asr;
+ asr_data = new_data;
+
+ Cyg_Scheduler::unlock();
+}
+
+// -------------------------------------------------------------------------
+// Clear ASR
+
+void Cyg_SchedThread::clear_asr()
+{
+ CYG_REPORT_FUNCTION();
+
+ // Do this with the scheduler locked...
+ Cyg_Scheduler::lock();
+
+ // Reset ASR to default.
+ asr = asr_default;
+ asr_data = 0;
+
+ Cyg_Scheduler::unlock();
+}
+
+// -------------------------------------------------------------------------
+// Default ASR function.
+// having this avoids our having to worry about ever seeing a NULL
+// pointer as the ASR function.
+
+void Cyg_SchedThread::asr_default(CYG_ADDRWORD data)
+{
+ CYG_REPORT_FUNCTION();
+
+ data=data;
+ return;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Generic priority protocol support
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
+
+void Cyg_SchedThread::set_inherited_priority( cyg_priority pri, Cyg_Thread *thread )
+{
+ CYG_REPORT_FUNCTION();
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
+
+ // This is the comon code for priority inheritance and ceiling
+ // protocols. This implementation provides a simplified version of
+ // the protocol.
+
+ Cyg_Thread *self = CYG_CLASSFROMBASE(Cyg_Thread,
+ Cyg_SchedThread,
+ this);
+
+ CYG_ASSERT( mutex_count > 0, "Non-positive mutex count");
+
+ // Compare with *current* priority in case thread has already
+ // inherited - for relay case below.
+ if( pri < priority )
+ {
+ cyg_priority mypri = priority;
+ cyg_bool already_inherited = priority_inherited;
+
+ // If this is first inheritance, copy the old pri
+ // and set inherited flag. We clear it before setting the
+ // pri since set_priority() is inheritance aware.
+ // This is called with the sched locked, so no race conditions.
+
+ priority_inherited = false; // so that set_prio DTRT
+
+ self->set_priority( pri );
+
+ if( !already_inherited )
+ original_priority = mypri;
+
+ priority_inherited = true; // regardless, because it is now
+
+ }
+
+#endif
+}
+
+void Cyg_SchedThread::relay_inherited_priority( Cyg_Thread *ex_owner, Cyg_ThreadQueue *pqueue)
+{
+ CYG_REPORT_FUNCTION();
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
+
+ // A simple implementation of priority inheritance.
+ // At its simplest, this member does nothing.
+
+ // If there is anyone else waiting, then the *new* owner inherits from
+ // the current one, since that is a maxima of the others waiting.
+ // (It's worth not doing if there's nobody waiting to prevent
+ // unneccessary priority skew.) This could be viewed as a discovered
+ // priority ceiling.
+
+ if ( !pqueue->empty() )
+ set_inherited_priority( ex_owner->get_current_priority(), ex_owner );
+
+#endif
+}
+
+void Cyg_SchedThread::clear_inherited_priority()
+{
+ CYG_REPORT_FUNCTION();
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
+
+ // A simple implementation of priority inheritance/ceiling
+ // protocols. The simplification in this algorithm is that we do
+ // not reduce our priority until we have freed all mutexes
+ // claimed. Hence we can continue to run at an artificially high
+ // priority even when we should not. However, since nested
+ // mutexes are rare, the thread we have inherited from is likely
+ // to be locking the same mutexes we are, and mutex claim periods
+ // should be very short, the performance difference between this
+ // and a more complex algorithm should be negligible. The most
+ // important advantage of this algorithm is that it is fast and
+ // deterministic.
+
+ Cyg_Thread *self = CYG_CLASSFROMBASE(Cyg_Thread,
+ Cyg_SchedThread,
+ this);
+
+ CYG_ASSERT( mutex_count >= 0, "Non-positive mutex count");
+
+ if( mutex_count == 0 && priority_inherited )
+ {
+ priority_inherited = false;
+
+ // Only make an effort if the priority must change
+ if( priority < original_priority )
+ self->set_priority( original_priority );
+
+ }
+
+#endif
+}
+
+#endif // CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
+
+// -------------------------------------------------------------------------
+// Priority inheritance support.
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+
+// -------------------------------------------------------------------------
+// Inherit the priority of the provided thread if it
+// has a higher priority than ours.
+
+void Cyg_SchedThread::inherit_priority( Cyg_Thread *thread)
+{
+ CYG_REPORT_FUNCTION();
+
+ Cyg_Thread *self = CYG_CLASSFROMBASE(Cyg_Thread,
+ Cyg_SchedThread,
+ this);
+
+ CYG_ASSERT( mutex_count > 0, "Non-positive mutex count");
+ CYG_ASSERT( self != thread, "Trying to inherit from self!");
+
+ self->set_inherited_priority( thread->get_current_priority(), thread );
+
+}
+
+// -------------------------------------------------------------------------
+// Inherit the priority of the ex-owner thread or from the queue if it
+// has a higher priority than ours.
+
+void Cyg_SchedThread::relay_priority( Cyg_Thread *ex_owner, Cyg_ThreadQueue *pqueue)
+{
+ CYG_REPORT_FUNCTION();
+
+ relay_inherited_priority( ex_owner, pqueue );
+}
+
+// -------------------------------------------------------------------------
+// Lose a priority inheritance
+
+void Cyg_SchedThread::disinherit_priority()
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( mutex_count >= 0, "Non-positive mutex count");
+
+ clear_inherited_priority();
+}
+
+#endif // CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+
+// -------------------------------------------------------------------------
+// Priority ceiling support
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+
+void Cyg_SchedThread::set_priority_ceiling( cyg_priority pri )
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( mutex_count > 0, "Non-positive mutex count");
+
+ set_inherited_priority( pri );
+
+}
+
+void Cyg_SchedThread::clear_priority_ceiling( )
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( mutex_count >= 0, "Non-positive mutex count");
+
+ clear_inherited_priority();
+}
+
+#endif // CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+
+// -------------------------------------------------------------------------
+// EOF sched/sched.cxx
diff --git a/ecos/packages/kernel/current/src/sync/bin_sem.cxx b/ecos/packages/kernel/current/src/sync/bin_sem.cxx
new file mode 100644
index 0000000000..cfba947b33
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sync/bin_sem.cxx
@@ -0,0 +1,276 @@
+//==========================================================================
+//
+// sync/bin_sem.cxx
+//
+// Binary semaphore implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-24
+// Purpose: Cyg_Binary_Semaphore implementation
+// Description: This file contains the implementations of the binary semaphore
+// class.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/thread.inl> // Cyg_Thread inlines
+
+#include <cyg/kernel/sema.hxx> // our header
+
+#include <cyg/kernel/sched.inl> // scheduler inlines
+
+// -------------------------------------------------------------------------
+
+Cyg_Binary_Semaphore::Cyg_Binary_Semaphore (
+ cyg_bool init_state
+)
+{
+ state = init_state;
+}
+
+// -------------------------------------------------------------------------
+
+Cyg_Binary_Semaphore::~Cyg_Binary_Semaphore ( )
+{
+ CYG_ASSERT( queue.empty(), "Destroying semaphore with waiting threads");
+}
+
+// -------------------------------------------------------------------------
+
+cyg_bool Cyg_Binary_Semaphore::wait()
+{
+ cyg_bool result = true;
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_BINSEM( CLAIM, this, state );
+
+ while( !state && result )
+ {
+ self->set_sleep_reason( Cyg_Thread::WAIT );
+
+ self->sleep();
+
+ queue.enqueue( self );
+
+ CYG_INSTRUMENT_BINSEM( WAIT, this, 0 );
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_INSTRUMENT_BINSEM( WOKE, this, state );
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ if( result ) state = false;
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Wait until the state can be set false or timeout
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+cyg_bool
+Cyg_Binary_Semaphore::wait( cyg_tick_count timeout )
+{
+ cyg_bool result = true;
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_BINSEM( CLAIM, this, state );
+
+ // Set the timer _once_ outside the loop.
+ self->set_timer( timeout, Cyg_Thread::TIMEOUT );
+
+ // If the timeout is in the past, the wake reason will have been
+ // set to something other than NONE already. If the semaphore is
+ // not available, set the result false to force an immediate
+ // return. If it is available, then go ahead and claim it.
+
+ if( self->get_wake_reason() != Cyg_Thread::NONE && !state )
+ result = false;
+
+ while ( !state && result ) {
+
+ // must reset the sleep reason every time
+ self->set_sleep_reason( Cyg_Thread::TIMEOUT );
+
+ self->sleep();
+
+ queue.enqueue( self );
+
+ CYG_INSTRUMENT_BINSEM( WAIT, this, 0 );
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_INSTRUMENT_BINSEM( WOKE, this, state );
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::TIMEOUT:
+ result = false;
+ CYG_INSTRUMENT_BINSEM( TIMEOUT, this, state);
+ break;
+
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Clear the timeout. It is irrelevant whether the alarm has
+ // actually gone off or not.
+ self->clear_timer();
+
+ if( result ) state = false;
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ return result;
+}
+
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+
+// -------------------------------------------------------------------------
+
+cyg_bool Cyg_Binary_Semaphore::trywait()
+{
+ cyg_bool result = true;
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ if( state ) state = false;
+ else result = false;
+
+ CYG_INSTRUMENT_BINSEM( TRY, this, result );
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ return result;
+}
+
+// -------------------------------------------------------------------------
+
+void Cyg_Binary_Semaphore::post()
+{
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_BINSEM( POST, this, 0 );
+
+ state = true;
+
+ if( !queue.empty() ) {
+
+ // The queue is non-empty, so grab the next
+ // thread from it and wake it up. The waiter
+ // will clear the flag.
+
+ Cyg_Thread *thread = queue.dequeue();
+
+ thread->set_wake_reason( Cyg_Thread::DONE );
+
+ thread->wake();
+
+ CYG_INSTRUMENT_BINSEM( WAKE, this, thread );
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+}
+
+// -------------------------------------------------------------------------
+
+cyg_bool Cyg_Binary_Semaphore::posted()
+{
+ // This is a single read of the value of state.
+ // This is already atomic, hence there is no need
+ // to lock the scheduler.
+
+ return state;
+}
+
+// -------------------------------------------------------------------------
+// EOF sync/bin_sem.cxx
diff --git a/ecos/packages/kernel/current/src/sync/cnt_sem.cxx b/ecos/packages/kernel/current/src/sync/cnt_sem.cxx
new file mode 100644
index 0000000000..b418d0aee1
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sync/cnt_sem.cxx
@@ -0,0 +1,283 @@
+//==========================================================================
+//
+// sync/cnt_sem.cxx
+//
+// Counting semaphore implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-24
+// Purpose: Cyg_Counting_Semaphore implementation
+// Description: This file contains the implementations of the counting semaphore
+// class.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/thread.inl> // Cyg_Thread inlines
+
+#include <cyg/kernel/sema.hxx> // our header
+
+#include <cyg/kernel/sched.inl> // scheduler inlines
+
+// -------------------------------------------------------------------------
+// Constructor
+
+Cyg_Counting_Semaphore::Cyg_Counting_Semaphore(
+ cyg_count32 init_count // Initial count value
+ )
+{
+ count = init_count;
+}
+
+// -------------------------------------------------------------------------
+// Destructor
+
+Cyg_Counting_Semaphore::~Cyg_Counting_Semaphore()
+{
+ CYG_ASSERT( queue.empty(), "Destroying semaphore with waiting threads");
+}
+
+// -------------------------------------------------------------------------
+// Wait until the count can be decremented without it becoming
+// negative.
+
+cyg_bool Cyg_Counting_Semaphore::wait()
+{
+ cyg_bool result = true;
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_CNTSEM( CLAIM, this, count );
+
+ while( count == 0 && result )
+ {
+ self->set_sleep_reason( Cyg_Thread::WAIT );
+
+ self->sleep();
+
+ queue.enqueue( self );
+
+ CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 );
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_INSTRUMENT_CNTSEM( WOKE, this, count );
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if( result ) count--;
+
+ // Unlock the scheduler
+ Cyg_Scheduler::unlock();
+
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Wait until the count can be decremented without it becoming
+// negative.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+cyg_bool
+Cyg_Counting_Semaphore::wait( cyg_tick_count timeout )
+{
+ cyg_bool result = true;
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_CNTSEM( CLAIM, this, count );
+
+ // Set the timer _once_ outside the loop.
+ self->set_timer( timeout, Cyg_Thread::TIMEOUT );
+
+ // If the timeout is in the past, the wake reason will have been
+ // set to something other than NONE already. If the count is zero,
+ // set the result false to force an immediate return. If the count
+ // is non-zero, then this wait will succeed anyway.
+
+ if( self->get_wake_reason() != Cyg_Thread::NONE &&
+ 0 == count )
+ result = false;
+
+ while ( 0 == count && result ) {
+
+ // must reset the sleep reason every time
+ self->set_sleep_reason( Cyg_Thread::TIMEOUT );
+
+ self->sleep();
+
+ queue.enqueue( self );
+
+ CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 );
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_INSTRUMENT_CNTSEM( WOKE, this, count );
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::TIMEOUT:
+ result = false;
+ CYG_INSTRUMENT_CNTSEM( TIMEOUT, this, count);
+ break;
+
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Clear the timeout. It is irrelevant whether the alarm has
+ // actually gone off or not.
+ self->clear_timer();
+
+ if ( result ) count--;
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ return result;
+}
+
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+
+// -------------------------------------------------------------------------
+// Try to decrement, but fail if not possible
+
+cyg_bool Cyg_Counting_Semaphore::trywait()
+{
+ cyg_bool result = true;
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ if( count > 0 ) count--;
+ else result = false;
+
+ CYG_INSTRUMENT_CNTSEM( TRY, this, result );
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Increment count
+
+void Cyg_Counting_Semaphore::post()
+{
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_CNTSEM( POST, this, 0 );
+
+ count++;
+
+ if( !queue.empty() ) {
+
+ // The queue is non-empty, so grab the next
+ // thread from it and wake it up. The waiter
+ // will decrement the count when he is awakened.
+
+ Cyg_Thread *thread = queue.dequeue();
+
+ thread->set_wake_reason( Cyg_Thread::DONE );
+
+ thread->wake();
+
+ CYG_INSTRUMENT_CNTSEM( WAKE, this, thread );
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+}
+
+// -------------------------------------------------------------------------
+// Get current count value
+
+cyg_count32 Cyg_Counting_Semaphore::peek() const
+{
+ // This is a single read of the value of count.
+ // This is already atomic, hence there is no need
+ // to lock the scheduler.
+
+ return count;
+}
+
+// -------------------------------------------------------------------------
+// EOF sync/cnt_sem.cxx
diff --git a/ecos/packages/kernel/current/src/sync/cnt_sem2.cxx b/ecos/packages/kernel/current/src/sync/cnt_sem2.cxx
new file mode 100644
index 0000000000..c1be327040
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sync/cnt_sem2.cxx
@@ -0,0 +1,295 @@
+//==========================================================================
+//
+// sync/cnt_sem2.cxx
+//
+// Counting semaphore implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1997-09-24
+// Purpose: Cyg_Counting_Semaphore implementation
+// Description: This file contains the implementations of the counting semaphore
+// class.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/thread.inl> // Cyg_Thread inlines
+
+#include <cyg/kernel/sema2.hxx> // our header
+
+#include <cyg/kernel/sched.inl> // scheduler inlines
+
+// -------------------------------------------------------------------------
+// Constructor
+
+Cyg_Counting_Semaphore2::Cyg_Counting_Semaphore2(
+ cyg_count32 init_count // Initial count value
+ )
+{
+ count = init_count;
+}
+
+// -------------------------------------------------------------------------
+// Destructor
+
+Cyg_Counting_Semaphore2::~Cyg_Counting_Semaphore2()
+{
+ CYG_REPORT_FUNCTION();
+#if 0
+ CYG_ASSERT( queue.empty(), "Destroying semaphore with waiting threads");
+#endif
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ while ( ! queue.empty() ) {
+ Cyg_Thread *thread = queue.dequeue();
+ thread->set_wake_reason( Cyg_Thread::DESTRUCT );
+ thread->wake();
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Wait until the count can be decremented without it becoming
+// negative.
+
+cyg_bool Cyg_Counting_Semaphore2::wait()
+{
+ CYG_REPORT_FUNCTION();
+ Cyg_Thread *self = Cyg_Thread::self();
+ cyg_bool result = true;
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_CNTSEM( CLAIM, this, count );
+
+ if ( 0 < count ) {
+ count--;
+ Cyg_Scheduler::unlock();
+ }
+ else {
+ self->set_sleep_reason( Cyg_Thread::WAIT );
+ self->sleep();
+ queue.enqueue( self );
+
+ CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 );
+
+ Cyg_Scheduler::unlock();
+
+ CYG_INSTRUMENT_CNTSEM( WOKE, this, count );
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Wait until the count can be decremented without it becoming
+// negative.
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+cyg_bool
+Cyg_Counting_Semaphore2::wait( cyg_tick_count abs_timeout )
+{
+ CYG_REPORT_FUNCTION();
+ Cyg_Thread *self = Cyg_Thread::self();
+ cyg_bool result = true;
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_CNTSEM( CLAIM, this, count );
+
+ if ( 0 < count ) {
+ count--;
+ Cyg_Scheduler::unlock();
+ }
+ else {
+
+ // Put thread in sleep state before setting timer since if the
+ // timeout is in the past, it will be re-awoken
+ // immediately. If this happens then wake_reason will not be
+ // NONE.
+
+ self->sleep();
+
+ self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
+
+ // only enqueue if the timeout did not already happen
+ if( Cyg_Thread::NONE == self->get_wake_reason() )
+ queue.enqueue( self );
+
+ CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 );
+
+
+ Cyg_Scheduler::unlock();
+
+ // Clear the timeout. It is irrelevant whether the alarm has
+ // actually gone off or not.
+ self->clear_timer();
+
+ CYG_INSTRUMENT_CNTSEM( WOKE, this, count );
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::TIMEOUT:
+ result = false;
+ CYG_INSTRUMENT_CNTSEM( TIMEOUT, this, count);
+ break;
+
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+
+// -------------------------------------------------------------------------
+// Try to decrement, but fail if not possible
+
+cyg_bool Cyg_Counting_Semaphore2::trywait()
+{
+ CYG_REPORT_FUNCTION();
+ cyg_bool result = true;
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ if( 0 < count ) count--;
+ else result = false;
+
+ CYG_INSTRUMENT_CNTSEM( TRY, this, result );
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Increment count
+
+void Cyg_Counting_Semaphore2::post()
+{
+ CYG_REPORT_FUNCTION();
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_CNTSEM( POST, this, 0 );
+
+ if( queue.empty() ) {
+ count++;
+ }
+ else {
+ // The queue is non-empty, so grab the next
+ // thread from it and wake it up. The waiter
+ // won't decrement the count when he is awakened,
+ // for we never incremented it in the first place
+
+ Cyg_Thread *thread = queue.dequeue();
+
+ thread->set_wake_reason( Cyg_Thread::DONE );
+
+ thread->wake();
+
+ CYG_INSTRUMENT_CNTSEM( WAKE, this, thread );
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Get current count value
+
+cyg_count32 Cyg_Counting_Semaphore2::peek() const
+{
+ // This is a single read of the value of count.
+ // This is already atomic, hence there is no need
+ // to lock the scheduler.
+
+ return count;
+}
+
+// -------------------------------------------------------------------------
+// EOF sync/cnt_sem2.cxx
diff --git a/ecos/packages/kernel/current/src/sync/flag.cxx b/ecos/packages/kernel/current/src/sync/flag.cxx
new file mode 100644
index 0000000000..976d84dbc5
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sync/flag.cxx
@@ -0,0 +1,418 @@
+//==========================================================================
+//
+// flag.cxx
+//
+// Flag class implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 1998-02-11
+// Purpose: Flag implementation
+// Description: This file contains the implementations of the flag class
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/thread.inl> // thread inlines
+
+#include <cyg/kernel/flag.hxx> // our own header
+
+#include <cyg/kernel/sched.inl> // scheduler inlines
+#include <cyg/kernel/clock.inl> // clock inlines
+
+// -------------------------------------------------------------------------
+// Constructor
+
+Cyg_Flag::Cyg_Flag( Cyg_FlagValue init )
+{
+ CYG_REPORT_FUNCTION();
+ value = init;
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Destructor
+
+Cyg_Flag::~Cyg_Flag()
+{
+ CYG_REPORT_FUNCTION();
+#if 0
+ CYG_ASSERT( queue.empty(), "Deleting flag with threads waiting");
+#endif
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ while ( ! queue.empty() ) {
+ Cyg_Thread *thread = queue.dequeue();
+ thread->set_wake_reason( Cyg_Thread::DESTRUCT );
+ thread->wake();
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// debugging/assert function
+
+#ifdef CYGDBG_USE_ASSERTS
+cyg_bool
+Cyg_Flag::check_this(cyg_assert_class_zeal zeal) const
+{
+ CYG_REPORT_FUNCTION();
+
+ if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() )
+ // then the whole thing is invalid, and we know it.
+ // so return OK, since this check should NOT make an error.
+ return true;
+
+ // check that we have a non-NULL pointer first
+ if( this == NULL ) {
+ CYG_REPORT_RETVAL( false );
+ return false;
+ }
+
+ // there ain't a lot to check here.
+ CYG_REPORT_RETVAL( true );
+ return true;
+}
+#endif
+
+// -------------------------------------------------------------------------
+// now the members themselves:
+
+// clear some bits in the value (all of them by default) by ANDing with the
+// argument. This cannot make a wait condition become true, so there's not
+// much to it.
+void
+Cyg_Flag::maskbits( Cyg_FlagValue arg )
+{
+ CYG_REPORT_FUNCTION();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ value &= arg;
+ // no need to wake anyone up; no waiter can become valid in
+ // consequence of this operation.
+
+ // Unlock scheduler and allow other threads to run
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+}
+
+
+// -------------------------------------------------------------------------
+// set some bits in the value (all of them by default) and wake up any
+// affected waiting threads; we do the decision making here so as to get
+// atomicity wrt the other threads waking up - the value might have changed
+// by the time they get to run.
+
+void
+Cyg_Flag::setbits( Cyg_FlagValue arg )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ // OR in the argument to get a new flag value.
+ value |= arg;
+
+ // anyone waiting?
+ if ( !(queue.empty()) ) {
+ FlagWaitInfo *p;
+ Cyg_Thread *thread;
+ Cyg_ThreadQueue holding;
+
+ do {
+ thread = queue.dequeue();
+ p = (FlagWaitInfo *)(thread->get_wait_info());
+
+ CYG_ASSERT( (p->allmask == 0) != (p->anymask == 0),
+ "Both masks set" );
+ CYG_ASSERT( 0 == p->value_out, "Thread already awoken?" );
+
+ if ( ((p->allmask != 0) && (p->allmask & value) == p->allmask) ||
+ ((p->anymask & value) != 0 ) ) {
+ // success! awaken the thread
+ thread->set_wake_reason( Cyg_Thread::DONE );
+ thread->wake();
+ // return the successful value to it
+ p->value_out = value;
+ // do we clear the value; is this the end?
+ if ( p->do_clear ) {
+ // we can break here but need to preserve ordering
+ value = 0;
+ // so let it cycle the whole queue regardless
+ }
+ }
+ else {
+ // preserve the entry on the holding queue
+ holding.enqueue( thread );
+ }
+ } while ( !(queue.empty()) );
+
+ // Now re-queue the unaffected threads back into the flag queue
+ while ( !(holding.empty()) ) {
+ queue.enqueue( holding.dequeue() );
+ }
+ }
+ // Unlock scheduler and allow other threads to run
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Wait for a match on our pattern, according to the flags given.
+// Return the matching value.
+Cyg_FlagValue
+Cyg_Flag::wait( Cyg_FlagValue pattern, WaitMode mode )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" );
+
+ Cyg_FlagValue result;
+
+ // Prevent preemption so that we compare atomically
+ Cyg_Scheduler::lock();
+
+ // try the current value
+ result = poll( pattern, mode );
+
+ if ( 0 != result ) {
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETVAL( result );
+ return result; // all done
+ }
+
+ // we have to wait until we are awoken
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ FlagWaitInfo saveme;
+ saveme.allmask = (Cyg_Flag::OR & mode) ? 0 : pattern;
+ saveme.anymask = (Cyg_Flag::OR & mode) ? pattern : 0;
+ saveme.do_clear = (0 != (Cyg_Flag::CLR & mode));
+
+ self->set_wait_info( (CYG_ADDRWORD)&saveme );
+
+ result = true; // just being used as an early-out flag now
+ // this loop allows us to deal correctly with spurious wakeups
+ while ( result && (0 == saveme.value_out) ) {
+ self->set_sleep_reason( Cyg_Thread::WAIT );
+ self->sleep();
+ // keep track of myself on the queue of waiting threads
+ queue.enqueue( self );
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_ASSERT( ((CYG_ADDRWORD)&saveme) ==
+ Cyg_Thread::self()->get_wait_info(),
+ "Wait info lost" );
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ CYG_ASSERT( (false == result) ^ (0 != saveme.value_out),
+ "Break out but also good result!" );
+
+ // Unlock scheduler and allow other threads to run
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETVAL( saveme.value_out );
+ return saveme.value_out;
+}
+
+// -------------------------------------------------------------------------
+// Wait for a match on our pattern, with a timeout.
+// Return the matching value, or zero if timed out.
+// (zero cannot match any pattern).
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+Cyg_FlagValue
+Cyg_Flag::wait( Cyg_FlagValue pattern, WaitMode mode,
+ cyg_tick_count abs_timeout )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" );
+
+ Cyg_FlagValue result;
+
+ // Prevent preemption so that we compare atomically
+ Cyg_Scheduler::lock();
+
+ // try the current value
+ result = poll( pattern, mode );
+
+ if ( 0 != result ) {
+ Cyg_Scheduler::unlock();
+ CYG_REPORT_RETVAL( result );
+ return result; // all done
+ }
+
+ // we have to wait until we are awoken
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ FlagWaitInfo saveme;
+ saveme.allmask = (Cyg_Flag::OR & mode) ? 0 : pattern;
+ saveme.anymask = (Cyg_Flag::OR & mode) ? pattern : 0;
+ saveme.do_clear = (0 != (Cyg_Flag::CLR & mode));
+
+ self->set_wait_info( (CYG_ADDRWORD)&saveme );
+
+ // Set the timer _once_ outside the loop.
+ self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT );
+
+ // If the timeout was in the past, it will have changed the value
+ // of wake_reason, so avoid going into the loop.
+ if( self->get_wake_reason() != Cyg_Thread::NONE )
+ result = false;
+ else result = true;
+
+ // Result is just being used as an early-out flag now. This loop
+ // allows us to deal correctly with spurious wakeups.
+
+ while ( result && (0 == saveme.value_out) ) {
+ self->set_sleep_reason( Cyg_Thread::TIMEOUT );
+ self->sleep();
+ // keep track of myself on the queue of waiting threads
+ queue.enqueue( self );
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_ASSERT( ((CYG_ADDRWORD)&saveme) ==
+ Cyg_Thread::self()->get_wait_info(),
+ "Wait info lost" );
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::TIMEOUT:
+ result = false;
+ break;
+
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ CYG_ASSERT( (false == result) ^ (0 != saveme.value_out),
+ "Break out but also good result!" );
+
+ // clear the timer; if it actually fired, no worries.
+ self->clear_timer();
+
+ // Unlock scheduler and allow other threads to run
+ Cyg_Scheduler::unlock();
+ // in this version, value_out might be zero meaning timed out.
+ CYG_REPORT_RETVAL( saveme.value_out );
+ return saveme.value_out;
+}
+#endif // CYGFUN_KERNEL_THREADS_TIMER
+
+// -------------------------------------------------------------------------
+// Test for a match on our pattern, according to the flags given.
+// Return the matching value if success, else zero.
+Cyg_FlagValue
+Cyg_Flag::poll( Cyg_FlagValue pattern, WaitMode mode )
+{
+ CYG_REPORT_FUNCTION();
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" );
+
+ // Prevent preemption so that we compare atomically
+ Cyg_Scheduler::lock();
+
+ Cyg_FlagValue result = 0;
+
+ if ( Cyg_Flag::OR & mode ) {
+ if ( 0 != (value & pattern) )
+ result = value;
+ }
+ else { // Cyg_Flag::AND - all must be set
+ if ( (pattern != 0) && (pattern == (value & pattern)) )
+ result = value;
+ }
+
+ // result != 0 <=> test passed
+ if ( result && (Cyg_Flag::CLR & mode) )
+ value = 0;
+
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETVAL( result );
+ return result;
+}
+
+
+// -------------------------------------------------------------------------
+// EOF flag.cxx
diff --git a/ecos/packages/kernel/current/src/sync/mbox.cxx b/ecos/packages/kernel/current/src/sync/mbox.cxx
new file mode 100644
index 0000000000..158f863469
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sync/mbox.cxx
@@ -0,0 +1,170 @@
+//==========================================================================
+//
+// mbox.cxx
+//
+// Mbox mbox template class implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 1998-02-11
+// Purpose: Mbox implementation
+// Description: This file contains the implementations of the mbox class
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/thread.inl> // Cyg_Thread inlines
+
+#include <cyg/kernel/mbox.hxx> // our own header
+
+#ifndef CYGIMP_MBOXT_INLINE // force inlining
+#define CYGIMP_MBOXT_INLINE // of implementation
+#endif
+
+#ifdef CYGIMP_MBOX_USE_MBOXT_PLAIN
+#include <cyg/kernel/mboxt.inl> // mbox template implementation
+#else
+#include <cyg/kernel/mboxt2.inl> // mbox template implementation
+#endif
+
+// -------------------------------------------------------------------------
+// This module exists to cause exactly one instance of these functions to
+// exist; this is just like a vanilla class, except we use the template
+// class to acquire an implementation. The template functions are inlined
+// in each of these methods.
+
+
+// -------------------------------------------------------------------------
+// Constructor
+
+Cyg_Mbox::Cyg_Mbox()
+{
+}
+
+// -------------------------------------------------------------------------
+// Destructor
+
+Cyg_Mbox::~Cyg_Mbox()
+{
+}
+
+// -------------------------------------------------------------------------
+// debugging/assert function
+
+#ifdef CYGDBG_USE_ASSERTS
+cyg_bool
+Cyg_Mbox::check_this(cyg_assert_class_zeal zeal) const
+{
+ return m.check_this(zeal);
+}
+#endif
+
+// -------------------------------------------------------------------------
+// now the members themselves:
+
+void *
+Cyg_Mbox::get()
+{
+ void * p;
+ if ( ! m.get( p ) )
+ return NULL;
+ return p;
+}
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+void *
+Cyg_Mbox::get( cyg_tick_count timeout )
+{
+ void * p;
+ if ( ! m.get( p, timeout ) )
+ return NULL;
+ return p;
+}
+#endif
+
+void *
+Cyg_Mbox::tryget()
+{
+ void * p=NULL;
+ if ( ! m.tryget( p ) )
+ return NULL;
+ return p;
+}
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+cyg_bool
+Cyg_Mbox::put( void *item )
+{
+ return m.put( item );
+}
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+cyg_bool
+Cyg_Mbox::put( void *item, cyg_tick_count timeout )
+{
+ return m.put( item, timeout );
+}
+#endif
+#endif // CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+
+cyg_bool
+Cyg_Mbox::tryput( void *item )
+{
+ return m.tryput( item );
+}
+
+void *
+Cyg_Mbox::peek_item() // Get next item to be returned
+{
+ void *p=NULL;
+ if ( ! m.peek_item( p ) )
+ return NULL;
+ return p;
+}
+
+// -------------------------------------------------------------------------
+// EOF mbox.cxx
diff --git a/ecos/packages/kernel/current/src/sync/mqueue.cxx b/ecos/packages/kernel/current/src/sync/mqueue.cxx
new file mode 100644
index 0000000000..6e174ed89e
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sync/mqueue.cxx
@@ -0,0 +1,65 @@
+//==========================================================================
+//
+// sync/mqueue.cxx
+//
+// Mqueue message queue non-inline implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): jlarmour
+// Contributors:
+// Date: 2001-10-12
+// Purpose: Non-inlined implementation of mqueue message queue.
+// Description: This file contains the non-inlined instantiations of the
+// mqueue message queue implementation functions.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#ifdef CYGIMP_KERNEL_SYNCH_MQUEUE_NOT_INLINE
+
+#define CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE
+#include <cyg/kernel/mqueue.hxx>
+#include <cyg/kernel/mqueue.inl>
+
+#endif
+
+// -------------------------------------------------------------------------
+// EOF sync/mqueue.cxx
diff --git a/ecos/packages/kernel/current/src/sync/mutex.cxx b/ecos/packages/kernel/current/src/sync/mutex.cxx
new file mode 100644
index 0000000000..f5af2fce25
--- /dev/null
+++ b/ecos/packages/kernel/current/src/sync/mutex.cxx
@@ -0,0 +1,863 @@
+//==========================================================================
+//
+// sync/mutex.cxx
+//
+// Mutex and condition variable implementation
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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, jlarmour
+// Date: 1999-02-17
+// Purpose: Mutex implementation
+// Description: This file contains the implementations of the mutex
+// and condition variable classes.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+#include <cyg/kernel/instrmnt.h> // instrumentation
+
+#include <cyg/kernel/mutex.hxx> // our header
+
+#include <cyg/kernel/thread.inl> // thread inlines
+#include <cyg/kernel/sched.inl> // scheduler inlines
+#include <cyg/kernel/clock.inl> // clock inlines
+
+// -------------------------------------------------------------------------
+// Mutex protocol test macros.
+// If the dynamic protocol option is enabled, then these generate appropriate
+// tests on the protocol field. If there is no dynamic choice then they simply
+// result in empty statements.
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+
+#define IF_PROTOCOL_INHERIT if( protocol == INHERIT )
+#define IF_PROTOCOL_CEILING if( protocol == CEILING )
+#define IF_PROTOCOL_ACTIVE if( protocol != NONE )
+
+#else
+
+#define IF_PROTOCOL_INHERIT
+#define IF_PROTOCOL_CEILING
+#define IF_PROTOCOL_ACTIVE
+
+#endif
+
+// -------------------------------------------------------------------------
+// Constructor
+
+Cyg_Mutex::Cyg_Mutex()
+{
+ CYG_REPORT_FUNCTION();
+
+ locked = false;
+ owner = NULL;
+
+#if defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT) && \
+ defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC)
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT
+ protocol = INHERIT;
+#endif
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_CEILING
+ protocol = CEILING;
+ ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY;
+#endif
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_NONE
+ protocol = NONE;
+#endif
+
+#else // not (DYNAMIC and DEFAULT defined)
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY
+
+ // if there is a default priority ceiling defined, use that to initialize
+ // the ceiling.
+ ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY;
+
+#else
+
+ // Otherwise set it to zero.
+ ceiling = 0;
+
+#endif
+#endif
+
+#endif // DYNAMIC and DEFAULT defined
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Construct with defined protocol
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+
+Cyg_Mutex::Cyg_Mutex( cyg_protcol protocol_arg )
+{
+ CYG_REPORT_FUNCTION();
+
+ locked = false;
+ owner = NULL;
+
+ protocol = protocol_arg;
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY
+
+ // if there is a default priority ceiling defined, use that to initialize
+ // the ceiling.
+ ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY;
+
+#else
+
+ // Otherwise set it to zero.
+ ceiling = 0;
+
+#endif
+#endif
+
+ CYG_REPORT_RETURN();
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Destructor
+
+Cyg_Mutex::~Cyg_Mutex()
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( owner == NULL, "Deleting mutex with owner");
+ CYG_ASSERT( queue.empty(), "Deleting mutex with waiting threads");
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGDBG_USE_ASSERTS
+
+cyg_bool
+Cyg_Mutex::check_this( cyg_assert_class_zeal zeal) const
+{
+// CYG_REPORT_FUNCTION();
+
+ // check that we have a non-NULL pointer first
+ if( this == NULL ) return false;
+
+ switch( zeal )
+ {
+ case cyg_system_test:
+ case cyg_extreme:
+ case cyg_thorough:
+ case cyg_quick:
+ case cyg_trivial:
+ if( locked && owner == NULL ) return false;
+ if( !locked && owner != NULL ) return false;
+ case cyg_none:
+ default:
+ break;
+ };
+
+ return true;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Lock and/or wait
+
+cyg_bool
+Cyg_Mutex::lock(void)
+{
+ CYG_REPORT_FUNCTYPE("returning %d");
+
+ cyg_bool result = true;
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ CYG_INSTRUMENT_MUTEX(LOCK, this, 0);
+
+ // Loop while the mutex is locked, sleeping each time around
+ // the loop. This copes with the possibility of a higher priority
+ // thread grabbing the mutex between the wakeup in unlock() and
+ // this thread actually starting.
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
+
+ IF_PROTOCOL_ACTIVE
+ self->count_mutex();
+
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+
+ IF_PROTOCOL_CEILING
+ self->set_priority_ceiling(ceiling);
+
+#endif
+
+ while( locked && result )
+ {
+ CYG_ASSERT( self != owner, "Locking mutex I already own");
+
+ self->set_sleep_reason( Cyg_Thread::WAIT );
+
+ self->sleep();
+
+ queue.enqueue( self );
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+
+ IF_PROTOCOL_INHERIT
+ owner->inherit_priority(self);
+
+#endif
+
+ CYG_INSTRUMENT_MUTEX(WAIT, this, 0);
+
+ // Allow other threads to run
+ Cyg_Scheduler::reschedule();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::DESTRUCT:
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ if( result )
+ {
+ locked = true;
+ owner = self;
+
+ CYG_INSTRUMENT_MUTEX(LOCKED, this, 0);
+ }
+ else
+ {
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
+
+ IF_PROTOCOL_ACTIVE
+ self->uncount_mutex();
+
+#endif
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+
+ IF_PROTOCOL_INHERIT
+ self->disinherit_priority();
+
+#endif
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+
+ IF_PROTOCOL_CEILING
+ self->clear_priority_ceiling();
+
+#endif
+ }
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ CYG_REPORT_RETVAL(result);
+
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Try to lock and return success
+
+cyg_bool
+Cyg_Mutex::trylock(void)
+{
+ CYG_REPORT_FUNCTYPE("returning %d");
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ cyg_bool result = true;
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ // If the mutex is not locked, grab it
+ // for ourself. Otherwise return failure.
+ if( !locked )
+ {
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ locked = true;
+ owner = self;
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
+
+ IF_PROTOCOL_ACTIVE
+ self->count_mutex();
+
+#endif
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+
+ IF_PROTOCOL_CEILING
+ self->set_priority_ceiling(ceiling);
+
+#endif
+
+ }
+ else result = false;
+
+ CYG_INSTRUMENT_MUTEX(TRY, this, result);
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETVAL(result);
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// unlock
+
+void
+Cyg_Mutex::unlock(void)
+{
+ CYG_REPORT_FUNCTION();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MUTEX(UNLOCK, this, 0);
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_ASSERT( locked, "Unlock mutex that is not locked");
+ CYG_ASSERT( owner == Cyg_Thread::self(), "Unlock mutex I do not own");
+
+ if( !queue.empty() ) {
+
+ // The queue is non-empty, so grab the next
+ // thread from it and wake it up.
+
+ Cyg_Thread *thread = queue.dequeue();
+
+ CYG_ASSERTCLASS( thread, "Bad thread pointer");
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+
+ // Give the owner-to-be a chance to inherit from the remaining
+ // queue or the relinquishing thread:
+
+ IF_PROTOCOL_INHERIT
+ thread->relay_priority(owner, &queue);
+
+#endif
+
+ thread->set_wake_reason( Cyg_Thread::DONE );
+
+ thread->wake();
+
+ CYG_INSTRUMENT_MUTEX(WAKE, this, thread);
+
+ }
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL
+
+ IF_PROTOCOL_ACTIVE
+ owner->uncount_mutex();
+
+#endif
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+
+ IF_PROTOCOL_INHERIT
+ owner->disinherit_priority();
+
+#endif
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+
+ IF_PROTOCOL_CEILING
+ owner->clear_priority_ceiling();
+
+#endif
+
+ locked = false;
+ owner = NULL;
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Release all waiting threads.
+
+void Cyg_Mutex::release()
+{
+ CYG_REPORT_FUNCTION();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_MUTEX(RELEASE, this, 0);
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ while( !queue.empty() )
+ {
+ // The queue is non-empty, so grab each
+ // thread from it and release it.
+
+ Cyg_Thread *thread = queue.dequeue();
+
+ CYG_ASSERTCLASS( thread, "Bad thread pointer");
+
+ thread->release();
+
+ CYG_INSTRUMENT_MUTEX(RELEASED, this, thread);
+
+ }
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Set ceiling priority for priority ceiling protocol
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+
+void Cyg_Mutex::set_ceiling( cyg_priority priority )
+{
+ CYG_REPORT_FUNCTION();
+
+// CYG_ASSERT( priority >= CYG_THREAD_MAX_PRIORITY, "Priority out of range");
+// CYG_ASSERT( priority <= CYG_THREAD_MIN_PRIORITY, "Priority out of range");
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ ceiling = priority;
+
+ // Unlock the scheduler
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Set priority inversion protocol
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+void Cyg_Mutex::set_protocol( cyg_protcol new_protocol )
+{
+ CYG_REPORT_FUNCTION();
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ protocol = new_protocol;
+
+ // Unlock the scheduler
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+#endif
+
+
+//==========================================================================
+// Condition variables
+
+Cyg_Condition_Variable::Cyg_Condition_Variable(
+ Cyg_Mutex &mx // linked mutex
+ )
+{
+ CYG_REPORT_FUNCTION();
+
+ mutex = &mx;
+
+ CYG_ASSERTCLASS( mutex, "Invalid mutex argument");
+
+ CYG_REPORT_RETURN();
+}
+
+Cyg_Condition_Variable::Cyg_Condition_Variable()
+{
+ CYG_REPORT_FUNCTION();
+
+ mutex = NULL;
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Destructor
+
+Cyg_Condition_Variable::~Cyg_Condition_Variable()
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERT( queue.empty(), "Deleting condvar with waiting threads");
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+
+#ifdef CYGDBG_USE_ASSERTS
+
+cyg_bool
+Cyg_Condition_Variable::check_this( cyg_assert_class_zeal zeal) const
+{
+ bool result = true;
+
+ CYG_REPORT_FUNCTYPE("returning %d");
+ CYG_REPORT_FUNCARG1("zeal = %d", zeal);
+
+ // check that we have a non-NULL pointer first
+ if( this == NULL )
+ result = false;
+ else {
+
+ switch( zeal )
+ {
+ case cyg_system_test:
+ case cyg_extreme:
+ case cyg_thorough:
+ if( mutex != NULL && !mutex->check_this(zeal) )
+ result = false;
+ case cyg_quick:
+ case cyg_trivial:
+ case cyg_none:
+ default:
+ break;
+ }
+ }
+
+ CYG_REPORT_RETVAL(result);
+ return result;
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// Wait for condition to be true
+// Note: if this function is entered with the scheduler locked (e.g. to
+// suspend DSR processing) then there is no need to take the lock. Also
+// in this case, exit with the scheduler locked, which allows this function
+// to be used in a totally thread-safe manner.
+
+cyg_bool
+Cyg_Condition_Variable::wait_inner( Cyg_Mutex *mx )
+{
+ CYG_REPORT_FUNCTION();
+
+ cyg_bool result = true;
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ Cyg_Scheduler::lock();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_ASSERTCLASS( mx, "Corrupt mutex");
+ CYG_ASSERTCLASS( self, "Bad self thread");
+
+ CYG_INSTRUMENT_CONDVAR(WAIT, this, 0);
+
+ mx->unlock();
+
+ self->set_sleep_reason( Cyg_Thread::WAIT );
+
+ self->sleep();
+
+ queue.enqueue( self );
+
+ // Avoid calling ASRs during the following unlock.
+ self->set_asr_inhibit();
+
+ // Unlock the scheduler and switch threads
+ Cyg_Scheduler::unlock_reschedule();
+
+ // Allow ASRs again
+ self->clear_asr_inhibit();
+
+ CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason());
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_ASSERTCLASS( mx, "Corrupt mutex");
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::DESTRUCT: // which, the cv or the mutex?
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+
+ // When we awake, we must re-acquire the mutex. Note that while
+ // it is essential to release the mutex and queue on the CV
+ // atomically relative to other threads, to avoid races, it is not
+ // necessary for us to re-acquire the mutex in the same atomic
+ // action. Hence we can do it after unlocking the scheduler.
+ // We need to loop here in case the thread is released while waiting
+ // for the mutex. It is essential that we exit this function with the
+ // mutex claimed.
+
+ while ( !mx->lock() )
+ continue;
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_ASSERTCLASS( mx, "Corrupt mutex");
+ CYG_ASSERT( mx->owner == self, "Not mutex owner");
+
+ CYG_REPORT_RETURN();
+
+ return result;
+}
+
+// -------------------------------------------------------------------------
+// Wake one thread
+
+void
+Cyg_Condition_Variable::signal(void)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_CONDVAR(SIGNAL, this, 0);
+
+ if( !queue.empty() )
+ {
+ // The queue is non-empty, so grab the next
+ // thread from it and wake it up.
+
+ Cyg_Thread *thread = queue.dequeue();
+
+ CYG_ASSERTCLASS( thread, "Bad thread pointer");
+
+ thread->set_wake_reason( Cyg_Thread::DONE );
+
+ thread->wake();
+
+ CYG_INSTRUMENT_CONDVAR(WAKE, this, thread);
+
+ }
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Set cond true, wake all threads
+
+void
+Cyg_Condition_Variable::broadcast(void)
+{
+ CYG_REPORT_FUNCTION();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_CONDVAR(BROADCAST, this, 0);
+
+ // Grab all the threads from the queue and let them
+ // go.
+
+ while( !queue.empty() )
+ {
+ Cyg_Thread *thread = queue.dequeue();
+
+ CYG_ASSERTCLASS( thread, "Bad thread pointer");
+
+ thread->set_wake_reason( Cyg_Thread::DONE );
+
+ thread->wake();
+
+ CYG_INSTRUMENT_CONDVAR(WAKE, this, thread);
+ }
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+
+ // Unlock the scheduler and maybe switch threads
+ Cyg_Scheduler::unlock();
+
+ CYG_REPORT_RETURN();
+}
+
+// -------------------------------------------------------------------------
+// Optional timed wait on a CV
+
+#if defined(CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT)
+
+cyg_bool
+Cyg_Condition_Variable::wait_inner( Cyg_Mutex *mx, cyg_tick_count timeout )
+{
+ CYG_REPORT_FUNCTYPE("returning %d");
+ CYG_REPORT_FUNCARG1("timeout = %d", timeout);
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_ASSERTCLASS( mx, "Corrupt mutex");
+
+ cyg_bool result = true;
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ CYG_ASSERTCLASS( self, "Bad self thread");
+
+ // Prevent preemption
+ Cyg_Scheduler::lock();
+
+ CYG_INSTRUMENT_CONDVAR(TIMED_WAIT, this, 0 );
+
+ mx->unlock();
+
+ // The ordering of sleep() and set_timer() here are
+ // important. If the timeout is in the past, the thread
+ // will be woken up immediately and will not sleep.
+
+ self->sleep();
+
+ // Set the timer and sleep reason
+ self->set_timer( timeout, Cyg_Thread::TIMEOUT );
+
+ // Only enqueue if the timeout has not already fired.
+ if( self->get_wake_reason() == Cyg_Thread::NONE )
+ queue.enqueue( self );
+
+ // Avoid calling ASRs during the following unlock.
+ self->set_asr_inhibit();
+
+ // Unlock the scheduler and switch threads
+ Cyg_Scheduler::unlock_reschedule();
+
+ // Allow ASRs again
+ self->clear_asr_inhibit();
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_ASSERTCLASS( mx, "Corrupt mutex");
+
+ self->clear_timer();
+
+ CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason());
+
+ switch( self->get_wake_reason() )
+ {
+ case Cyg_Thread::TIMEOUT:
+ case Cyg_Thread::DESTRUCT: // which, the cv or the mutex?
+ case Cyg_Thread::BREAK:
+ result = false;
+ break;
+
+ case Cyg_Thread::EXIT:
+ self->exit();
+ break;
+
+ default:
+ break;
+ }
+
+
+ // When we awake, we must re-acquire the mutex. Note that while
+ // it is essential to release the mutex and queue on the CV
+ // atomically relative to other threads, to avoid races, it is not
+ // necessary for us to re-acquire the mutex in the same atomic
+ // action. Hence we can do it after unlocking the scheduler.
+
+ while ( !mx->lock() )
+ continue;
+
+ CYG_ASSERTCLASS( this, "Bad this pointer");
+ CYG_ASSERTCLASS( mx, "Corrupt mutex");
+
+ CYG_REPORT_RETVAL(result);
+
+ return result;
+}
+
+#endif
+
+
+// -------------------------------------------------------------------------
+// EOF sync/mutex.cxx
diff --git a/ecos/packages/kernel/current/tests/bin_sem0.cxx b/ecos/packages/kernel/current/tests/bin_sem0.cxx
new file mode 100644
index 0000000000..06de873bc2
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/bin_sem0.cxx
@@ -0,0 +1,89 @@
+//==========================================================================
+//
+// bin_sem0.cxx
+//
+// Binary semaphore test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-24
+// Description: Limited to checking constructors/destructors
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include "testaux.hxx"
+
+static Cyg_Binary_Semaphore sema0, sema1(false), sema2(true);
+
+
+static bool flash( void )
+{
+ Cyg_Binary_Semaphore s0;
+
+ Cyg_Binary_Semaphore s1(true);
+
+ Cyg_Binary_Semaphore s2(false);
+
+ return true;
+}
+
+void bin_sem0_main( void )
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ CYG_TEST_PASS_FINISH("Binary Semaphore 0 OK");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ bin_sem0_main();
+}
+// EOF bin_sem0.cxx
diff --git a/ecos/packages/kernel/current/tests/bin_sem1.cxx b/ecos/packages/kernel/current/tests/bin_sem1.cxx
new file mode 100644
index 0000000000..3bfd7deb4f
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/bin_sem1.cxx
@@ -0,0 +1,130 @@
+//==========================================================================
+//
+// bin_sem1.cxx
+//
+// Binary semaphore test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-24
+// Description: Tests basic binary semaphore functionality.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start()
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+#include <cyg/kernel/thread.inl>
+
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+
+#define NTHREADS 2
+
+#include "testaux.hxx"
+
+static Cyg_Binary_Semaphore s0(true), s1(false), s2;
+
+static volatile cyg_ucount8 q = 0;
+
+static void entry0( CYG_ADDRWORD data )
+{
+ s0.wait();
+ CHECK( 0 == q++ );
+ s1.post();
+ s0.wait();
+ CHECK( 2 == q++ );
+ CHECK( ! s0.posted() );
+ CHECK( ! s0.trywait() );
+ s0.post();
+ CHECK( 3 == q++ );
+ CHECK( s0.posted() );
+ s1.post();
+ CHECK( ! s2.posted() );
+ s2.wait();
+ CHECK( 5 == q++ );
+ CYG_TEST_PASS_FINISH("Binary Semaphore 1 OK");
+}
+
+static void entry1( CYG_ADDRWORD data )
+{
+ CHECK( s1.posted() );
+ s1.wait();
+ CHECK( 1 == q++ );
+ CHECK( ! s0.posted() );
+ s0.post();
+ s1.wait();
+ CHECK( 4 == q++ );
+ CHECK( s0.posted() );
+ CHECK( s0.trywait() );
+ CHECK( ! s0.posted() );
+ s2.post();
+ s0.wait();
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+void bin_sem1_main( void )
+{
+ CYG_TEST_INIT();
+
+ new_thread( entry0, 0);
+ new_thread( entry1, 1);
+
+#ifdef CYGIMP_THREAD_PRIORITY
+ thread[0]->set_priority( 4 );
+ thread[1]->set_priority( 5 ); // make sure the threads execute as intended
+#endif
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ bin_sem1_main();
+}
+// EOF bin_sem1.cxx
diff --git a/ecos/packages/kernel/current/tests/bin_sem2.cxx b/ecos/packages/kernel/current/tests/bin_sem2.cxx
new file mode 100644
index 0000000000..7be38e8fc9
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/bin_sem2.cxx
@@ -0,0 +1,224 @@
+//==========================================================================
+//
+// bin_sem2.cxx
+//
+// Binary semaphore test 2
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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,dsm
+// Contributors: dsm
+// Date: 1998-03-10
+// Description:
+// Dining philosophers test. Based on philo.cxx
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/mutex.hxx>
+
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+
+static cyg_ucount16 PHILO_LOOPS = 1000;
+
+#define PHILOSOPHERS 15
+#define NTHREADS PHILOSOPHERS
+#include "testaux.hxx"
+
+static Cyg_Binary_Semaphore chopstick[PHILOSOPHERS];
+
+static char pstate[PHILOSOPHERS+1]; // state of each philosopher
+
+static cyg_ucount16 state_changes = 0;
+// state_changes keep track of number of changes to pstate so
+// we can exit after we've seen enough.
+
+
+static Cyg_Mutex pstate_mutex;
+static Cyg_Mutex cycle_mutex;
+
+static inline int left(cyg_count8 i)
+{
+ return (0 == i) ? PHILOSOPHERS-1 : i-1 ;
+}
+static inline int right(cyg_count8 i)
+{
+ return (PHILOSOPHERS == i+1) ? 0 : i+1 ;
+}
+
+void change_state(int id, char newstate)
+{
+ if (PHILO_LOOPS == state_changes++)
+ CYG_TEST_PASS_FINISH("Binary Semaphore 2 OK");
+
+
+ pstate_mutex.lock(); {
+ pstate[id] = newstate;
+ bool all_hungry = true; // until proved otherwise
+ for(cyg_ucount8 i=0; i < PHILOSOPHERS; i++) {
+ if('E' == pstate[i]) {
+ CHECK('E' != pstate[left(i)]);
+ CHECK('E' != pstate[right(i)]);
+ }
+ if('H' != pstate[i]) {
+ all_hungry = false;
+ }
+ }
+ // Theoretically it is possible for all the philosophers to be
+ // hungry but not waiting on semaphores. But in practice this
+ // means something is wrong.
+ CHECK(false == all_hungry);
+ } pstate_mutex.unlock();
+}
+
+char get_state(int id)
+{
+ pstate_mutex.lock();
+
+ char s = pstate[id];
+
+ pstate_mutex.unlock();
+
+ return s;
+}
+
+// -------------------------------------------------------------------------
+// Thread to behave like a philosopher
+
+void Philosopher( CYG_ADDRESS id )
+{
+ Cyg_Thread *self = Cyg_Thread::self();
+ Cyg_Binary_Semaphore *first_stick = &chopstick[id];
+ Cyg_Binary_Semaphore *second_stick = &chopstick[(id+1)%PHILOSOPHERS];
+
+ CHECK( id >= 0 && id < PHILOSOPHERS);
+
+ // Deadlock avoidance. The easiest way to make the philosophers
+ // behave is to make each pick up the lowest numbered stick
+ // first. This is how it works out anyway for all the philosophers
+ // except the last, who must have his sticks swapped.
+
+ if( id == PHILOSOPHERS-1 )
+ {
+ Cyg_Binary_Semaphore *t = first_stick;
+ first_stick = second_stick;
+ second_stick = t;
+ }
+
+
+ // The following variable is shared by all philosophers.
+ // It is incremented unprotected, but this does not matter
+ // since it is only present to introduce a little variability
+ // into the think and eat times.
+
+ static int cycle = 0;
+
+ for(;;)
+ {
+ // Think for a bit
+
+ self->delay((id+cycle++)%12); // Cogito ergo sum...
+
+ // I am now hungry, try to get the chopsticks
+ change_state(id,'H');
+
+ // Get the sticks
+ first_stick->wait();
+ second_stick->wait();
+
+ // Got them, now eat
+ change_state(id,'E');
+
+ // Check that the world is as I think it is...
+ CYG_TEST_CHECK( !first_stick->posted(),
+ "Not got first stick");
+ CYG_TEST_CHECK( !second_stick->posted(),
+ "Not got second stick");
+ CYG_TEST_CHECK( get_state(left(id)) != 'E',
+ "Left neighbour also eating!!");
+ CYG_TEST_CHECK( get_state(right(id)) != 'E',
+ "Right neighbour also eating!!");
+
+ self->delay((id+cycle++)%6); // munch munch
+
+ // Finished eating, put down sticks.
+
+ change_state(id,'T');
+
+ // put sticks back on table
+ first_stick->post();
+ second_stick->post();
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void bin_sem2_main( void )
+{
+ CYG_TEST_INIT();
+
+ if (cyg_test_is_simulator)
+ PHILO_LOOPS = 100;
+
+ for( int i = 0; i < PHILOSOPHERS; i++ )
+ {
+ pstate[i] = 'T'; // starting state
+ new_thread(Philosopher, i);
+
+ // make the matching chopstick present
+ chopstick[i].post();
+ }
+
+ Cyg_Scheduler::scheduler.start();
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ bin_sem2_main();
+}
+// EOF bin_sem2.cxx
diff --git a/ecos/packages/kernel/current/tests/bin_sem3.cxx b/ecos/packages/kernel/current/tests/bin_sem3.cxx
new file mode 100644
index 0000000000..b72e1396e8
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/bin_sem3.cxx
@@ -0,0 +1,138 @@
+//==========================================================================
+//
+// bin_sem3.cxx
+//
+// Binary semaphore test 3
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): David Brennan
+// Contributors: David Brennan
+// Date: 2003-06-06
+// Description: Tests basic binary semaphore timeout functionality.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start()
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+#include <cyg/kernel/thread.inl>
+
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+
+#define NTHREADS 2
+
+#include "testaux.hxx"
+
+static Cyg_Binary_Semaphore s0(true), s1(false), s2;
+
+static volatile cyg_ucount8 q = 0;
+
+static void entry0( CYG_ADDRWORD data )
+{
+ s0.wait();
+ CHECK( 0 == q++ );
+ s1.post();
+ s0.wait();
+ CHECK( 2 == q++ );
+ CHECK( ! s0.posted() );
+#ifndef CYGFUN_KERNEL_THREADS_TIMER
+ CHECK( ! s0.trywait() );
+#else // !CYGFUN_KERNEL_THREADS_TIMER
+ CHECK( ! s0.wait(10) );
+#endif // !CYGFUN_KERNEL_THREADS_TIMER
+ s0.post();
+ CHECK( 3 == q++ );
+ CHECK( s0.posted() );
+ s1.post();
+ CHECK( ! s2.posted() );
+ s2.wait();
+ CHECK( 5 == q++ );
+ CYG_TEST_PASS_FINISH("Binary Semaphore 3 OK");
+}
+
+static void entry1( CYG_ADDRWORD data )
+{
+ CHECK( s1.posted() );
+ s1.wait();
+ CHECK( 1 == q++ );
+ CHECK( ! s0.posted() );
+ s0.post();
+ s1.wait();
+ CHECK( 4 == q++ );
+ CHECK( s0.posted() );
+#ifndef CYGFUN_KERNEL_THREADS_TIMER
+ CHECK( s0.trywait() );
+#else // !CYGFUN_KERNEL_THREADS_TIMER
+ CHECK( s0.wait(10) );
+#endif // !CYGFUN_KERNEL_THREADS_TIMER
+ CHECK( ! s0.posted() );
+ s2.post();
+ s0.wait();
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+void bin_sem3_main( void )
+{
+ CYG_TEST_INIT();
+
+ new_thread( entry0, 0);
+ new_thread( entry1, 1);
+
+#ifdef CYGIMP_THREAD_PRIORITY
+ thread[0]->set_priority( 4 );
+ thread[1]->set_priority( 5 ); // make sure the threads execute as intended
+#endif
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ bin_sem3_main();
+}
+// EOF bin_sem1.cxx
diff --git a/ecos/packages/kernel/current/tests/clock0.cxx b/ecos/packages/kernel/current/tests/clock0.cxx
new file mode 100644
index 0000000000..42bdbb3fd8
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/clock0.cxx
@@ -0,0 +1,286 @@
+//==========================================================================
+//
+// clock0.cxx
+//
+// Clock test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-13
+// Description: Tests some basic clock functions.
+// Omissions: Doesn't test likely boundary conditions for
+// CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE
+// Real Time Clock Testing is limited
+// Options:
+// CYGIMP_KERNEL_COUNTERS_SINGLE_LIST
+// CYGIMP_KERNEL_COUNTERS_MULTI_LIST
+// CYGVAR_KERNEL_COUNTERS_CLOCK
+// CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE
+// Assumptions: This assumes we have long long support and
+// that counters are 64 bits.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/clock.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/clock.inl>
+
+#include "testaux.hxx"
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+
+cyg_alarm_fn call_me;
+
+bool flash( void )
+{
+ Cyg_Counter counter0 = Cyg_Counter();
+ Cyg_Counter counter1 = Cyg_Counter(723);
+
+ CYG_ASSERTCLASSO( counter0, "error" );
+ CYG_ASSERTCLASSO( counter1, "error" );
+
+ Cyg_Alarm alarm0 = Cyg_Alarm(&counter0, call_me, 12);
+
+ CYG_ASSERTCLASSO( alarm0, "error" );
+
+ Cyg_Clock::cyg_resolution res = {1,2};
+
+ Cyg_Clock clock0(res);
+
+ CYG_ASSERTCLASSO( clock0, "error" );
+
+ return true;
+}
+
+// Testing alarms
+//
+// call_me is a function that will be called when an alarm is
+// triggered. It updates a global variable called which is CHECKed
+// explicitly to see if the approriate alarms have been called.
+
+cyg_uint16 called = 0x0;
+
+void call_me(Cyg_Alarm *alarm, CYG_ADDRWORD data)
+{
+ called ^= data;
+}
+
+void call_me2(Cyg_Alarm *alarm, CYG_ADDRWORD data)
+{
+ call_me(alarm, data^0x10);
+}
+
+
+void clock0_main(void)
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ const cyg_uint32 big_number = 3333222111u;
+ Cyg_Counter counter0 = Cyg_Counter();
+
+ CHECK( 0 == counter0.current_value() );
+ CHECK( 0 == counter0.current_value_lo() );
+ CHECK( 0 == counter0.current_value_hi() );
+
+ counter0.tick();
+
+ CHECK( 1 == counter0.current_value() );
+ CHECK( 1 == counter0.current_value_lo() );
+ CHECK( 0 == counter0.current_value_hi() );
+
+ counter0.tick(6);
+
+ CHECK( 7 == counter0.current_value() );
+ CHECK( 7 == counter0.current_value_lo() );
+ CHECK( 0 == counter0.current_value_hi() );
+
+ counter0.set_value( 0xfffffffc );
+
+ CHECK( 0xfffffffc == counter0.current_value() );
+ CHECK( 0xfffffffc == counter0.current_value_lo() );
+ CHECK( 0 == counter0.current_value_hi() );
+
+ counter0.tick( 0x13 ); // Overflows 32 bits
+
+ CHECK( 0x10000000fULL == counter0.current_value() );
+ CHECK( 0xf == counter0.current_value_lo() );
+ CHECK( 0x1 == counter0.current_value_hi() );
+
+
+ Cyg_Counter counter1 = Cyg_Counter(big_number);
+
+ CHECK( 0 == counter1.current_value() );
+ CHECK( 0 == counter1.current_value_lo() );
+ CHECK( 0 == counter1.current_value_hi() );
+
+ counter1.tick(2);
+
+ CHECK( 2ll*big_number == counter1.current_value() );
+ CHECK( ((2ll*big_number) & 0xffffffff) ==
+ counter1.current_value_lo() );
+ CHECK( ((2ll*big_number) >> 32) == counter1.current_value_hi() );
+
+ counter1.tick();
+
+ CHECK( 3ll*big_number == counter1.current_value() );
+ CHECK( ((3ll*big_number) & 0xffffffff) ==
+ counter1.current_value_lo() );
+ CHECK( ((3ll*big_number) >> 32) == counter1.current_value_hi() );
+
+ counter1.tick();
+
+ CHECK( 4ll*big_number == counter1.current_value() );
+ CHECK( ((4ll*big_number) & 0xffffffff) ==
+ counter1.current_value_lo() );
+ CHECK( ((4ll*big_number) >> 32) == counter1.current_value_hi() );
+
+ counter1.set_value(1222333444555ll);
+ CHECK( 1222333444555ll == counter1.current_value() );
+
+ counter0.set_value(11);
+ CHECK( 11 == counter0.current_value() );
+
+ // the call_me functions cause the "called" bits to toggle
+ // CHECKing the value of called TEST_CHECKs the parity of # of calls
+ // made by each alarm.
+
+ Cyg_Alarm alarm0 = Cyg_Alarm(&counter0, call_me, 0x1);
+ Cyg_Alarm alarm1 = Cyg_Alarm(&counter0, call_me, 0x2);
+ Cyg_Alarm alarm2 = Cyg_Alarm(&counter0, call_me2, 0x4);
+
+ CHECK( 0x00 == called );
+ alarm0.initialize(12,3);
+ alarm2.initialize(21,2);
+ CHECK( 0x00 == called );
+
+ counter0.tick(); // 12 a0
+ CHECK( 0x01 == called );
+
+ alarm1.initialize(13,0);
+ counter0.tick(); // 13 a1
+ CHECK( 0x03 == called );
+
+ alarm1.initialize(17,0);
+ counter0.tick(); // 14
+ CHECK( 0x03 == called );
+
+ counter0.tick(); // 15 a0
+ CHECK( 0x02 == called );
+
+ counter0.tick(2); // 17 a1
+ CHECK( 0x00 == called );
+
+ counter0.tick(); // 18 a0
+ CHECK( 0x01 == called );
+
+ counter0.tick(3); // 21 a0 a2
+ CHECK( 0x14 == called );
+
+ counter0.tick(2); // 23 a2
+ CHECK( 0x00 == called );
+
+ alarm2.disable();
+
+ counter0.tick(2); // 25 a0(24)
+ CHECK( 0x01 == called );
+
+ alarm2.enable(); // a2 (enabled at 25)
+ CHECK( 0x15 == called );
+
+ counter0.tick(); // 26
+ CHECK( 0x15 == called );
+
+ counter0.tick(2); // 28 a0(27) a2(27)
+ CHECK( 0x00 == called );
+
+ counter0.tick(3); // 31 a0(30) a2(29 31)
+ CHECK( 0x01 == called );
+
+ Cyg_Clock::cyg_resolution res0;
+
+ res0.dividend = 100;
+ res0.divisor = 3;
+
+ Cyg_Clock::cyg_resolution res1;
+
+ Cyg_Clock clock0 = Cyg_Clock(res0);
+
+ res1 = clock0.get_resolution();
+ CHECK( res0.dividend == res1.dividend );
+ CHECK( res0.divisor == res1.divisor );
+
+ res1.dividend = 12;
+ res1.divisor = 25;
+
+ clock0.set_resolution(res1);
+ res0 = clock0.get_resolution();
+ CHECK( res0.dividend == res1.dividend );
+ CHECK( res0.divisor == res1.divisor );
+
+ res0 = Cyg_Clock::real_time_clock->get_resolution();
+
+ CYG_TEST_PASS_FINISH("Clock 0 OK");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ clock0_main();
+}
+
+#else // def CYGVAR_KERNEL_COUNTERS_CLOCK
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( "Kernel real-time clock disabled");
+}
+
+#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK
+// EOF clock0.cxx
diff --git a/ecos/packages/kernel/current/tests/clock1.cxx b/ecos/packages/kernel/current/tests/clock1.cxx
new file mode 100644
index 0000000000..bb8b2ae637
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/clock1.cxx
@@ -0,0 +1,132 @@
+//==========================================================================
+//
+// clock1.cxx
+//
+// Clock test 1 - Real Time Clock
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-16
+// Description: Tests the Kernel Real Time Clock
+// This test creates a thread, starts the scheduler and
+// delays for a time of about 5 seconds. This test should
+// be expected to run for about this length of time.
+// Omissions:
+// Doesn't test alarms attached to RTC.
+// Assumptions:
+// CYGVAR_KERNEL_COUNTERS_CLOCK must be set.
+// Resolution of clock small compared with 5s.
+// Overhead small compared with 5s.
+// Options:
+// CYGIMP_KERNEL_COUNTERS_SINGLE_LIST
+// CYGIMP_KERNEL_COUNTERS_MULTI_LIST
+// CYGVAR_KERNEL_COUNTERS_CLOCK
+// CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/clock.hxx>
+#include <cyg/kernel/thread.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/clock.inl>
+#include <cyg/kernel/thread.inl>
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+
+
+#define NTHREADS 1
+#include "testaux.hxx"
+
+static cyg_uint32 ticks; // Number of ticks thread[0] will delay for
+
+static cyg_uint64 TEST_DELAY;
+
+static void entry0( CYG_ADDRWORD data )
+{
+ ((Cyg_Thread *)data)->delay(ticks);
+
+ CYG_TEST_PASS_FINISH("Clock 1 OK");
+}
+
+void clock1_main( void )
+{
+ CYG_TEST_INIT();
+
+ if (cyg_test_is_simulator) {
+ TEST_DELAY = 100000000ll;
+ } else {
+ TEST_DELAY = 3000000000ll;
+ }
+
+ new_thread(entry0, (CYG_ADDRWORD)&thread_obj[0]);
+
+ Cyg_Clock::cyg_resolution res;
+
+ res = Cyg_Clock::real_time_clock->get_resolution ();
+
+ // RTC takes res.dividend/res.divisor ns/tick
+ ticks = ((cyg_uint64)TEST_DELAY * res.divisor) / res.dividend;
+
+ Cyg_Scheduler::start();
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ clock1_main();
+}
+
+#else // def CYGVAR_KERNEL_COUNTERS_CLOCK
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( "Kernel real-time clock disabled");
+}
+
+#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK
+
+// EOF clock1.cxx
diff --git a/ecos/packages/kernel/current/tests/clockcnv.cxx b/ecos/packages/kernel/current/tests/clockcnv.cxx
new file mode 100644
index 0000000000..0b47482814
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/clockcnv.cxx
@@ -0,0 +1,287 @@
+//==========================================================================
+//
+// clockcnv.cxx
+//
+// Clock Converter 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) 2003 Gary Thomas
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 2000-01-24
+// Description: Tests the Kernel Real Time Clock Converter subsystem
+//
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/clock.hxx>
+#include <cyg/kernel/thread.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/clock.inl>
+#include <cyg/kernel/thread.inl>
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+
+#include <cyg/infra/diag.h>
+
+static void null_printf(const char *, ...)
+{ /* nothing */ }
+
+#define PRINTF0 diag_printf
+#define nPRINTF0 null_printf
+
+#define nPRINTF1 diag_printf
+#define PRINTF1 null_printf
+
+#define nPRINTF2 diag_printf
+#define PRINTF2 null_printf
+
+
+#define NTHREADS 1
+#include "testaux.hxx"
+
+static struct { cyg_uint32 ns; double scale; } ns_tickers[] = {
+ { 70000000, 7.0 }, // 7cS
+ { 50000000, 5.0 }, // 5cS
+ { 45000000, 4.5 }, // 4.5cS
+ { 30000000, 3.0 }, // 3cS
+ { 20000000, 2.0 }, // 2cS
+ { 10000000, 1.0 }, // 1cS - no change
+ { 5000000, 0.5 }, // 1/2 a cS
+ { 4900000, 0.49 }, // a bit below
+ { 3333333, 0.3333333 }, // 1/3 cS
+ { 1250000, 0.125 }, // 800Hz
+ { 1000000, 0.1 }, // 1000Hz
+ { 909090, 0.0909090 }, // 1100Hz
+ { 490000, 0.049 }, // 490uS
+ { 333333, 0.0333333 }, // 1/30 cS, 1/3mS
+ { 49000, 0.0049 }, // 49uS
+ { 33333, 0.0033333 }, // 1/30 mS
+ { 4900, 0.00049 }, // 4.9uS
+ // now some outlandish ones
+ { 170, 0.000017 }, // 170nS
+ { 11, 0.0000011 }, // 11nS
+ { 1000000000u, 100.0 }, // one second
+ { 1234567777u, 123.4567777 }, // 1.234... seconds
+ { 4294967291u, 429.4967291 }, // 4.3 seconds, nearly maxint.
+ // now some which are prime in the nS per tick field
+ { 909091, 0.0909091 }, // also 1100Hz - but 909091 is a prime!
+ // and some eye-pleasing primes from the www - if they're not actually
+ // prime, don't blame me. http://www.rsok.com/~jrm/printprimes.html
+ { 1000003, 0.1000003 },
+ { 1477771, 0.1477771 },
+ { 2000003, 0.2000003 },
+ { 2382001, 0.2382001 },
+ { 3333133, 0.3333133 },
+ { 3999971, 0.3999971 },
+ { 5555591, 0.5555591 },
+ { 6013919, 0.6013919 },
+ // That's enough
+};
+
+static void entry0( CYG_ADDRWORD data )
+{
+ // First just try it with the clock as default:
+ Cyg_Clock *rtc = Cyg_Clock::real_time_clock;
+
+ Cyg_Clock::converter cv, rcv;
+ Cyg_Clock::cyg_resolution res;
+
+ unsigned int counter = 0;
+ unsigned int skipped = 0;
+
+ unsigned int i;
+ for ( i = 0; i < sizeof( ns_tickers )/sizeof( ns_tickers[0] ); i++ ) {
+
+ unsigned int lcounter = 0;
+ unsigned int lskipped = 0;
+
+ rtc->get_other_to_clock_converter( ns_tickers[i].ns, &cv );
+ rtc->get_clock_to_other_converter( ns_tickers[i].ns, &rcv );
+
+ PRINTF1( "ns per tick: %d\n", ns_tickers[i].ns );
+ PRINTF1( " converter: * %d / %d * %d / %d\n",
+ (int)cv.mul1, (int)cv.div1, (int)cv.mul2,(int) cv.div2 );
+ PRINTF1( " reverser: * %d / %d * %d / %d\n",
+ (int)rcv.mul1, (int)rcv.div1, (int)rcv.mul2, (int)rcv.div2 );
+
+ double d = 1.0;
+ d *= (double)cv.mul1;
+ d /= (double)cv.div1;
+ d *= (double)cv.mul2;
+ d /= (double)cv.div2;
+ d *= (double)rcv.mul1;
+ d /= (double)rcv.div1;
+ d *= (double)rcv.mul2;
+ d /= (double)rcv.div2;
+ PRINTF1( " composite product %d.%d\n",
+ (int)d, ((int)(d * 1000000) % 1000000 ) );
+ d -= 1.0;
+ CYG_TEST_CHECK( d < +0.0001, "Overflow in composite product" );
+ CYG_TEST_CHECK( d > -0.0001, "Underflow in composite product" );
+
+ res = rtc->get_resolution();
+
+ double factor_other_to_clock;
+ double factor_clock_to_other;
+
+ // res.dividend/res.divisor is the number of nS in a system
+ // clock tick. So:
+ d = (double)res.dividend/(double)res.divisor;
+
+ factor_other_to_clock = ns_tickers[i].scale * 1.0e7 / d ;
+ factor_clock_to_other = d / (ns_tickers[i].scale * 1.0e7);
+
+ unsigned int j;
+ for ( j = 1; j < 100; j++ ) {
+ cyg_uint64 delay;
+ if (cyg_test_is_simulator)
+ j += 30; // test fewer values
+ /* tr.b..m..k.. */
+
+#ifdef CYGPKG_HAL_V85X_V850_CEB
+ j += 30; // test fewer values
+#endif
+
+ for ( delay = j; delay < 1000000000000ll; delay *= 10 ) {
+ // get the converted result
+ cyg_uint64 result = Cyg_Clock::convert( delay, &cv );
+
+ counter++; lcounter++;
+ if ( (double)delay * (double)cv.mul1 > 1.6e+19 ||
+ (double)delay * (double)rcv.mul1 > 1.6e+19 ) {
+ // in silly territory now, give up.
+ // (that's MAXINT squared, approx.)
+ skipped++; lskipped++;
+ continue; // so the counter is accurate
+ }
+
+ PRINTF2( "delay %x%08x to result %x%08x\n",
+ (int)(delay >> 32), (int)delay,
+ (int)(result >> 32), (int)result );
+
+ // get what it should be in double maths
+ double delta = factor_other_to_clock * (double)delay;
+ if ( delta > 1000.0 ) {
+ delta = (double)result - delta;
+ delta /= (double)result;
+ CYG_TEST_CHECK( delta <= +0.01,
+ "Proportional overflow in conversion to" );
+ CYG_TEST_CHECK( delta >= -0.01,
+ "Proportional underflow in conversion to" );
+ }
+ else {
+ cyg_uint64 lo = (cyg_uint64)(delta); // assume TRUNCATION
+ cyg_uint64 hi = lo + 1;
+ CYG_TEST_CHECK( hi >= result,
+ "Range overflow in conversion to" );
+ CYG_TEST_CHECK( lo <= result,
+ "Range underflow in conversion to" );
+ }
+
+ // get the converted result
+ result = Cyg_Clock::convert( delay, &rcv );
+
+ PRINTF2( "delay %x%08x from result %x%08x\n",
+ (int)(delay >> 32), (int)delay,
+ (int)(result >> 32), (int)result );
+
+ // get what it should be in double maths
+ delta = factor_clock_to_other * (double)delay;
+ if ( delta > 1000.0 ) {
+ delta = (double)result - delta;
+ delta /= (double)result;
+ CYG_TEST_CHECK( delta <= +0.01,
+ "Proportional overflow in conversion from" );
+ CYG_TEST_CHECK( delta >= -0.01,
+ "Proportional underflow in conversion from" );
+ }
+ else {
+ cyg_uint64 lo = (cyg_uint64)(delta); // assume TRUNCATION
+ cyg_uint64 hi = lo + 1;
+ CYG_TEST_CHECK( hi >= result,
+ "Range overflow in conversion from" );
+ CYG_TEST_CHECK( lo <= result,
+ "Range underflow in conversion from" );
+ }
+
+ if (cyg_test_is_simulator)
+ break;
+ }
+ }
+ PRINTF0( "INFO:<%d nS/tick: tested %d values, skipped %d because of overflow>\n",
+ ns_tickers[i].ns, lcounter, lskipped );
+ }
+
+ PRINTF0( "INFO:<tested %d values, total skipped %d because of overflow>\n",
+ counter, skipped );
+
+ CYG_TEST_PASS_FINISH("ClockCnv OK");
+}
+
+void clockcnv_main( void )
+{
+ CYG_TEST_INIT();
+ new_thread(entry0, (CYG_ADDRWORD)&thread_obj[0]);
+ Cyg_Scheduler::start();
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ clockcnv_main();
+}
+
+#else // def CYGVAR_KERNEL_COUNTERS_CLOCK
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( "Kernel real-time clock disabled");
+}
+
+#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK
+
+// EOF clockcnv.cxx
diff --git a/ecos/packages/kernel/current/tests/clocktruth.cxx b/ecos/packages/kernel/current/tests/clocktruth.cxx
new file mode 100644
index 0000000000..c8dbad1ffd
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/clocktruth.cxx
@@ -0,0 +1,155 @@
+//==========================================================================
+//
+// clocktruth.cxx
+//
+// Clock Converter 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) 2003 Gary Thomas
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 2001-06-05
+// Description: Tests the Kernel Real Time Clock for accuracy using a human
+//
+//####DESCRIPTIONEND####
+
+
+// This is for a human to watch to sanity check the clock rate.
+// It's easier to see what's happening if you enable this:
+#define nRUNFOREVER
+
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/clock.hxx>
+#include <cyg/kernel/sema.hxx>
+#include <cyg/kernel/thread.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/clock.inl>
+#include <cyg/kernel/thread.inl>
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+
+#include <cyg/infra/diag.h>
+
+#define NTHREADS 1
+#include "testaux.hxx"
+
+#ifdef RUNFOREVER
+#define ENDPOINT 8192
+#else
+#define ENDPOINT 20
+#endif
+
+static cyg_alarm_fn alarmfunc;
+static void alarmfunc( Cyg_Alarm *alarm, CYG_ADDRWORD data )
+{
+ Cyg_Binary_Semaphore *sp = (Cyg_Binary_Semaphore *)data;
+ sp->post();
+}
+
+
+static void entry0( CYG_ADDRWORD data )
+{
+ cyg_uint32 now, then;
+ int i;
+
+ Cyg_Clock *rtc = Cyg_Clock::real_time_clock;
+
+ Cyg_Binary_Semaphore sema;
+
+ Cyg_Alarm alarm( rtc, &alarmfunc, (CYG_ADDRWORD)&sema );
+
+ // First, print 100 lines as fast as you can, of distinct ticks.
+ for ( i = 0; i < 100; i++ ) {
+ now = rtc->current_value_lo();
+ then = now;
+ while ( then == now )
+ now = rtc->current_value_lo();
+
+ diag_printf( "INFO<time now %8d>\n", now );
+ }
+
+ diag_printf( "INFO<per-second times are: %8d>\n", rtc->current_value_lo() );
+ for ( i = 0; i < 20; i++ ) {
+ Cyg_Thread::counted_sleep( 100 );
+ diag_printf( "INFO<per-second time %2d is %8d>\n",
+ i, rtc->current_value_lo() );
+ }
+
+ alarm.initialize( rtc->current_value() + 100, 100 );
+ alarm.enable();
+ for ( i = 0; i < ENDPOINT; i++ ) {
+ sema.wait();
+ diag_printf( "INFO<alarm time %2d is %8d>\n",
+ i, rtc->current_value_lo() );
+ }
+
+ CYG_TEST_PASS_FINISH("Clock truth OK");
+}
+
+void clocktruth_main( void )
+{
+ CYG_TEST_INIT();
+ new_thread(entry0, (CYG_ADDRWORD)&thread_obj[0]);
+ Cyg_Scheduler::start();
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ clocktruth_main();
+}
+
+#else // def CYGVAR_KERNEL_COUNTERS_CLOCK
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( "Kernel real-time clock disabled");
+}
+
+#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK
+
+// EOF clocktruth.cxx
diff --git a/ecos/packages/kernel/current/tests/cnt_sem0.cxx b/ecos/packages/kernel/current/tests/cnt_sem0.cxx
new file mode 100644
index 0000000000..8ef0f1656c
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/cnt_sem0.cxx
@@ -0,0 +1,89 @@
+//==========================================================================
+//
+// cnt_sem0.cxx
+//
+// Counting semaphore test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-24
+// Description: Limited to checking constructors/destructors
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+static Cyg_Counting_Semaphore sema0, sema1(0), sema2(1);
+
+#include "testaux.hxx"
+
+static bool flash( void )
+{
+ Cyg_Counting_Semaphore s0;
+
+ Cyg_Counting_Semaphore s1(97);
+
+ Cyg_Counting_Semaphore s2(0);
+
+ return true;
+}
+
+void cnt_sem0_main( void )
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ CYG_TEST_PASS_FINISH("Counting Semaphore 0 OK");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ cnt_sem0_main();
+}
+
+// EOF cnt_sem0.cxx
diff --git a/ecos/packages/kernel/current/tests/cnt_sem1.cxx b/ecos/packages/kernel/current/tests/cnt_sem1.cxx
new file mode 100644
index 0000000000..f23b63f7d3
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/cnt_sem1.cxx
@@ -0,0 +1,135 @@
+//==========================================================================
+//
+// cnt_sem1.cxx
+//
+// Counting semaphore test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-24
+// Description: Tests basic counting semaphore functionality.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start()
+
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+
+
+#define NTHREADS 2
+#include "testaux.hxx"
+
+static Cyg_Counting_Semaphore s0(0), s1(2), s2;
+
+static volatile cyg_ucount8 q = 0;
+
+static void entry0( CYG_ADDRWORD data )
+{
+ s0.wait();
+ CHECK( 1 == q++ );
+ s1.post();
+ s0.wait();
+ CHECK( 3 == q++ );
+ CHECK( 0 == s0.peek() );
+ CHECK( ! s0.trywait() );
+ s0.post();
+ CHECK( 4 == q++ );
+ CHECK( 1 == s0.peek() );
+ s0.post();
+ CHECK( 2 == s0.peek() );
+ s1.post();
+ CHECK( 0 == s2.peek() );
+ s2.wait();
+ CHECK( 6 == q++ );
+ CYG_TEST_PASS_FINISH("Counting Semaphore 1 OK");
+}
+
+static void entry1( CYG_ADDRWORD data )
+{
+ CHECK( 2 == s1.peek() );
+ s1.wait();
+ CHECK( 1 == s1.peek() );
+ s1.wait();
+ CHECK( 0 == q++ );
+ CHECK( 0 == s0.peek() );
+ s0.post();
+ s1.wait();
+ CHECK( 2 == q++ );
+ s0.post();
+ s1.wait();
+ CHECK( 5 == q++ );
+ CHECK( 2 == s0.peek() );
+ CHECK( s0.trywait() );
+ CHECK( 1 == s0.peek() );
+ CHECK( s0.trywait() );
+ CHECK( 0 == s0.peek() );
+ s2.post();
+ s0.wait();
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+void cnt_sem1_main( void )
+{
+ CYG_TEST_INIT();
+
+ new_thread(entry0, 0);
+ new_thread(entry1, 1);
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ cnt_sem1_main();
+}
+
+// EOF cnt_sem1.cxx
diff --git a/ecos/packages/kernel/current/tests/dhrystone.c b/ecos/packages/kernel/current/tests/dhrystone.c
new file mode 100644
index 0000000000..6eb3d0a4ec
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/dhrystone.c
@@ -0,0 +1,1176 @@
+//=============================================================================
+//####UNSUPPORTEDBEGIN####
+//
+// -------------------------------------------
+// This source file has been contributed to eCos/Red Hat. It may have been
+// changed slightly to provide an interface consistent with those of other
+// files.
+//
+// The functionality and contents of this file is supplied "AS IS"
+// without any form of support and will not necessarily be kept up
+// to date by Red Hat.
+//
+// The style of programming used in this file may not comply with the
+// eCos programming guidelines. Please do not use as a base for other
+// files.
+//
+// All inquiries about this file, or the functionality provided by it,
+// should be directed to the 'ecos-discuss' mailing list (see
+// http://ecos.sourceware.org/ecos/intouch.html for details).
+//
+// -------------------------------------------
+//
+//####UNSUPPORTEDEND####
+//=============================================================================
+// Originally three different files, dhry.h, dhry21a.c and dhry21b.c
+// Merged into one file and changed a little to avoid compilation warnings.
+// The files were found at:
+// FTP ftp.nosc.mil/pub/aburto/dhrystone
+//=============================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/infra.h>
+#include <pkgconf/kernel.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/testcase.h>
+
+#if !defined(CYGPKG_ISOINFRA)
+# define NA_MSG "Requires CYGPKG_ISOINFRA"
+#else
+# include <pkgconf/isoinfra.h>
+
+# if !defined(CYGFUN_KERNEL_API_C) \
+ || !defined(CYGINT_ISO_STDIO_FORMATTED_IO) \
+ || CYGINT_ISO_MALLOC == 0 \
+ || !defined(CYGINT_ISO_STRING_STRFUNCS)
+
+# define NA_MSG "Requires CYGFUN_KERNEL_API_C && CYGINT_ISO_STDIO_FORMATTED_IO && CYGINT_ISO_MALLOC && CYGINT_ISO_STRING_STRFUNCS"
+
+# elif !defined(__OPTIMIZE__) \
+ || defined(CYGPKG_INFRA_DEBUG) \
+ || defined(CYGPKG_KERNEL_INSTRUMENT)
+# define NA_MSG "Only runs with optimized code, no tracing and no asserts"
+# elif defined(CYGDBG_INFRA_DIAG_USE_DEVICE)
+# define NA_MSG "Must use HAL diag output to avoid background DSR activity"
+# endif
+#endif
+
+#ifndef NA_MSG
+
+#include <cyg/hal/hal_cache.h>
+#include <cyg/kernel/kapi.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Time in seconds.
+double
+dtime(void)
+{
+ return (double) cyg_current_time() / 100;
+}
+
+// Number of loops to run.
+#if defined(CYGPRI_KERNEL_TESTS_DHRYSTONE_PASSES)
+# define PASSES CYGPRI_KERNEL_TESTS_DHRYSTONE_PASSES
+#else
+# define PASSES 400000
+#endif
+
+// Used in the code below to mark changes to the code.
+#define __ECOS__
+
+#undef true
+#undef false
+
+
+/*
+ *************************************************************************
+ *
+ * "DHRYSTONE" Benchmark Program
+ * -----------------------------
+ *
+ * Version: C, Version 2.1
+ *
+ * File: dhry.h (part 1 of 3)
+ *
+ * Date: May 25, 1988
+ *
+ * Author: Reinhold P. Weicker
+ * Siemens Nixdorf Inf. Syst.
+ * STM OS 32
+ * Otto-Hahn-Ring 6
+ * W-8000 Muenchen 83
+ * Germany
+ * Phone: [+49]-89-636-42436
+ * (8-17 Central European Time)
+ * UUCP: weicker@ztivax.uucp@unido.uucp
+ * Internet: weicker@ztivax.siemens.com
+ *
+ * Original Version (in Ada) published in
+ * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
+ * pp. 1013 - 1030, together with the statistics
+ * on which the distribution of statements etc. is based.
+ *
+ * In this C version, the following C library functions are
+ * used:
+ * - strcpy, strcmp (inside the measurement loop)
+ * - printf, scanf (outside the measurement loop)
+ *
+ * Collection of Results:
+ * Reinhold Weicker (address see above) and
+ *
+ * Rick Richardson
+ * PC Research. Inc.
+ * 94 Apple Orchard Drive
+ * Tinton Falls, NJ 07724
+ * Phone: (201) 834-1378 (9-17 EST)
+ * UUCP: ...!uunet!pcrat!rick
+ *
+ * Please send results to Rick Richardson and/or Reinhold Weicker.
+ * Complete information should be given on hardware and software
+ * used. Hardware information includes: Machine type, CPU, type and
+ * size of caches; for microprocessors: clock frequency, memory speed
+ * (number of wait states). Software information includes: Compiler
+ * (and runtime library) manufacturer and version, compilation
+ * switches, OS version. The Operating System version may give an
+ * indication about the compiler; Dhrystone itself performs no OS
+ * calls in the measurement loop.
+ *
+ * The complete output generated by the program should be mailed
+ * such that at least some checks for correctness can be made.
+ *
+ *************************************************************************
+ *
+ * History: This version C/2.1 has been made for two reasons:
+ *
+ * 1) There is an obvious need for a common C version of
+ * Dhrystone, since C is at present the most popular system
+ * programming language for the class of processors
+ * (microcomputers, minicomputers) where Dhrystone is used
+ * most. There should be, as far as possible, only one C
+ * version of Dhrystone such that results can be compared
+ * without restrictions. In the past, the C versions
+ * distributed by Rick Richardson (Version 1.1) and by
+ * Reinhold Weicker had small (though not significant)
+ * differences.
+ *
+ * 2) As far as it is possible without changes to the
+ * Dhrystone statistics, optimizing compilers should be
+ * prevented from removing significant statements.
+ *
+ * This C version has been developed in cooperation with
+ * Rick Richardson (Tinton Falls, NJ), it incorporates many
+ * ideas from the "Version 1.1" distributed previously by
+ * him over the UNIX network Usenet.
+ * I also thank Chaim Benedelac (National Semiconductor),
+ * David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
+ * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
+ * for their help with comments on earlier versions of the
+ * benchmark.
+ *
+ * Changes: In the initialization part, this version follows mostly
+ * Rick Richardson's version distributed via Usenet, not the
+ * version distributed earlier via floppy disk by Reinhold
+ * Weicker. As a concession to older compilers, names have
+ * been made unique within the first 8 characters. Inside the
+ * measurement loop, this version follows the version
+ * previously distributed by Reinhold Weicker.
+ *
+ * At several places in the benchmark, code has been added,
+ * but within the measurement loop only in branches that
+ * are not executed. The intention is that optimizing
+ * compilers should be prevented from moving code out of the
+ * measurement loop, or from removing code altogether. Since
+ * the statements that are executed within the measurement
+ * loop have NOT been changed, the numbers defining the
+ * "Dhrystone distribution" (distribution of statements,
+ * operand types and locality) still hold. Except for
+ * sophisticated optimizing compilers, execution times for
+ * this version should be the same as for previous versions.
+ *
+ * Since it has proven difficult to subtract the time for the
+ * measurement loop overhead in a correct way, the loop check
+ * has been made a part of the benchmark. This does have
+ * an impact - though a very minor one - on the distribution
+ * statistics which have been updated for this version.
+ *
+ * All changes within the measurement loop are described
+ * and discussed in the companion paper "Rationale for
+ * Dhrystone version 2".
+ *
+ * Because of the self-imposed limitation that the order and
+ * distribution of the executed statements should not be
+ * changed, there are still cases where optimizing compilers
+ * may not generate code for some statements. To a certain
+ * degree, this is unavoidable for small synthetic
+ * benchmarks. Users of the benchmark are advised to check
+ * code listings whether code is generated for all statements
+ * of Dhrystone.
+ *
+ * Version 2.1 is identical to version 2.0 distributed via
+ * the UNIX network Usenet in March 1988 except that it
+ * corrects some minor deficiencies that were found by users
+ * of version 2.0. The only change within the measurement
+ * loop is that a non-executed "else" part was added to the
+ * "if" statement in Func_3, and a non-executed "else" part
+ * removed from Proc_3.
+ *
+ *************************************************************************
+ *
+ * Defines: The following "Defines" are possible:
+ * -DROPT (default: Not defined)
+ * As an approximation to what an average C
+ * programmer might do, the "register" storage class
+ * is applied (if enabled by -DROPT)
+ * - for local variables, if they are used
+ * (dynamically) five or more times
+ * - for parameters if they are used (dynamically)
+ * six or more times
+ * Note that an optimal "register" strategy is
+ * compiler-dependent, and that "register"
+ * declarations do not necessarily lead to faster
+ * execution.
+ * -DNOSTRUCTASSIGN (default: Not defined)
+ * Define if the C compiler does not support
+ * assignment of structures.
+ * -DNOENUMS (default: Not defined)
+ * Define if the C compiler does not support
+ * enumeration types.
+ *
+ *************************************************************************
+ *
+ * Compilation model and measurement (IMPORTANT):
+ *
+ * This C version of Dhrystone consists of three files:
+ * - dhry.h (this file, containing global definitions and comments)
+ * - dhry_1.c (containing the code corresponding to Ada package Pack_1)
+ * - dhry_2.c (containing the code corresponding to Ada package Pack_2)
+ *
+ * The following "ground rules" apply for measurements:
+ * - Separate compilation
+ * - No procedure merging
+ * - Otherwise, compiler optimizations are allowed but should be
+ * indicated
+ * - Default results are those without register declarations
+ * See the companion paper "Rationale for Dhrystone Version 2" for a more
+ * detailed discussion of these ground rules.
+ *
+ * For 16-Bit processors (e.g. 80186, 80286), times for all compilation
+ * models ("small", "medium", "large" etc.) should be given if possible,
+ * together with a definition of these models for the compiler system
+ * used.
+ *
+ *************************************************************************
+ *
+ * Dhrystone (C version) statistics:
+ *
+ * [Comment from the first distribution, updated for version 2.
+ * Note that because of language differences, the numbers are slightly
+ * different from the Ada version.]
+ *
+ * The following program contains statements of a high level programming
+ * language (here: C) in a distribution considered representative:
+ *
+ * assignments 52 (51.0 %)
+ * control statements 33 (32.4 %)
+ * procedure, function calls 17 (16.7 %)
+ *
+ * 103 statements are dynamically executed. The program is balanced with
+ * respect to the three aspects:
+ *
+ * - statement type
+ * - operand type
+ * - operand locality
+ * operand global, local, parameter, or constant.
+ *
+ * The combination of these three aspects is balanced only approximately.
+ *
+ * 1. Statement Type:
+ * ----------------- number
+ *
+ * V1 = V2 9
+ * (incl. V1 = F(..)
+ * V = Constant 12
+ * Assignment, 7
+ * with array element
+ * Assignment, 6
+ * with record component
+ * --
+ * 34 34
+ *
+ * X = Y +|-|"&&"|"|" Z 5
+ * X = Y +|-|"==" Constant 6
+ * X = X +|- 1 3
+ * X = Y *|/ Z 2
+ * X = Expression, 1
+ * two operators
+ * X = Expression, 1
+ * three operators
+ * --
+ * 18 18
+ *
+ * if .... 14
+ * with "else" 7
+ * without "else" 7
+ * executed 3
+ * not executed 4
+ * for ... 7 | counted every time
+ * while ... 4 | the loop condition
+ * do ... while 1 | is evaluated
+ * switch ... 1
+ * break 1
+ * declaration with 1
+ * initialization
+ * --
+ * 34 34
+ *
+ * P (...) procedure call 11
+ * user procedure 10
+ * library procedure 1
+ * X = F (...)
+ * function call 6
+ * user function 5
+ * library function 1
+ * --
+ * 17 17
+ * ---
+ * 103
+ *
+ * The average number of parameters in procedure or function calls
+ * is 1.82 (not counting the function values as implicit parameters).
+ *
+ *
+ * 2. Operators
+ * ------------
+ * number approximate
+ * percentage
+ *
+ * Arithmetic 32 50.8
+ *
+ * + 21 33.3
+ * - 7 11.1
+ * * 3 4.8
+ * / (int div) 1 1.6
+ *
+ * Comparison 27 42.8
+ *
+ * == 9 14.3
+ * /= 4 6.3
+ * > 1 1.6
+ * < 3 4.8
+ * >= 1 1.6
+ * <= 9 14.3
+ *
+ * Logic 4 6.3
+ *
+ * && (AND-THEN) 1 1.6
+ * | (OR) 1 1.6
+ * ! (NOT) 2 3.2
+ *
+ * -- -----
+ * 63 100.1
+ *
+ *
+ * 3. Operand Type (counted once per operand reference):
+ * ---------------
+ * number approximate
+ * percentage
+ *
+ * Integer 175 72.3 %
+ * Character 45 18.6 %
+ * Pointer 12 5.0 %
+ * String30 6 2.5 %
+ * Array 2 0.8 %
+ * Record 2 0.8 %
+ * --- -------
+ * 242 100.0 %
+ *
+ * When there is an access path leading to the final operand (e.g. a
+ * record component), only the final data type on the access path is
+ * counted.
+ *
+ *
+ * 4. Operand Locality:
+ * -------------------
+ * number approximate
+ * percentage
+ *
+ * local variable 114 47.1 %
+ * global variable 22 9.1 %
+ * parameter 45 18.6 %
+ * value 23 9.5 %
+ * reference 22 9.1 %
+ * function result 6 2.5 %
+ * constant 55 22.7 %
+ * --- -------
+ * 242 100.0 %
+ *
+ *
+ * The program does not compute anything meaningful, but it is
+ * syntactically and semantically correct. All variables have a value
+ * assigned to them before they are used as a source operand.
+ *
+ * There has been no explicit effort to account for the effects of a
+ * cache, or to balance the use of long or short displacements for code
+ * or data.
+ *
+ *************************************************************************
+ */
+
+/* Compiler and system dependent definitions: */
+
+#define Mic_secs_Per_Second 1000000.0
+ /* Berkeley UNIX C returns process times in seconds/HZ */
+
+#ifdef NOSTRUCTASSIGN
+#define structassign(d, s) memcpy(&(d), &(s), sizeof(d))
+#else
+#define structassign(d, s) d = s
+#endif
+
+#ifdef NOENUM
+#define Ident_1 0
+#define Ident_2 1
+#define Ident_3 2
+#define Ident_4 3
+#define Ident_5 4
+ typedef int Enumeration;
+#else
+ typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
+ Enumeration;
+#endif
+ /* for boolean and enumeration types in Ada, Pascal */
+
+/* General definitions: */
+
+#include <stdio.h>
+ /* for strcpy, strcmp */
+
+#define Null 0
+ /* Value of a Null pointer */
+#define true 1
+#define false 0
+
+typedef int One_Thirty;
+typedef int One_Fifty;
+typedef char Capital_Letter;
+typedef int Boolean;
+typedef char Str_30 [31];
+typedef int Arr_1_Dim [50];
+typedef int Arr_2_Dim [50] [50];
+
+typedef struct record
+ {
+ struct record *Ptr_Comp;
+ Enumeration Discr;
+ union {
+ struct {
+ Enumeration Enum_Comp;
+ int Int_Comp;
+ char Str_Comp [31];
+ } var_1;
+ struct {
+ Enumeration E_Comp_2;
+ char Str_2_Comp [31];
+ } var_2;
+ struct {
+ char Ch_1_Comp;
+ char Ch_2_Comp;
+ } var_3;
+ } variant;
+ } Rec_Type, *Rec_Pointer;
+
+#ifdef __ECOS__
+
+#ifndef ROPT
+#define REG
+ /* REG becomes defined as empty */
+ /* i.e. no register variables */
+#else
+#define REG register
+#endif
+
+Boolean Func_2 (Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref);
+Boolean Func_3 (Enumeration Enum_Par_Val);
+
+void Proc_1 (REG Rec_Pointer Ptr_Val_Par);
+void Proc_2 (One_Fifty* Int_Par_Ref);
+void Proc_3 (Rec_Pointer *Ptr_Ref_Par);
+void Proc_4 (void);
+void Proc_5 (void);
+void Proc_6 (Enumeration Enum_Val_Par, Enumeration* Enum_Ref_Par);
+void Proc_7 (One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val,
+ One_Fifty* Int_Par_Ref);
+void Proc_8 (Arr_1_Dim Arr_1_Par_Ref, Arr_2_Dim Arr_2_Par_Ref,
+ int Int_1_Par_Val, int Int_2_Par_Val);
+Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val);
+
+#endif // __ECOS__
+
+/*
+ *************************************************************************
+ *
+ * "DHRYSTONE" Benchmark Program
+ * -----------------------------
+ *
+ * Version: C, Version 2.1
+ *
+ * File: dhry_1.c (part 2 of 3)
+ *
+ * Date: May 25, 1988
+ *
+ * Author: Reinhold P. Weicker
+ *
+ *************************************************************************
+ */
+
+#include <stdio.h>
+#ifndef __ECOS__
+#include "dhry.h"
+#endif // __ECOS__
+
+/* Global Variables: */
+
+Rec_Pointer Ptr_Glob,
+ Next_Ptr_Glob;
+int Int_Glob;
+Boolean Bool_Glob;
+char Ch_1_Glob,
+ Ch_2_Glob;
+int Arr_1_Glob [50];
+int Arr_2_Glob [50] [50];
+
+char Reg_Define[] = "Register option selected.";
+
+#ifndef __ECOS__
+extern char *malloc ();
+Enumeration Func_1 ();
+#endif
+ /*
+ forward declaration necessary since Enumeration may not simply be int
+ */
+
+#ifndef __ECOS__
+#ifndef ROPT
+#define REG
+ /* REG becomes defined as empty */
+ /* i.e. no register variables */
+#else
+#define REG register
+#endif
+#endif
+
+/* variables for time measurement: */
+
+#define Too_Small_Time 2
+ /* Measurements should last at least 2 seconds */
+
+double Begin_Time,
+ End_Time,
+ User_Time;
+
+double Microseconds,
+ Dhrystones_Per_Second,
+ Vax_Mips;
+
+/* end of variables for time measurement */
+
+
+#ifndef __ECOS__
+void main ()
+#else // __ECOS__
+int main (void)
+#endif // __ECOS__
+/*****/
+
+ /* main program, corresponds to procedures */
+ /* Main and Proc_0 in the Ada version */
+{
+#ifndef __ECOS__
+ double dtime();
+#endif // __ECOS__
+
+ One_Fifty Int_1_Loc;
+ REG One_Fifty Int_2_Loc;
+ One_Fifty Int_3_Loc;
+ REG char Ch_Index;
+ Enumeration Enum_Loc;
+ Str_30 Str_1_Loc;
+ Str_30 Str_2_Loc;
+ REG int Run_Index;
+ REG int Number_Of_Runs;
+
+
+#ifdef __ECOS__
+
+ CYG_TEST_INIT();
+
+#ifdef CYG_HAL_I386_LINUX
+ CYG_TEST_NA("Only runs on hardware...");
+#else
+ if (cyg_test_is_simulator)
+ CYG_TEST_NA("Only runs on hardware...");
+#endif
+
+#else // __ECOS__
+ FILE *Ap;
+
+ /* Initializations */
+
+ if ((Ap = fopen("dhry.res","a+")) == NULL)
+ {
+ printf("Can not open dhry.res\n\n");
+ exit(1);
+ }
+#endif // __ECOS__
+
+ Next_Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+ Ptr_Glob = (Rec_Pointer) malloc (sizeof (Rec_Type));
+
+ Ptr_Glob->Ptr_Comp = Next_Ptr_Glob;
+ Ptr_Glob->Discr = Ident_1;
+ Ptr_Glob->variant.var_1.Enum_Comp = Ident_3;
+ Ptr_Glob->variant.var_1.Int_Comp = 40;
+ strcpy (Ptr_Glob->variant.var_1.Str_Comp,
+ "DHRYSTONE PROGRAM, SOME STRING");
+ strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
+
+ Arr_2_Glob [8][7] = 10;
+ /* Was missing in published program. Without this statement, */
+ /* Arr_2_Glob [8][7] would have an undefined value. */
+ /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */
+ /* overflow may occur for this array element. */
+
+ printf ("\n");
+ printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n");
+ printf ("\n");
+/*
+ if (Reg)
+ {
+ printf ("Program compiled with 'register' attribute\n");
+ printf ("\n");
+ }
+ else
+ {
+ printf ("Program compiled without 'register' attribute\n");
+ printf ("\n");
+ }
+*/
+#ifdef __ECOS__
+ Number_Of_Runs = PASSES;
+#else // __ECOS__
+ printf ("Please give the number of runs through the benchmark: ");
+ {
+ int n;
+ scanf ("%d", &n);
+ Number_Of_Runs = n;
+ }
+ printf ("\n");
+#endif // __ECOS__
+
+ printf ("Execution starts, %d runs through Dhrystone\n",Number_Of_Runs);
+
+ /***************/
+ /* Start timer */
+ /***************/
+
+ Begin_Time = dtime();
+
+ for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index)
+ {
+
+ Proc_5();
+ Proc_4();
+ /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
+ Int_1_Loc = 2;
+ Int_2_Loc = 3;
+ strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
+ Enum_Loc = Ident_2;
+ Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
+ /* Bool_Glob == 1 */
+ while (Int_1_Loc < Int_2_Loc) /* loop body executed once */
+ {
+ Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
+ /* Int_3_Loc == 7 */
+ Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
+ /* Int_3_Loc == 7 */
+ Int_1_Loc += 1;
+ } /* while */
+ /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+ Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
+ /* Int_Glob == 5 */
+ Proc_1 (Ptr_Glob);
+ for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
+ /* loop body executed twice */
+ {
+ if (Enum_Loc == Func_1 (Ch_Index, 'C'))
+ /* then, not executed */
+ {
+ Proc_6 (Ident_1, &Enum_Loc);
+ strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
+ Int_2_Loc = Run_Index;
+ Int_Glob = Run_Index;
+ }
+ }
+ /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+ Int_2_Loc = Int_2_Loc * Int_1_Loc;
+ Int_1_Loc = Int_2_Loc / Int_3_Loc;
+ Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
+ /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
+ Proc_2 (&Int_1_Loc);
+ /* Int_1_Loc == 5 */
+
+ } /* loop "for Run_Index" */
+
+ /**************/
+ /* Stop timer */
+ /**************/
+
+ End_Time = dtime();
+
+ printf ("Execution ends\n");
+ printf ("\n");
+ printf ("Final values of the variables used in the benchmark:\n");
+ printf ("\n");
+ printf ("Int_Glob: %d\n", Int_Glob);
+ printf (" should be: %d\n", 5);
+ printf ("Bool_Glob: %d\n", Bool_Glob);
+ printf (" should be: %d\n", 1);
+ printf ("Ch_1_Glob: %c\n", Ch_1_Glob);
+ printf (" should be: %c\n", 'A');
+ printf ("Ch_2_Glob: %c\n", Ch_2_Glob);
+ printf (" should be: %c\n", 'B');
+ printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]);
+ printf (" should be: %d\n", 7);
+ printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]);
+ printf (" should be: Number_Of_Runs + 10\n");
+ printf ("Ptr_Glob->\n");
+ printf (" Ptr_Comp: %d\n", (int) Ptr_Glob->Ptr_Comp);
+ printf (" should be: (implementation-dependent)\n");
+ printf (" Discr: %d\n", Ptr_Glob->Discr);
+ printf (" should be: %d\n", 0);
+ printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp);
+ printf (" should be: %d\n", 2);
+ printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp);
+ printf (" should be: %d\n", 17);
+ printf (" Str_Comp: %s\n", Ptr_Glob->variant.var_1.Str_Comp);
+ printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
+ printf ("Next_Ptr_Glob->\n");
+ printf (" Ptr_Comp: %d\n", (int) Next_Ptr_Glob->Ptr_Comp);
+ printf (" should be: (implementation-dependent), same as above\n");
+ printf (" Discr: %d\n", Next_Ptr_Glob->Discr);
+ printf (" should be: %d\n", 0);
+ printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp);
+ printf (" should be: %d\n", 1);
+ printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp);
+ printf (" should be: %d\n", 18);
+ printf (" Str_Comp: %s\n", Next_Ptr_Glob->variant.var_1.Str_Comp);
+ printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
+ printf ("Int_1_Loc: %d\n", Int_1_Loc);
+ printf (" should be: %d\n", 5);
+ printf ("Int_2_Loc: %d\n", Int_2_Loc);
+ printf (" should be: %d\n", 13);
+ printf ("Int_3_Loc: %d\n", Int_3_Loc);
+ printf (" should be: %d\n", 7);
+ printf ("Enum_Loc: %d\n", Enum_Loc);
+ printf (" should be: %d\n", 1);
+ printf ("Str_1_Loc: %s\n", Str_1_Loc);
+ printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n");
+ printf ("Str_2_Loc: %s\n", Str_2_Loc);
+ printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n");
+ printf ("\n");
+
+ User_Time = End_Time - Begin_Time;
+
+ if (User_Time < Too_Small_Time)
+ {
+ printf ("Measured time too small to obtain meaningful results\n");
+ printf ("Please increase number of runs\n");
+ printf ("\n");
+ }
+ else
+ {
+ Microseconds = User_Time * Mic_secs_Per_Second
+ / (double) Number_Of_Runs;
+ Dhrystones_Per_Second = (double) Number_Of_Runs / User_Time;
+ Vax_Mips = Dhrystones_Per_Second / 1757.0;
+
+#ifdef ROPT
+ printf ("Register option selected? YES\n");
+#else
+ printf ("Register option selected? NO\n");
+#ifndef __ECOS__
+ strcpy(Reg_Define, "Register option not selected.");
+#endif // __ECOS__
+#endif
+ printf ("Microseconds for one run through Dhrystone: ");
+#ifdef __ECOS__
+ printf ("%7.1f \n", Microseconds);
+ printf ("Dhrystones per Second: ");
+ printf ("%10.1f \n", Dhrystones_Per_Second);
+ printf ("VAX MIPS rating = %10.3f \n",Vax_Mips);
+ printf ("\n");
+#else // __ECOS__
+ printf ("%7.1lf \n", Microseconds);
+ printf ("Dhrystones per Second: ");
+ printf ("%10.1lf \n", Dhrystones_Per_Second);
+ printf ("VAX MIPS rating = %10.3lf \n",Vax_Mips);
+ printf ("\n");
+
+ fprintf(Ap,"\n");
+ fprintf(Ap,"Dhrystone Benchmark, Version 2.1 (Language: C)\n");
+ fprintf(Ap,"%s\n",Reg_Define);
+ fprintf(Ap,"Microseconds for one loop: %7.1lf\n",Microseconds);
+ fprintf(Ap,"Dhrystones per second: %10.1lf\n",Dhrystones_Per_Second);
+ fprintf(Ap,"VAX MIPS rating: %10.3lf\n",Vax_Mips);
+ fclose(Ap);
+#endif // __ECOS__
+ }
+
+#ifdef __ECOS__
+ CYG_TEST_PASS_FINISH("Dhrystone test");
+#endif // __ECOS__
+}
+
+
+#ifdef __ECOS__
+void
+#endif // __ECOS__
+Proc_1 (Ptr_Val_Par)
+/******************/
+
+REG Rec_Pointer Ptr_Val_Par;
+ /* executed once */
+{
+ REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
+ /* == Ptr_Glob_Next */
+ /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */
+ /* corresponds to "rename" in Ada, "with" in Pascal */
+
+ structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob);
+ Ptr_Val_Par->variant.var_1.Int_Comp = 5;
+ Next_Record->variant.var_1.Int_Comp
+ = Ptr_Val_Par->variant.var_1.Int_Comp;
+ Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
+ Proc_3 (&Next_Record->Ptr_Comp);
+ /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp
+ == Ptr_Glob->Ptr_Comp */
+ if (Next_Record->Discr == Ident_1)
+ /* then, executed */
+ {
+ Next_Record->variant.var_1.Int_Comp = 6;
+ Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp,
+ &Next_Record->variant.var_1.Enum_Comp);
+ Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
+ Proc_7 (Next_Record->variant.var_1.Int_Comp, 10,
+ &Next_Record->variant.var_1.Int_Comp);
+ }
+ else /* not executed */
+ structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
+} /* Proc_1 */
+
+
+#ifdef __ECOS__
+void
+#endif // __ECOS__
+Proc_2 (Int_Par_Ref)
+/******************/
+ /* executed once */
+ /* *Int_Par_Ref == 1, becomes 4 */
+
+One_Fifty *Int_Par_Ref;
+{
+ One_Fifty Int_Loc;
+#ifdef __ECOS__
+ Enumeration Enum_Loc = Ident_1;
+#else // __ECOS__
+ Enumeration Enum_Loc;
+#endif // __ECOS__
+
+ Int_Loc = *Int_Par_Ref + 10;
+ do /* executed once */
+ if (Ch_1_Glob == 'A')
+ /* then, executed */
+ {
+ Int_Loc -= 1;
+ *Int_Par_Ref = Int_Loc - Int_Glob;
+ Enum_Loc = Ident_1;
+ } /* if */
+ while (Enum_Loc != Ident_1); /* true */
+} /* Proc_2 */
+
+
+#ifdef __ECOS__
+void
+#endif // __ECOS__
+Proc_3 (Ptr_Ref_Par)
+/******************/
+ /* executed once */
+ /* Ptr_Ref_Par becomes Ptr_Glob */
+
+Rec_Pointer *Ptr_Ref_Par;
+
+{
+ if (Ptr_Glob != Null)
+ /* then, executed */
+ *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp;
+ Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp);
+} /* Proc_3 */
+
+
+#ifdef __ECOS__
+void
+#endif // __ECOS__
+Proc_4 () /* without parameters */
+/*******/
+ /* executed once */
+{
+ Boolean Bool_Loc;
+
+ Bool_Loc = Ch_1_Glob == 'A';
+ Bool_Glob = Bool_Loc | Bool_Glob;
+ Ch_2_Glob = 'B';
+} /* Proc_4 */
+
+
+#ifdef __ECOS__
+void
+#endif // __ECOS__
+Proc_5 () /* without parameters */
+/*******/
+ /* executed once */
+{
+ Ch_1_Glob = 'A';
+ Bool_Glob = false;
+} /* Proc_5 */
+
+
+ /* Procedure for the assignment of structures, */
+ /* if the C compiler doesn't support this feature */
+#ifdef NOSTRUCTASSIGN
+memcpy (d, s, l)
+register char *d;
+register char *s;
+register int l;
+{
+ while (l--) *d++ = *s++;
+}
+#endif
+
+/*
+ *************************************************************************
+ *
+ * "DHRYSTONE" Benchmark Program
+ * -----------------------------
+ *
+ * Version: C, Version 2.1
+ *
+ * File: dhry_2.c (part 3 of 3)
+ *
+ * Date: May 25, 1988
+ *
+ * Author: Reinhold P. Weicker
+ *
+ *************************************************************************
+ */
+
+#ifndef __ECOS__
+#include "dhry.h"
+
+#ifndef REG
+#define REG
+ /* REG becomes defined as empty */
+ /* i.e. no register variables */
+#else
+#define REG register
+#endif
+#endif // __ECOS__
+
+extern int Int_Glob;
+extern char Ch_1_Glob;
+
+#ifdef __ECOS__
+void
+#endif // __ECOS__
+Proc_6 (Enum_Val_Par, Enum_Ref_Par)
+/*********************************/
+ /* executed once */
+ /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
+
+Enumeration Enum_Val_Par;
+Enumeration *Enum_Ref_Par;
+{
+ *Enum_Ref_Par = Enum_Val_Par;
+ if (! Func_3 (Enum_Val_Par))
+ /* then, not executed */
+ *Enum_Ref_Par = Ident_4;
+ switch (Enum_Val_Par)
+ {
+ case Ident_1:
+ *Enum_Ref_Par = Ident_1;
+ break;
+ case Ident_2:
+ if (Int_Glob > 100)
+ /* then */
+ *Enum_Ref_Par = Ident_1;
+ else *Enum_Ref_Par = Ident_4;
+ break;
+ case Ident_3: /* executed */
+ *Enum_Ref_Par = Ident_2;
+ break;
+ case Ident_4: break;
+ case Ident_5:
+ *Enum_Ref_Par = Ident_3;
+ break;
+ } /* switch */
+} /* Proc_6 */
+
+
+#ifdef __ECOS__
+void
+#endif // __ECOS__
+Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref)
+/**********************************************/
+ /* executed three times */
+ /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */
+ /* Int_Par_Ref becomes 7 */
+ /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
+ /* Int_Par_Ref becomes 17 */
+ /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
+ /* Int_Par_Ref becomes 18 */
+One_Fifty Int_1_Par_Val;
+One_Fifty Int_2_Par_Val;
+One_Fifty *Int_Par_Ref;
+{
+ One_Fifty Int_Loc;
+
+ Int_Loc = Int_1_Par_Val + 2;
+ *Int_Par_Ref = Int_2_Par_Val + Int_Loc;
+} /* Proc_7 */
+
+
+#ifdef __ECOS__
+void
+#endif // __ECOS__
+Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val)
+/*********************************************************************/
+ /* executed once */
+ /* Int_Par_Val_1 == 3 */
+ /* Int_Par_Val_2 == 7 */
+Arr_1_Dim Arr_1_Par_Ref;
+Arr_2_Dim Arr_2_Par_Ref;
+int Int_1_Par_Val;
+int Int_2_Par_Val;
+{
+ REG One_Fifty Int_Index;
+ REG One_Fifty Int_Loc;
+
+ Int_Loc = Int_1_Par_Val + 5;
+ Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
+ Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
+ Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
+ for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
+ Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
+ Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
+ Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
+ Int_Glob = 5;
+} /* Proc_8 */
+
+
+Enumeration Func_1 (Ch_1_Par_Val, Ch_2_Par_Val)
+/*************************************************/
+ /* executed three times */
+ /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */
+ /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */
+ /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */
+
+Capital_Letter Ch_1_Par_Val;
+Capital_Letter Ch_2_Par_Val;
+{
+ Capital_Letter Ch_1_Loc;
+ Capital_Letter Ch_2_Loc;
+
+ Ch_1_Loc = Ch_1_Par_Val;
+ Ch_2_Loc = Ch_1_Loc;
+ if (Ch_2_Loc != Ch_2_Par_Val)
+ /* then, executed */
+ return (Ident_1);
+ else /* not executed */
+ {
+ Ch_1_Glob = Ch_1_Loc;
+ return (Ident_2);
+ }
+} /* Func_1 */
+
+
+Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref)
+/*************************************************/
+ /* executed once */
+ /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
+ /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
+
+Str_30 Str_1_Par_Ref;
+Str_30 Str_2_Par_Ref;
+{
+ REG One_Thirty Int_Loc;
+#ifdef __ECOS__
+ Capital_Letter Ch_Loc = 'A';
+#else // __ECOS__
+ Capital_Letter Ch_Loc;
+#endif // __ECOS__
+
+ Int_Loc = 2;
+ while (Int_Loc <= 2) /* loop body executed once */
+ if (Func_1 (Str_1_Par_Ref[Int_Loc],
+ Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
+ /* then, executed */
+ {
+ Ch_Loc = 'A';
+ Int_Loc += 1;
+ } /* if, while */
+ if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
+ /* then, not executed */
+ Int_Loc = 7;
+ if (Ch_Loc == 'R')
+ /* then, not executed */
+ return (true);
+ else /* executed */
+ {
+ if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
+ /* then, not executed */
+ {
+ Int_Loc += 7;
+ Int_Glob = Int_Loc;
+ return (true);
+ }
+ else /* executed */
+ return (false);
+ } /* if Ch_Loc */
+} /* Func_2 */
+
+
+Boolean Func_3 (Enum_Par_Val)
+/***************************/
+ /* executed once */
+ /* Enum_Par_Val == Ident_3 */
+Enumeration Enum_Par_Val;
+{
+ Enumeration Enum_Loc;
+
+ Enum_Loc = Enum_Par_Val;
+ if (Enum_Loc == Ident_3)
+ /* then, executed */
+ return (true);
+ else /* not executed */
+ return (false);
+} /* Func_3 */
+
+#else /* ifndef NA_MSG */
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA(NA_MSG);
+}
+#endif
diff --git a/ecos/packages/kernel/current/tests/except1.cxx b/ecos/packages/kernel/current/tests/except1.cxx
new file mode 100644
index 0000000000..4736bd3286
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/except1.cxx
@@ -0,0 +1,271 @@
+//=================================================================
+//
+// except1.cxx
+//
+// Exception test 1
+//
+//=================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm, jlarmour
+// Date: 1999-02-16
+// Description: Test basic exception functionality
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGPKG_KERNEL_EXCEPTIONS
+
+#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start()
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+#include <cyg/kernel/intr.hxx> // cyg_VSR
+
+#include <cyg/hal/hal_intr.h> // exception ranges
+
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/thread.inl>
+
+#define NTHREADS 1
+#include "testaux.hxx"
+
+#ifndef CYGPKG_HAL_ARM_PID
+#define EXCEPTION_DATA_ACCESS
+#endif
+
+static int d0;
+#ifdef EXCEPTION_DATA_ACCESS
+static cyg_exception_handler handler0;
+
+static void handler0(CYG_ADDRWORD data, cyg_code number, CYG_ADDRWORD info)
+{
+ CYG_TEST_INFO("handler 0 called");
+
+ CYG_TEST_CHECK((CYG_ADDRWORD)123 == data, "handler given wrong data");
+
+ // ignore machine specific stuff
+ CYG_UNUSED_PARAM(cyg_code, number);
+ CYG_UNUSED_PARAM(CYG_ADDRWORD, info);
+
+ CYG_TEST_PASS_FINISH("Except 1 OK");
+}
+#endif
+
+static void handler1(CYG_ADDRWORD data, cyg_code number, CYG_ADDRWORD info)
+{
+ CYG_TEST_INFO("handler 1 called");
+
+ CYG_TEST_CHECK((CYG_ADDRWORD)&d0 == data, "handler given wrong data");
+
+#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE
+ CYG_TEST_CHECK(number == CYGNUM_HAL_EXCEPTION_MAX, "handler given wrong number");
+#else
+ CYG_UNUSED_PARAM(cyg_code, number);
+#endif
+
+ CYG_TEST_CHECK((CYG_ADDRWORD)99 == info, "handler given wrong info");
+}
+
+#ifdef EXCEPTION_DATA_ACCESS
+// The following function attempts to cause an exception in various
+// hacky ways. It is machine dependent what exception is generated.
+// It does reads rather than writes hoping not to corrupt anything
+// important.
+static int
+cause_fpe(int num)
+{
+ double a;
+
+ a = 1.0/num; // Depending on FPU emulation and/or
+ // the FPU architecture, this may
+ // cause an exception.
+ // (float division by zero)
+
+ return ((int)a)/num; // This may cause an exception if
+ // the architecture supports it.
+ // (integer division by zero).
+} // cause_fpe()
+
+void cause_exception(void)
+{
+ int x;
+ unsigned int p=0;
+
+ // First try for an address exception (unaligned access exception
+ // or SEGV/BUS exceptions)
+ do {
+ x=*(volatile int *)(p-1);
+ p+=0x100000;
+ } while(p != 0);
+
+ // Next try an integer or floating point divide-by-zero exception.
+ cause_fpe(0);
+}
+#endif
+
+static void entry0( CYG_ADDRWORD data )
+{
+#ifdef EXCEPTION_DATA_ACCESS
+ cyg_code n;
+#endif
+ cyg_exception_handler *old_handler, *old_handler1;
+ CYG_ADDRWORD old_data, old_data1;
+ Cyg_Thread *p=Cyg_Thread::self();
+
+ CYG_UNUSED_PARAM(CYG_ADDRESS, data);
+
+ p->register_exception(
+ CYGNUM_HAL_EXCEPTION_MAX,
+ &handler1,
+ (CYG_ADDRWORD)&d0,
+ &old_handler,
+ &old_data);
+
+ p->register_exception(
+ CYGNUM_HAL_EXCEPTION_MAX,
+ &handler1,
+ (CYG_ADDRWORD)&d0,
+ &old_handler1,
+ &old_data1);
+
+ CYG_TEST_CHECK(old_handler1 == &handler1,
+ "register exception: old_handler not the one previously registered");
+ CYG_TEST_CHECK(old_data1 == (CYG_ADDRWORD)&d0,
+ "register exception: old_data not those previously registered");
+
+ p->deliver_exception(CYGNUM_HAL_EXCEPTION_MAX, (CYG_ADDRWORD)99);
+
+ CYG_TEST_INFO("handler 1 returned");
+
+ p->deregister_exception(CYGNUM_HAL_EXCEPTION_MAX);
+ p->deregister_exception(CYGNUM_HAL_EXCEPTION_MAX);
+
+#ifdef EXCEPTION_DATA_ACCESS
+
+#if 0
+#elif defined(CYGPKG_HAL_POWERPC_SIM)
+ // The exception generated by the SIM is not recognized by GDB.
+ // PR 19945 workaround.
+ CYG_TEST_NA("Not applicable to PowerPC SIM");
+#endif
+
+ for(n = CYGNUM_HAL_EXCEPTION_MIN; n <= CYGNUM_HAL_EXCEPTION_MAX; n++) {
+ p->register_exception(
+ n,
+ handler0,
+ (CYG_ADDRWORD)123,
+ &old_handler1,
+ &old_data1);
+ }
+
+ CYG_TEST_PASS("Attempting to provoke exception");
+
+ cause_exception();
+
+ CYG_TEST_FAIL_FINISH("Couldn't cause exception");
+#else // EXCEPTION_DATA_ACCESS
+ CYG_TEST_NA("Platform does not support data exceptions");
+#endif
+
+}
+
+#ifdef CYG_HAL_MIPS_TX39_JMR3904
+
+externC cyg_VSR __default_exception_vsr;
+cyg_VSR *old_vsr;
+
+#endif
+
+void except0_main( void )
+{
+ // Use CYG_TEST_GDBCMD _before_ CYG_TEST_INIT()
+ CYG_TEST_GDBCMD("handle SIGBUS nostop");
+ CYG_TEST_GDBCMD("handle SIGSEGV nostop");
+ CYG_TEST_GDBCMD("handle SIGFPE nostop");
+
+ CYG_TEST_INIT();
+
+#ifdef HAL_VSR_SET_TO_ECOS_HANDLER
+ // Reclaim the VSR off CygMon possibly
+#ifdef CYGNUM_HAL_EXCEPTION_DATA_ACCESS
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_ACCESS, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_DIV_BY_ZERO
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DIV_BY_ZERO, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_FPU
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_FPU, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO, NULL );
+#endif
+#endif
+
+ new_thread(entry0, 0);
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ except0_main();
+}
+#else // def CYGPKG_KERNEL_EXCEPTIONS
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Exceptions disabled");
+}
+#endif // def CYGPKG_KERNEL_EXCEPTIONS
+
+// EOF except1.cxx
diff --git a/ecos/packages/kernel/current/tests/flag0.cxx b/ecos/packages/kernel/current/tests/flag0.cxx
new file mode 100644
index 0000000000..aeb4b3c3cc
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/flag0.cxx
@@ -0,0 +1,88 @@
+//==========================================================================
+//
+// flag0.cxx
+//
+// Flag test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-05-11
+// Description: Limited to checking constructors/destructors
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/flag.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include "testaux.hxx"
+
+static Cyg_Flag f0, f1;
+
+
+static bool flash( void )
+{
+ Cyg_Flag f0;
+
+ Cyg_Flag f1;
+
+ return true;
+}
+
+void flag0_main( void )
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ CYG_TEST_PASS_FINISH("Flag 0 OK");
+
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ flag0_main();
+}
+// EOF flag0.cxx
diff --git a/ecos/packages/kernel/current/tests/flag1.cxx b/ecos/packages/kernel/current/tests/flag1.cxx
new file mode 100644
index 0000000000..17274a197c
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/flag1.cxx
@@ -0,0 +1,219 @@
+//==========================================================================
+//
+// flag1.cxx
+//
+// Flag test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: dsm
+// Contributors: dsm
+// Date: 1998-05-11
+// Description: Tests basic flag functionality.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start()
+
+#include <cyg/kernel/flag.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+
+
+#define NTHREADS 3
+#include "testaux.hxx"
+
+static Cyg_Flag f0, f1;
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+static Cyg_Flag f2;
+#endif
+
+static volatile cyg_atomic q = 0;
+#define FIRST_THREAD_WAIT_TIME 5
+#define SECOND_THREAD_WAIT_TIME 10
+#define THIRD_THREAD_WAIT_TIME 20
+
+static void entry0( CYG_ADDRWORD data )
+{
+ CYG_TEST_INFO("Testing setbits() and maskbits()");
+ CYG_TEST_CHECK(0==f0.peek(), "flag not initialized properly");
+ f0.setbits(0x1);
+ CYG_TEST_CHECK(1==f0.peek(), "setbits");
+ f0.setbits(0x3);
+ CYG_TEST_CHECK(3==f0.peek(), "setbits");
+ f0.maskbits(~0x5);
+ CYG_TEST_CHECK(2==f0.peek(), "maskbits");
+ f0.setbits();
+ CYG_TEST_CHECK(~0u==f0.peek(), "setbits no arg");
+ f0.maskbits();
+ CYG_TEST_CHECK(0==f0.peek(), "maskbits no arg");
+ CYG_TEST_CHECK(0==q++, "bad synchronization");
+
+ CYG_TEST_INFO("Testing wait()");
+ f1.setbits(0x4);
+ CYG_TEST_CHECK(0x4==f1.peek(), "maskbits no arg");
+ CYG_TEST_CHECK(1==q++, "bad synchronization");
+ f1.setbits(0x18); // wake t1
+ f1.wait(0x11, Cyg_Flag::AND | Cyg_Flag::CLR);
+ CYG_TEST_CHECK(0==f1.peek(), "flag value wrong");
+ CYG_TEST_CHECK(3==q++, "bad synchronization");
+ f0.setbits(0x2); // wake t1
+ f1.wait(0x10, Cyg_Flag::AND );
+ f0.setbits(0x1); // wake t1
+
+ f1.wait(0x11, Cyg_Flag::AND | Cyg_Flag::CLR);
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ f2.wait(0x2, Cyg_Flag::OR);
+ CYG_TEST_CHECK(20==q,"bad synchronization");
+ f2.wait(0x10, Cyg_Flag::AND,
+ Cyg_Clock::real_time_clock->current_value()+THIRD_THREAD_WAIT_TIME);
+ CYG_TEST_CHECK(21==q++,"bad synchronization");
+#endif
+ f0.wait(1, Cyg_Flag::OR);
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+static void entry1( CYG_ADDRWORD data )
+{
+ f1.wait(0xc, Cyg_Flag::AND);
+ CYG_TEST_CHECK(2==q++, "bad synchronization");
+ CYG_TEST_CHECK(0x1c==f1.peek(), "flag value wrong");
+ f1.setbits(0x1); // wake t0
+ f0.wait(0x3, Cyg_Flag::OR);
+ CYG_TEST_CHECK(4==q++, "bad synchronization");
+ CYG_TEST_CHECK(2==f0.peek(), "flag value wrong");
+
+ f1.setbits(0xf0); // wake t0,t2
+ f0.wait(0x5, Cyg_Flag::AND | Cyg_Flag::CLR); // wait for t0 & t2
+ CYG_TEST_CHECK(0==f0.peek(), "flag value wrong");
+ CYG_TEST_CHECK(0xf0==f1.peek(), "flag value wrong");
+ CYG_TEST_CHECK(5==q++, "bad synchronization");
+ f1.maskbits();
+ CYG_TEST_CHECK(0==f1.peek(), "flag value wrong");
+
+ CYG_TEST_INFO("Testing poll()");
+ f0.setbits(0x55);
+ CYG_TEST_CHECK(0x55==f0.peek(), "flag value wrong");
+ CYG_TEST_CHECK(0x55==f0.poll(0x3, Cyg_Flag::OR),"bad poll() return");
+ CYG_TEST_CHECK(0==f0.poll(0xf, Cyg_Flag::AND),"poll()");
+ CYG_TEST_CHECK(0==f0.poll(0xa, Cyg_Flag::OR),"poll()");
+ CYG_TEST_CHECK(0x55==f0.peek(), "flag value wrong");
+ CYG_TEST_CHECK(0x55==f0.poll(0xf, Cyg_Flag::OR | Cyg_Flag::CLR),"poll");
+ CYG_TEST_CHECK(0x0==f0.peek(), "flag value wrong");
+ f0.setbits(0x50);
+ CYG_TEST_CHECK(0x50==f0.poll(0x10, Cyg_Flag::AND | Cyg_Flag::CLR),"poll");
+ CYG_TEST_CHECK(0x0==f0.peek(), "flag value wrong");
+
+ CYG_TEST_INFO("Testing waiting()");
+ f0.maskbits();
+ CYG_TEST_CHECK(!f0.waiting(), "waiting()");
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ thread[1]->delay( 10 ); // allow other threads to reach wait on f1
+ CYG_TEST_CHECK(f1.waiting(), "waiting() not true");
+ f1.setbits(); // wake one of t0,t2
+ CYG_TEST_CHECK(f1.waiting(), "waiting() not true");
+#else
+ f1.setbits(0x11); // wake one of t0,t2
+#endif
+ f1.setbits(0x11); // wake other of t0,t2
+ CYG_TEST_CHECK(!f1.waiting(), "waiting not false");
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ CYG_TEST_INFO("Testing wait() with timeout");
+ q=20;
+ f2.setbits(0x2); // synchronize with t0,t2
+ CYG_TEST_CHECK(20==q,"bad synchronization");
+ f2.wait(0x20, Cyg_Flag::AND,
+ Cyg_Clock::real_time_clock->current_value()+SECOND_THREAD_WAIT_TIME);
+ CYG_TEST_CHECK(22==q++,"bad synchronization");
+#endif
+
+ CYG_TEST_PASS_FINISH("Flag 1 OK");
+}
+
+static void entry2( CYG_ADDRWORD data )
+{
+ f1.wait(0x60, Cyg_Flag::OR);
+ f0.setbits(0x4);
+
+ f1.wait(0x11, Cyg_Flag::AND | Cyg_Flag::CLR);
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ f2.wait(0x2, Cyg_Flag::OR);
+ CYG_TEST_CHECK(20==q,"bad synchronization");
+ CYG_TEST_CHECK(0==f2.wait(0x40, Cyg_Flag::AND,
+ Cyg_Clock::real_time_clock->current_value()+FIRST_THREAD_WAIT_TIME),
+ "timed wait() wrong");
+ CYG_TEST_CHECK(20==q++,"bad synchronization");
+ // Now wake t0 before it times out
+ f2.setbits(0x10);
+#endif
+ f0.wait(1, Cyg_Flag::OR);
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+void flag1_main( void )
+{
+ CYG_TEST_INIT();
+
+ new_thread(entry0, 0);
+ new_thread(entry1, 1);
+ new_thread(entry2, 2);
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ flag1_main();
+}
+
+// EOF flag1.cxx
diff --git a/ecos/packages/kernel/current/tests/fptest.c b/ecos/packages/kernel/current/tests/fptest.c
new file mode 100644
index 0000000000..f455c8b3b3
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/fptest.c
@@ -0,0 +1,364 @@
+//==========================================================================
+//
+// fptest.cxx
+//
+// Basic FPU test
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003 Nick Garnett
+//
+// 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.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): nickg@calivar.com
+// Contributors: nickg@calivar.com
+// Date: 2003-01-27
+// Description: Simple FPU test. This is not very sophisticated as far
+// as checking FPU performance or accuracy. It is more
+// concerned with checking that several threads doing FP
+// operations do not interfere with eachother's use of the
+// FPU.
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/hal.h>
+
+#include <cyg/hal/hal_arch.h>
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+
+//#include <cyg/kernel/test/stackmon.h>
+//#include CYGHWR_MEMORY_LAYOUT_H
+
+//==========================================================================
+
+#if defined(CYGFUN_KERNEL_API_C) && \
+ defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \
+ (CYGNUM_KERNEL_SCHED_PRIORITIES > 12)
+
+//==========================================================================
+// Base priority for all threads.
+
+#define BASE_PRI 5
+
+//==========================================================================
+// Runtime
+//
+// This is the number of ticks that the program will run for. 3000
+// ticks is equal to 30 seconds in the default configuration. For
+// simulators we reduce the run time to 3 simulated seconds.
+
+#define RUN_TICKS 3000
+#define RUN_TICKS_SIM 300
+
+//==========================================================================
+// Thread parameters
+
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_MINIMUM)
+
+static cyg_uint8 stacks[3][STACK_SIZE];
+static cyg_handle_t thread[3];
+static cyg_thread thread_struct[3];
+
+//==========================================================================
+// Alarm parameters.
+
+static cyg_alarm alarm_struct;
+static cyg_handle_t alarm;
+
+static cyg_count8 cur_thread = 0;
+static cyg_count32 alarm_ticks = 0;
+static cyg_count32 run_ticks = RUN_TICKS;
+
+//==========================================================================
+
+static int errors = 0;
+
+//==========================================================================
+// Random number generator. Ripped out of the C library.
+
+static int rand( unsigned int *seed )
+{
+// This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom
+
+#define RAND_MAX 0x7fffffff
+#define MM 2147483647 // a Mersenne prime
+#define AA 48271 // this does well in the spectral test
+#define QQ 44488 // (long)(MM/AA)
+#define RR 3399 // MM % AA; it is important that RR<QQ
+
+ *seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ);
+ if (*seed < 0)
+ *seed += MM;
+
+ return (int)( *seed & RAND_MAX );
+}
+
+//==========================================================================
+// Test calculation.
+//
+// Generates an array of random FP values and then repeatedly applies
+// a calculation to them and checks that the same result is reached
+// each time. The calculation, in the macro CALC, is intended to make
+// maximum use of the FPU registers. However, the i386 compiler
+// doesn't let this expression get very complex before it starts
+// spilling values out to memory.
+
+static void do_test( double *values,
+ int count,
+ int loops,
+ int test,
+ const char *name)
+{
+ unsigned int i, j;
+ // volatiles necessary to force
+ // values to 64 bits for comparison
+ volatile double sum = 1.0;
+ volatile double last_sum;
+ unsigned int seed;
+
+#define V(__i) (values[(__i)%count])
+#define CALC ((V(i-1)*V(i+1))*(V(i-2)*V(i+2))*(V(i-3)*sum))
+
+ seed = ((unsigned int)&i)*count;
+
+ // Set up an array of values...
+ for( i = 0; i < count; i++ )
+ values[i] = (double)rand( &seed )/(double)0x7fffffff;
+
+ // Now calculate something from them...
+ for( i = 0; i < count; i++ )
+ sum += CALC;
+ last_sum = sum;
+
+ // Now recalculate the sum in a loop and look for errors
+ for( j = 0; j < loops ; j++ )
+ {
+ sum = 1.0;
+ for( i = 0; i < count; i++ )
+ sum += CALC;
+
+ if( sum != last_sum )
+ {
+ union double_int_union {
+ double d;
+ cyg_uint32 i[2];
+ } diu_sum, diu_lastsum;
+
+ diu_sum.d = sum;
+ diu_lastsum.d = last_sum;
+
+ errors++;
+ if (sizeof(double) != 2*sizeof(cyg_uint32)) {
+ diag_printf("Warning: sizeof(double) != 2*sizeof(cyg_uint32), therefore next line may\n"
+ "have invalid sum/last_sum values\n");
+ }
+ diag_printf("%s: Sum mismatch! %d sum=[%08x:%08x] last_sum=[%08x:%08x]\n",
+ name,j, diu_sum.i[0], diu_sum.i[1], diu_lastsum.i[0], diu_lastsum.i[1] );
+ }
+
+#if 0
+ if( ((j*count)%1000000) == 0 )
+ diag_printf("INFO:<%s: %2d calculations done>\n",name,j*count);
+#endif
+ }
+
+}
+
+//==========================================================================
+// Alarm handler
+//
+// This is called every tick. It lowers the priority of the currently
+// running thread and raises the priority of the next. Thus we
+// implement a form of timelslicing between the threads at one tick
+// granularity.
+
+static void alarm_fn(cyg_handle_t alarm, cyg_addrword_t data)
+{
+ alarm_ticks++;
+
+ if( alarm_ticks >= run_ticks )
+ {
+ if( errors )
+ CYG_TEST_FAIL("Errors detected");
+ else
+ CYG_TEST_PASS("OK");
+
+ CYG_TEST_FINISH("FP Test done");
+ }
+ else
+ {
+ cyg_thread_set_priority( thread[cur_thread], BASE_PRI );
+
+ cur_thread = (cur_thread+1)%3;
+
+ cyg_thread_set_priority( thread[cur_thread], BASE_PRI-1 );
+ }
+}
+
+
+//==========================================================================
+
+#define FP1_COUNT 1000
+
+static double fpt1_values[FP1_COUNT];
+
+void fptest1( CYG_ADDRWORD id )
+{
+ while(1)
+ do_test( fpt1_values, FP1_COUNT, 2000000000, id, "fptest1" );
+}
+
+//==========================================================================
+
+#define FP2_COUNT 10000
+
+static double fpt2_values[FP2_COUNT];
+
+void fptest2( CYG_ADDRWORD id )
+{
+ while(1)
+ do_test( fpt2_values, FP2_COUNT, 2000000000, id, "fptest2" );
+}
+
+//==========================================================================
+
+#define FP3_COUNT 100
+
+static double fpt3_values[FP3_COUNT];
+
+void fptest3( CYG_ADDRWORD id )
+{
+ while(1)
+ do_test( fpt3_values, FP3_COUNT, 2000000000, id, "fptest3" );
+}
+
+//==========================================================================
+
+void fptest_main( void )
+{
+
+ CYG_TEST_INIT();
+
+ if( cyg_test_is_simulator )
+ {
+ run_ticks = RUN_TICKS_SIM;
+ }
+
+ CYG_TEST_INFO("Run fptest in cyg_start");
+ do_test( fpt3_values, FP3_COUNT, 1000, 0, "start" );
+ CYG_TEST_INFO( "cyg_start run done");
+
+ cyg_thread_create( BASE_PRI-1,
+ fptest1,
+ 0,
+ "fptest1",
+ &stacks[0][0],
+ STACK_SIZE,
+ &thread[0],
+ &thread_struct[0]);
+
+ cyg_thread_resume( thread[0] );
+
+ cyg_thread_create( BASE_PRI,
+ fptest2,
+ 1,
+ "fptest2",
+ &stacks[1][0],
+ STACK_SIZE,
+ &thread[1],
+ &thread_struct[1]);
+
+ cyg_thread_resume( thread[1] );
+
+ cyg_thread_create( BASE_PRI,
+ fptest3,
+ 2,
+ "fptest3",
+ &stacks[2][0],
+ STACK_SIZE,
+ &thread[2],
+ &thread_struct[2]);
+
+ cyg_thread_resume( thread[2] );
+
+ cyg_alarm_create( cyg_real_time_clock(),
+ alarm_fn,
+ 0,
+ &alarm,
+ &alarm_struct );
+
+ cyg_alarm_initialize( alarm, cyg_current_time()+1, 1 );
+
+ 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
+ fptest_main();
+}
+
+//==========================================================================
+
+#else // CYGFUN_KERNEL_API_C...
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_INFO("FP test requires:\n"
+ "CYGFUN_KERNEL_API_C && \n"
+ "CYGSEM_KERNEL_SCHED_MLQUEUE && \n"
+ "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n");
+ CYG_TEST_NA("FP test requirements");
+}
+
+#endif // CYGFUN_KERNEL_API_C, etc.
+
+//==========================================================================
+// EOF fptest.cxx
diff --git a/ecos/packages/kernel/current/tests/intr0.cxx b/ecos/packages/kernel/current/tests/intr0.cxx
new file mode 100644
index 0000000000..f2be469e3b
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/intr0.cxx
@@ -0,0 +1,209 @@
+//=================================================================
+//
+// intr0.cxx
+//
+// Interrupt test 0
+//
+//=================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm, jlarmour
+// Date: 1999-02-16
+// Description: Very basic test of interrupt objects
+// Options:
+// CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
+// CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE
+// CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/intr.hxx>
+#include <cyg/hal/hal_intr.h>
+
+#include <cyg/infra/testcase.h>
+
+#include "testaux.hxx"
+
+static cyg_ISR isr0, isr1;
+static cyg_DSR dsr0, dsr1;
+
+static char intr0_obj[sizeof(Cyg_Interrupt)];
+static char intr1_obj[sizeof(Cyg_Interrupt)];
+
+static cyg_uint32 isr0(cyg_vector vector, CYG_ADDRWORD data)
+{
+ CYG_UNUSED_PARAM(CYG_ADDRWORD, data);
+
+ Cyg_Interrupt::acknowledge_interrupt(vector);
+ return 0;
+}
+
+static void dsr0(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data)
+{
+ CYG_UNUSED_PARAM(cyg_vector, vector);
+ CYG_UNUSED_PARAM(cyg_ucount32, count);
+ CYG_UNUSED_PARAM(CYG_ADDRWORD, data);
+}
+
+static cyg_uint32 isr1(cyg_vector vector, CYG_ADDRWORD data)
+{
+ CYG_UNUSED_PARAM(cyg_vector, vector);
+ CYG_UNUSED_PARAM(CYG_ADDRWORD, data);
+ return 0;
+}
+
+static void dsr1(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data)
+{
+ CYG_UNUSED_PARAM(cyg_vector, vector);
+ CYG_UNUSED_PARAM(cyg_ucount32, count);
+ CYG_UNUSED_PARAM(CYG_ADDRWORD, data);
+}
+
+static bool flash( void )
+{
+ Cyg_Interrupt intr0 = Cyg_Interrupt(CYGNUM_HAL_ISR_MIN, 0, (CYG_ADDRWORD)333, isr0, dsr0 );
+
+ return true;
+}
+
+/* IMPORTANT: The calling convention for VSRs is target dependent. It is
+ * unlikely that a plain C or C++ routine would function correctly on any
+ * particular platform, even if it could correctly access the system
+ * resources necessary to handle the event that caused it to be called.
+ * VSRs usually must be written in assembly language.
+ *
+ * This is just a test program. The routine vsr0() below is defined simply
+ * to define an address that will be in executable memory. If an event
+ * causes this VSR to be called, all bets are off. If it is accidentally
+ * installed in the vector for the realtime clock, the system will likely
+ * freeze.
+ */
+
+static cyg_VSR vsr0;
+
+static void vsr0()
+{
+}
+
+void intr0_main( void )
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ // Make sure the chosen levels are not already in use.
+ int in_use;
+ cyg_vector lvl1 = CYGNUM_HAL_ISR_MIN + (1 % CYGNUM_HAL_ISR_COUNT);
+ HAL_INTERRUPT_IN_USE( lvl1, in_use );
+ Cyg_Interrupt* intr0 = NULL;
+ if (!in_use)
+ intr0 = new((void *)&intr0_obj[0]) Cyg_Interrupt( lvl1, 1, (CYG_ADDRWORD)777, isr0, dsr0 );
+
+ cyg_vector lvl2 = CYGNUM_HAL_ISR_MIN + ( 15 % CYGNUM_HAL_ISR_COUNT);
+ HAL_INTERRUPT_IN_USE( lvl2, in_use );
+ Cyg_Interrupt* intr1 = NULL;
+ if (!in_use && lvl1 != lvl2)
+ intr1 = new((void *)&intr1_obj[0]) Cyg_Interrupt( lvl2, 1, 888, isr1, dsr1 );
+
+ // Check these functions at least exist
+ Cyg_Interrupt::disable_interrupts();
+ Cyg_Interrupt::enable_interrupts();
+
+ if (intr0)
+ intr0->attach();
+ if (intr1)
+ intr1->attach();
+ if (intr0)
+ intr0->detach();
+ if (intr1)
+ intr1->detach();
+
+ // If this attaching interrupt replaces the previous interrupt
+ // instead of adding to it we could be in a big mess if the
+ // vector is being used by something important.
+
+ cyg_vector v = (CYGNUM_HAL_VSR_MIN + 11) % CYGNUM_HAL_VSR_COUNT;
+ cyg_VSR *old_vsr, *new_vsr;
+ Cyg_Interrupt::set_vsr( v, vsr0, &old_vsr );
+ Cyg_Interrupt::get_vsr( v, &new_vsr );
+ CHECK( vsr0 == new_vsr );
+
+ new_vsr = NULL;
+ Cyg_Interrupt::set_vsr( v, old_vsr, &new_vsr );
+ CHECK( new_vsr == vsr0 );
+
+ Cyg_Interrupt::set_vsr( v, new_vsr );
+ new_vsr = NULL;
+ Cyg_Interrupt::get_vsr( v, &new_vsr );
+ CHECK( vsr0 == new_vsr );
+
+ Cyg_Interrupt::set_vsr( v, old_vsr );
+ CHECK( vsr0 == new_vsr );
+ new_vsr = NULL;
+ Cyg_Interrupt::get_vsr( v, &new_vsr );
+ CHECK( old_vsr == new_vsr );
+
+ CHECK( NULL != vsr0 );
+
+ cyg_vector v1;
+#ifdef CYGPKG_HAL_MIPS_TX39
+ // This can be removed when PR 17831 is fixed
+ if ( cyg_test_is_simulator )
+ v1 = 12 % CYGNUM_HAL_ISR_COUNT;
+ else /* NOTE TRAILING ELSE... */
+#endif
+ v1 = CYGNUM_HAL_ISR_MIN + (6 % CYGNUM_HAL_ISR_COUNT);
+
+ Cyg_Interrupt::mask_interrupt(v1);
+ Cyg_Interrupt::unmask_interrupt(v1);
+
+ Cyg_Interrupt::configure_interrupt(v1, true, true);
+
+ CYG_TEST_PASS_FINISH("Intr 0 OK");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ intr0_main();
+}
+// EOF intr0.cxx
diff --git a/ecos/packages/kernel/current/tests/kalarm0.c b/ecos/packages/kernel/current/tests/kalarm0.c
new file mode 100644
index 0000000000..d3d27e3097
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kalarm0.c
@@ -0,0 +1,191 @@
+//==========================================================================
+//
+// kalarm0
+//
+// Alarm functionality test
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003 Nick Garnett <nickg@calivar.com>
+//
+// 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 the
+// copyright holders.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): nickg
+// Contributors: nickg
+// Date: 2003-06-25
+// Description: Tests the ability of alarms to be added and removed by the
+// alarm functions of other alarms.
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+//==========================================================================
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \
+ defined(CYGFUN_KERNEL_API_C)
+
+#include "testaux.h"
+
+//==========================================================================
+
+//#define db_printf diag_printf
+#define db_printf( fmt, ... )
+
+//==========================================================================
+
+static cyg_counter counter_obj;
+static cyg_handle_t counter;
+static cyg_alarm alarm_obj[3];
+static cyg_handle_t alarm[3];
+
+static cyg_uint32 alarmfn_called[3];
+
+//==========================================================================
+
+void alarmfn0(cyg_handle_t alarmh, cyg_addrword_t data)
+{
+ db_printf("%s: %d\n",__PRETTY_FUNCTION__,cyg_counter_current_value( counter ));
+
+ // alarmfn0 just counts how many times it has been called
+
+ alarmfn_called[0]++;
+}
+
+//==========================================================================
+
+void alarmfn1(cyg_handle_t alarmh, cyg_addrword_t data)
+{
+ db_printf("%s: %d\n",__PRETTY_FUNCTION__,cyg_counter_current_value( counter ));
+
+ alarmfn_called[1]++;
+
+ // Reschedule alarm[0] to run every tick until alarm[2] next runs.
+
+ cyg_alarm_initialize( alarm[0], cyg_counter_current_value( counter )+1, 1 );
+
+}
+
+//==========================================================================
+
+void alarmfn2(cyg_handle_t alarmh, cyg_addrword_t data)
+{
+ db_printf("%s: %d\n",__PRETTY_FUNCTION__,cyg_counter_current_value( counter ));
+
+ alarmfn_called[2]++;
+
+ // Reschedule alarm[0] to run every 2 ticks until alarm[1] next runs.
+
+ cyg_alarm_initialize( alarm[0], cyg_counter_current_value( counter )+1, 2 );
+
+ // Reschedule alarm[1] to run every 3 ticks starting in 6 ticks time.
+
+ cyg_alarm_initialize( alarm[1], cyg_counter_current_value( counter )+6, 3 );
+}
+
+//==========================================================================
+
+void alarm0_main(void)
+{
+ int i;
+
+ CYG_TEST_INIT();
+
+ // Create the counter
+ cyg_counter_create( &counter, &counter_obj );
+
+ // Create the alarms
+ cyg_alarm_create( counter,
+ alarmfn0,
+ 0,
+ &alarm[0],
+ &alarm_obj[0]);
+
+
+ cyg_alarm_create( counter,
+ alarmfn1,
+ 1,
+ &alarm[1],
+ &alarm_obj[1]);
+
+ cyg_alarm_create( counter,
+ alarmfn2,
+ 2,
+ &alarm[2],
+ &alarm_obj[2]);
+
+
+ // Kick it all off by starting alarm[2]
+ cyg_alarm_initialize( alarm[2], 0, 10 );
+
+ // Run the whole thing for 10000 ticks
+ for( i = 0; i < 10000; i++ )
+ cyg_counter_tick( counter );
+
+ db_printf("alarmfn_called: %d %d %d\n",
+ alarmfn_called[0],alarmfn_called[1],alarmfn_called[2]);
+
+ CYG_TEST_CHECK( alarmfn_called[0]==5000, "alarmfn0 not called 5000 times\n");
+ CYG_TEST_CHECK( alarmfn_called[1]==2000, "alarmfn1 not called 2000 times\n");
+ CYG_TEST_CHECK( alarmfn_called[2]==1001, "alarmfn2 not called 1001 times\n");
+
+ CYG_TEST_PASS_FINISH("KAlarm0");
+}
+
+//==========================================================================
+
+externC void
+cyg_start( void )
+{
+ alarm0_main();
+}
+
+//==========================================================================
+
+#else
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( "This test needs CYGVAR_KERNEL_COUNTERS_CLOCK "
+ "and CYGFUN_KERNEL_API_C" );
+}
+
+#endif
+
+//==========================================================================
+// End of kalarm0.c
diff --git a/ecos/packages/kernel/current/tests/kcache1.c b/ecos/packages/kernel/current/tests/kcache1.c
new file mode 100644
index 0000000000..dbb82a0c76
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kcache1.c
@@ -0,0 +1,422 @@
+/*=================================================================
+//
+// kcache1.c
+//
+// Cache timing test
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm, nickg
+// Date: 1998-06-18
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/hal/hal_cache.h>
+
+#if defined(HAL_DCACHE_SIZE) || defined(HAL_UCACHE_SIZE)
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+#ifdef CYGFUN_KERNEL_API_C
+
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_intr.h>
+
+// -------------------------------------------------------------------------
+// If the HAL does not supply this, we supply our own version
+
+#ifndef HAL_DCACHE_PURGE_ALL
+# ifdef HAL_DCACHE_SYNC
+
+#define HAL_DCACHE_PURGE_ALL() HAL_DCACHE_SYNC()
+
+# else
+
+static cyg_uint8 dca[HAL_DCACHE_SIZE + HAL_DCACHE_LINE_SIZE*2];
+
+#define HAL_DCACHE_PURGE_ALL() \
+CYG_MACRO_START \
+ volatile cyg_uint8 *addr = &dca[HAL_DCACHE_LINE_SIZE]; \
+ volatile cyg_uint8 tmp = 0; \
+ int i; \
+ for( i = 0; i < HAL_DCACHE_SIZE; i += HAL_DCACHE_LINE_SIZE ) \
+ { \
+ tmp = addr[i]; \
+ } \
+CYG_MACRO_END
+
+# endif
+#endif
+
+// -------------------------------------------------------------------------
+
+#define NTHREADS 1
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static cyg_handle_t thread[NTHREADS];
+
+static cyg_thread thread_obj[NTHREADS];
+static char stack[NTHREADS][STACKSIZE];
+
+#ifndef MAX_STRIDE
+#define MAX_STRIDE 64
+#endif
+
+volatile char m[(HAL_DCACHE_SIZE/HAL_DCACHE_LINE_SIZE)*MAX_STRIDE];
+
+// -------------------------------------------------------------------------
+
+static void time0(register cyg_uint32 stride)
+{
+ register cyg_uint32 j,k;
+ cyg_tick_count_t count0, count1;
+ cyg_ucount32 t;
+ register char c;
+
+ count0 = cyg_current_time();
+
+ k = 0;
+ if ( cyg_test_is_simulator )
+ k = 3960;
+
+ for(; k<4000;k++) {
+ for(j=0; j<(HAL_DCACHE_SIZE/HAL_DCACHE_LINE_SIZE); j++) {
+ c=m[stride*j];
+ }
+ }
+
+ count1 = cyg_current_time();
+ t = count1 - count0;
+ diag_printf("stride=%d, time=%d\n", stride, t);
+}
+
+// -------------------------------------------------------------------------
+
+void time1(void)
+{
+ cyg_uint32 i;
+
+ for(i=1; i<=MAX_STRIDE; i+=i) {
+ time0(i);
+ }
+}
+
+// -------------------------------------------------------------------------
+// With an ICache invalidate in the middle:
+#ifdef HAL_ICACHE_INVALIDATE_ALL
+static void time0II(register cyg_uint32 stride)
+{
+ register cyg_uint32 j,k;
+ cyg_tick_count_t count0, count1;
+ cyg_ucount32 t;
+ register char c;
+
+ count0 = cyg_current_time();
+
+ k = 0;
+ if ( cyg_test_is_simulator )
+ k = 3960;
+
+ for(; k<4000;k++) {
+ for(j=0; j<(HAL_DCACHE_SIZE/HAL_DCACHE_LINE_SIZE); j++) {
+ HAL_ICACHE_INVALIDATE_ALL();
+ c=m[stride*j];
+ }
+ }
+
+ count1 = cyg_current_time();
+ t = count1 - count0;
+ diag_printf("stride=%d, time=%d\n", stride, t);
+}
+
+// -------------------------------------------------------------------------
+
+void time1II(void)
+{
+ cyg_uint32 i;
+
+ for(i=1; i<=MAX_STRIDE; i+=i) {
+ time0II(i);
+ }
+}
+#endif
+// -------------------------------------------------------------------------
+// With a DCache invalidate in the middle:
+// This is guaranteed to produce bogus timing results since interrupts
+// have to be disabled to prevent accidental loss of state.
+#ifdef HAL_DCACHE_INVALIDATE_ALL
+static void time0DI(register cyg_uint32 stride)
+{
+ register cyg_uint32 j,k;
+ volatile cyg_tick_count_t count0;
+ cyg_tick_count_t count1;
+ cyg_ucount32 t;
+ register char c;
+ register CYG_INTERRUPT_STATE oldints;
+
+ count0 = cyg_current_time();
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+
+ k = 0;
+ if ( cyg_test_is_simulator )
+ k = 3960;
+
+ for(; k<4000;k++) {
+ for(j=0; j<(HAL_DCACHE_SIZE/HAL_DCACHE_LINE_SIZE); j++) {
+ HAL_DCACHE_INVALIDATE_ALL();
+ c=m[stride*j];
+ }
+ }
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ count1 = cyg_current_time();
+ t = count1 - count0;
+ diag_printf("stride=%d, time=%d\n", stride, t);
+}
+
+// -------------------------------------------------------------------------
+
+void time1DI(void)
+{
+ cyg_uint32 i;
+
+ for(i=1; i<=MAX_STRIDE; i+=i) {
+ time0DI(i);
+ }
+}
+#endif
+// -------------------------------------------------------------------------
+// This test could be improved by counting number of passes possible
+// in a given number of ticks.
+
+static void entry0( cyg_addrword_t data )
+{
+ register CYG_INTERRUPT_STATE oldints;
+
+#ifdef HAL_CACHE_UNIFIED
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL(); // rely on above definition
+ HAL_UCACHE_INVALIDATE_ALL();
+ HAL_UCACHE_DISABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Cache off");
+ time1();
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL(); // rely on above definition
+ HAL_UCACHE_INVALIDATE_ALL();
+ HAL_UCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Cache on");
+ time1();
+
+#ifdef HAL_DCACHE_INVALIDATE_ALL
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL();
+ HAL_UCACHE_INVALIDATE_ALL();
+ HAL_UCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Cache on: invalidate Cache (expect bogus timing)");
+ time1DI();
+#endif
+
+#else // HAL_CACHE_UNIFIED
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL();
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_ICACHE_DISABLE();
+ HAL_DCACHE_DISABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Dcache off Icache off");
+ time1();
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL();
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_ICACHE_DISABLE();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Dcache on Icache off");
+ time1();
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL();
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_ICACHE_ENABLE();
+ HAL_DCACHE_DISABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Dcache off Icache on");
+ time1();
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL();
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_ICACHE_ENABLE();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Dcache on Icache on");
+ time1();
+
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL();
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_ICACHE_DISABLE();
+ HAL_DCACHE_DISABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Dcache off Icache off (again)");
+ time1();
+
+#if defined(HAL_DCACHE_INVALIDATE_ALL) || defined(HAL_ICACHE_INVALIDATE_ALL)
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL();
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_ICACHE_ENABLE();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Dcache on Icache on (again)");
+ time1();
+
+#if defined(CYGPKG_HAL_MIPS)
+ // In some architectures, the time taken for the next two tests is
+ // very long, partly because HAL_XCACHE_INVALIDATE_ALL() is implemented
+ // with a loop over the cache. Hence these tests take longer than the
+ // testing infrastructure is prepared to wait. The simplest way to get
+ // these tests to run quickly is to make them think they are running
+ // under a simulator.
+ // If the target actually is a simulator, skip the below - it's very
+ // slow on the simulator, even with reduced loop counts.
+ if (cyg_test_is_simulator)
+ CYG_TEST_PASS_FINISH("End of test");
+
+#if defined(CYGPKG_HAL_MIPS_TX49)
+ // The TX49 has a large cache, and even with reduced loop count,
+ // 90+ seconds elapses between each INFO output.
+ CYG_TEST_PASS_FINISH("End of test");
+#endif
+
+ cyg_test_is_simulator = 1;
+#endif
+
+#ifdef HAL_ICACHE_INVALIDATE_ALL
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL();
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_ICACHE_ENABLE();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Dcache on Icache on: invalidate ICache each time");
+ time1II();
+#endif
+#ifdef HAL_DCACHE_INVALIDATE_ALL
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_PURGE_ALL();
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_ICACHE_ENABLE();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ CYG_TEST_INFO("Dcache on Icache on: invalidate DCache (expect bogus times)");
+ time1DI();
+#endif
+#endif // either INVALIDATE_ALL macro
+
+#endif // HAL_CACHE_UNIFIED
+
+ CYG_TEST_PASS_FINISH("End of test");
+}
+
+// -------------------------------------------------------------------------
+
+void kcache2_main( void )
+{
+ CYG_TEST_INIT();
+
+ cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kcache1",
+ (void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]);
+ cyg_thread_resume(thread[0]);
+
+ cyg_scheduler_start();
+}
+
+// -------------------------------------------------------------------------
+
+externC void
+cyg_start( void )
+{
+ kcache2_main();
+}
+
+// -------------------------------------------------------------------------
+
+#else // def CYGFUN_KERNEL_API_C
+#define N_A_MSG "Kernel C API layer disabled"
+#endif // def CYGFUN_KERNEL_API_C
+#else // def CYGVAR_KERNEL_COUNTERS_CLOCK
+#define N_A_MSG "Kernel real-time clock disabled"
+#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK
+#else // def HAL_DCACHE_SIZE
+#define N_A_MSG "No caches defined"
+#endif // def HAL_DCACHE_SIZE
+
+#ifdef N_A_MSG
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( N_A_MSG );
+}
+#endif // N_A_MSG
+
+// -------------------------------------------------------------------------
+/* EOF kcache1.c */
diff --git a/ecos/packages/kernel/current/tests/kcache2.c b/ecos/packages/kernel/current/tests/kcache2.c
new file mode 100644
index 0000000000..da200d0fb9
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kcache2.c
@@ -0,0 +1,920 @@
+/*=================================================================
+//
+// kcache2.c
+//
+// Cache feature/timing tests
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Gary Thomas
+//
+// 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): jskov, based on kcache1.c by dsm
+// Contributors: jskov, gthomas
+// Date: 1998-12-10
+// Description: Tests some of the more exotic cache macros.
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+#ifdef CYGFUN_KERNEL_API_C
+
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_cache.h>
+
+// -------------------------------------------------------------------------
+
+#define NTHREADS 1
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+// The following are defaults for loop variables. Note they will be overriden
+// on simulator targets, where detected - there is no point testing a cache
+// which doesn't exist :-).
+
+#define TEST_DZERO_LOOPS 5000 // default number of loops for test_dzero()
+#define TIME_ILOCK_LOOPS 10000 // default number of loops for time_ilock()
+#define TIME_DLOCK_LOOPS 10000 // default number of loops for time_dlock()
+
+// Define this to enable a simple, but hopefully useful, data cache
+// test. It may help discover if the cache support has been defined
+// properly (in terms of size and shape)
+#ifdef HAL_DCACHE_LINE_SIZE
+#define _TEST_DCACHE_OPERATION
+#endif
+
+static cyg_handle_t thread[NTHREADS];
+
+static cyg_thread thread_obj[NTHREADS];
+static char stack[NTHREADS][STACKSIZE];
+
+#define MAXSIZE 1<<18
+
+volatile char m[MAXSIZE];
+
+// -------------------------------------------------------------------------
+// Test of data cache zero.
+// o Timing comparison with instructions doing the same amount of work.
+// o Check that area cleared with the DCACHE_ZERO macro contains zeros.
+#ifdef HAL_DCACHE_ZERO
+static void test_dzero(void)
+{
+ register cyg_uint32 k, i;
+ cyg_tick_count_t count0, count1;
+ cyg_ucount32 t;
+ volatile cyg_uint32* aligned_p;
+ volatile cyg_uint32* p;
+ register CYG_INTERRUPT_STATE oldints;
+ cyg_ucount32 test_dzero_loops = TEST_DZERO_LOOPS;
+
+ CYG_TEST_INFO("Data cache zero");
+
+ if (cyg_test_is_simulator)
+ test_dzero_loops=10;
+
+ aligned_p = (volatile cyg_uint32*)
+ (((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
+ & ~(HAL_DCACHE_LINE_SIZE-1));
+
+ // Time with conventional instructions.
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ count0 = cyg_current_time();
+ for (k = 0; k < test_dzero_loops; k++) {
+ p = aligned_p;
+ for (i = 0; i < HAL_DCACHE_SETS; i++) {
+#if (16 == HAL_DCACHE_LINE_SIZE)
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+#elif (32 == HAL_DCACHE_LINE_SIZE)
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = 0;
+#else
+#error "Not defined for this cache line size."
+#endif
+ }
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ }
+ count1 = cyg_current_time();
+ t = count1 - count0;
+ diag_printf("time with instructions: %d\n", t);
+
+ // Initialize the area with non-zero so we can check whether
+ // the macro cleared the area properly.
+ p = aligned_p;
+ for (i = 0;
+ i < HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE/sizeof(cyg_uint32);
+ i++) {
+ *p++ = 0xdeadbeef;
+ }
+
+ // Time with DCACHE_ZERO.
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ count0 = cyg_current_time();
+ for (k = 0; k < test_dzero_loops; k++) {
+ HAL_DCACHE_ZERO(aligned_p, HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE);
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ }
+ count1 = cyg_current_time();
+ t = count1 - count0;
+ diag_printf("time with HAL_DCACHE_ZERO: %d\n", t);
+
+ // Verify that the area was actually cleared.
+ {
+ cyg_uint32 d;
+
+ d = 0;
+ p = aligned_p;
+ for (i = 0;
+ i < HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE/sizeof(cyg_uint32);
+ i++) {
+ d |= *p++;
+ }
+
+ CYG_TEST_CHECK(0 == d, "region not properly cleared");
+ }
+
+}
+#endif
+
+// -------------------------------------------------------------------------
+// Test of data cache write hint.
+// Just check that the macro compiles.
+#ifdef HAL_DCACHE_WRITE_HINT
+static void test_dwrite_hint(void)
+{
+ register cyg_uint32 k;
+ register CYG_INTERRUPT_STATE oldints;
+
+ CYG_TEST_INFO("Data cache write hint");
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ HAL_DCACHE_WRITE_HINT(&m[HAL_DCACHE_LINE_SIZE*2], 2*HAL_DCACHE_LINE_SIZE);
+ for (k = 0; k < 20; k++);
+ m[HAL_DCACHE_LINE_SIZE*2] = 42;
+}
+#endif
+
+// -------------------------------------------------------------------------
+// Test of data cache read hint.
+// Just check that the macro compiles.
+#ifdef HAL_DCACHE_READ_HINT
+static void test_dread_hint(void)
+{
+ register char c;
+ register cyg_uint32 k;
+ register CYG_INTERRUPT_STATE oldints;
+
+ CYG_TEST_INFO("Data cache read hint");
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ HAL_DCACHE_READ_HINT(&m[HAL_DCACHE_LINE_SIZE*2], 2*HAL_DCACHE_LINE_SIZE);
+ for (k = 0; k < 20; k++);
+ c = m[HAL_DCACHE_LINE_SIZE*2];
+}
+#endif
+
+// -------------------------------------------------------------------------
+// Test of data cache line store
+// o No semantic requirement.
+// o Check that flushed data is written to memory.
+// o Simple invocation check of macro.
+#ifdef HAL_DCACHE_STORE
+static void test_dstore(void)
+{
+ volatile cyg_uint8* aligned_p;
+ cyg_int32 i;
+ register CYG_INTERRUPT_STATE oldints;
+
+ CYG_TEST_INFO("Data cache store region");
+
+ for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++)
+ m[i] = 0;
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+
+ aligned_p = (volatile cyg_uint8*)
+ (((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
+ & ~(HAL_DCACHE_LINE_SIZE-1));
+
+ aligned_p[0] = 42 + aligned_p[1]; // Load causes cache to be used!
+
+ HAL_DCACHE_STORE(aligned_p, HAL_DCACHE_LINE_SIZE);
+
+ CYG_TEST_CHECK(42 == aligned_p[0],
+ "memory didn't contain flushed data");
+
+ HAL_DCACHE_INVALIDATE_ALL(); // Discard...
+
+ CYG_TEST_CHECK(42 == aligned_p[0],
+ "memory didn't contain flushed data after invalidate all");
+
+ HAL_RESTORE_INTERRUPTS(oldints);
+}
+#endif
+
+// -------------------------------------------------------------------------
+// Test of data cache total flush (sync).
+// o No semantic requirement.
+// o Check that flushed data is written to memory.
+// o Simple invocation check of macro.
+#ifdef HAL_DCACHE_LINE_SIZE // So we can find our way around memory
+
+#ifdef _TEST_DCACHE_OPERATION
+static void
+test_dcache_operation(void)
+{
+ long *lp = (long *)m;
+ int i, errs;
+ cyg_uint32 oldints;
+
+ CYG_TEST_INFO("Data cache basic");
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ // Fill test buffer
+ for (i = 0; i < sizeof(m)/sizeof(*lp); i++) {
+ lp[i] = i;
+ }
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ // Now push data through the cache
+ // Note: 256 seems like a reasonable offset. It may be useful to actually
+ // compute this (and the size of the test region) based on cache geometry
+ for (i = 256; i < 256+HAL_DCACHE_SIZE/sizeof(*lp); i++) {
+ lp[i] = 0xFF000000 + i;
+ }
+ // Now force cache clean and off
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ // Verify the data
+ diag_printf("Verify data with cache off\n");
+ errs = 0;
+ for (i = 0; i < sizeof(m)/sizeof(*lp); i++) {
+ if ((i >= 256) && (i < 256+HAL_DCACHE_SIZE/sizeof(*lp))) {
+ if (lp[i] != (0xFF000000 + i)) {
+ if (++errs < 16) {
+ diag_printf("Data inside test range changed - was: %x, is %lx, index: %x\n",
+ 0xFF000000+i, lp[i], i);
+ }
+ }
+ } else {
+ if (lp[i] != i) {
+ if (++errs < 16) {
+ diag_printf("Data outside test range changed - was: %x, is %lx, index: %x\n",
+ i, lp[i], i);
+ }
+ }
+ }
+ }
+ CYG_TEST_CHECK(0 == errs, "dcache basic failed");
+#if 0 // Additional information
+ diag_printf("%d total errors during compare\n", errs);
+ diag_dump_buf(&lp[240], 128);
+#endif
+ HAL_RESTORE_INTERRUPTS(oldints);
+}
+#endif
+
+static void test_dsync(void)
+{
+ volatile cyg_uint8* aligned_p;
+ cyg_int32 i;
+ register CYG_INTERRUPT_STATE oldints;
+
+ CYG_TEST_INFO("Data cache sync all");
+
+ for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++)
+ m[i] = 0;
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+
+ aligned_p = (volatile cyg_uint8*)
+ (((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
+ & ~(HAL_DCACHE_LINE_SIZE-1));
+
+ aligned_p[0] = 42 + aligned_p[1]; // Load causes cache to be used!
+ aligned_p[HAL_DCACHE_LINE_SIZE] = 43 + aligned_p[HAL_DCACHE_LINE_SIZE + 1];
+
+ HAL_DCACHE_SYNC();
+
+ CYG_TEST_CHECK(42 == aligned_p[0],
+ "memory didn't contain flushed data");
+ CYG_TEST_CHECK(43 == aligned_p[HAL_DCACHE_LINE_SIZE],
+ "memory didn't contain flushed data next block");
+
+ HAL_DCACHE_INVALIDATE_ALL();
+
+ CYG_TEST_CHECK(42 == aligned_p[0],
+ "memory didn't contain flushed data after invalidate");
+ CYG_TEST_CHECK(43 == aligned_p[HAL_DCACHE_LINE_SIZE],
+ "memory didn't contain flushed data next block after invalidate");
+
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_DCACHE_DISABLE();
+
+ CYG_TEST_CHECK(42 == aligned_p[0],
+ "memory didn't contain flushed data after disable");
+ CYG_TEST_CHECK(43 == aligned_p[HAL_DCACHE_LINE_SIZE],
+ "memory didn't contain flushed data next block after disable");
+
+ HAL_DCACHE_ENABLE();
+}
+#endif // HAL_DCACHE_LINE_SIZE
+
+// -------------------------------------------------------------------------
+// Test of data cache line flush.
+// o Requires write-back cache.
+// o Check that flushed data is written to memory.
+// o Simple range check of macro.
+#ifdef HAL_DCACHE_QUERY_WRITE_MODE // only if we know this, can we test:
+#ifdef HAL_DCACHE_FLUSH
+static void test_dflush(void)
+{
+ volatile cyg_uint8* aligned_p;
+ cyg_int32 i;
+ register CYG_INTERRUPT_STATE oldints;
+
+ CYG_TEST_INFO("Data cache flush region");
+
+ for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++)
+ m[i] = 0;
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ aligned_p = (volatile cyg_uint8*)
+ (((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
+ & ~(HAL_DCACHE_LINE_SIZE-1));
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+
+ aligned_p[0] = 42 + aligned_p[1]; // Load causes cache to be used!
+ aligned_p[HAL_DCACHE_LINE_SIZE] = 43 + aligned_p[HAL_DCACHE_LINE_SIZE + 1];
+
+ HAL_DCACHE_FLUSH(aligned_p, HAL_DCACHE_LINE_SIZE);
+
+ HAL_DCACHE_DISABLE();
+
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ CYG_TEST_CHECK(42 == aligned_p[0],
+ "memory didn't contain flushed data");
+ CYG_TEST_CHECK(0 == aligned_p[HAL_DCACHE_LINE_SIZE],
+ "flushed beyond region");
+
+ HAL_DCACHE_ENABLE();
+}
+#endif
+#endif
+
+// -------------------------------------------------------------------------
+// Test of data cache disable (which does NOT force contents out to RAM)
+// o Requires write-back cache [so NOT invoked unconditionally]
+// o Check that dirty data is not written to memory and is invalidated
+// in the cache.
+// o Simple invocation check of macro.
+#ifdef HAL_DCACHE_QUERY_WRITE_MODE // only if we know this, can we test:
+static void test_ddisable(void)
+{
+ volatile cyg_uint8* aligned_p;
+ cyg_int32 i;
+ register CYG_INTERRUPT_STATE oldints;
+
+ CYG_TEST_INFO("Data cache gross disable");
+
+ for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++)
+ m[i] = 0;
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ aligned_p = (volatile cyg_uint8*)
+ (((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
+ & ~(HAL_DCACHE_LINE_SIZE-1));
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+
+ aligned_p[0] = 43 + aligned_p[1]; // Load causes cache to be used!
+ aligned_p[HAL_DCACHE_LINE_SIZE-1] = 43;
+
+ aligned_p[HAL_DCACHE_LINE_SIZE] = 42 + aligned_p[HAL_DCACHE_LINE_SIZE + 1];
+
+ HAL_DCACHE_DISABLE();
+
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ CYG_TEST_CHECK(0 == aligned_p[0] &&
+ 0 == aligned_p[HAL_DCACHE_LINE_SIZE-1],
+ "cache/memory contained invalidated data");
+ CYG_TEST_CHECK(0 == aligned_p[HAL_DCACHE_LINE_SIZE],
+ "next block contained invalidated data");
+
+ HAL_DCACHE_ENABLE();
+}
+#endif // def HAL_DCACHE_QUERY_WRITE_MODE
+
+// -------------------------------------------------------------------------
+// Test of data cache total invalidate.
+// o Requires write-back cache.
+// o Check that invalidated data is not written to memory and is invalidated
+// in the cache.
+// o Simple invocation check of macro.
+#ifdef HAL_DCACHE_QUERY_WRITE_MODE // only if we know this, can we test:
+#ifdef HAL_DCACHE_INVALIDATE_ALL
+static void test_dinvalidate_all(void)
+{
+ volatile cyg_uint8* aligned_p;
+ cyg_int32 i;
+ register CYG_INTERRUPT_STATE oldints;
+
+ CYG_TEST_INFO("Data cache invalidate all");
+
+ for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++)
+ m[i] = 0;
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+
+ aligned_p = (volatile cyg_uint8*)
+ (((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
+ & ~(HAL_DCACHE_LINE_SIZE-1));
+
+ aligned_p[0] = 43 + aligned_p[1]; // Load causes cache to be used!
+ aligned_p[HAL_DCACHE_LINE_SIZE-1] = 43;
+
+ aligned_p[HAL_DCACHE_LINE_SIZE] = 42 + aligned_p[HAL_DCACHE_LINE_SIZE + 1];
+
+ HAL_DCACHE_INVALIDATE_ALL();
+
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ CYG_TEST_CHECK(0 == aligned_p[0] &&
+ 0 == aligned_p[HAL_DCACHE_LINE_SIZE-1],
+ "cache/memory contained invalidated data");
+ CYG_TEST_CHECK(0 == aligned_p[HAL_DCACHE_LINE_SIZE],
+ "next block contained invalidated data");
+}
+#endif
+#endif // def HAL_DCACHE_QUERY_WRITE_MODE
+
+// -------------------------------------------------------------------------
+// Test of data cache line invalidate.
+// o Requires write-back cache.
+// o Check that invalidated data is not written to memory and is invalidated
+// in the cache.
+// o Simple range check of macro.
+#ifdef HAL_DCACHE_QUERY_WRITE_MODE // only if we know this, can we test:
+#ifdef HAL_DCACHE_INVALIDATE
+static void test_dinvalidate(void)
+{
+ volatile cyg_uint8* aligned_p;
+ cyg_int32 i;
+ register CYG_INTERRUPT_STATE oldints;
+
+ CYG_TEST_INFO("Data cache invalidate region");
+
+ for (i = 0; i < HAL_DCACHE_LINE_SIZE*16; i++)
+ m[i] = 0;
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ aligned_p = (volatile cyg_uint8*)
+ (((unsigned long) &m[HAL_DCACHE_LINE_SIZE*2])
+ & ~(HAL_DCACHE_LINE_SIZE-1));
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+
+ aligned_p[0] = 43 + aligned_p[1]; // Load causes cache to be used!
+ aligned_p[HAL_DCACHE_LINE_SIZE-1] = 43;
+
+ aligned_p[HAL_DCACHE_LINE_SIZE] = 42 + aligned_p[HAL_DCACHE_LINE_SIZE + 1];
+
+ HAL_DCACHE_INVALIDATE(aligned_p, HAL_DCACHE_LINE_SIZE);
+
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ CYG_TEST_CHECK(0 == aligned_p[0] &&
+ 0 == aligned_p[HAL_DCACHE_LINE_SIZE-1],
+ "cache/memory contained invalidated data");
+ CYG_TEST_CHECK(42 == aligned_p[HAL_DCACHE_LINE_SIZE],
+ "invalidated beyond range");
+
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+
+ CYG_TEST_CHECK(0 == aligned_p[0] &&
+ 0 == aligned_p[HAL_DCACHE_LINE_SIZE-1],
+ "cache/memory contained invalidated data after SYNC/DIS");
+ CYG_TEST_CHECK(42 == aligned_p[HAL_DCACHE_LINE_SIZE],
+ "invalidated beyond range after SYNC/DIS");
+
+ HAL_DCACHE_ENABLE();
+}
+#endif
+#endif // def HAL_DCACHE_QUERY_WRITE_MODE
+
+// -------------------------------------------------------------------------
+// Test of instruction cache locking.
+// o Time difference between repeatedly executing a bunch of instructions
+// with and without locking.
+#ifdef HAL_ICACHE_LOCK
+static void iloop(unsigned long* start, unsigned long* end, int dummy)
+{
+ // dummy is just used to fool the compiler to not move the labels
+ // around. All callers should call with dummy=0;
+
+ register char c;
+ register CYG_INTERRUPT_STATE oldints;
+
+ if (1 == dummy) goto label_end;
+
+ label_start:
+ // Invalidating shouldn't affect locked lines.
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_ICACHE_DISABLE();
+ HAL_ICACHE_INVALIDATE_ALL();
+ HAL_ICACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+
+ c = m[HAL_DCACHE_LINE_SIZE*0];
+ c = m[HAL_DCACHE_LINE_SIZE*1];
+ c = m[HAL_DCACHE_LINE_SIZE*2];
+ c = m[HAL_DCACHE_LINE_SIZE*3];
+ c = m[HAL_DCACHE_LINE_SIZE*4];
+ c = m[HAL_DCACHE_LINE_SIZE*5];
+ c = m[HAL_DCACHE_LINE_SIZE*6];
+ c = m[HAL_DCACHE_LINE_SIZE*7];
+ c = m[HAL_DCACHE_LINE_SIZE*8];
+ c = m[HAL_DCACHE_LINE_SIZE*9];
+ c = m[HAL_DCACHE_LINE_SIZE*10];
+ c = m[HAL_DCACHE_LINE_SIZE*11];
+ c = m[HAL_DCACHE_LINE_SIZE*12];
+ c = m[HAL_DCACHE_LINE_SIZE*13];
+ c = m[HAL_DCACHE_LINE_SIZE*14];
+ c = m[HAL_DCACHE_LINE_SIZE*15];
+ c = m[HAL_DCACHE_LINE_SIZE*16];
+ c = m[HAL_DCACHE_LINE_SIZE*17];
+ c = m[HAL_DCACHE_LINE_SIZE*18];
+ c = m[HAL_DCACHE_LINE_SIZE*19];
+ c = m[HAL_DCACHE_LINE_SIZE*20];
+ c = m[HAL_DCACHE_LINE_SIZE*21];
+ c = m[HAL_DCACHE_LINE_SIZE*22];
+ c = m[HAL_DCACHE_LINE_SIZE*23];
+ c = m[HAL_DCACHE_LINE_SIZE*24];
+ c = m[HAL_DCACHE_LINE_SIZE*25];
+ c = m[HAL_DCACHE_LINE_SIZE*26];
+ c = m[HAL_DCACHE_LINE_SIZE*27];
+ c = m[HAL_DCACHE_LINE_SIZE*28];
+ c = m[HAL_DCACHE_LINE_SIZE*29];
+ c = m[HAL_DCACHE_LINE_SIZE*30];
+ c = m[HAL_DCACHE_LINE_SIZE*31];
+ c = m[HAL_DCACHE_LINE_SIZE*32];
+ c = m[HAL_DCACHE_LINE_SIZE*33];
+ c = m[HAL_DCACHE_LINE_SIZE*34];
+ c = m[HAL_DCACHE_LINE_SIZE*35];
+ c = m[HAL_DCACHE_LINE_SIZE*36];
+ c = m[HAL_DCACHE_LINE_SIZE*37];
+ c = m[HAL_DCACHE_LINE_SIZE*38];
+ c = m[HAL_DCACHE_LINE_SIZE*39];
+ c = m[HAL_DCACHE_LINE_SIZE*40];
+ c = m[HAL_DCACHE_LINE_SIZE*41];
+ c = m[HAL_DCACHE_LINE_SIZE*42];
+ c = m[HAL_DCACHE_LINE_SIZE*43];
+ c = m[HAL_DCACHE_LINE_SIZE*44];
+ c = m[HAL_DCACHE_LINE_SIZE*45];
+ c = m[HAL_DCACHE_LINE_SIZE*46];
+ c = m[HAL_DCACHE_LINE_SIZE*47];
+ c = m[HAL_DCACHE_LINE_SIZE*48];
+ c = m[HAL_DCACHE_LINE_SIZE*49];
+ c = m[HAL_DCACHE_LINE_SIZE*50];
+ c = m[HAL_DCACHE_LINE_SIZE*51];
+ c = m[HAL_DCACHE_LINE_SIZE*52];
+ c = m[HAL_DCACHE_LINE_SIZE*53];
+ c = m[HAL_DCACHE_LINE_SIZE*54];
+ c = m[HAL_DCACHE_LINE_SIZE*55];
+ c = m[HAL_DCACHE_LINE_SIZE*56];
+ c = m[HAL_DCACHE_LINE_SIZE*57];
+ c = m[HAL_DCACHE_LINE_SIZE*58];
+ c = m[HAL_DCACHE_LINE_SIZE*59];
+ c = m[HAL_DCACHE_LINE_SIZE*60];
+ c = m[HAL_DCACHE_LINE_SIZE*61];
+ c = m[HAL_DCACHE_LINE_SIZE*62];
+ c = m[HAL_DCACHE_LINE_SIZE*63];
+
+ label_end:
+
+ *start = (unsigned long) &&label_start;
+ *end = (unsigned long) &&label_end;
+
+ if (1 == dummy) goto label_start;
+}
+
+static void time_ilock(void)
+{
+ register cyg_ucount32 k;
+ cyg_tick_count_t count0, count1;
+ cyg_ucount32 t;
+ unsigned long start, end;
+ register cyg_ucount32 time_ilock_loops = TIME_ILOCK_LOOPS;
+
+ CYG_TEST_INFO("Instruction cache lock");
+
+ if (cyg_test_is_simulator)
+ time_ilock_loops = 10;
+
+ count0 = cyg_current_time();
+ for (k = 0; k < time_ilock_loops; k++) {
+ iloop(&start, &end, 0);
+ }
+ count1 = cyg_current_time();
+ t = count1 - count0;
+ diag_printf("time without lock: %d\n", t);
+
+ HAL_ICACHE_LOCK(start, end-start);
+
+ count0 = cyg_current_time();
+ for (k = 0; k < time_ilock_loops; k++) {
+ iloop(&start, &end, 0);
+ }
+ count1 = cyg_current_time();
+ t = count1 - count0;
+ diag_printf("time with lock: %d\n", t);
+
+ HAL_ICACHE_UNLOCK(start, end-start);
+}
+#endif // ifdef HAL_ICACHE_LOCK
+
+// -------------------------------------------------------------------------
+// Test of data cache locking.
+// o Time difference between repeatedly accessing a memory region
+// with and without locking.
+#ifdef HAL_DCACHE_LOCK
+static void dloop(void)
+{
+ register cyg_uint32 j;
+ register char c;
+ register CYG_INTERRUPT_STATE oldints;
+
+ HAL_DISABLE_INTERRUPTS(oldints);
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_DISABLE();
+ HAL_DCACHE_SYNC();
+ HAL_DCACHE_INVALIDATE_ALL();
+ HAL_DCACHE_ENABLE();
+ HAL_RESTORE_INTERRUPTS(oldints);
+ for (j = 0; j < HAL_DCACHE_SETS; j++) {
+ c = m[HAL_DCACHE_LINE_SIZE*j];
+ }
+}
+
+static void time_dlock(void)
+{
+ register cyg_ucount32 k;
+ cyg_tick_count_t count0, count1;
+ cyg_ucount32 t;
+ register cyg_ucount32 time_dlock_loops = TIME_DLOCK_LOOPS;
+
+ CYG_TEST_INFO("Data cache lock");
+
+ if (cyg_test_is_simulator)
+ time_dlock_loops = 10;
+
+ count0 = cyg_current_time();
+ for (k = 0; k < time_dlock_loops; k++) {
+ dloop();
+ }
+ count1 = cyg_current_time();
+ t = count1 - count0;
+ diag_printf("time without lock: %d\n", t);
+
+ HAL_DCACHE_LOCK(&m[0], HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE);
+
+ count0 = cyg_current_time();
+ for (k = 0; k < time_dlock_loops; k++) {
+ dloop();
+ }
+ count1 = cyg_current_time();
+ t = count1 - count0;
+ diag_printf("time with lock: %d\n", t);
+
+ HAL_DCACHE_UNLOCK(&m[0], HAL_DCACHE_SETS*HAL_DCACHE_LINE_SIZE);
+}
+#endif // ifdef HAL_DCACHE_LOCK
+
+// -------------------------------------------------------------------------
+static void entry0( cyg_addrword_t data )
+{
+ int numtests = 0;
+#ifdef HAL_DCACHE_QUERY_WRITE_MODE
+ int wmode;
+#endif
+#ifdef HAL_DCACHE_LOCK
+ time_dlock(); numtests++;
+#endif
+#ifdef HAL_ICACHE_LOCK
+ time_ilock(); numtests++;
+#endif
+#ifdef HAL_DCACHE_LINE_SIZE // So we can find our way around memory
+ test_dsync(); numtests++;
+#endif
+#ifdef HAL_DCACHE_STORE
+ test_dstore(); numtests++;
+#endif
+#ifdef _TEST_DCACHE_OPERATION
+ test_dcache_operation(); numtests++;
+#endif
+#ifdef HAL_DCACHE_READ_HINT
+ test_dread_hint(); numtests++;
+#endif
+#ifdef HAL_DCACHE_WRITE_HINT
+ test_dwrite_hint(); numtests++;
+#endif
+#ifdef HAL_DCACHE_ZERO
+ test_dzero(); numtests++;
+#endif
+
+ // The below tests only work on a copy-back cache.
+#ifdef HAL_DCACHE_QUERY_WRITE_MODE
+ HAL_DCACHE_QUERY_WRITE_MODE( wmode );
+
+ if ( HAL_DCACHE_WRITEBACK_MODE == wmode ) {
+ test_ddisable(); numtests++;
+#ifdef HAL_DCACHE_INVALIDATE
+ test_dinvalidate_all(); numtests++;
+#endif
+#ifdef HAL_DCACHE_FLUSH
+ test_dflush(); numtests++;
+#endif
+#ifdef HAL_DCACHE_INVALIDATE
+ test_dinvalidate(); numtests++;
+#endif
+ }
+#endif // def HAL_DCACHE_QUERY_WRITE_MODE
+ if ( numtests ) {
+ CYG_TEST_PASS_FINISH("End of test");
+ }
+ else {
+ CYG_TEST_NA( "No applicable cache tests" );
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void kcache2_main( void )
+{
+ CYG_TEST_INIT();
+
+ cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kcache2",
+ (void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]);
+ cyg_thread_resume(thread[0]);
+
+ cyg_scheduler_start();
+}
+
+// -------------------------------------------------------------------------
+
+externC void
+cyg_start( void )
+{
+ kcache2_main();
+}
+
+// -------------------------------------------------------------------------
+
+#else // def CYGFUN_KERNEL_API_C
+#define N_A_MSG "Kernel C API layer disabled"
+#endif // def CYGFUN_KERNEL_API_C
+#else // def CYGVAR_KERNEL_COUNTERS_CLOCK
+#define N_A_MSG "Kernel real-time clock disabled"
+#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK
+
+#ifdef N_A_MSG
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( N_A_MSG );
+}
+#endif // N_A_MSG
+
+// -------------------------------------------------------------------------
+/* EOF kcache2.c */
diff --git a/ecos/packages/kernel/current/tests/kclock0.c b/ecos/packages/kernel/current/tests/kclock0.c
new file mode 100644
index 0000000000..91c126700c
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kclock0.c
@@ -0,0 +1,274 @@
+/*=================================================================
+//
+// kclock0.c
+//
+// Kernel C API Clock test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-20
+// Description: Tests some basic clock functions.
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGVAR_KERNEL_COUNTERS_CLOCK
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+cyg_alarm_t call_me;
+
+cyg_counter counter0o, counter1o;
+cyg_handle_t counter0, counter1;
+
+cyg_alarm alarmo[3];
+cyg_handle_t alarm0, alarm1, alarm2;
+
+cyg_resolution_t res, res0, res1;
+
+cyg_clock clock0o;
+cyg_handle_t clock0;
+
+const cyg_uint32 big_number = 3333222111u;
+
+cyg_bool_t flash( void )
+{
+ cyg_counter_create( &counter0, &counter0o );
+ cyg_counter_create( &counter1, &counter1o );
+
+ cyg_alarm_create( counter0,
+ call_me,
+ (cyg_addrword_t)12,
+ &alarm0,
+ &alarmo[0]);
+
+ res.dividend = 1;
+ res.divisor = 2;
+
+ cyg_clock_create( res, &clock0, &clock0o );
+ cyg_clock_delete( clock0 );
+
+ cyg_alarm_delete( alarm0 );
+
+ cyg_counter_delete( counter0 );
+ cyg_counter_delete( counter1 );
+
+ return true;
+}
+
+/* Testing alarms
+//
+// call_me is a function that will be called when an alarm is
+// triggered. It updates a global variable called which is CHECKed
+// explicitly to see if the approriate alarms have been called.
+*/
+
+cyg_uint16 called = 0x0;
+
+void call_me(cyg_handle_t alarm, cyg_addrword_t data)
+{
+ called ^= (int)data;
+}
+
+void call_me2(cyg_handle_t alarm, cyg_addrword_t data)
+{
+ call_me(alarm, (cyg_addrword_t)((int)data^0x10));
+}
+
+
+void kclock0_main(void)
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ cyg_counter_create( &counter0, &counter0o);
+
+ CHECK( 0 == cyg_counter_current_value( counter0 ) );
+
+ cyg_counter_tick(counter0);
+
+ CHECK( 1 == cyg_counter_current_value(counter0) );
+
+ cyg_counter_tick(counter0);
+
+ CHECK( 2 == cyg_counter_current_value(counter0) );
+
+ cyg_counter_set_value( counter0, 0xffffffff );
+
+ CHECK( 0xffffffff == cyg_counter_current_value(counter0) );
+
+ cyg_counter_tick(counter0); // Overflows 32 bits
+
+ CHECK( 0x100000000ULL == cyg_counter_current_value(counter0) );
+
+ cyg_counter_set_value(counter0, 11);
+ CHECK( 11 == cyg_counter_current_value(counter0) );
+
+ /* the call_me functions cause the "called" bits to toggle
+ // checking the value of called checks the parity of # of calls
+ // made by each alarm.
+ */
+
+ cyg_alarm_create(counter0,
+ call_me, (cyg_addrword_t)0x1, &alarm0, &alarmo[0]);
+ cyg_alarm_create(counter0,
+ call_me, (cyg_addrword_t)0x2, &alarm1, &alarmo[1]);
+ cyg_alarm_create(counter0,
+ call_me2, (cyg_addrword_t)0x4, &alarm2, &alarmo[2]);
+
+ CHECK( 0x00 == called );
+ cyg_alarm_initialize(alarm0, 12,3);
+ cyg_alarm_initialize(alarm2, 21,2);
+ CHECK( 0x00 == called );
+
+ cyg_counter_tick(counter0); /* 12 a0 */
+ CHECK( 0x01 == called );
+
+ cyg_alarm_initialize(alarm1, 13,0);
+ cyg_counter_tick(counter0); /* 13 a1 */
+ CHECK( 0x03 == called );
+
+ cyg_alarm_initialize(alarm1, 17,0);
+ cyg_counter_tick(counter0); /* 14 */
+ CHECK( 0x03 == called );
+
+ cyg_counter_tick(counter0); /* 15 a0 */
+ CHECK( 0x02 == called );
+
+ cyg_counter_tick(counter0); /* 16 */
+ cyg_counter_tick(counter0); /* 17 a1 */
+ CHECK( 0x00 == called );
+
+ cyg_counter_tick(counter0); /* 18 a0 */
+ CHECK( 0x01 == called );
+
+ cyg_counter_tick(counter0); /* 19 */
+ cyg_counter_tick(counter0); /* 20 */
+ cyg_counter_tick(counter0); /* 21 a0 a2 */
+ CHECK( 0x14 == called );
+
+ cyg_counter_tick(counter0); /* 22 */
+ cyg_counter_tick(counter0); /* 23 a2 */
+ CHECK( 0x00 == called );
+
+ cyg_alarm_disable(alarm2);
+
+ cyg_counter_tick(counter0); /* 24 a0 */
+ cyg_counter_tick(counter0); /* 25 */
+ CHECK( 0x01 == called );
+
+ cyg_alarm_enable(alarm2); /* a2 (enabled at 25) */
+ CHECK( 0x15 == called );
+
+ cyg_counter_tick(counter0); /* 26 */
+ CHECK( 0x15 == called );
+
+ cyg_counter_tick(counter0); /* 27 a0 a2 */
+ cyg_counter_tick(counter0); /* 28 */
+ CHECK( 0x00 == called );
+
+ cyg_counter_tick(counter0); /* 29 a2 */
+ cyg_counter_tick(counter0); /* 30 a0 */
+ cyg_counter_tick(counter0); /* 31 a2 */
+ CHECK( 0x01 == called );
+
+ res0.dividend = 100;
+ res0.divisor = 3;
+
+ cyg_clock_create( res0, &clock0, &clock0o );
+
+ res1 = cyg_clock_get_resolution(clock0);
+ CHECK( res0.dividend == res1.dividend );
+ CHECK( res0.divisor == res1.divisor );
+
+ res1.dividend = 12;
+ res1.divisor = 25;
+
+ cyg_clock_set_resolution(clock0, res1);
+ res0 = cyg_clock_get_resolution(clock0);
+ CHECK( res0.dividend == res1.dividend );
+ CHECK( res0.divisor == res1.divisor );
+
+ cyg_clock_to_counter(clock0, &counter1);
+
+ CHECK( 0 == cyg_counter_current_value( counter1 ) );
+ CHECK( 0 == cyg_current_time() );
+
+ cyg_counter_tick(counter1);
+
+ CHECK( 1 == cyg_counter_current_value(counter1) );
+
+ res0 = cyg_clock_get_resolution(cyg_real_time_clock());
+
+ /* Current time should be 0 as interrupts will still be disabled */
+ CHECK( 0 == cyg_current_time() );
+
+ CYG_TEST_PASS_FINISH("Kernel C API Clock 0 OK");
+}
+
+externC void
+cyg_start( void )
+{
+ kclock0_main();
+}
+
+#else // def CYGFUN_KERNEL_API_C
+#define N_A_MSG "Kernel C API layer disabled"
+#endif // def CYGFUN_KERNEL_API_C
+#else // def CYGVAR_KERNEL_COUNTERS_CLOCK
+#define N_A_MSG "Kernel real-time clock disabled"
+#endif // def CYGVAR_KERNEL_COUNTERS_CLOCK
+
+#ifdef N_A_MSG
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( N_A_MSG );
+}
+#endif // N_A_MSG
+
+// EOF kclock0.c
diff --git a/ecos/packages/kernel/current/tests/kclock1.c b/ecos/packages/kernel/current/tests/kclock1.c
new file mode 100644
index 0000000000..9eaf502516
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kclock1.c
@@ -0,0 +1,153 @@
+/*=================================================================
+//
+// kclock1.c
+//
+// Kernel C API Clock test 1 - Real Time Clock
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-20
+// Description: Tests the Kernel Real Time Clock
+// This test creates a thread, starts the scheduler and
+// delays for a time of about 5 seconds. This test should
+// be expected to run for about this length of time.
+// Omissions:
+// Doesn't test alarms attached to RTC.
+// Assumptions:
+// CYGVAR_KERNEL_COUNTERS_CLOCK must be set.
+// Resolution of clock small compared with 5s.
+// Overhead small compared with 5s.
+// Options:
+// CYGIMP_KERNEL_COUNTERS_SINGLE_LIST
+// CYGIMP_KERNEL_COUNTERS_MULTI_LIST
+// CYGVAR_KERNEL_COUNTERS_CLOCK
+// CYGNUM_KERNEL_COUNTERS_MULTI_LIST_SIZE
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+
+static cyg_uint64 TEST_DELAY;
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+#define NTHREADS 1
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static cyg_handle_t thread[NTHREADS];
+
+static cyg_thread thread_obj[NTHREADS];
+static char stack[NTHREADS][STACKSIZE];
+
+static void entry0( cyg_addrword_t data )
+{
+ cyg_resolution_t res;
+ cyg_uint32 ticks;
+ cyg_tick_count_t count0, count1;
+ cyg_handle_t rtclock, rtcounter;
+
+ rtclock = cyg_real_time_clock();
+ cyg_clock_to_counter(rtclock, &rtcounter);
+
+ res = cyg_clock_get_resolution (rtclock);
+
+ /* RTC takes res.dividend/res.divisor ns/tick */
+ ticks = ((cyg_uint64)TEST_DELAY * res.divisor) / res.dividend;
+
+ count0 = cyg_counter_current_value(rtcounter);
+ cyg_thread_delay(ticks);
+ count1 = cyg_counter_current_value(rtcounter);
+
+ CYG_TEST_CHECK(count0+ticks <= count1,
+ "real time clock's counter not counting");
+
+ CYG_TEST_CHECK(count1 <= cyg_current_time(),"cyg_current_time()");
+
+ CYG_TEST_PASS_FINISH("Kernel C API Clock 1 OK");
+}
+
+void kclock1_main( void )
+{
+ CYG_TEST_INIT();
+
+ if (cyg_test_is_simulator) {
+ TEST_DELAY = 100000000ll;
+ } else {
+ TEST_DELAY = 3000000000ll;
+ }
+
+ cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kclock1",
+ (void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]);
+ cyg_thread_resume(thread[0]);
+
+ cyg_scheduler_start();
+}
+
+externC void
+cyg_start( void )
+{
+ kclock1_main();
+}
+
+#else // def CYGFUN_KERNEL_API_C
+#define N_A_MSG "Kernel C API layer disabled"
+#endif // def CYGFUN_KERNEL_API_C
+#else // def CYGFUN_KERNEL_THREADS_TIMER
+#define N_A_MSG "Kernel threads timer disabled"
+#endif // def CYGFUN_KERNEL_THREADS_TIMER
+
+#ifdef N_A_MSG
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( N_A_MSG );
+}
+#endif // N_A_MSG
+
+// EOF kclock1.c
diff --git a/ecos/packages/kernel/current/tests/kexcept1.c b/ecos/packages/kernel/current/tests/kexcept1.c
new file mode 100644
index 0000000000..d85687f6a4
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kexcept1.c
@@ -0,0 +1,288 @@
+/*=================================================================
+//
+// kexcept1.cxx
+//
+// Kernel C API Exception test 1
+//
+//=================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm, jlarmour
+// Date: 1999-02-16
+// Description: Test basic exception functionality
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGPKG_KERNEL_EXCEPTIONS
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include <cyg/hal/hal_intr.h> // exception ranges
+
+#include "testaux.h"
+
+#ifndef CYGPKG_HAL_ARM_PID
+#define EXCEPTION_DATA_ACCESS
+#endif
+
+#define NTHREADS 1
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static cyg_handle_t thread[NTHREADS];
+
+static cyg_thread thread_obj[NTHREADS];
+static char stack[NTHREADS][STACKSIZE];
+
+
+
+#ifdef EXCEPTION_DATA_ACCESS
+static cyg_exception_handler_t handler0;
+
+static void handler0(cyg_addrword_t data, cyg_code_t number, cyg_addrword_t info)
+{
+ CYG_TEST_INFO("handler 0 called");
+
+ CYG_TEST_CHECK((cyg_addrword_t)123 == data, "handler given wrong data");
+
+ // ignore machine specific stuff
+ CYG_UNUSED_PARAM(cyg_code_t, number);
+ CYG_UNUSED_PARAM(cyg_addrword_t, info);
+
+ CYG_TEST_PASS_FINISH("Except 1 OK");
+}
+#endif
+
+static int d0;
+
+static void handler1(cyg_addrword_t data, cyg_code_t number, cyg_addrword_t info)
+{
+ CYG_TEST_INFO("handler 1 called");
+
+ CYG_TEST_CHECK((cyg_addrword_t)&d0 == data, "handler given wrong data");
+
+#ifdef CYGSEM_KERNEL_EXCEPTIONS_DECODE
+ CYG_TEST_CHECK(number == CYGNUM_HAL_EXCEPTION_MAX, "handler given wrong number");
+#else
+ CYG_UNUSED_PARAM(cyg_code_t, number);
+#endif
+
+ CYG_TEST_CHECK((cyg_addrword_t)99 == info, "handler given wrong info");
+}
+
+
+#ifdef EXCEPTION_DATA_ACCESS
+// The following function attempts to cause an exception in various
+// hacky ways. It is machine dependent what exception is generated.
+// It does reads rather than writes hoping not to corrupt anything
+// important.
+static int
+cause_fpe(int num)
+{
+ double a;
+
+ a = 1.0/num; // Depending on FPU emulation and/or
+ // the FPU architecture, this may
+ // cause an exception.
+ // (float division by zero)
+
+ return ((int)a)/num; // This may cause an exception if
+ // the architecture supports it.
+ // (integer division by zero).
+} // cause_fpe()
+
+void cause_exception(void)
+{
+ int x;
+ unsigned int p=0;
+
+ // First try for an address exception (unaligned access exception
+ // or SEGV/BUS exceptions)
+ do {
+ x=*(volatile int *)(p-1);
+ p+=0x100000;
+ } while(p != 0);
+
+ // Next try an integer or floating point divide-by-zero exception.
+ cause_fpe(0);
+}
+#endif
+
+static void entry0( CYG_ADDRWORD data )
+{
+#ifdef EXCEPTION_DATA_ACCESS
+ cyg_code_t n;
+#endif
+ cyg_exception_handler_t *old_handler, *old_handler1;
+ cyg_addrword_t old_data, old_data1;
+
+ CYG_UNUSED_PARAM(CYG_ADDRESS, data);
+
+ cyg_exception_set_handler(
+ CYGNUM_HAL_EXCEPTION_MAX,
+ &handler1,
+ (cyg_addrword_t)&d0,
+ &old_handler,
+ &old_data);
+
+ cyg_exception_set_handler(
+ CYGNUM_HAL_EXCEPTION_MAX,
+ &handler1,
+ (cyg_addrword_t)&d0,
+ &old_handler1,
+ &old_data1);
+
+ CYG_TEST_CHECK(old_handler1 == &handler1,
+ "register exception: old_handler not the one previously registered");
+ CYG_TEST_CHECK(old_data1 == (cyg_addrword_t)&d0,
+ "register exception: old_data not those previously registered");
+
+ cyg_exception_call_handler(
+ cyg_thread_self(),
+ CYGNUM_HAL_EXCEPTION_MAX,
+ (cyg_addrword_t)99);
+
+ CYG_TEST_INFO("handler 1 returned");
+
+ cyg_exception_clear_handler(CYGNUM_HAL_EXCEPTION_MAX);
+ cyg_exception_clear_handler(CYGNUM_HAL_EXCEPTION_MAX);
+
+#ifdef EXCEPTION_DATA_ACCESS
+
+#if 0
+#elif defined(CYGPKG_HAL_POWERPC_SIM)
+ // The exception generated by the SIM is not recognized by GDB.
+ // PR 19945 workaround.
+ CYG_TEST_NA("Not applicable to PowerPC SIM");
+#endif
+
+ for(n = CYGNUM_HAL_EXCEPTION_MIN; n <= CYGNUM_HAL_EXCEPTION_MAX; n++) {
+ cyg_exception_set_handler(
+ n,
+ handler0,
+ (cyg_addrword_t)123,
+ &old_handler1,
+ &old_data1);
+ }
+
+ CYG_TEST_PASS("Attempting to provoke exception");
+
+ cause_exception();
+
+ CYG_TEST_FAIL_FINISH("Couldn't cause exception");
+#else // EXCEPTION_DATA_ACCESS
+ CYG_TEST_NA("Platform does not support data exceptions");
+#endif
+}
+
+#ifdef CYG_HAL_MIPS_TX39_JMR3904
+
+extern void __default_exception_vsr(void);
+
+#endif
+
+void except0_main( void )
+{
+ // Use CYG_TEST_GDBCMD _before_ CYG_TEST_INIT()
+ CYG_TEST_GDBCMD("handle SIGBUS nostop");
+ CYG_TEST_GDBCMD("handle SIGSEGV nostop");
+ CYG_TEST_GDBCMD("handle SIGFPE nostop");
+
+ CYG_TEST_INIT();
+
+#ifdef HAL_VSR_SET_TO_ECOS_HANDLER
+ // Reclaim the VSR off CygMon possibly
+#ifdef CYGNUM_HAL_EXCEPTION_DATA_ACCESS
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_ACCESS, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_TLBMISS_ACCESS, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DATA_UNALIGNED_ACCESS, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_DIV_BY_ZERO
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_DIV_BY_ZERO, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_FPU
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_FPU, NULL );
+#endif
+#ifdef CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO
+ HAL_VSR_SET_TO_ECOS_HANDLER( CYGNUM_HAL_EXCEPTION_FPU_DIV_BY_ZERO, NULL );
+#endif
+#endif
+
+ cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kexcept1",
+ (void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]);
+ cyg_thread_resume(thread[0]);
+
+ cyg_scheduler_start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+ except0_main();
+}
+
+#else // def CYGFUN_KERNEL_API_C
+#define N_A_MSG "Kernel C API layer disabled"
+#endif // def CYGFUN_KERNEL_API_C
+#else // def CYGPKG_KERNEL_EXCEPTIONS
+#define N_A_MSG "Exceptions disabled"
+#endif // def CYGPKG_KERNEL_EXCEPTIONS
+
+#ifdef N_A_MSG
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( N_A_MSG);
+}
+#endif // N_A_MSG
+
+/* EOF kexcept1.c */
diff --git a/ecos/packages/kernel/current/tests/kflag0.c b/ecos/packages/kernel/current/tests/kflag0.c
new file mode 100644
index 0000000000..d5483db11b
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kflag0.c
@@ -0,0 +1,99 @@
+/*==========================================================================
+//
+// kflag0.cxx
+//
+// Kernel C API Flag test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: hmt
+// Date: 1998-10-19
+// Description: Limited to checking constructors/destructors
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+cyg_flag_t f0, f1, f2;
+
+static bool flash( void )
+{
+ cyg_flag_init( &f0 );
+ cyg_flag_init( &f1 );
+ cyg_flag_init( &f2 );
+
+ cyg_flag_destroy( &f0 );
+ cyg_flag_destroy( &f1 );
+ cyg_flag_destroy( &f2 );
+
+ return true;
+}
+
+void kflag0_main( void )
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ CYG_TEST_PASS_FINISH("Kernel C API Flag 0 OK");
+
+}
+
+externC void
+cyg_start( void )
+{
+ kflag0_main();
+}
+
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+// EOF kflag0.cxx
diff --git a/ecos/packages/kernel/current/tests/kflag1.c b/ecos/packages/kernel/current/tests/kflag1.c
new file mode 100644
index 0000000000..d09ddec1ba
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kflag1.c
@@ -0,0 +1,244 @@
+/*==========================================================================
+//
+// kflag1.cxx
+//
+// Kernel C API Flag test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: dsm
+// Contributors: hmt
+// Date: 1998-10-19
+// Description: Tests basic flag functionality.
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+
+#define NTHREADS 3
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static cyg_handle_t thread[NTHREADS];
+
+static cyg_thread thread_obj[NTHREADS];
+static char stack[NTHREADS][STACKSIZE];
+
+static cyg_flag_t f0, f1;
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+static cyg_flag_t f2;
+#endif
+
+static volatile cyg_ucount8 q = 0;
+#define FIRST_THREAD_WAIT_TIME 5
+#define SECOND_THREAD_WAIT_TIME 10
+#define THIRD_THREAD_WAIT_TIME 20
+
+static void entry0( cyg_addrword_t data )
+{
+ CYG_TEST_INFO("Testing cyg_flag_setbits() and cyg_flag_maskbits()");
+ CYG_TEST_CHECK(0==cyg_flag_peek( &f0 ), "flag not initialized properly");
+ cyg_flag_setbits( &f0, 0x1);
+ CYG_TEST_CHECK(1==cyg_flag_peek( &f0 ), "setbits");
+ cyg_flag_setbits( &f0, 0x3);
+ CYG_TEST_CHECK(3==cyg_flag_peek( &f0 ), "setbits");
+ cyg_flag_maskbits( &f0, ~0x5);
+ CYG_TEST_CHECK(2==cyg_flag_peek( &f0 ), "maskbits");
+ cyg_flag_setbits( &f0, ~0 );
+ CYG_TEST_CHECK(~0u==cyg_flag_peek( &f0 ), "setbits all set");
+ cyg_flag_maskbits( &f0, 0 );
+ CYG_TEST_CHECK(0==cyg_flag_peek( &f0 ), "maskbits all clear");
+ CYG_TEST_CHECK(0==q++, "bad synchronization");
+
+ CYG_TEST_INFO("Testing cyg_flag_wait()");
+ cyg_flag_setbits( &f1, 0x4);
+ CYG_TEST_CHECK(0x4==cyg_flag_peek( &f1 ), "setbits");
+ CYG_TEST_CHECK(1==q++, "bad synchronization");
+ cyg_flag_setbits( &f1, 0x18); // wake t1
+ cyg_flag_wait( &f1, 0x11, CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR);
+ CYG_TEST_CHECK(0==cyg_flag_peek( &f1 ), "flag value wrong");
+ CYG_TEST_CHECK(3==q++, "bad synchronization");
+ cyg_flag_setbits( &f0, 0x2); // wake t1
+ cyg_flag_wait( &f1, 0x10, CYG_FLAG_WAITMODE_AND );
+ cyg_flag_setbits( &f0, 0x1); // wake t1
+
+ cyg_flag_wait( &f1, 0x11, CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR);
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_flag_wait( &f2, 0x2, CYG_FLAG_WAITMODE_OR);
+ CYG_TEST_CHECK(20==q,"bad synchronization");
+ cyg_flag_timed_wait( &f2, 0x10, CYG_FLAG_WAITMODE_AND,
+ cyg_current_time()+THIRD_THREAD_WAIT_TIME);
+ CYG_TEST_CHECK(21==q++,"bad synchronization");
+#endif
+ cyg_flag_wait( &f0, 1, CYG_FLAG_WAITMODE_OR);
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+static void entry1( cyg_addrword_t data )
+{
+ cyg_flag_wait( &f1, 0xc, CYG_FLAG_WAITMODE_AND);
+ CYG_TEST_CHECK(2==q++, "bad synchronization");
+ CYG_TEST_CHECK(0x1c==cyg_flag_peek( &f1 ), "flag value wrong");
+ cyg_flag_setbits( &f1, 0x1); // wake t0
+ cyg_flag_wait( &f0, 0x3, CYG_FLAG_WAITMODE_OR);
+ CYG_TEST_CHECK(4==q++, "bad synchronization");
+ CYG_TEST_CHECK(2==cyg_flag_peek( &f0 ), "flag value wrong");
+
+ cyg_flag_setbits( &f1, 0xf0); // wake t0,t2
+ cyg_flag_wait( &f0, 0x5, CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR);
+ CYG_TEST_CHECK(0==cyg_flag_peek( &f0 ), "flag value wrong");
+ CYG_TEST_CHECK(0xf0==cyg_flag_peek( &f1 ), "flag value wrong");
+ CYG_TEST_CHECK(5==q++, "bad synchronization");
+ cyg_flag_maskbits( &f1, 0 );
+ CYG_TEST_CHECK(0==cyg_flag_peek( &f1 ), "flag value wrong");
+
+ CYG_TEST_INFO("Testing cyg_flag_poll()");
+ cyg_flag_setbits( &f0, 0x55);
+ CYG_TEST_CHECK(0x55==cyg_flag_peek( &f0 ), "flag value wrong");
+ CYG_TEST_CHECK(0x55==cyg_flag_poll( &f0, 0x3, CYG_FLAG_WAITMODE_OR),"bad poll() return");
+ CYG_TEST_CHECK(0==cyg_flag_poll( &f0, 0xf, CYG_FLAG_WAITMODE_AND),"poll()");
+ CYG_TEST_CHECK(0==cyg_flag_poll( &f0, 0xa, CYG_FLAG_WAITMODE_OR),"poll()");
+ CYG_TEST_CHECK(0x55==cyg_flag_peek( &f0 ), "flag value wrong");
+ CYG_TEST_CHECK(0x55==cyg_flag_poll( &f0, 0xf, CYG_FLAG_WAITMODE_OR | CYG_FLAG_WAITMODE_CLR),"poll");
+ CYG_TEST_CHECK(0x0==cyg_flag_peek( &f0 ), "flag value wrong");
+ cyg_flag_setbits( &f0, 0x50);
+ CYG_TEST_CHECK(0x50==cyg_flag_poll( &f0, 0x10, CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR),"poll");
+ CYG_TEST_CHECK(0x0==cyg_flag_peek( &f0 ), "flag value wrong");
+
+ CYG_TEST_INFO("Testing cyg_flag_waiting()");
+ cyg_flag_maskbits( &f0, 0 );
+ CYG_TEST_CHECK(!cyg_flag_waiting( &f0 ), "waiting()");
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_thread_delay( 10 ); // allow other threads to reach wait on f1
+ CYG_TEST_CHECK(cyg_flag_waiting( &f1 ), "waiting() not true");
+ cyg_flag_setbits( &f1, ~0 ); // wake one of t0,t2
+ CYG_TEST_CHECK(cyg_flag_waiting( &f1 ),"waiting() not true");
+#else
+ cyg_flag_setbits( &f1, 0x11); // wake one of t0,t2
+#endif
+ cyg_flag_setbits( &f1, 0x11); // wake other of t0,t2
+ CYG_TEST_CHECK(!cyg_flag_waiting( &f1 ),"waiting not false");
+ CYG_TEST_CHECK(0x0==cyg_flag_peek( &f1 ), "flag value wrong");
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ CYG_TEST_INFO("Testing cyg_flag_timed_wait()");
+ q=20;
+ cyg_flag_setbits( &f2, 0x2); // synchronize with t0,t2
+ CYG_TEST_CHECK(20==q,"bad synchronization");
+ cyg_flag_timed_wait( &f2, 0x20, CYG_FLAG_WAITMODE_AND,
+ cyg_current_time()+SECOND_THREAD_WAIT_TIME);
+ CYG_TEST_CHECK(22==q++,"bad synchronization");
+#endif
+
+ CYG_TEST_PASS_FINISH("Kernel C API Flag 1 OK");
+}
+
+static void entry2( cyg_addrword_t data )
+{
+ cyg_flag_wait( &f1, 0x60, CYG_FLAG_WAITMODE_OR);
+ cyg_flag_setbits( &f0, 0x4);
+
+ cyg_flag_wait( &f1, 0x11, CYG_FLAG_WAITMODE_AND | CYG_FLAG_WAITMODE_CLR);
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_flag_wait( &f2, 0x2, CYG_FLAG_WAITMODE_OR);
+ CYG_TEST_CHECK(20==q,"bad synchronization");
+ CYG_TEST_CHECK(0==cyg_flag_timed_wait( &f2, 0x40, CYG_FLAG_WAITMODE_AND,
+ cyg_current_time()+FIRST_THREAD_WAIT_TIME),
+ "timed wait() wrong");
+ CYG_TEST_CHECK(20==q++,"bad synchronization");
+ // Now wake t0 before it times out
+ cyg_flag_setbits( &f2, 0x10);
+#endif
+ cyg_flag_wait( &f0, 1, CYG_FLAG_WAITMODE_OR);
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+void kflag1_main( void )
+{
+ CYG_TEST_INIT();
+
+ cyg_flag_init( &f0 );
+ cyg_flag_init( &f1 );
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_flag_init( &f2 );
+#endif
+
+ cyg_thread_create( 1, entry0 , (cyg_addrword_t)0, "kflag1-0",
+ (void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]);
+ cyg_thread_resume(thread[0]);
+
+ cyg_thread_create( 1, entry1 , (cyg_addrword_t)1, "kflag1-1",
+ (void *)stack[1], STACKSIZE, &thread[1], &thread_obj[1]);
+ cyg_thread_resume(thread[1]);
+
+ cyg_thread_create( 1, entry2 , (cyg_addrword_t)2, "kflag1-2",
+ (void *)stack[2], STACKSIZE, &thread[2], &thread_obj[2]);
+ cyg_thread_resume(thread[2]);
+
+ cyg_scheduler_start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+ kflag1_main();
+}
+
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+// EOF flag1.cxx
diff --git a/ecos/packages/kernel/current/tests/kill.cxx b/ecos/packages/kernel/current/tests/kill.cxx
new file mode 100644
index 0000000000..032403b82e
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kill.cxx
@@ -0,0 +1,199 @@
+//==========================================================================
+//
+// kill.cxx
+//
+// Thread kill test
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1998-04-24
+// Description: Tests the functionality of thread kill() and
+// reinitalize().
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/mutex.hxx>
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+#include <cyg/kernel/sched.inl>
+
+#define NTHREADS 3
+
+#include "testaux.hxx"
+
+// In general, this delay has to be long enough to account for slow targets
+// and potential problems on e.g. the linux synthetic target to avoid
+// potential problems due to timing inaccuracy and scheduling of Linux
+// tasks. It is decreased further below for simulators.
+int delay_ticks = 5;
+
+
+static Cyg_Binary_Semaphore s0, s1;
+
+volatile cyg_atomic thread0_state;
+volatile cyg_atomic thread1_state;
+volatile cyg_atomic thread2_state;
+
+static void entry0( CYG_ADDRWORD data )
+{
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ thread0_state = 1;
+
+ s0.wait();
+
+ thread0_state = 2;
+
+ CYG_TEST_FAIL_FINISH("Thread not killed");
+
+ self->exit();
+}
+
+
+static void entry1( CYG_ADDRWORD data )
+{
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ thread1_state = 1;
+
+ self->delay(delay_ticks);
+
+ if( thread2_state != 1 )
+ CYG_TEST_FAIL_FINISH("Thread2 in wrong state");
+
+ thread1_state = 2;
+
+ thread[0]->kill();
+
+ thread1_state = 3;
+
+ thread[2]->kill();
+
+ thread1_state = 4;
+
+ self->delay(delay_ticks);
+
+ thread1_state = 5;
+ thread2_state = 0;
+
+ thread[2]->reinitialize();
+ thread[2]->resume();
+
+ self->delay(delay_ticks);
+
+ if( thread2_state != 1 )
+ CYG_TEST_FAIL_FINISH("Thread2 in wrong state");
+
+ thread1_state = 6;
+
+ self->delay(delay_ticks);
+
+ if( thread2_state != 2 )
+ CYG_TEST_FAIL_FINISH("Thread2 in wrong state");
+
+ thread[2]->kill();
+
+ thread1_state = 7;
+
+ CYG_TEST_PASS_FINISH("Kill OK");
+
+ Cyg_Thread::self()->exit();
+}
+
+static void entry2( CYG_ADDRWORD data )
+{
+ thread2_state = 1;
+
+ while( thread1_state != 6 ) continue;
+
+ thread2_state = 2;
+
+ for(;;) continue;
+
+}
+
+void release_main(void)
+{
+ CYG_TEST_INIT();
+
+ if (cyg_test_is_simulator)
+ delay_ticks = 2;
+
+ new_thread( entry0, 0);
+ new_thread( entry1, 1);
+ new_thread( entry2, 2);
+
+ thread[0]->set_priority(5);
+ thread[1]->set_priority(6);
+ thread[2]->set_priority(7);
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ release_main();
+}
+
+#else // ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel threads timer disabled");
+}
+
+#endif // ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+// EOF kill.cxx
diff --git a/ecos/packages/kernel/current/tests/kintr0.c b/ecos/packages/kernel/current/tests/kintr0.c
new file mode 100644
index 0000000000..6bc53f672b
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kintr0.c
@@ -0,0 +1,230 @@
+/*=================================================================
+//
+// kintr0.c
+//
+// Kernel C API Intr test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm, jlarmour
+// Date: 1999-02-16
+// Description: Very basic test of interrupt objects
+// Options:
+// CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
+// CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE_MAX
+// CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/kernel/kapi.h>
+#include <cyg/hal/hal_intr.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+static cyg_interrupt intr_obj[2];
+
+static cyg_handle_t intr0, intr1;
+
+
+static cyg_ISR_t isr0, isr1;
+static cyg_DSR_t dsr0, dsr1;
+
+static cyg_uint32 isr0(cyg_vector_t vector, cyg_addrword_t data)
+{
+ CYG_UNUSED_PARAM(cyg_addrword_t, data);
+
+ cyg_interrupt_acknowledge(vector);
+ return 0;
+}
+
+static void dsr0(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+ CYG_UNUSED_PARAM(cyg_vector_t, vector);
+ CYG_UNUSED_PARAM(cyg_ucount32, count);
+ CYG_UNUSED_PARAM(cyg_addrword_t, data);
+}
+
+static cyg_uint32 isr1(cyg_vector_t vector, cyg_addrword_t data)
+{
+ CYG_UNUSED_PARAM(cyg_vector_t, vector);
+ CYG_UNUSED_PARAM(cyg_addrword_t, data);
+ return 0;
+}
+
+static void dsr1(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+ CYG_UNUSED_PARAM(cyg_vector_t, vector);
+ CYG_UNUSED_PARAM(cyg_ucount32, count);
+ CYG_UNUSED_PARAM(cyg_addrword_t, data);
+}
+
+static bool flash( void )
+{
+ cyg_handle_t handle;
+ cyg_interrupt intr;
+
+ cyg_interrupt_create(CYGNUM_HAL_ISR_MIN, 0, (cyg_addrword_t)333,
+ isr0, dsr0, &handle, &intr );
+ cyg_interrupt_delete(handle);
+
+ return true;
+}
+
+/* IMPORTANT: The calling convention for VSRs is target dependent. It is
+ * unlikely that a plain C or C++ routine would function correctly on any
+ * particular platform, even if it could correctly access the system
+ * resources necessary to handle the event that caused it to be called.
+ * VSRs usually must be written in assembly language.
+ *
+ * This is just a test program. The routine vsr0() below is defined simply
+ * to define an address that will be in executable memory. If an event
+ * causes this VSR to be called, all bets are off. If it is accidentally
+ * installed in the vector for the realtime clock, the system will likely
+ * freeze.
+ */
+
+static cyg_VSR_t vsr0;
+
+static void vsr0()
+{
+}
+
+void kintr0_main( void )
+{
+ cyg_vector_t v = (CYGNUM_HAL_VSR_MIN + 11) % CYGNUM_HAL_VSR_COUNT;
+ cyg_vector_t v1;
+ cyg_vector_t lvl1 = CYGNUM_HAL_ISR_MIN + (1 % CYGNUM_HAL_ISR_COUNT);
+ cyg_vector_t lvl2 = CYGNUM_HAL_ISR_MIN + (15 % CYGNUM_HAL_ISR_COUNT);
+ int in_use;
+
+ cyg_VSR_t *old_vsr, *new_vsr;
+
+ CYG_TEST_INIT();
+
+#ifdef CYGPKG_HAL_MIPS_TX39
+ // This can be removed when PR 17831 is fixed
+ if ( cyg_test_is_simulator )
+ v1 = 12 % CYGNUM_HAL_ISR_COUNT;
+ else /* NOTE TRAILING ELSE... */
+#endif
+ v1 = CYGNUM_HAL_ISR_MIN + ( 6 % CYGNUM_HAL_ISR_COUNT);
+
+ CHECK(flash());
+ CHECK(flash());
+
+ // Make sure the chosen levels are not already in use.
+ HAL_INTERRUPT_IN_USE( lvl1, in_use );
+ intr0 = 0;
+ if (!in_use)
+ cyg_interrupt_create(lvl1, 1, (cyg_addrword_t)777, isr0, dsr0,
+ &intr0, &intr_obj[0]);
+
+ HAL_INTERRUPT_IN_USE( lvl2, in_use );
+ intr1 = 0;
+ if (!in_use && lvl1 != lvl2)
+ cyg_interrupt_create(lvl2, 1, 888, isr1, dsr1, &intr1, &intr_obj[1]);
+
+ // Check these functions at least exist
+
+ cyg_interrupt_disable();
+ cyg_interrupt_enable();
+
+ if (intr0)
+ cyg_interrupt_attach(intr0);
+ if (intr1)
+ cyg_interrupt_attach(intr1);
+ if (intr0)
+ cyg_interrupt_detach(intr0);
+ if (intr1)
+ cyg_interrupt_detach(intr1);
+
+ // If this attaching interrupt replaces the previous interrupt
+ // instead of adding to it we could be in a big mess if the
+ // vector is being used by something important.
+
+ cyg_interrupt_get_vsr( v, &old_vsr );
+ cyg_interrupt_set_vsr( v, vsr0 );
+ cyg_interrupt_get_vsr( v, &new_vsr );
+ CHECK( vsr0 == new_vsr );
+
+ new_vsr = NULL;
+ cyg_interrupt_get_vsr( v, &new_vsr );
+ cyg_interrupt_set_vsr( v, old_vsr );
+ CHECK( new_vsr == vsr0 );
+
+ cyg_interrupt_set_vsr( v, new_vsr );
+ new_vsr = NULL;
+ cyg_interrupt_get_vsr( v, &new_vsr );
+ CHECK( vsr0 == new_vsr );
+
+ cyg_interrupt_set_vsr( v, old_vsr );
+ CHECK( vsr0 == new_vsr );
+ new_vsr = NULL;
+ cyg_interrupt_get_vsr( v, &new_vsr );
+ CHECK( old_vsr == new_vsr );
+
+ CHECK( NULL != vsr0 );
+
+ cyg_interrupt_mask(v1);
+ cyg_interrupt_unmask(v1);
+
+ cyg_interrupt_configure(v1, true, true);
+
+ CYG_TEST_PASS_FINISH("Kernel C API Intr 0 OK");
+}
+
+externC void
+cyg_start( void )
+{
+ kintr0_main();
+}
+
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+/* EOF kintr0.c */
diff --git a/ecos/packages/kernel/current/tests/klock.c b/ecos/packages/kernel/current/tests/klock.c
new file mode 100644
index 0000000000..fefc3cab11
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/klock.c
@@ -0,0 +1,318 @@
+/*=================================================================
+//
+// klock.c
+//
+// Kernel lock test
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-18
+// Description: Tests some basic thread functions.
+//####DESCRIPTIONEND####
+*/
+//==========================================================================
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+//==========================================================================
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#if (CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES == 0)
+
+//==========================================================================
+
+#include "testaux.h"
+
+#include <cyg/hal/hal_arch.h> // for CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+//==========================================================================
+
+#ifdef CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#else
+#define STACKSIZE 2000
+#endif
+
+//==========================================================================
+
+static char stack[2][STACKSIZE];
+
+static cyg_thread thread[2];
+
+static cyg_handle_t pt0,pt1;
+
+static cyg_mutex_t mx;
+static cyg_cond_t cv;
+static cyg_sem_t sem;
+static cyg_flag_t fl;
+static cyg_mbox mbox;
+static cyg_handle_t mbh;
+
+volatile static int thread0_state = 0;
+volatile static int thread1_state = 0;
+
+//==========================================================================
+
+static void entry0( cyg_addrword_t data )
+{
+ CHECK( 222 == (int)data );
+
+ // Do everything with the scheduler locked.
+ cyg_scheduler_lock();
+
+ // --------------------------------------------------
+ // Mutex test
+
+ cyg_mutex_lock( &mx );
+ thread0_state = 1;
+
+ // Get thread 2 running.
+ cyg_thread_resume(pt1);
+ thread0_state = 2;
+
+#ifdef CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT
+ cyg_cond_wait( &cv );
+ thread0_state = 3;
+
+ while( thread1_state < 2 ) cyg_thread_yield();
+
+ cyg_cond_broadcast( &cv );
+ thread0_state = 4;
+#endif
+
+ cyg_mutex_unlock( &mx );
+ thread0_state = 5;
+
+
+ // --------------------------------------------------
+ // Semaphore test
+
+ cyg_semaphore_wait( &sem );
+ thread0_state = 6;
+
+ cyg_semaphore_post( &sem );
+ thread0_state = 7;
+
+ while( thread1_state < 7 ) cyg_thread_yield();
+
+ // --------------------------------------------------
+ // Flags test
+
+ cyg_flag_wait( &fl, 1, CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR);
+ thread0_state = 8;
+
+ cyg_flag_setbits( &fl, 2 );
+ thread0_state = 9;
+
+ // --------------------------------------------------
+ // Message box test
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ {
+ void *mbret;
+
+ mbret = cyg_mbox_get( mbh );
+ CYG_TEST_CHECK( mbret == (void *)0xAAAAAAAA , "bad result from cyg_mbox_timed_get()");
+ thread0_state = 10;
+
+ cyg_mbox_put( mbh, (void *)0xBBBBBBBB );
+ thread0_state = 11;
+ }
+#endif
+ // --------------------------------------------------
+
+ thread0_state = 999;
+
+ cyg_thread_yield();
+ cyg_thread_yield();
+ cyg_thread_yield();
+
+ CYG_TEST_CHECK( thread0_state == 999, "thread 0 not in exit state");
+ CYG_TEST_CHECK( thread1_state == 999, "thread 1 not in exit state");
+ CYG_TEST_PASS_FINISH("Kernel lock test OK");
+}
+
+//==========================================================================
+
+static void entry1( cyg_addrword_t data )
+{
+ cyg_bool res;
+
+ CHECK( 333 == (int)data );
+
+ // Do everything with the scheduler locked.
+ cyg_scheduler_lock();
+
+ // --------------------------------------------------
+ // Mutex test
+#ifdef CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT
+ cyg_mutex_lock( &mx );
+ thread1_state = 1;
+
+ while( thread0_state < 2 ) cyg_thread_yield();
+
+ cyg_cond_signal( &cv );
+ thread1_state = 2;
+
+ res = cyg_cond_timed_wait( &cv, cyg_current_time()+10 );
+ CYG_TEST_CHECK( res , "FALSE result from cyg_cond_timed_wait()" );
+ thread1_state = 3;
+
+ cyg_mutex_unlock( &mx );
+ thread1_state = 4;
+#endif
+
+ // --------------------------------------------------
+ // Semaphore test
+
+ while( thread0_state < 5 ) cyg_thread_yield();
+
+ cyg_semaphore_post( &sem );
+ thread1_state = 5;
+
+ while( thread0_state < 6 ) cyg_thread_yield();
+ thread1_state = 6;
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ res = cyg_semaphore_timed_wait( &sem, cyg_current_time()+10 );
+#else
+ res = cyg_semaphore_wait( &sem );
+#endif
+ CYG_TEST_CHECK( res , "FALSE result from cyg_semaphore[_timed]_wait()" );
+ thread1_state = 7;
+
+ // --------------------------------------------------
+ // Flags test
+
+ cyg_flag_setbits( &fl, 1 );
+ thread1_state = 8;
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_flag_timed_wait( &fl, 2, CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR,
+ cyg_current_time()+10 );
+#else
+ cyg_flag_wait( &fl, 2, CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR );
+#endif
+ thread1_state = 9;
+
+ // --------------------------------------------------
+ // Message box test
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ {
+ void *mbret;
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ cyg_mbox_timed_put( mbh, (void *)0xAAAAAAAA, cyg_current_time()+10 );
+#else
+ cyg_mbox_put( mbh, (void *)0xAAAAAAAA );
+#endif
+ thread1_state = 10;
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ mbret = cyg_mbox_timed_get( mbh, cyg_current_time()+10);
+#else
+ mbret = cyg_mbox_get( mbh );
+#endif
+ CYG_TEST_CHECK( mbret == (void *)0xBBBBBBBB , "bad result from cyg_mbox[_timed]_get()");
+ thread1_state = 9;
+ }
+#endif
+ // --------------------------------------------------
+
+ thread1_state = 999;
+ cyg_thread_exit();
+}
+
+//==========================================================================
+
+void kthread1_main( void )
+{
+ CYG_TEST_INIT();
+
+ cyg_thread_create(4, entry0, (cyg_addrword_t)222, "kthread1-0",
+ (void *)stack[0], STACKSIZE, &pt0, &thread[0] );
+ cyg_thread_create(4, entry1, (cyg_addrword_t)333, "kthread1-1",
+ (void *)stack[1], STACKSIZE, &pt1, &thread[1] );
+
+ // Init all the objects
+
+ cyg_mutex_init( &mx );
+ cyg_cond_init( &cv, &mx );
+ cyg_semaphore_init( &sem, 0 );
+ cyg_flag_init( &fl );
+ cyg_mbox_create( &mbh, &mbox );
+
+ cyg_thread_resume(pt0);
+
+ cyg_scheduler_start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+//==========================================================================
+
+externC void
+cyg_start( void )
+{
+ kthread1_main();
+}
+
+//==========================================================================
+
+#else /* CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES == 0 */
+# define NA_MSG "Schedule has unique priorities"
+#endif
+
+#else /* def CYGFUN_KERNEL_API_C */
+# define NA_MSG "Kernel C API layer disabled"
+#endif
+
+#ifdef NA_MSG
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA(NA_MSG);
+}
+#endif
+
+//==========================================================================
+/* EOF klock.c */
diff --git a/ecos/packages/kernel/current/tests/kmbox1.c b/ecos/packages/kernel/current/tests/kmbox1.c
new file mode 100644
index 0000000000..8b0983731a
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kmbox1.c
@@ -0,0 +1,217 @@
+/*==========================================================================
+//
+// kmbox1.cxx
+//
+// Kernel Mbox test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: dsm
+// Contributors: dsm
+// Date: 1998-06-02
+// Description: Tests basic mbox functionality.
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+#define NTHREADS 2
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static cyg_handle_t thread[NTHREADS];
+
+static cyg_thread thread_obj[NTHREADS];
+static char stack[NTHREADS][STACKSIZE];
+
+static cyg_handle_t m0, m1, m2;
+static cyg_mbox mbox0, mbox1, mbox2;
+
+static cyg_atomic q = 0;
+
+#ifndef CYGMTH_MBOX_PUT_CAN_WAIT
+#define cyg_mbox_PUT cyg_mbox_tryput
+#endif
+
+static void entry0( cyg_addrword_t data )
+{
+ cyg_count8 u,i,j;
+
+ CYG_TEST_INFO("Testing put() and tryput() without wakeup");
+ CYG_TEST_CHECK(!cyg_mbox_waiting_to_get(m0), "mbox not initialized properly");
+ CYG_TEST_CHECK(0==cyg_mbox_peek(m0), "mbox not initialized properly");
+ CYG_TEST_CHECK(NULL==cyg_mbox_peek_item(m0), "mbox not initialized properly");
+ cyg_mbox_PUT(m0, (void *)55);
+ CYG_TEST_CHECK(1==cyg_mbox_peek(m0), "peek() wrong");
+ CYG_TEST_CHECK(55==(cyg_count8)cyg_mbox_peek_item(m0), "peek_item() wrong");
+ for(u=1; cyg_mbox_tryput(m0, (void*)u); u++) {
+ CYG_TEST_CHECK(55==(cyg_count8)cyg_mbox_peek_item(m0), "peek_item() wrong");
+ CYG_TEST_CHECK(u+1==cyg_mbox_peek(m0), "peek() wrong");
+ }
+ CYG_TEST_CHECK(u == CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE, "mbox not configured size");
+
+ // m0 now contains ( 55 1 2 .. u-1 )
+ CYG_TEST_CHECK(u==cyg_mbox_peek(m0), "peek() wrong");
+ CYG_TEST_CHECK(55==(cyg_count8)cyg_mbox_peek_item(m0), "peek_item() wrong");
+
+ CYG_TEST_INFO("Testing get(), tryget()");
+
+ i = (cyg_count8)cyg_mbox_tryget(m0);
+ CYG_TEST_CHECK( 55 == i, "Got wrong message" );
+ for(j=1; j<u;j++) {
+ CYG_TEST_CHECK( j == (cyg_count8)cyg_mbox_peek_item(m0), "peek_item()" );
+ CYG_TEST_CHECK( cyg_mbox_peek(m0) == u - j, "peek() wrong" );
+ i = (cyg_count8)cyg_mbox_get(m0);
+ CYG_TEST_CHECK( j == i, "Got wrong message" );
+ }
+
+ CYG_TEST_CHECK( NULL == cyg_mbox_peek_item(m0), "peek_item()" );
+ CYG_TEST_CHECK( 0 == cyg_mbox_peek(m0), "peek()");
+
+ // m0 now empty
+
+ CYG_TEST_CHECK(!cyg_mbox_waiting_to_put(m0), "waiting_to_put()");
+ CYG_TEST_CHECK(!cyg_mbox_waiting_to_get(m0), "waiting_to_get()");
+
+ CYG_TEST_INFO("Testing get(), blocking");
+
+ CYG_TEST_CHECK(0==q++, "bad synchronization");
+ cyg_mbox_PUT(m1, (void*)99); // wakes t1
+ i = (cyg_count8)cyg_mbox_get(m0); // sent by t1
+ CYG_TEST_CHECK(3==i, "Recieved wrong message");
+ CYG_TEST_CHECK(2==q++, "bad synchronization");
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ CYG_TEST_CHECK(NULL==cyg_mbox_timed_get(m0, cyg_current_time()+10),
+ "unexpectedly found message");
+ CYG_TEST_CHECK(3==q++, "bad synchronization");
+ // Allow t1 to run as this get times out
+ // t1 must not be waiting...
+ CYG_TEST_CHECK(cyg_mbox_waiting_to_get(m0), "waiting_to_get()");
+
+ cyg_mbox_PUT(m0, (void*)7); // wake t1 from timed get
+#ifdef CYGMTH_MBOX_PUT_CAN_WAIT
+ q=10;
+ while(cyg_mbox_tryput(m0, (void*)6)) // fill m0's queue
+ ;
+ // m0 now contains ( 6 ... 6 )
+ CYG_TEST_CHECK(10==q++, "bad synchronization");
+ cyg_mbox_put(m1, (void*)4); // wake t1
+ CYG_TEST_CHECK(!cyg_mbox_timed_put(m0, (void*)8, cyg_current_time()+10),
+ "timed put() unexpectedly worked");
+ CYG_TEST_CHECK(12==q++, "bad synchronization");
+ // m0 still contains ( 6 ... 6 )
+ cyg_mbox_put(m0, (void*)9);
+ CYG_TEST_CHECK(13==q++, "bad synchronization");
+#endif
+#endif
+ i=(cyg_count8)cyg_mbox_get(m2);
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+static void entry1( cyg_addrword_t data )
+{
+ cyg_count8 i;
+ i = (cyg_count8)cyg_mbox_get(m1);
+ CYG_TEST_CHECK(1==q++, "bad synchronization");
+ cyg_mbox_PUT(m0, (void *)3); // wake t0
+
+#if defined(CYGFUN_KERNEL_THREADS_TIMER)
+ CYG_TEST_INFO("Testing timed functions");
+ CYG_TEST_CHECK(7==(cyg_count8)cyg_mbox_timed_get(m0,cyg_current_time()+20),
+ "timed get()");
+ CYG_TEST_CHECK(4==q++, "bad synchronization");
+#ifdef CYGMTH_MBOX_PUT_CAN_WAIT
+ CYG_TEST_CHECK(4==(cyg_count8)cyg_mbox_get(m1));
+
+ CYG_TEST_CHECK(11==q++, "bad synchronization");
+ thread[0]->delay(20); // allow t0 to reach put on m1
+ CYG_TEST_CHECK(14==q++, "bad synchronization");
+ CYG_TEST_CHECK(cyg_mbox_waiting_to_put(m0), "waiting_to_put()");
+ do {
+ // after first get m0 contains ( 6 .. 6 9 )
+ i=(cyg_count8)cyg_mbox_tryget(m0);
+ } while(6==i);
+ CYG_TEST_CHECK(9==i,"put gone awry");
+#endif
+#endif
+ CYG_TEST_PASS_FINISH("Kernel C API Mbox 1 OK");
+}
+
+void kmbox1_main( void )
+{
+ CYG_TEST_INIT();
+
+ cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kmbox1-0",
+ (void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]);
+ cyg_thread_resume(thread[0]);
+
+ cyg_thread_create(4, entry1 , (cyg_addrword_t)1, "kmbox1-1",
+ (void *)stack[1], STACKSIZE, &thread[1], &thread_obj[1]);
+ cyg_thread_resume(thread[1]);
+
+ cyg_mbox_create( &m0, &mbox0 );
+ cyg_mbox_create( &m1, &mbox1 );
+ cyg_mbox_create( &m2, &mbox2 );
+
+ cyg_scheduler_start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+ kmbox1_main();
+}
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+/* EOF kmbox1.c */
diff --git a/ecos/packages/kernel/current/tests/kmutex0.c b/ecos/packages/kernel/current/tests/kmutex0.c
new file mode 100644
index 0000000000..465dfb811e
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kmutex0.c
@@ -0,0 +1,98 @@
+/*=================================================================
+//
+// kmutex0.c
+//
+// Kernel C API Mutex and condition variable test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-23
+// Description: Limited to checking constructors/destructors
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+static cyg_mutex_t mutex0;
+
+static cyg_cond_t cvar0;
+
+static bool flash( void )
+{
+ cyg_mutex_init( &mutex0 );
+ cyg_cond_init( &cvar0, &mutex0 );
+
+ cyg_cond_destroy( &cvar0 );
+ cyg_mutex_destroy( &mutex0 );
+
+ return true;
+}
+
+void kmutex0_main( void )
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ CYG_TEST_PASS_FINISH("Kernel C API Mutex 0 OK");
+}
+
+externC void
+cyg_start( void )
+{
+ kmutex0_main();
+}
+
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+/* EOF kmutex0.c */
diff --git a/ecos/packages/kernel/current/tests/kmutex1.c b/ecos/packages/kernel/current/tests/kmutex1.c
new file mode 100644
index 0000000000..dda80d0219
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kmutex1.c
@@ -0,0 +1,188 @@
+/*=================================================================
+//
+// kmutex1.c
+//
+// Kernel C API Mutex test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-23
+// Description: Tests basic mutex functionality.
+// Omissions: Timed wait.
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+#define NTHREADS 3
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static cyg_handle_t thread[NTHREADS];
+
+static cyg_thread thread_obj[NTHREADS];
+static char stack[NTHREADS][STACKSIZE];
+
+
+static cyg_mutex_t m0, m1;
+static cyg_cond_t cvar0, cvar1, cvar2;
+
+static cyg_ucount8 m0d=0, m1d=0;
+
+static void finish( cyg_ucount8 t )
+{
+ cyg_mutex_lock( &m1 ); {
+ m1d |= 1<<t;
+ if( 0x7 == m1d )
+ CYG_TEST_PASS_FINISH("Kernel C API Mutex 1 OK");
+ cyg_cond_wait( &cvar2 );
+ } /* cyg_mutex_unlock( &m1 ); */
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+static void entry0( cyg_addrword_t data )
+{
+ cyg_mutex_lock( &m0 ); {
+ CHECK( ! cyg_mutex_trylock( &m0 ) );
+ cyg_mutex_lock( &m1 ); {
+ CHECK( ! cyg_mutex_trylock( &m0 ) );
+ } cyg_mutex_unlock( &m1 );
+ } cyg_mutex_unlock( &m0 );
+
+ cyg_mutex_lock( &m0 ); {
+ while ( 0 == m0d )
+ cyg_cond_wait( &cvar0 );
+ CHECK( 1 == m0d++ );
+ cyg_cond_signal( &cvar0 );
+ while ( 4 != m0d )
+ cyg_cond_wait( &cvar1 );
+ CHECK( 4 == m0d );
+ } cyg_mutex_unlock( &m0 );
+
+ finish( (cyg_ucount8)data );
+}
+
+static void entry1( cyg_addrword_t data )
+{
+ cyg_mutex_lock( &m0 ); {
+ CHECK( cyg_mutex_trylock( &m1 ) ); {
+ } cyg_mutex_unlock( &m1 );
+ } cyg_mutex_unlock( &m0 );
+
+ cyg_mutex_lock( &m0 ); {
+ CHECK( 0 == m0d++ );
+ cyg_cond_broadcast( &cvar0 );
+ } cyg_mutex_unlock( &m0 );
+
+ cyg_mutex_lock( &m0 ); {
+ while( 1 == m0d )
+ cyg_cond_wait( &cvar0 );
+ CHECK( 2 == m0d++ );
+ cyg_cond_signal( &cvar0 );
+ while( 3 == m0d )
+ cyg_cond_wait( &cvar1 );
+ } cyg_mutex_unlock( &m0 );
+
+ finish( (cyg_ucount8)data );
+}
+
+static void entry2( cyg_addrword_t data )
+{
+ cyg_mutex_lock( &m0 ); {
+ while( 3 != m0d ) {
+ cyg_cond_wait( &cvar0 );
+ }
+ CHECK( 3 == m0d++ );
+ cyg_cond_broadcast( &cvar1 );
+ } cyg_mutex_unlock( &m0 );
+
+ finish( (cyg_ucount8)data );
+}
+
+void kmutex1_main( void )
+{
+ CYG_TEST_INIT();
+
+ cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "kmutex1-0",
+ (void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]);
+ cyg_thread_resume(thread[0]);
+
+ cyg_thread_create(4, entry1 , (cyg_addrword_t)1, "kmutex1-1",
+ (void *)stack[1], STACKSIZE, &thread[1], &thread_obj[1]);
+ cyg_thread_resume(thread[1]);
+
+ cyg_thread_create(4, entry2 , (cyg_addrword_t)2, "kmutex1-2",
+ (void *)stack[2], STACKSIZE, &thread[2], &thread_obj[2]);
+ cyg_thread_resume(thread[2]);
+
+ cyg_mutex_init( &m0 );
+ cyg_mutex_init( &m1 );
+
+ cyg_cond_init( &cvar0, &m0 );
+ cyg_cond_init( &cvar1, &m0 );
+ cyg_cond_init( &cvar2, &m1 );
+
+ cyg_scheduler_start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+ kmutex1_main();
+}
+
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+/* EOF kmutex1.c */
diff --git a/ecos/packages/kernel/current/tests/kmutex3.c b/ecos/packages/kernel/current/tests/kmutex3.c
new file mode 100644
index 0000000000..5dba368b81
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kmutex3.c
@@ -0,0 +1,639 @@
+//==========================================================================
+//
+// kmutex3.c
+//
+// Mutex test 3 - priority inheritance
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 2000-01-06, 2001-08-10
+// Description: Tests mutex priority inheritance. This is simply a
+// translation of the similarly named kernel test to the
+// KAPI, with the intention of also testing the new
+// "set the protocol at run-time" extensions.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/infra/diag.h> // diag_printf
+
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+externC void
+cyg_hal_invoke_constructors();
+#endif
+
+// ------------------------------------------------------------------------
+//
+// These checks should be enough; any other scheduler which has priorities
+// should manifest as having no priority inheritance, but otherwise fine,
+// so the test should work correctly.
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \
+ (CYGNUM_KERNEL_SCHED_PRIORITIES > 20) && \
+ defined(CYGFUN_KERNEL_API_C) && \
+ !defined(CYGPKG_KERNEL_SMP_SUPPORT)
+
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/cyg_trac.h>
+#include <cyg/infra/diag.h> // diag_printf
+
+
+// ------------------------------------------------------------------------
+// manufacture a simpler feature test macro for priority inheritance than
+// the configuration gives us. We have priority inheritance if it is configured
+// as the only protocol, or if it is the default protocol for dynamic protocol
+// choice.
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT
+# define PRIORITY_INHERITANCE "dynamic-default-inherit"
+# endif
+# else
+# define PRIORITY_INHERITANCE "static-inherit"
+# endif
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_CEILING
+# if CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY <= 5
+# define PRIORITY_INHERITANCE "dynamic-default-ceiling-high"
+# elif CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY >= 15
+# define NO_PRIORITY_INHERITANCE "dynamic-default-ceiling-low"
+# else
+# define PRIORITY_UNKNOWN "dynamic-default-ceiling-mid"
+# endif
+# endif
+# else
+# if CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY <= 5
+# define PRIORITY_INHERITANCE "static-ceiling-high"
+# elif CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY >= 15
+# define NO_PRIORITY_INHERITANCE "static-ceiling-low"
+# else
+# define PRIORITY_UNKNOWN "static-ceiling-mid"
+# endif
+# endif
+#endif
+
+#ifndef PRIORITY_INHERITANCE
+# ifndef NO_PRIORITY_INHERITANCE
+# define NO_PRIORITY_INHERITANCE "no scheme selected"
+# endif
+#endif
+
+// ------------------------------------------------------------------------
+// Management functions
+//
+// Stolen from testaux.hxx and copied in here because I want to be able to
+// reset the world also.
+//
+// Translated into KAPI also.
+
+#define NTHREADS 7
+
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static cyg_handle_t thread[NTHREADS] = { 0 };
+
+typedef cyg_uint64 CYG_ALIGNMENT_TYPE;
+
+static cyg_thread thread_obj[NTHREADS];
+
+static CYG_ALIGNMENT_TYPE stack[NTHREADS] [
+ (STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1)
+ / sizeof(CYG_ALIGNMENT_TYPE) ];
+
+static volatile int nthreads = 0;
+
+#undef NULL
+#define NULL (0)
+
+static cyg_handle_t new_thread( cyg_thread_entry_t *entry,
+ cyg_addrword_t data,
+ cyg_addrword_t priority,
+ int do_resume )
+{
+ int _nthreads = nthreads++;
+
+ CYG_ASSERT(_nthreads < NTHREADS,
+ "Attempt to create more than NTHREADS threads");
+
+ cyg_thread_create( priority,
+ entry,
+ data,
+ NULL, // no name
+ (void *)(stack[_nthreads]),
+ STACKSIZE,
+ &thread[_nthreads],
+ &thread_obj[_nthreads] );
+
+ if ( do_resume )
+ cyg_thread_resume( thread[_nthreads] );
+
+ return thread[_nthreads];
+}
+
+
+static void kill_threads( void )
+{
+ CYG_ASSERT(nthreads <= NTHREADS,
+ "More than NTHREADS threads");
+ CYG_ASSERT( cyg_thread_self() == thread[0],
+ "kill_threads() not called from thread 0");
+ while ( nthreads > 1 ) {
+ nthreads--;
+ if ( NULL != thread[nthreads] ) {
+ do
+ cyg_thread_kill( thread[nthreads] );
+ while ( ! cyg_thread_delete ( thread[nthreads] ) );
+ thread[nthreads] = NULL;
+ }
+ }
+ CYG_ASSERT(nthreads == 1,
+ "No threads left");
+}
+
+// ------------------------------------------------------------------------
+
+#define DELAYFACTOR 1 // for debugging
+
+// ------------------------------------------------------------------------
+
+static cyg_mutex_t mutex_obj;
+static cyg_mutex_t *mutex;
+
+// These are for reporting back to the master thread
+volatile int got_it = 0;
+volatile int t3ran = 0;
+volatile int t3ended = 0;
+volatile int extras[4] = {0,0,0,0};
+
+volatile int go_flag = 0; // but this one controls thread 3 from thread 2
+
+// ------------------------------------------------------------------------
+// 0 to 3 of these run generally to interfere with the other processing,
+// to cause multiple prio inheritances, and clashes in any orders.
+
+static void extra_thread( cyg_addrword_t data )
+{
+ cyg_handle_t self = cyg_thread_self();
+
+#define XINFO( z ) \
+ do { z[13] = '0' + data; CYG_TEST_INFO( z ); } while ( 0 )
+
+ static char running[] = "Extra thread Xa running";
+ static char exiting[] = "Extra thread Xa exiting";
+ static char resumed[] = "Extra thread Xa resumed";
+ static char locked[] = "Extra thread Xa locked";
+ static char unlocked[] = "Extra thread Xa unlocked";
+
+ XINFO( running );
+
+ cyg_thread_suspend( self );
+
+ XINFO( resumed );
+
+ cyg_mutex_lock( mutex );
+
+ XINFO( locked );
+
+ cyg_mutex_unlock( mutex );
+
+ XINFO( unlocked );
+
+ extras[ data ] ++;
+
+ XINFO( exiting );
+
+}
+
+// ------------------------------------------------------------------------
+
+static void t1( cyg_addrword_t data )
+{
+ cyg_handle_t self = cyg_thread_self();
+
+ CYG_TEST_INFO( "Thread 1 running" );
+
+ cyg_thread_suspend( self );
+
+ cyg_mutex_lock( mutex );
+
+ got_it++;
+
+ CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,1]" );
+
+ cyg_mutex_unlock( mutex );
+
+ CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,2]" );
+
+ // That's all.
+
+ CYG_TEST_INFO( "Thread 1 exit" );
+}
+
+// ------------------------------------------------------------------------
+
+static void t2( cyg_addrword_t data )
+{
+ cyg_handle_t self = cyg_thread_self();
+ int i;
+ cyg_tick_count_t then, now;
+
+ CYG_TEST_INFO( "Thread 2 running" );
+
+ CYG_TEST_CHECK( 0 == (data & ~0x77), "Bad T2 arg: extra bits" );
+ CYG_TEST_CHECK( 0 == (data & (data >> 4)), "Bad T2 arg: overlap" );
+
+ cyg_thread_suspend( self );
+
+ // depending on our config argument, optionally restart some of the
+ // extra threads to throw noise into the scheduler:
+ for ( i = 0; i < 3; i++ )
+ if ( (1 << i) & data ) // bits 0-2 control
+ cyg_thread_resume( thread[i+4] ); // extras are thread[4-6]
+
+ cyg_thread_delay( DELAYFACTOR * 10 ); // let those threads run
+
+ cyg_scheduler_lock(); // do this next lot atomically
+
+ go_flag = 1; // unleash thread 3
+ cyg_thread_resume( thread[1] ); // resume thread 1
+
+ // depending on our config argument, optionally restart some of the
+ // extra threads to throw noise into the scheduler at this later point:
+ for ( i = 4; i < 7; i++ )
+ if ( (1 << i) & data ) // bits 4-6 control
+ cyg_thread_resume( thread[i] ); // extras are thread[4-6]
+
+ cyg_scheduler_unlock(); // let scheduling proceed
+
+ // Need a delay (but not a CPU yield) to allow t3 to awaken and act on
+ // the go_flag, otherwise we check these details below too soon.
+ // Actually, waiting for the clock to tick a couple of times would be
+ // better, so that is what we will do. Must be a busy-wait.
+ then = cyg_current_time();
+ do {
+ now = cyg_current_time();
+ // Wait longer than the delay in t3 waiting on go_flag
+ } while ( now < (then + 3) );
+
+#ifdef PRIORITY_UNKNOWN
+ CYG_TEST_INFO( "Not checking: " PRIORITY_UNKNOWN );
+#else
+#ifdef PRIORITY_INHERITANCE
+ CYG_TEST_INFO( "Checking priority scheme: " PRIORITY_INHERITANCE );
+ CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" );
+ CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+#else
+ CYG_TEST_INFO( "Checking NO priority scheme: " NO_PRIORITY_INHERITANCE );
+ CYG_TEST_CHECK( 0 == t3ran, "Thread 3 DID run" );
+ CYG_TEST_CHECK( 0 == got_it, "Thread 1 DID get the mutex" );
+#endif
+#endif
+
+ CYG_TEST_CHECK( 0 == t3ended, "Thread 3 ended prematurely [T2,1]" );
+
+ cyg_thread_delay( DELAYFACTOR * 20 ); // let those threads run
+
+ CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" );
+ CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+ CYG_TEST_CHECK( 1 == t3ended, "Thread 3 has not ended" );
+
+ for ( i = 0; i < 3; i++ )
+ if ( (1 << i) & (data | data >> 4) ) // bits 0-2 and 4-6 control
+ CYG_TEST_CHECK( 1 == extras[i+1], "Extra thread did not run" );
+ else
+ CYG_TEST_CHECK( 0 == extras[i+1], "Extra thread ran" );
+
+ CYG_TEST_PASS( "Thread 2 exiting, AOK" );
+ // That's all: restart the control thread.
+ cyg_thread_resume( thread[0] );
+}
+
+// ------------------------------------------------------------------------
+
+static void t3( cyg_addrword_t data )
+{
+ CYG_TEST_INFO( "Thread 3 running" );
+
+ cyg_mutex_lock( mutex );
+
+ cyg_thread_delay( DELAYFACTOR * 5 ); // let thread 3a run
+
+ cyg_thread_resume( thread[2] ); // resume thread 2
+
+ while ( 0 == go_flag )
+ cyg_thread_delay(1); // wait until we are told to go
+
+ t3ran ++; // record the fact
+
+ CYG_TEST_CHECK( 0 == got_it, "Thread 1 claims to have got my mutex" );
+
+ cyg_mutex_unlock( mutex );
+
+ t3ended ++; // record that we came back
+
+ CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+
+ CYG_TEST_INFO( "Thread 3 exit" );
+}
+
+// ------------------------------------------------------------------------
+
+static void control_thread( cyg_addrword_t data )
+{
+ cyg_handle_t self = cyg_thread_self();
+ int i, z;
+
+ CYG_TEST_INIT();
+ CYG_TEST_INFO( "Control Thread running" );
+
+ // Go through the 27 possibilities of resuming the extra threads
+ // 0: not at all
+ // 1: early in the process
+ // 2: later on
+ // which are represented by bits 0-3 and 4-6 resp in the argument to
+ // thread 2 (none set means no resume at all).
+ for ( i = 0; i < 27; i++ ) {
+ static int xx[] = { 0, 1, 16 };
+ int j = i % 3;
+ int k = (i / 3) % 3;
+ int l = (i / 9) % 3;
+
+ int d = xx[j] | (xx[k]<<1) | (xx[l]<<2) ;
+
+ if ( cyg_test_is_simulator && (0 != i && 13 != i && 26 != i) )
+ continue; // 13 is 111 base 3, 26 is 222 base 3
+
+#ifdef PRIORITY_INHERITANCE
+ // If the simple scheme plus relay enhancement, or any other
+ // *complete* scheme, we can run all three ancillary threads no
+ // problem, so no special action here.
+
+#else
+ // If no priority inheritance at all, running threads 1a and 2a is
+ // OK, but not thread 3a; it blocks the world.
+ if ( l ) // Cannot run thread 3a if no
+ break; // priority inheritance at all.
+#endif
+
+ mutex = &mutex_obj;
+ cyg_mutex_init( mutex );
+
+ got_it = 0;
+ t3ran = 0;
+ t3ended = 0;
+ for ( z = 0; z < 4; z++ ) extras[z] = 0;
+ go_flag = 0;
+
+ new_thread( t1, 0, 5, 1 ); // Slot 1
+ new_thread( t2, d, 10, 1 ); // Slot 2
+ new_thread( t3, 0, 15, 1 ); // Slot 3
+
+ new_thread( extra_thread, 1, 8, j ); // Slot 4
+ new_thread( extra_thread, 2, 12, k ); // Slot 5
+ new_thread( extra_thread, 3, 17, l ); // Slot 6
+
+ {
+ static char *a[] = { "inactive", "run early", "run late" };
+ diag_printf( "\n----- [%2d] New Cycle: 0x%02x, Threads 1a %s, 2a %s, 3a %s -----\n",
+ i, d, a[j], a[k], a[l] );
+ }
+
+ cyg_thread_suspend( self );
+
+ kill_threads();
+ cyg_mutex_destroy( mutex );
+ }
+ CYG_TEST_EXIT( "Control Thread exit" );
+}
+
+// ------------------------------------------------------------------------
+
+externC void
+cyg_user_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ new_thread( control_thread, 0, 2, 1 );
+}
+
+#else // CYGVAR_KERNEL_COUNTERS_CLOCK &c
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_INFO("KMutex3 test requires:\n"
+ "CYGFUN_KERNEL_API_C &&\n"
+ "CYGVAR_KERNEL_COUNTERS_CLOCK &&\n"
+ "(CYGNUM_KERNEL_SCHED_PRIORITIES > 20) &&\n"
+ "!defined(CYGPKG_KERNEL_SMP_SUPPORT)\n");
+ CYG_TEST_NA("KMutex3 test requirements");
+}
+#endif // CYGVAR_KERNEL_COUNTERS_CLOCK &c
+
+
+// ------------------------------------------------------------------------
+// Documentation: enclosed is the design of this test.
+//
+// It has been carefully constructed so that it does NOT use other kernel
+// facilities (aside from delay-task) to test that priority inheritance is
+// working, or not, as intended by the configuration.
+//
+// These notes describe the flow of control in one run of the test with the
+// ancillary tasks optionally interspersed. The details of how those extra
+// tasks are or are not allowed to run are not described.
+//
+//
+//
+// The only change in the test that depends on whether there is inheritance or
+// not is the check in thread 2 on "3-ran" and "got it" flags marked ****
+//
+//
+// volatile &c booleans:
+// "got it" = FALSE
+// "3-ran" = FALSE
+// "3-ended" = FALSE
+// "extras"[3] = FALSE
+//
+// thread 1. prio 5, self-suspend.
+//
+// thread 1a, prio 8, self-suspend.
+//
+// thread 2. prio 10, self-suspend.
+//
+// thread 2a, prio 12, self-suspend.
+//
+// thread 3. prio 15, runs, lock mutex, resume(2)
+//
+// thread 3a, prio 17, self-suspend.
+//
+// 2. runs,
+// 2. resume(3a) +++OPTIONAL
+// 2. resume(2a) +++OPTIONAL
+// 2. resume(1a) +++OPTIONAL
+// [1a lock-fail] thread 3->prio := 8
+//
+// [3. runs maybe, does the looping thing]
+//
+// 2. sleep a while...
+//
+// [2a lock-fail] thread 3->prio := 12
+//
+// [3. runs maybe, does the looping thing]
+//
+// [3a lock-fail] thread 3->prio unchanged
+//
+// [3. runs maybe, does the looping thing]
+//
+// 2. lock scheduler
+// 2. set "go-flag"
+// 2. resume(1)
+// 2. resume(1a) +++OPTIONAL
+// 2. resume(2a) +++OPTIONAL
+// 2. resume(3a) +++OPTIONAL
+// 2. unlock scheduler
+//
+// 1. runs, lock mutex - thread 3 has it locked
+//
+// 2. busy-waits a bit for thread 3 to come out of its delay() loop.
+// This must be a *busy*wait so that 3 can only run via the
+// inherited raised priority.
+//
+// [xa. all do the same: lock mutex, ]
+// [xa. unlock mutex ]
+// [xa. set a flag "extras"[x] to say we are done. ]
+// [xa. exit ]
+//
+//
+//
+// INHERIT
+// -------
+//
+// thread 3->prio := 5
+//
+// 3. runs,
+// 3. set a flag to say "3-ran",
+// 3. loop with a sleep(1) until "go-flag" is set.
+// 3. check "got it" is false,
+// 3. then unlock mutex,
+//
+// thread 3->prio := 15
+//
+// 1. runs, set a flag to say "got it",
+// 1. check "3-ended" flag is false
+// 1. unlock mutex,
+// 1. check "3-ended" flag is still false
+// 1. exit.
+//
+// [1a locks, unlocks, exits]
+//
+// 2. runs, check "3-ran" and "got it" flags are TRUE ****
+// 2. check "3-ended" flag is false
+// 2. sleeps for a while so that...
+//
+// [2a locks, unlocks, exits]
+//
+// 3. runs, set "3-ended" flag,
+// 3. check "3-ran" and "got it" flags
+// 3. exit
+//
+// [3a locks, unlocks, exits]
+//
+// 2. awakens, checks all flags true,
+// 2. check that all "extra" threads that we started have indeed run
+// 2. end of test.
+//
+//
+//
+//
+// NO-INHERIT
+// ----------
+// thread 1 is waiting on the mutex
+//
+// [1a lock-fail]
+//
+// 2. runs, checks that "3-ran" and "got it" flags are FALSE ****
+// 2. check "3-ended" flag is false
+// 2. sleeps for a while so that...
+//
+// [2a. lock-fail]
+//
+// 3. runs, set a flag to say "3-ran",
+// 3. check "got it" is false,
+// 3. then unlock mutex,
+//
+// 1. runs, set a flag to say "got it",
+// 1. check "3-ended" flag is false
+// 1. unlock mutex,
+// 1. check "3-ended" flag is still false
+// 1. exit.
+//
+// [1a locks, unlocks, exits]
+// [2a locks, unlocks, exits]
+//
+// 3. runs, set "3-ended" flag,
+// 3. check "3-ran" and "got it" flags
+// 3. exit
+//
+// [3a locks, unlocks, exits]
+//
+// 2. awakens, checks all flags true,
+// 2. check that all "extra" threads that we started have indeed run
+// 2. end of test.
+//
+//
+// (the end)
+//
+//
+// ------------------------------------------------------------------------
+
+// EOF mutex3.c
diff --git a/ecos/packages/kernel/current/tests/kmutex4.c b/ecos/packages/kernel/current/tests/kmutex4.c
new file mode 100644
index 0000000000..c7539176dd
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kmutex4.c
@@ -0,0 +1,526 @@
+//==========================================================================
+//
+// kmutex4.c
+//
+// Mutex test 4 - dynamic priority inheritance protocol
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 2000-01-06, 2001-08-10, 2001-08-21
+// Description: Tests mutex priority inheritance. This is an extension of
+// kmutex3.c, to test the new "set the protocol at run-time"
+// extensions.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/infra/diag.h> // diag_printf
+
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+externC void
+cyg_hal_invoke_constructors();
+#endif
+
+// ------------------------------------------------------------------------
+//
+// These checks should be enough; any other scheduler which has priorities
+// should manifest as having no priority inheritance, but otherwise fine,
+// so the test should work correctly.
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \
+ (CYGNUM_KERNEL_SCHED_PRIORITIES > 20) && \
+ defined(CYGFUN_KERNEL_API_C) && \
+ !defined(CYGPKG_KERNEL_SMP_SUPPORT) && \
+ defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC) \
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/cyg_trac.h>
+#include <cyg/infra/diag.h> // diag_printf
+
+// ------------------------------------------------------------------------
+
+#define nVERBOSE
+
+// ------------------------------------------------------------------------
+// We have dynamic protocol choice, so we can set the protocol to whatever
+// we want. We'll do these combinations:
+// NONE
+// INHERIT
+// CEILING = 4 = higher than any thread === INHERIT in behaviour
+// CEILING = 11 = mixed in with threads === cannot check anything
+// CEILING = 17 = lower than any threads === NONE in behaviour
+
+#define PROTO_NONE (0)
+#define PROTO_INHERIT (1)
+#define PROTO_CEILING_HIGH (2)
+#define PROTO_CEILING_MID (3)
+#define PROTO_CEILING_LOW (4)
+
+int proto;
+
+static char * protnames[] = {
+ "none",
+ "inherit",
+ "high ceiling",
+ "medium ceiling",
+ "low ceiling",
+};
+
+// ------------------------------------------------------------------------
+// Management functions
+//
+// Stolen from testaux.hxx and copied in here because I want to be able to
+// reset the world also.
+//
+// Translated into KAPI also.
+
+#define NTHREADS 7
+
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static cyg_handle_t thread[NTHREADS] = { 0 };
+
+typedef cyg_uint64 CYG_ALIGNMENT_TYPE;
+
+static cyg_thread thread_obj[NTHREADS];
+
+static CYG_ALIGNMENT_TYPE stack[NTHREADS] [
+ (STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1)
+ / sizeof(CYG_ALIGNMENT_TYPE) ];
+
+static volatile int nthreads = 0;
+
+#undef NULL
+#define NULL (0)
+
+static cyg_handle_t new_thread( cyg_thread_entry_t *entry,
+ cyg_addrword_t data,
+ cyg_addrword_t priority,
+ int do_resume,
+ char *name )
+{
+ int _nthreads = nthreads++;
+
+ CYG_ASSERT(_nthreads < NTHREADS,
+ "Attempt to create more than NTHREADS threads");
+
+ cyg_thread_create( priority,
+ entry,
+ data,
+ name,
+ (void *)(stack[_nthreads]),
+ STACKSIZE,
+ &thread[_nthreads],
+ &thread_obj[_nthreads] );
+
+ if ( do_resume )
+ cyg_thread_resume( thread[_nthreads] );
+
+ return thread[_nthreads];
+}
+
+
+static void kill_threads( void )
+{
+ CYG_ASSERT(nthreads <= NTHREADS,
+ "More than NTHREADS threads");
+ CYG_ASSERT( cyg_thread_self() == thread[0],
+ "kill_threads() not called from thread 0");
+ while ( nthreads > 1 ) {
+ nthreads--;
+ if ( NULL != thread[nthreads] ) {
+ do
+ cyg_thread_kill( thread[nthreads] );
+ while ( ! cyg_thread_delete ( thread[nthreads] ) );
+ thread[nthreads] = NULL;
+ }
+ }
+ CYG_ASSERT(nthreads == 1,
+ "No threads left");
+}
+
+// ------------------------------------------------------------------------
+
+#define DELAYFACTOR 1 // for debugging
+
+// ------------------------------------------------------------------------
+
+static cyg_mutex_t mutex_obj;
+static cyg_mutex_t *mutex;
+
+// These are for reporting back to the master thread
+volatile int got_it = 0;
+volatile int t3ran = 0;
+volatile int t3ended = 0;
+volatile int extras[4] = {0,0,0,0};
+
+volatile int go_flag = 0; // but this one controls thread 3 from thread 2
+
+// ------------------------------------------------------------------------
+// 0 to 3 of these run generally to interfere with the other processing,
+// to cause multiple prio inheritances, and clashes in any orders.
+
+static void extra_thread( cyg_addrword_t data )
+{
+ cyg_handle_t self = cyg_thread_self();
+
+
+#ifdef VERBOSE
+#define xXINFO( z ) \
+ do { z[13] = '0' + data; CYG_TEST_INFO( z ); } while ( 0 )
+
+ static char running[] = "Extra thread Xa running";
+ static char exiting[] = "Extra thread Xa exiting";
+ static char resumed[] = "Extra thread Xa resumed";
+ static char locked[] = "Extra thread Xa locked";
+ static char unlocked[] = "Extra thread Xa unlocked";
+#else
+#define XINFO( z ) /* nothing */
+#endif
+
+ XINFO( running );
+
+ cyg_thread_suspend( self );
+
+ XINFO( resumed );
+
+ cyg_mutex_lock( mutex );
+
+ XINFO( locked );
+
+ cyg_mutex_unlock( mutex );
+
+ XINFO( unlocked );
+
+ extras[ data ] ++;
+
+ XINFO( exiting );
+
+}
+
+// ------------------------------------------------------------------------
+
+static void t1( cyg_addrword_t data )
+{
+ cyg_handle_t self = cyg_thread_self();
+#ifdef VERBOSE
+ CYG_TEST_INFO( "Thread 1 running" );
+#endif
+ cyg_thread_suspend( self );
+
+ cyg_mutex_lock( mutex );
+
+ got_it++;
+
+ CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,1]" );
+
+ cyg_mutex_unlock( mutex );
+
+ CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,2]" );
+
+ // That's all.
+#ifdef VERBOSE
+ CYG_TEST_INFO( "Thread 1 exit" );
+#endif
+}
+
+// ------------------------------------------------------------------------
+
+static void t2( cyg_addrword_t data )
+{
+ cyg_handle_t self = cyg_thread_self();
+ int i;
+ cyg_tick_count_t then, now;
+#ifdef VERBOSE
+ CYG_TEST_INFO( "Thread 2 running" );
+#endif
+ CYG_TEST_CHECK( 0 == (data & ~0x77), "Bad T2 arg: extra bits" );
+ CYG_TEST_CHECK( 0 == (data & (data >> 4)), "Bad T2 arg: overlap" );
+
+ cyg_thread_suspend( self );
+
+ // depending on our config argument, optionally restart some of the
+ // extra threads to throw noise into the scheduler:
+ for ( i = 0; i < 3; i++ )
+ if ( (1 << i) & data ) // bits 0-2 control
+ cyg_thread_resume( thread[i+4] ); // extras are thread[4-6]
+
+ cyg_thread_delay( DELAYFACTOR * 10 ); // let those threads run
+
+ cyg_scheduler_lock(); // do this next lot atomically
+
+ go_flag = 1; // unleash thread 3
+ cyg_thread_resume( thread[1] ); // resume thread 1
+
+ // depending on our config argument, optionally restart some of the
+ // extra threads to throw noise into the scheduler at this later point:
+ for ( i = 4; i < 7; i++ )
+ if ( (1 << i) & data ) // bits 4-6 control
+ cyg_thread_resume( thread[i] ); // extras are thread[4-6]
+
+ cyg_scheduler_unlock(); // let scheduling proceed
+
+ // Need a delay (but not a CPU yield) to allow t3 to awaken and act on
+ // the go_flag, otherwise we check these details below too soon.
+ // Actually, waiting for the clock to tick a couple of times would be
+ // better, so that is what we will do. Must be a busy-wait.
+ then = cyg_current_time();
+ do {
+ now = cyg_current_time();
+ // Wait longer than the delay in t3 waiting on go_flag
+ } while ( now < (then + 3) );
+
+ // Check for whatever result we expect from the protocol selected:
+ // This mirrors what is done in configury in kmutex3.c and mutex3.cxx
+ if ( PROTO_CEILING_MID == proto ) {
+ CYG_TEST_INFO( "Not checking: ceiling mid value" );
+ }
+ else if ( PROTO_INHERIT == proto ||
+ PROTO_CEILING_HIGH == proto ) {
+ CYG_TEST_INFO( "Checking priority scheme operating" );
+ CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" );
+ CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+ }
+ else {
+ CYG_TEST_INFO( "Checking NO priority scheme operating" );
+ CYG_TEST_CHECK( 0 == t3ran, "Thread 3 DID run" );
+ CYG_TEST_CHECK( 0 == got_it, "Thread 1 DID get the mutex" );
+ }
+
+ CYG_TEST_CHECK( 0 == t3ended, "Thread 3 ended prematurely [T2,1]" );
+
+ cyg_thread_delay( DELAYFACTOR * 20 ); // let those threads run
+
+ CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" );
+ CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+ CYG_TEST_CHECK( 1 == t3ended, "Thread 3 has not ended" );
+
+ for ( i = 0; i < 3; i++ )
+ if ( (1 << i) & (data | data >> 4) ) // bits 0-2 and 4-6 control
+ CYG_TEST_CHECK( 1 == extras[i+1], "Extra thread did not run" );
+ else
+ CYG_TEST_CHECK( 0 == extras[i+1], "Extra thread ran" );
+
+ CYG_TEST_PASS( "Thread 2 exiting, AOK" );
+ // That's all: restart the control thread.
+ cyg_thread_resume( thread[0] );
+}
+
+// ------------------------------------------------------------------------
+
+static void t3( cyg_addrword_t data )
+{
+#ifdef VERBOSE
+ CYG_TEST_INFO( "Thread 3 running" );
+#endif
+ cyg_mutex_lock( mutex );
+
+ cyg_thread_delay( DELAYFACTOR * 5 ); // let thread 3a run
+
+ cyg_thread_resume( thread[2] ); // resume thread 2
+
+ while ( 0 == go_flag )
+ cyg_thread_delay(1); // wait until we are told to go
+
+ t3ran ++; // record the fact
+
+ CYG_TEST_CHECK( 0 == got_it, "Thread 1 claims to have got my mutex" );
+
+ cyg_mutex_unlock( mutex );
+
+ t3ended ++; // record that we came back
+
+ CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+#ifdef VERBOSE
+ CYG_TEST_INFO( "Thread 3 exit" );
+#endif
+}
+
+// ------------------------------------------------------------------------
+
+static void control_thread( cyg_addrword_t data )
+{
+ cyg_handle_t self = cyg_thread_self();
+ int i, z;
+
+ CYG_TEST_INIT();
+ CYG_TEST_INFO( "Control Thread running" );
+
+ // Go through the 27 possibilities of resuming the extra threads
+ // 0: not at all
+ // 1: early in the process
+ // 2: later on
+ // which are represented by bits 0-3 and 4-6 resp in the argument to
+ // thread 2 (none set means no resume at all).
+ for ( i = 0; i < 27; i++ ) {
+ static int xx[] = { 0, 1, 16 };
+ int j = i % 3;
+ int k = (i / 3) % 3;
+ int l = (i / 9) % 3;
+
+ int d = xx[j] | (xx[k]<<1) | (xx[l]<<2) ;
+
+ if ( cyg_test_is_simulator && (0 != i && 13 != i && 26 != i) )
+ continue; // 13 is 111 base 3, 26 is 222 base 3
+
+ // Go through all these priority inversion prevention protocols:
+ // (if supported in this configuration)
+ // PROTO_NONE (0)
+ // PROTO_INHERIT (1)
+ // PROTO_CEILING_HIGH (2)
+ // PROTO_CEILING_MID (3)
+ // PROTO_CEILING_LOW (4)
+ for ( proto = PROTO_NONE; proto <= PROTO_CEILING_LOW; proto++ ) {
+
+ // If no priority inheritance at all, running threads 1a and 2a is
+ // OK, but not thread 3a; it blocks the world.
+ if ( PROTO_NONE == proto ||
+ PROTO_CEILING_MID == proto ||
+ PROTO_CEILING_LOW == proto )
+ if ( l ) // Cannot run thread 3a if no
+ continue; // priority inheritance at all.
+
+ mutex = &mutex_obj;
+
+ switch ( proto ) {
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_NONE
+ case PROTO_NONE:
+ cyg_mutex_init( mutex );
+ cyg_mutex_set_protocol( mutex, CYG_MUTEX_NONE );
+ break;
+#endif
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+ case PROTO_INHERIT:
+ cyg_mutex_init( mutex );
+ cyg_mutex_set_protocol( mutex, CYG_MUTEX_INHERIT );
+ break;
+#endif
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+ case PROTO_CEILING_HIGH:
+ cyg_mutex_init( mutex );
+ cyg_mutex_set_protocol( mutex, CYG_MUTEX_CEILING );
+ cyg_mutex_set_ceiling( mutex, (cyg_priority_t) 4 );
+ break;
+ case PROTO_CEILING_MID:
+ cyg_mutex_init( mutex );
+ cyg_mutex_set_protocol( mutex, CYG_MUTEX_CEILING );
+ cyg_mutex_set_ceiling( mutex, (cyg_priority_t) 11 );
+ break;
+ case PROTO_CEILING_LOW:
+ cyg_mutex_init( mutex );
+ cyg_mutex_set_protocol( mutex, CYG_MUTEX_CEILING );
+ cyg_mutex_set_ceiling( mutex, (cyg_priority_t) 17 );
+ break;
+#endif
+ default:
+ continue; // Break out of the prio for loop - do nothing
+ }
+
+ got_it = 0;
+ t3ran = 0;
+ t3ended = 0;
+ for ( z = 0; z < 4; z++ ) extras[z] = 0;
+ go_flag = 0;
+
+ new_thread( t1, 0, 5, 1, "test 1" ); // Slot 1
+ new_thread( t2, d, 10, 1, "test 2" ); // Slot 2
+ new_thread( t3, 0, 15, 1, "test 3" ); // Slot 3
+
+ new_thread( extra_thread, 1, 8, j, "extra 1" ); // Slot 4
+ new_thread( extra_thread, 2, 12, k, "extra 2" ); // Slot 5
+ new_thread( extra_thread, 3, 17, l, "extra 3" ); // Slot 6
+
+ {
+ static char *a[] = { "inactive", "run early", "run late" };
+ diag_printf( "\n----- %s [%2d] New Cycle: 0x%02x, Threads 1a %s, 2a %s, 3a %s -----\n",
+ protnames[proto], i, d, a[j], a[k], a[l] );
+ }
+
+ cyg_thread_suspend( self );
+
+ kill_threads();
+ cyg_mutex_destroy( mutex );
+ }
+ }
+ CYG_TEST_EXIT( "Control Thread exit" );
+}
+
+// ------------------------------------------------------------------------
+
+externC void
+cyg_user_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ new_thread( control_thread, 0, 2, 1, "control thread" );
+}
+
+#else // CYGVAR_KERNEL_COUNTERS_CLOCK &c
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_INFO("KMutex4 test requires:\n"
+ "CYGFUN_KERNEL_API_C &&\n"
+ "CYGVAR_KERNEL_COUNTERS_CLOCK &&\n"
+ "(CYGNUM_KERNEL_SCHED_PRIORITIES > 20) &&\n"
+ "!defined(CYGPKG_KERNEL_SMP_SUPPORT) &&\n"
+ "defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC)\n"
+ );
+ CYG_TEST_NA("KMutex4 test requirements");
+}
+#endif // CYGVAR_KERNEL_COUNTERS_CLOCK &c
+
+
+// ------------------------------------------------------------------------
+// Documentation: enclosed is the design of this test.
+//
+// See mutex3.cxx or kmutex3.c
+
+// ------------------------------------------------------------------------
+// EOF mutex4.c
diff --git a/ecos/packages/kernel/current/tests/kphilo.c b/ecos/packages/kernel/current/tests/kphilo.c
new file mode 100644
index 0000000000..b21207ce86
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kphilo.c
@@ -0,0 +1,236 @@
+//==========================================================================
+//
+// kphilo.c
+//
+// A test of the dining philosophers problem
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-24
+// Description: A test of the dining philosophers problem
+//####DESCRIPTIONEND####
+//
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/kernel/diag.h>
+
+// -------------------------------------------------------------------------
+// Data for the philosophers problem
+
+#define PHILOSOPHERS 15 // number of philosophers
+#define STACKSIZE (2*1024) // size of thread stack
+
+// array of stacks for philosopher threads
+char thread_stack[PHILOSOPHERS][STACKSIZE];
+
+// array of threads.
+cyg_thread thread[PHILOSOPHERS];
+
+cyg_handle_t thread_handle[PHILOSOPHERS];
+
+// array of chopsticks
+cyg_sem_t chopstick[PHILOSOPHERS];
+
+cyg_ucount32 data_index;
+
+// -------------------------------------------------------------------------
+// State recording and display
+
+static char pstate[PHILOSOPHERS+1]; // state vector showing what each
+ // philosopher is doing
+
+cyg_mutex_t state_mutex;
+
+#ifdef CYG_HAL_MN10300_MN103002
+static cyg_count8 eaters = 0;
+#endif
+
+void change_state(int id, char newstate)
+{
+ cyg_mutex_lock(&state_mutex);
+
+#ifdef CYG_HAL_MN10300_MN103002
+ if( pstate[id] == 'E' ) eaters--;
+ if( newstate == 'E' ) eaters++;
+// led(eaters);
+#endif
+
+ pstate[id] = newstate;
+
+ diag_write_string(pstate);
+#if 0
+ diag_write_char(' ');
+ diag_write_dec(Cyg_Scheduler::get_thread_switches());
+#endif
+ diag_write_char('\n');
+
+ cyg_mutex_unlock(&state_mutex);
+
+}
+
+char get_state( int id)
+{
+ char s;
+ cyg_mutex_lock(&state_mutex);
+
+ s = pstate[id];
+
+ cyg_mutex_unlock(&state_mutex);
+
+ return s;
+}
+
+// -------------------------------------------------------------------------
+// Thread to behave like a philosopher
+
+void Philosopher( cyg_addrword_t vid )
+{
+ cyg_uint32 id = (cyg_uint32)vid;
+ cyg_sem_t *first_stick = &chopstick[id];
+ cyg_sem_t *second_stick = &chopstick[(id+1)%PHILOSOPHERS];
+#ifdef CYGPKG_INFRA_DEBUG
+ int left_philo = ((id==0)?PHILOSOPHERS:id)-1;
+ int right_philo = (id==PHILOSOPHERS-1)?0:(id+1);
+#endif
+
+ CYG_ASSERT( id >= 0 && id < PHILOSOPHERS, "Bad id");
+
+ // Deadlock avoidance. The easiest way to make the philosophers
+ // behave is to make each pick up the lowest numbered stick
+ // first. This is how it works out anyway for all the philosophers
+ // except the last, who must have his sticks swapped.
+
+ if( id == PHILOSOPHERS-1 )
+ {
+ cyg_sem_t *t = first_stick;
+ first_stick = second_stick;
+ second_stick = t;
+ }
+
+ for(;;)
+ {
+ cyg_ucount32 val;
+
+ // The following variable is shared by all philosophers.
+ // It is incremented unprotected, but this does not matter
+ // since it is only present to introduce a little variability
+ // into the think and eat times.
+
+ static volatile int cycle = 0;
+
+ // Think for a bit
+
+ cyg_thread_delay((id+cycle++)%12); // Cogito ergo sum...
+
+ // I am now hungry, try to get the chopsticks
+
+ change_state(id,'H');
+
+ // Get the first stick
+ cyg_semaphore_wait(first_stick);
+
+ // Get the second stick
+ cyg_semaphore_wait(second_stick);
+
+ // Got them, now eat
+
+ change_state(id,'E');
+
+ // Check that the world is as I think it is...
+ cyg_semaphore_peek( first_stick, &val);
+ CYG_ASSERT( val == 0, "Not got first stick");
+ cyg_semaphore_peek( second_stick, &val);
+ CYG_ASSERT( val == 0, "Not got second stick");
+ CYG_ASSERT( get_state(left_philo) != 'E', "Left neighbour also eating!!");
+ CYG_ASSERT( get_state(right_philo) != 'E', "Right neighbour also eating!!");
+
+ cyg_thread_delay((id+cycle++)%6); // munch munch
+
+ // Finished eating, put down sticks.
+
+ change_state(id,'T');
+
+ cyg_semaphore_post( first_stick );
+ cyg_semaphore_post( second_stick );
+
+ }
+}
+
+// -------------------------------------------------------------------------
+
+externC void
+cyg_start( void )
+{
+ int i;
+
+ diag_init();
+
+ diag_write_string("Philosophers\n");
+ diag_write_string("Started\n");
+
+ // Zero last element in state so it acts like
+ // a string.
+ pstate[PHILOSOPHERS] = 0;
+
+#if 1
+ for( i = 0; i < PHILOSOPHERS; i++ )
+ {
+ change_state(i,'T'); // starting state
+
+ cyg_thread_create(4, Philosopher, (cyg_addrword_t)i, "philosopher",
+ (void *)(&thread_stack[i]), STACKSIZE,
+ &thread_handle[i], &thread[i]);
+
+ // resume it
+ cyg_thread_resume(thread_handle[i]);
+
+ // and make the matching chopstick present
+ cyg_semaphore_init( &chopstick[i], 1);
+ }
+#endif
+
+ // Get the world going
+ cyg_scheduler_start();
+
+}
+
+// -------------------------------------------------------------------------
+// EOF kphilo.c
diff --git a/ecos/packages/kernel/current/tests/ksched1.c b/ecos/packages/kernel/current/tests/ksched1.c
new file mode 100644
index 0000000000..d1bf1c7d55
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/ksched1.c
@@ -0,0 +1,103 @@
+/*=================================================================
+//
+// ksched1.c
+//
+// Kernel C API Sched test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-23
+// Description: Simply checks the world starts
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+#define NTHREADS 2
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static cyg_handle_t thread[NTHREADS];
+
+static cyg_thread thread_obj[NTHREADS];
+static char stack[NTHREADS][STACKSIZE];
+
+
+static void entry0( cyg_addrword_t data )
+{
+ CHECK( 222 == (int)data );
+ CYG_TEST_PASS_FINISH( "Kernel C API Sched 1 OK");
+}
+
+void ksched1_main(void)
+{
+ CYG_TEST_INIT();
+
+ cyg_thread_create( 4, entry0 , (cyg_addrword_t)222, "ksched1",
+ (void *)stack[0], STACKSIZE, &thread[0], &thread_obj[0]);
+ cyg_thread_resume(thread[0]);
+
+ cyg_scheduler_start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+ ksched1_main();
+}
+
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+/* EOF ksched1.c */
diff --git a/ecos/packages/kernel/current/tests/ksem0.c b/ecos/packages/kernel/current/tests/ksem0.c
new file mode 100644
index 0000000000..4a7f359dc5
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/ksem0.c
@@ -0,0 +1,100 @@
+/*=================================================================
+//
+// ksem0.c
+//
+// Kernel C API Semaphore test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-20
+// Description: Limited to checking initialisation/destruction
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+cyg_sem_t s0, s1, s2;
+
+static bool flash( void )
+{
+ cyg_semaphore_init( &s0, 0 );
+ cyg_semaphore_init( &s1, 1 );
+ cyg_semaphore_init( &s2, 17 );
+
+ cyg_semaphore_destroy( &s0 );
+ cyg_semaphore_destroy( &s1 );
+ cyg_semaphore_destroy( &s2 );
+
+ return true;
+}
+
+void ksem0_main( void )
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ CYG_TEST_PASS_FINISH("Kernel C API Semaphore 0 OK");
+
+}
+
+externC void
+cyg_start( void )
+{
+ ksem0_main();
+}
+
+
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+/* EOF ksem0.c */
diff --git a/ecos/packages/kernel/current/tests/ksem1.c b/ecos/packages/kernel/current/tests/ksem1.c
new file mode 100644
index 0000000000..89ed2cc431
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/ksem1.c
@@ -0,0 +1,169 @@
+/*=================================================================
+//
+// ksem1.c
+//
+// C API semaphore test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-20
+// Description: Tests basic semaphore functionality.
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+#define NTHREADS 2
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static cyg_handle_t thread[NTHREADS];
+
+static cyg_thread thread_obj[NTHREADS];
+static char stack[NTHREADS][STACKSIZE];
+
+
+static cyg_sem_t s0, s1, s2;
+
+static volatile cyg_ucount8 q = 0;
+
+static void entry0( cyg_addrword_t data )
+{
+ cyg_count32 val;
+
+ cyg_semaphore_wait(&s0);
+ CHECK( 1 == q++ );
+ cyg_semaphore_post(&s1);
+ cyg_semaphore_wait(&s0);
+ CHECK( 3 == q++ );
+ cyg_semaphore_peek(&s0, &val);
+ CHECK( 0 == val);
+ CHECK( ! cyg_semaphore_trywait(&s0) );
+ cyg_semaphore_post(&s0);
+ CHECK( 4 == q++ );
+ cyg_semaphore_peek(&s0, &val);
+ CHECK( 1 == val);
+ cyg_semaphore_post(&s0);
+ cyg_semaphore_peek(&s0, &val);
+ CHECK( 2 == val);
+ cyg_semaphore_post(&s1);
+ cyg_semaphore_peek(&s2, &val);
+ CHECK( 0 == val);
+ cyg_semaphore_wait(&s2);
+ CHECK( 6 == q++ );
+ CYG_TEST_PASS_FINISH("Kernel C API Semaphore 1 OK");
+}
+
+static void entry1( cyg_addrword_t data )
+{
+ cyg_count32 val;
+
+ cyg_semaphore_peek(&s1, &val);
+ CHECK( 2 == val);
+ cyg_semaphore_wait(&s1);
+ cyg_semaphore_peek(&s1, &val);
+ CHECK( 1 == val);
+ cyg_semaphore_wait(&s1);
+ CHECK( 0 == q++ );
+ cyg_semaphore_peek(&s0, &val);
+ CHECK( 0 == val);
+ cyg_semaphore_post(&s0);
+ cyg_semaphore_wait(&s1);
+ CHECK( 2 == q++ );
+ cyg_semaphore_post(&s0);
+ cyg_semaphore_wait(&s1);
+ CHECK( 5 == q++ );
+ cyg_semaphore_peek(&s0, &val);
+ CHECK( 2 == val);
+ CHECK( cyg_semaphore_trywait(&s0) );
+ cyg_semaphore_peek(&s0, &val);
+ CHECK( 1 == val);
+ CHECK( cyg_semaphore_trywait(&s0) );
+ cyg_semaphore_peek(&s0, &val);
+ CHECK( 0 == val);
+ cyg_semaphore_post(&s2);
+ cyg_semaphore_wait(&s0);
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+void ksem1_main( void )
+{
+ CYG_TEST_INIT();
+
+ cyg_semaphore_init( &s0, 0);
+ cyg_semaphore_init( &s1, 2);
+ cyg_semaphore_init( &s2, 0);
+
+ cyg_thread_create(4, entry0 , (cyg_addrword_t)0, "ksem1-0",
+ (void *)stack[0], STACKSIZE,&thread[0], &thread_obj[0]);
+ cyg_thread_resume(thread[0]);
+
+ cyg_thread_create(4, entry1 , (cyg_addrword_t)1, "ksem1-1",
+ (void *)stack[1], STACKSIZE, &thread[1], &thread_obj[1]);
+ cyg_thread_resume(thread[1]);
+
+ cyg_scheduler_start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+ ksem1_main();
+}
+
+
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+/* EOF ksem1.c */
diff --git a/ecos/packages/kernel/current/tests/kthread0.c b/ecos/packages/kernel/current/tests/kthread0.c
new file mode 100644
index 0000000000..eb1deaa4b7
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kthread0.c
@@ -0,0 +1,120 @@
+/*=================================================================
+//
+// kthread0.c
+//
+// Kernel C API Thread test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-18
+// Description: Limited to checking constructors/destructors
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/hal/hal_arch.h> // CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static char stack[STACKSIZE];
+
+static cyg_thread_entry_t entry;
+
+static void entry( cyg_addrword_t data )
+{
+}
+
+static int *p;
+
+#if 0
+static cyg_handle_t t0,t1;
+static cyg_thread thread0, thread1;
+#endif
+
+static cyg_handle_t t2;
+static cyg_thread thread2;
+
+static bool flash( void )
+{
+#if 0 // no facility to allocate stack exists yet.
+ cyg_thread_create( entry, 0x111, NULL, 0, &t0, &thread0 );
+
+ cyg_thread_create( entry, (cyg_addrword_t)&t0, STACKSIZE, 0, &t1, &thread0 );
+#endif
+
+ cyg_thread_create(4, entry, (cyg_addrword_t)p, "kthread0",
+ (void *)stack, STACKSIZE, &t2, &thread2 );
+
+ return true;
+}
+
+void kthread0_main( void )
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ CYG_TEST_PASS_FINISH("Kernel C API Thread 0 OK");
+
+}
+
+externC void
+cyg_start( void )
+{
+ kthread0_main();
+}
+
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+/* EOF kthread0.c */
diff --git a/ecos/packages/kernel/current/tests/kthread1.c b/ecos/packages/kernel/current/tests/kthread1.c
new file mode 100644
index 0000000000..3ceba97802
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/kthread1.c
@@ -0,0 +1,136 @@
+/*=================================================================
+//
+// kthread1.c
+//
+// Kernel C API Thread test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-18
+// Description: Tests some basic thread functions.
+//####DESCRIPTIONEND####
+*/
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_API_C
+
+#include "testaux.h"
+
+#include <cyg/hal/hal_arch.h> // for CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#ifdef CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#else
+#define STACKSIZE 2000
+#endif
+
+static char stack[2][STACKSIZE];
+
+static cyg_thread thread[2];
+
+static cyg_handle_t pt0,pt1;
+
+
+static void entry0( cyg_addrword_t data )
+{
+ CHECK( 222 == (int)data );
+
+ cyg_thread_suspend(pt1);
+ cyg_thread_resume(pt1);
+
+ cyg_thread_delay(1);
+
+ cyg_thread_resume(pt1);
+
+ cyg_thread_delay(1);
+
+ CYG_TEST_PASS_FINISH("Kernel C API Thread 1 OK");
+}
+
+static void entry1( cyg_addrword_t data )
+{
+ cyg_handle_t self;
+ CHECK( 333 == (int)data );
+
+ self = cyg_thread_self();
+
+ CHECK( self == pt1 );
+
+ cyg_thread_suspend(pt1);
+
+ cyg_thread_exit(); // no guarantee this will be called
+}
+
+void kthread1_main( void )
+{
+ CYG_TEST_INIT();
+
+ cyg_thread_create(4, entry0, (cyg_addrword_t)222, "kthread1-0",
+ (void *)stack[0], STACKSIZE, &pt0, &thread[0] );
+ cyg_thread_create(4, entry1, (cyg_addrword_t)333, "kthread1-1",
+ (void *)stack[1], STACKSIZE, &pt1, &thread[1] );
+
+ cyg_thread_resume(pt0);
+ cyg_thread_resume(pt1);
+
+ cyg_scheduler_start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+ kthread1_main();
+}
+
+
+#else /* def CYGFUN_KERNEL_API_C */
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel C API layer disabled");
+}
+#endif /* def CYGFUN_KERNEL_API_C */
+
+/* EOF kthread1.c */
diff --git a/ecos/packages/kernel/current/tests/mbox1.cxx b/ecos/packages/kernel/current/tests/mbox1.cxx
new file mode 100644
index 0000000000..443b689bab
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/mbox1.cxx
@@ -0,0 +1,201 @@
+//==========================================================================
+//
+// mbox1.cxx
+//
+// Mbox test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: dsm
+// Contributors: dsm
+// Date: 1998-05-19
+// Description: Tests basic mbox functionality.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start()
+
+#include <cyg/kernel/mbox.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+
+#include <cyg/kernel/timer.hxx> // Cyg_Timer
+#include <cyg/kernel/clock.inl> // Cyg_Clock
+
+#define NTHREADS 2
+#include "testaux.hxx"
+
+static Cyg_Mbox m0, m1, m2;
+
+static volatile cyg_atomic q = 0;
+
+#ifndef CYGMTH_MBOX_PUT_CAN_WAIT
+#define PUT tryput
+#endif
+
+static void entry0( CYG_ADDRWORD data )
+{
+ cyg_count8 u,i;
+
+ CYG_TEST_INFO("Testing put() and tryput() without wakeup");
+ CYG_TEST_CHECK(!m0.waiting_to_get(), "mbox not initialized properly");
+ CYG_TEST_CHECK(0==m0.peek(), "mbox not initialized properly");
+ CYG_TEST_CHECK(NULL==m0.peek_item(), "mbox not initialized properly");
+ m0.PUT((void *)55);
+ CYG_TEST_CHECK(1==m0.peek(), "peek() wrong");
+ CYG_TEST_CHECK(55==(cyg_count8)m0.peek_item(), "peek_item() wrong");
+ for(u=1; m0.tryput((void*)u); u++) {
+ CYG_TEST_CHECK(55==(cyg_count8)m0.peek_item(), "peek_item() wrong");
+ CYG_TEST_CHECK(u+1==m0.peek(), "peek() wrong");
+ }
+ CYG_TEST_CHECK(u == CYGNUM_KERNEL_SYNCH_MBOX_QUEUE_SIZE, "mbox not configured size");
+
+ // m0 now contains ( 55 1 2 .. u-1 )
+ CYG_TEST_CHECK(u==m0.peek(), "peek() wrong");
+ CYG_TEST_CHECK(55==(cyg_count8)m0.peek_item(), "peek_item() wrong");
+
+ CYG_TEST_INFO("Testing get(), tryget()");
+
+ i = (cyg_count8)m0.tryget();
+ CYG_TEST_CHECK( 55 == i, "Got wrong message" );
+ for(cyg_count8 j=1; j<u;j++) {
+ CYG_TEST_CHECK( j == (cyg_count8)m0.peek_item(), "peek_item()" );
+ CYG_TEST_CHECK( m0.peek() == u - j, "peek() wrong" );
+ i = (cyg_count8)m0.get();
+ CYG_TEST_CHECK( j == i, "Got wrong message" );
+ }
+
+ CYG_TEST_CHECK( NULL == m0.peek_item(), "peek_item()" );
+ CYG_TEST_CHECK( 0 == m0.peek(), "peek()");
+
+ // m0 now empty
+
+ CYG_TEST_CHECK(!m0.waiting_to_put(), "waiting_to_put()");
+ CYG_TEST_CHECK(!m0.waiting_to_get(), "waiting_to_get()");
+
+ CYG_TEST_INFO("Testing get(), blocking");
+
+ CYG_TEST_CHECK(0==q++, "bad synchronization");
+ m1.PUT((void*)99); // wakes t1
+ i = (cyg_count8)m0.get(); // sent by t1
+ CYG_TEST_CHECK(3==i, "Recieved wrong message");
+ CYG_TEST_CHECK(2==q++, "bad synchronization");
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ CYG_TEST_CHECK(NULL==m0.get(
+ Cyg_Clock::real_time_clock->current_value() + 10),
+ "unexpectedly found message");
+ CYG_TEST_CHECK(3==q++, "bad synchronization");
+ // Allow t1 to run as this get times out
+ // t1 must not be waiting...
+ CYG_TEST_CHECK(m0.waiting_to_get(), "waiting_to_get()");
+
+ m0.PUT((void*)7); // wake t1 from timed get
+#ifdef CYGMTH_MBOX_PUT_CAN_WAIT
+ q=10;
+ while(m0.tryput((void*)6)) // fill m0's queue
+ ;
+ // m0 now contains ( 6 ... 6 )
+ CYG_TEST_CHECK(10==q++, "bad synchronization");
+ m1.put((void*)4); // wake t1
+ CYG_TEST_CHECK(!m0.put((void*)8, 2), "timed put() unexpectedly worked");
+ CYG_TEST_CHECK(12==q++, "bad synchronization");
+ // m0 still contains ( 6 ... 6 )
+ m0.put((void*)9);
+ CYG_TEST_CHECK(13==q++, "bad synchronization");
+#endif
+#endif
+ i=(cyg_count8)m2.get();
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+static void entry1( CYG_ADDRWORD data )
+{
+ cyg_count8 i;
+ i = (cyg_count8)m1.get();
+ CYG_TEST_CHECK(1==q++, "bad synchronization");
+ m0.PUT((void *)3); // wake t0
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+ CYG_TEST_INFO("Testing timed functions");
+ CYG_TEST_CHECK(7==(cyg_count8)m0.get(
+ Cyg_Clock::real_time_clock->current_value() + 20), "timed get()");
+ CYG_TEST_CHECK(4==q++, "bad synchronization");
+#ifdef CYGMTH_MBOX_PUT_CAN_WAIT
+ CYG_TEST_CHECK(4==(cyg_count8)m1.get());
+
+ CYG_TEST_CHECK(11==q++, "bad synchronization");
+ thread[0]->delay(20); // allow t0 to reach put on m1
+ CYG_TEST_CHECK(14==q++, "bad synchronization");
+ CYG_TEST_CHECK(m0.waiting_to_put(), "waiting_to_put()");
+ do {
+ // after first get m0 contains ( 6 .. 6 9 )
+ i=(cyg_count8)m0.tryget();
+ } while(6==i);
+ CYG_TEST_CHECK(9==i,"put gone awry");
+#endif
+#endif
+ CYG_TEST_PASS_FINISH("Mbox 1 OK");
+}
+
+void mbox1_main( void )
+{
+ CYG_TEST_INIT();
+
+ new_thread(entry0, 0);
+ new_thread(entry1, 1);
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ mbox1_main();
+}
+
+// EOF mbox1.cxx
diff --git a/ecos/packages/kernel/current/tests/mqueue1.cxx b/ecos/packages/kernel/current/tests/mqueue1.cxx
new file mode 100644
index 0000000000..3e392cc116
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/mqueue1.cxx
@@ -0,0 +1,411 @@
+/*========================================================================
+//
+// mqueue1.cxx
+//
+// Message queues tests
+//
+//========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): jlarmour
+// Contributors:
+// Date: 2000-05-12
+// Purpose: This file provides tests for eCos mqueues
+// Description:
+// Usage:
+//
+//####DESCRIPTIONEND####
+//
+//======================================================================
+*/
+
+/* CONFIGURATION */
+
+#include <pkgconf/kernel.h>
+
+/* INCLUDES */
+
+#include <cyg/infra/cyg_type.h> // common types and externC
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+#include <cyg/kernel/thread.inl>
+// Specially avoid inlining here due to the way we abuse the mqueue
+// implementation by making lots and lots of calls.
+#define CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE
+#include <cyg/kernel/mqueue.hxx> // Mqueue Header
+#include <cyg/kernel/sema.hxx> // semaphores
+#include <cyg/infra/testcase.h> // test API
+
+// use the common kernel test magic to define 2 threads
+#define NTHREADS 2
+#include "testaux.hxx"
+
+/* GLOBALS */
+
+static char mempool[500];
+static size_t storedmempoollen;
+Cyg_Mqueue *mq;
+static Cyg_Binary_Semaphore t0sem, t1sem;
+static int calledback;
+
+
+/* FUNCTIONS */
+
+static int
+my_memcmp(const void *m1, const void *m2, size_t n)
+{
+ char *s1 = (char *)m1;
+ char *s2 = (char *)m2;
+
+ while (n--) {
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ s1++;
+ s2++;
+ }
+ return 0;
+} // my_memcmp()
+
+static void *
+my_alloc( size_t len )
+{
+ if ( len > sizeof(mempool) )
+ return NULL;
+
+ storedmempoollen = len;
+ return &mempool[0];
+}
+
+static void
+my_free( void *ptr, size_t len )
+{
+ CYG_TEST_PASS_FAIL( (ptr == &mempool[0]) && (len == storedmempoollen),
+ "Freed pool correctly");
+ mq = NULL; // invalidate
+}
+
+static void
+callback(Cyg_Mqueue &mq, CYG_ADDRWORD data)
+{
+ calledback += (int)data;
+}
+
+//************************************************************************
+//************************************************************************
+
+static void
+t0( CYG_ADDRWORD data )
+{
+ Cyg_Mqueue::qerr_t err;
+ char buf[35];
+ size_t len;
+ unsigned int prio;
+ bool b;
+
+ Cyg_Mqueue the_mq(4, 32, &my_alloc, &my_free, &err );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err,
+ "Create queue" );
+ mq = &the_mq;
+
+//------------------------------------------------------------------------
+
+ err = mq->put( "Peter piper picked", sizeof("Peter piper picked"),
+ 5, true );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, "Simple (put)");
+
+ t1sem.post();
+
+//------------------------------------------------------------------------
+
+ t0sem.wait();
+
+ err = mq->get( buf, &len, &prio, true );
+ b = (err == Cyg_Mqueue::OK);
+ if (b)
+ b = (len == sizeof("a peck of"));
+ if (b)
+ b = (prio == 100);
+ if (b)
+ b = (0 ==
+ my_memcmp(buf, "a peck of", sizeof("a peck of"))
+ );
+ CYG_TEST_PASS_FAIL( b, "Blocking get");
+
+//------------------------------------------------------------------------
+
+ t0sem.wait();
+
+ CYG_TEST_PASS_FAIL( 4 == mq->count(), "mq count" );
+ err = mq->get( buf, &len, &prio, false );
+ b = (err == Cyg_Mqueue::OK);
+ if (b)
+ b = (len == sizeof("pickled peppers"));
+ if (b)
+ b = (prio == 300);
+ if (b)
+ b = (0 ==
+ my_memcmp(buf, "pickled peppers", sizeof("pickled peppers"))
+ );
+ if (b)
+ b = (3 == mq->count());
+ CYG_TEST_PASS_FAIL( b, "Prioritized (get 1)");
+
+ err = mq->get( buf, &len, &prio, false );
+ b = (err == Cyg_Mqueue::OK);
+ if (b)
+ b = (len == sizeof("."));
+ if (b)
+ b = (prio == 250);
+ if (b)
+ b = (0 ==
+ my_memcmp(buf, ".", sizeof("."))
+ );
+ if (b)
+ b = (2 == mq->count());
+ CYG_TEST_PASS_FAIL( b, "Prioritized (get 2)");
+
+ err = mq->get( buf, &len, &prio, false );
+ b = (err == Cyg_Mqueue::OK);
+ if (b)
+ b = (len == 1);
+ if (b)
+ b = (prio == 225);
+ if (b)
+ b = (0 ==
+ my_memcmp(buf, "", 1)
+ );
+ if (b)
+ b = (1 == mq->count());
+ CYG_TEST_PASS_FAIL( b, "Prioritized (get 3)");
+
+ err = mq->get( buf, &len, &prio, false );
+ b = (err == Cyg_Mqueue::OK);
+ if (b)
+ b = (len == sizeof("If Peter"));
+ if (b)
+ b = (prio == 200);
+ if (b)
+ b = (0 ==
+ my_memcmp(buf, "If Peter", sizeof("If Peter"))
+ );
+ if (b)
+ b = (0 == mq->count());
+ CYG_TEST_PASS_FAIL( b, "Prioritized (get 4)");
+
+//------------------------------------------------------------------------
+
+ err = mq->get( buf, &len, &prio, false );
+
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::WOULDBLOCK == err,
+ "Non-blocking get of empty queue" );
+
+//------------------------------------------------------------------------
+
+ Cyg_Mqueue::callback_fn_t oldcallback;
+
+ oldcallback = mq->setnotify( &callback, (CYG_ADDRWORD) 42 );
+
+ err = mq->put( "If Peter", sizeof("If Peter"),
+ 200, false );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err,
+ "Prioritized (put in empty queue)");
+ CYG_TEST_PASS_FAIL( 42 == calledback, "callback" );
+ CYG_TEST_PASS_FAIL( NULL == oldcallback, "oldcallback" );
+
+ err = mq->get( buf, &len, &prio, false );
+ b = (err == Cyg_Mqueue::OK);
+ if (b)
+ b = (len == sizeof("If Peter"));
+ if (b)
+ b = (prio == 200);
+ if (b)
+ b = (0 ==
+ my_memcmp(buf, "If Peter", sizeof("If Peter"))
+ );
+ CYG_TEST_PASS_FAIL( b, "Prioritized (get 2)");
+
+ t1sem.post();
+
+ err = mq->get( buf, &len, &prio, true );
+ b = (err == Cyg_Mqueue::OK);
+ if (b)
+ b = (len == 32);
+ if (b)
+ b = (42 == calledback);
+ if (b)
+ b = (prio == 250);
+ if (b)
+ b = (0 ==
+ my_memcmp(buf, "12345678901234567890123456789012", 32)
+ );
+ CYG_TEST_PASS_FAIL( b, "callback (blocked wait)");
+
+//------------------------------------------------------------------------
+
+ t1sem.post();
+ t0sem.wait();
+
+} // t0()
+
+
+//************************************************************************
+//************************************************************************
+
+
+static void
+t1( CYG_ADDRWORD data )
+{
+ Cyg_Mqueue::qerr_t err;
+ char buf[35];
+ size_t len;
+ unsigned int prio;
+ bool b;
+
+//------------------------------------------------------------------------
+
+ // wait till t0 says we can go
+ t1sem.wait();
+
+ err = mq->get( buf, &len, &prio, true );
+ b = (err == Cyg_Mqueue::OK);
+ if (b)
+ b = (len == sizeof("Peter piper picked"));
+ if (b)
+ b = (prio == 5);
+ if (b)
+ b = (0 ==
+ my_memcmp(buf, "Peter piper picked", sizeof("Peter piper picked"))
+ );
+
+ CYG_TEST_PASS_FAIL( b, "Simple");
+
+//------------------------------------------------------------------------
+
+ t0sem.post(); // t0 should run straight away
+ Cyg_Thread::yield(); // but just in case we have a funny sched
+
+ // by now t0 is blocked in mq->get
+
+ err = mq->put( "a peck of", sizeof("a peck of"),
+ 100, false );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err, "Block (put in empty queue)");
+
+//------------------------------------------------------------------------
+
+ err = mq->put( "If Peter", sizeof("If Peter"),
+ 200, false );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err,
+ "Prioritized (put in empty queue)");
+
+ err = mq->put( "pickled peppers", sizeof("pickled peppers"),
+ 300, false );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err,
+ "Prioritized (put in queue w/1)");
+
+ err = mq->put( ".", sizeof("."), 250, false );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err,
+ "Prioritized (put in queue w/2)");
+
+ err = mq->put( "", 1, 225, false );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err,
+ "Prioritized (put in queue w/3)");
+
+ err = mq->put( "foobar", 6, 1, false );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::WOULDBLOCK == err,
+ "Prioritized (full queue)");
+
+ t0sem.post();
+
+//------------------------------------------------------------------------
+
+ t1sem.wait();
+ Cyg_Thread::yield(); // but just in case we have a funny sched
+
+ err = mq->put( "12345678901234567890123456789012xxxx", 32,
+ 250, false );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::OK == err,
+ "callback (put in queue)");
+
+//------------------------------------------------------------------------
+
+ t1sem.wait();
+
+ // Create an oversized queue
+ {
+ Cyg_Mqueue huge_mq(99999, 99999, &my_alloc, &my_free, &err );
+ CYG_TEST_PASS_FAIL( Cyg_Mqueue::NOMEM == err,
+ "Oversized queue rejected" );
+ // and it now gets destructed - but that shouldn't call free
+ // to be called
+ }
+
+//------------------------------------------------------------------------
+
+ t0sem.post(); // t0 should run straight away
+ Cyg_Thread::yield(); // but just in case we have a funny sched
+
+ // 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");
+
+} // t1()
+
+
+//************************************************************************
+//************************************************************************
+
+externC void
+cyg_user_start(void)
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ CYG_TEST_INIT();
+
+ CYG_TEST_INFO( "Starting kernel mqueue test 1" );
+ new_thread( t0, 0);
+ new_thread( t1, 1);
+
+#ifdef CYGIMP_THREAD_PRIORITY
+ thread[0]->set_priority( 4 );
+ thread[1]->set_priority( 5 ); // make sure the threads execute as intended
+#endif
+} // cyg_user_start()
+
+//------------------------------------------------------------------------
+
+
+/* EOF mqueue1.cxx */
diff --git a/ecos/packages/kernel/current/tests/mutex0.cxx b/ecos/packages/kernel/current/tests/mutex0.cxx
new file mode 100644
index 0000000000..e8a208f0d7
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/mutex0.cxx
@@ -0,0 +1,96 @@
+//==========================================================================
+//
+// mutex0.cxx
+//
+// Mutex and condition variable test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-24
+// Description: Limited to checking constructors/destructors
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/mutex.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include "testaux.hxx"
+
+static Cyg_Mutex mutex0;
+
+static Cyg_Condition_Variable cvar0( mutex0 );
+
+static bool flash( void )
+{
+ Cyg_Mutex m0;
+
+ CYG_ASSERTCLASSO(m0, "error");
+
+ Cyg_Condition_Variable cv0( m0 );
+
+ CYG_ASSERTCLASSO(cv0, "error");
+
+ return true;
+}
+
+void mutex0_main( void )
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ CYG_ASSERTCLASSO(mutex0, "error");
+ CYG_ASSERTCLASSO(cvar0, "error");
+
+ CYG_TEST_PASS_FINISH("Mutex 0 OK");
+
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ mutex0_main();
+}
+// EOF mutex0.cxx
diff --git a/ecos/packages/kernel/current/tests/mutex1.cxx b/ecos/packages/kernel/current/tests/mutex1.cxx
new file mode 100644
index 0000000000..5233a3e67d
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/mutex1.cxx
@@ -0,0 +1,162 @@
+//==========================================================================
+//
+// mutex1.cxx
+//
+// Mutex test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-24
+// Description: Tests basic mutex functionality.
+// Omissions: Timed wait.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start()
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+
+#include <cyg/kernel/mutex.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/thread.inl>
+
+
+#define NTHREADS 3
+#include "testaux.hxx"
+
+static Cyg_Mutex m0, m1;
+static Cyg_Condition_Variable cvar0( m0 ), cvar1( m0 ), cvar2( m1 );
+
+static cyg_ucount8 m0d=0, m1d=0;
+
+static void finish( cyg_ucount8 t )
+{
+ m1.lock(); {
+ m1d |= 1<<t;
+ if( 0x7 == m1d )
+ CYG_TEST_PASS_FINISH("Mutex 1 OK");
+ cvar2.wait();
+ }
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+static void entry0( CYG_ADDRWORD data )
+{
+ m0.lock(); {
+ CHECK( ! m0.trylock() );
+ m1.lock(); {
+ CHECK( ! m0.trylock() );
+ } m1.unlock();
+ } m0.unlock();
+
+ m0.lock(); {
+ while ( 0 == m0d )
+ cvar0.wait();
+ CHECK( 1 == m0d++ );
+ cvar0.signal();
+ while ( 4 != m0d )
+ cvar1.wait();
+ CHECK( 4 == m0d );
+ } m0.unlock();
+
+ finish( data );
+}
+
+static void entry1( CYG_ADDRWORD data )
+{
+ m0.lock(); {
+ CHECK( m1.trylock() ); {
+ } m1.unlock();
+ } m0.unlock();
+
+ m0.lock(); {
+ CHECK( 0 == m0d++ );
+ cvar0.broadcast();
+ } m0.unlock();
+
+ m0.lock(); {
+ while( 1 == m0d )
+ cvar0.wait();
+ CHECK( 2 == m0d++ );
+ cvar0.signal();
+ while (3 == m0d )
+ cvar1.wait();
+ } m0.unlock();
+
+ finish( data ); // At most 1 finish inside m0 lock
+}
+
+static void entry2( CYG_ADDRWORD data )
+{
+ m0.lock(); {
+ while( 3 != m0d ) {
+ cvar0.wait();
+ }
+ CHECK( 3 == m0d++ );
+ cvar1.broadcast();
+ } m0.unlock();
+
+ finish( data );
+}
+
+void mutex1_main( void )
+{
+ CYG_TEST_INIT();
+
+ new_thread(entry0, 0);
+ new_thread(entry1, 1);
+ new_thread(entry2, 2);
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ mutex1_main();
+}
+// EOF mutex1.cxx
diff --git a/ecos/packages/kernel/current/tests/mutex2.cxx b/ecos/packages/kernel/current/tests/mutex2.cxx
new file mode 100644
index 0000000000..cc23bd29f8
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/mutex2.cxx
@@ -0,0 +1,272 @@
+//==========================================================================
+//
+// mutex1.cxx
+//
+// Mutex test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1999-02-19
+// Description: Tests mutex release functionality
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start()
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+
+#include <cyg/kernel/mutex.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/thread.inl>
+
+// ------------------------------------------------------------------------
+
+#if !defined(CYGPKG_KERNEL_SMP_SUPPORT)
+
+// ------------------------------------------------------------------------
+
+#define NTHREADS 4
+#include "testaux.hxx"
+#include "testaux.h"
+
+// ------------------------------------------------------------------------
+
+static Cyg_Mutex m0, m1;
+static Cyg_Condition_Variable cvar0( m0 ), cvar1( m0 ), cvar2( m1 );
+
+volatile int thread_state[NTHREADS];
+
+// ------------------------------------------------------------------------
+// This thread is meant to get hung up trying to re-acquire m0
+// after waiting on the cv.
+
+static void entry0( CYG_ADDRWORD data )
+{
+ CYG_TEST_INFO( "thread0: lock mutex 0");
+
+ m0.lock();
+
+ CYG_TEST_INFO( "thread0: wait cvar 0");
+
+ thread_state[data] = 1;
+
+ cvar0.wait();
+
+ thread_state[data] = 2;
+
+ CYG_TEST_INFO( "thread0: woke from cvar 0");
+
+ CYG_TEST_INFO( "thread0: unlock mutex 0");
+
+ m0.unlock();
+
+ thread_state[data] = 3;
+
+ CYG_TEST_INFO( "thread0: exit");
+
+ thread[data]->exit();
+}
+
+// ------------------------------------------------------------------------
+// This thread is meant to claim and keep m0.
+
+static void entry1( CYG_ADDRWORD data )
+{
+ CYG_TEST_INFO( "thread1: lock mutex 0");
+
+ m0.lock();
+
+ CYG_TEST_INFO( "thread1: lock mutex 1");
+
+ thread_state[data] = 1;
+
+ m1.lock();
+
+ thread_state[data] = 2;
+
+ CYG_TEST_INFO( "thread1: wait cvar 2");
+
+ cvar2.wait();
+
+ thread_state[data] = 3;
+
+ CYG_TEST_INFO( "thread1: woke from cvar 2");
+
+ CYG_TEST_INFO( "thread1: unlock mutex 1");
+
+ m1.unlock();
+
+ thread_state[data] = 4;
+
+ CYG_TEST_INFO( "thread1: unlock m0");
+
+ m0.unlock();
+
+ thread_state[data] = 5;
+
+ CYG_TEST_INFO( "thread1: exit");
+
+ thread[data]->exit();
+}
+
+// ------------------------------------------------------------------------
+// This thread is meant to get hung trying to acquire m0, and then get
+// released out of it by thread3.
+
+static void entry2( CYG_ADDRWORD data )
+{
+ CYG_TEST_INFO( "thread2: lock mutex 0");
+
+ thread_state[data] = 1;
+
+ if( m0.lock() )
+ {
+ thread_state[data] = 2;
+
+ CYG_TEST_INFO( "thread2: lock mutex 0 - returned TRUE");
+ CYG_TEST_FAIL_FINISH(" m0.lock() returned TRUE" );
+ }
+ else
+ {
+ thread_state[data] = 3;
+ CYG_TEST_INFO( "thread2: lock mutex 0 - returned FALSE");
+ }
+
+ CYG_TEST_INFO( "thread2: exit");
+
+ thread[data]->exit();
+}
+
+// ------------------------------------------------------------------------
+
+static void entry3( CYG_ADDRWORD data )
+{
+
+ CHECK( thread_state[0] == 1 );
+ CHECK( thread_state[1] == 2 );
+ CHECK( thread_state[2] == 1 );
+
+ CYG_TEST_INFO( "thread3: signal cvar 0");
+
+ cvar0.signal();
+
+ CHECK( thread_state[0] == 1 );
+ CHECK( thread_state[1] == 2 );
+ CHECK( thread_state[2] == 1 );
+
+ CYG_TEST_INFO( "thread3: release mutex 0");
+
+ m0.release();
+
+ CHECK( thread_state[0] == 1 );
+ CHECK( thread_state[1] == 2 );
+ CHECK( thread_state[2] == 3 );
+
+ CYG_TEST_INFO( "thread3: signal cvar 2");
+
+ cvar2.signal();
+
+ CHECK( thread_state[0] == 3 );
+ CHECK( thread_state[1] == 5 );
+ CHECK( thread_state[2] == 3 );
+
+ CYG_TEST_PASS_FINISH( "mutex2 finished OK");
+
+ CYG_TEST_INFO( "thread3: exit");
+
+ thread[data]->exit();
+}
+
+// ------------------------------------------------------------------------
+
+void mutex2_main( void )
+{
+ CYG_TEST_INIT();
+
+ new_thread(entry0, 0);
+ new_thread(entry1, 1);
+ new_thread(entry2, 2);
+ new_thread(entry3, 3);
+
+ // Set priorities from the top to prevent two threads getting
+ // the same priority: this causes an ASSERT on some configurations.
+ thread[3]->set_priority( 5 );
+ thread[2]->set_priority( 4 );
+ thread[1]->set_priority( 3 );
+ thread[0]->set_priority( 2 );
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+// ------------------------------------------------------------------------
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ mutex2_main();
+}
+
+// ------------------------------------------------------------------------
+
+#else // CYGPKG_KERNEL_SMP_SUPPORT
+
+// ------------------------------------------------------------------------
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Mutex2 test requires: !defined(CYGPKG_KERNEL_SMP_SUPPORT)");
+
+}
+
+// ------------------------------------------------------------------------
+
+#endif // CYGPKG_KERNEL_SMP_SUPPORT
+
+// ------------------------------------------------------------------------
+// EOF mutex2.cxx
diff --git a/ecos/packages/kernel/current/tests/mutex3.cxx b/ecos/packages/kernel/current/tests/mutex3.cxx
new file mode 100644
index 0000000000..7abeec8af3
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/mutex3.cxx
@@ -0,0 +1,631 @@
+//==========================================================================
+//
+// mutex3.cxx
+//
+// Mutex test 3 - priority inheritance
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): hmt
+// Contributors: hmt
+// Date: 2000-01-06
+// Description: Tests mutex priority inheritance
+//####DESCRIPTIONEND####
+
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start()
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+
+#include <cyg/kernel/mutex.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/thread.inl>
+
+#include <cyg/infra/diag.h> // diag_printf
+
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+externC void
+cyg_hal_invoke_constructors();
+#endif
+
+// ------------------------------------------------------------------------
+//
+// These checks should be enough; any other scheduler which has priorities
+// should manifest as having no priority inheritance, but otherwise fine,
+// so the test should work correctly.
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \
+ (CYGNUM_KERNEL_SCHED_PRIORITIES > 20) && \
+ !defined(CYGPKG_KERNEL_SMP_SUPPORT)
+
+// ------------------------------------------------------------------------
+// Manufacture a simpler feature test macro for priority inheritance than
+// the configuration gives us. We have priority inheritance if it is configured
+// as the only protocol, or if it is the default protocol for dynamic protocol
+// choice.
+// FIXME: If we have dynamic protocol choice, we can also set priority inheritance
+// as the protocol to be used on the mutexes we are interested in. At present we
+// do not do this.
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT
+# define PRIORITY_INHERITANCE "dynamic-default-inherit"
+# endif
+# else
+# define PRIORITY_INHERITANCE "static-inherit"
+# endif
+#endif
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING
+# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_CEILING
+# if CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY <= 5
+# define PRIORITY_INHERITANCE "dynamic-default-ceiling-high"
+# elif CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY >= 15
+# define NO_PRIORITY_INHERITANCE "dynamic-default-ceiling-low"
+# else
+# define PRIORITY_UNKNOWN "dynamic-default-ceiling-mid"
+# endif
+# endif
+# else
+# if CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY <= 5
+# define PRIORITY_INHERITANCE "static-ceiling-high"
+# elif CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY >= 15
+# define NO_PRIORITY_INHERITANCE "static-ceiling-low"
+# else
+# define PRIORITY_UNKNOWN "static-ceiling-mid"
+# endif
+# endif
+#endif
+
+#ifndef PRIORITY_INHERITANCE
+# ifndef NO_PRIORITY_INHERITANCE
+# define NO_PRIORITY_INHERITANCE "no scheme selected"
+# endif
+#endif
+
+// ------------------------------------------------------------------------
+// Management functions
+//
+// Stolen from testaux.hxx and copied in here because I want to be able to
+// reset the world also.
+
+#define NTHREADS 7
+
+inline void *operator new(size_t size, void *ptr) { return ptr; };
+
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static Cyg_Thread *thread[NTHREADS] = { 0 };
+
+typedef CYG_WORD64 CYG_ALIGNMENT_TYPE;
+
+static CYG_ALIGNMENT_TYPE thread_obj[NTHREADS] [
+ (sizeof(Cyg_Thread)+sizeof(CYG_ALIGNMENT_TYPE)-1)
+ / sizeof(CYG_ALIGNMENT_TYPE) ];
+
+static CYG_ALIGNMENT_TYPE stack[NTHREADS] [
+ (STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1)
+ / sizeof(CYG_ALIGNMENT_TYPE) ];
+
+static volatile int nthreads = 0;
+
+static Cyg_Thread *new_thread( cyg_thread_entry *entry,
+ CYG_ADDRWORD data,
+ CYG_ADDRWORD priority,
+ int do_resume )
+{
+ int _nthreads = nthreads++;
+
+ CYG_ASSERT(_nthreads < NTHREADS,
+ "Attempt to create more than NTHREADS threads");
+
+ thread[_nthreads] = new( (void *)&thread_obj[_nthreads] )
+ Cyg_Thread(priority,
+ entry, data,
+ NULL, // no name
+ (CYG_ADDRESS)stack[_nthreads], STACKSIZE );
+
+ if ( do_resume )
+ thread[_nthreads]->resume();
+
+ return thread[_nthreads];
+}
+
+
+static void kill_threads( void )
+{
+ CYG_ASSERT(nthreads <= NTHREADS,
+ "More than NTHREADS threads");
+ CYG_ASSERT( Cyg_Thread::self() == thread[0],
+ "kill_threads() not called from thread 0");
+ while ( nthreads > 1 ) {
+ nthreads--;
+ if ( NULL != thread[nthreads] ) {
+ thread[nthreads]->kill();
+ thread[nthreads]->~Cyg_Thread();
+ thread[nthreads] = NULL;
+ }
+ }
+ CYG_ASSERT(nthreads == 1,
+ "No threads left");
+}
+
+// ------------------------------------------------------------------------
+
+#define DELAYFACTOR 1 // for debugging
+
+// ------------------------------------------------------------------------
+
+static Cyg_Mutex mutex;
+
+// These are for reporting back to the master thread
+volatile int got_it = 0;
+volatile int t3ran = 0;
+volatile int t3ended = 0;
+volatile int extras[4] = {0,0,0,0};
+
+volatile int go_flag = 0; // but this one controls thread 3 from thread 2
+
+// ------------------------------------------------------------------------
+// 0 to 3 of these run generally to interfere with the other processing,
+// to cause multiple prio inheritances, and clashes in any orders.
+
+static void extra_thread( CYG_ADDRWORD data )
+{
+#define XINFO( z ) \
+ do { z[13] = '0' + data; CYG_TEST_INFO( z ); } while ( 0 )
+
+ static char running[] = "Extra thread Xa running";
+ static char exiting[] = "Extra thread Xa exiting";
+ static char resumed[] = "Extra thread Xa resumed";
+ static char locked[] = "Extra thread Xa locked";
+ static char unlocked[] = "Extra thread Xa unlocked";
+
+ XINFO( running );
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ self->suspend();
+
+ XINFO( resumed );
+
+ mutex.lock();
+
+ XINFO( locked );
+
+ mutex.unlock();
+
+ XINFO( unlocked );
+
+ extras[ data ] ++;
+
+ XINFO( exiting );
+
+}
+
+// ------------------------------------------------------------------------
+
+static void t1( CYG_ADDRWORD data )
+{
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ CYG_TEST_INFO( "Thread 1 running" );
+
+ self->suspend();
+
+ mutex.lock();
+
+ got_it++;
+
+ CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,1]" );
+
+ mutex.unlock();
+
+ CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,2]" );
+
+ // That's all.
+
+ CYG_TEST_INFO( "Thread 1 exit" );
+}
+
+// ------------------------------------------------------------------------
+
+static void t2( CYG_ADDRWORD data )
+{
+ Cyg_Thread *self = Cyg_Thread::self();
+ int i;
+ cyg_tick_count then, now;
+
+
+ CYG_TEST_INFO( "Thread 2 running" );
+
+ CYG_TEST_CHECK( 0 == (data & ~0x77), "Bad T2 arg: extra bits" );
+ CYG_TEST_CHECK( 0 == (data & (data >> 4)), "Bad T2 arg: overlap" );
+
+ self->suspend();
+
+ // depending on our config argument, optionally restart some of the
+ // extra threads to throw noise into the scheduler:
+ for ( i = 0; i < 3; i++ )
+ if ( (1 << i) & data ) // bits 0-2 control
+ thread[i+4]->resume(); // made sure extras are thread[4-6]
+
+ self->delay( DELAYFACTOR * 10 ); // let those threads run
+
+ Cyg_Scheduler::lock(); // do this next lot atomically
+
+ go_flag = 1; // unleash thread 3
+ thread[1]->resume(); // resume thread 1
+
+ // depending on our config argument, optionally restart some of the
+ // extra threads to throw noise into the scheduler at this later point:
+ for ( i = 4; i < 7; i++ )
+ if ( (1 << i) & data ) // bits 4-6 control
+ thread[i]->resume(); // made sure extras are thread[4-6]
+
+ Cyg_Scheduler::unlock(); // let scheduling proceed
+
+ // Need a delay (but not a CPU yield) to allow t3 to awaken and act on
+ // the go_flag, otherwise we check these details below too soon.
+ // Actually, waiting for the clock to tick a couple of times would be
+ // better, so that is what we will do. Must be a busy-wait.
+ then = Cyg_Clock::real_time_clock->current_value();
+ do {
+ now = Cyg_Clock::real_time_clock->current_value();
+ // Wait longer than the delay in t3 waiting on go_flag
+ } while ( now < (then + 3) );
+
+#ifdef PRIORITY_UNKNOWN
+ CYG_TEST_INFO( "Not checking: " PRIORITY_UNKNOWN );
+#else
+#ifdef PRIORITY_INHERITANCE
+ CYG_TEST_INFO( "Checking priority scheme: " PRIORITY_INHERITANCE );
+ CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" );
+ CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+#else
+ CYG_TEST_INFO( "Checking NO priority scheme: " NO_PRIORITY_INHERITANCE );
+ CYG_TEST_CHECK( 0 == t3ran, "Thread 3 DID run" );
+ CYG_TEST_CHECK( 0 == got_it, "Thread 1 DID get the mutex" );
+#endif
+#endif
+
+ CYG_TEST_CHECK( 0 == t3ended, "Thread 3 ended prematurely [T2,1]" );
+
+ self->delay( DELAYFACTOR * 20 ); // let those threads run
+
+ CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" );
+ CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+ CYG_TEST_CHECK( 1 == t3ended, "Thread 3 has not ended" );
+
+ for ( i = 0; i < 3; i++ )
+ if ( (1 << i) & (data | data >> 4) ) // bits 0-2 and 4-6 control
+ CYG_TEST_CHECK( 1 == extras[i+1], "Extra thread did not run" );
+ else
+ CYG_TEST_CHECK( 0 == extras[i+1], "Extra thread ran" );
+
+ CYG_TEST_PASS( "Thread 2 exiting, AOK" );
+ // That's all: restart the control thread.
+ thread[0]->resume();
+}
+
+// ------------------------------------------------------------------------
+
+static void t3( CYG_ADDRWORD data )
+{
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ CYG_TEST_INFO( "Thread 3 running" );
+
+ mutex.lock();
+
+ self->delay( DELAYFACTOR * 5 ); // let thread 3a run
+
+ thread[2]->resume(); // resume thread 2
+
+ while ( 0 == go_flag )
+ self->delay(1); // wait until we are told to go
+
+ t3ran ++; // record the fact
+
+ CYG_TEST_CHECK( 0 == got_it, "Thread 1 claims to have got my mutex" );
+
+ mutex.unlock();
+
+ t3ended ++; // record that we came back
+
+ CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" );
+
+ CYG_TEST_INFO( "Thread 3 exit" );
+}
+
+// ------------------------------------------------------------------------
+
+static void control_thread( CYG_ADDRWORD data )
+{
+ Cyg_Thread *self = Cyg_Thread::self();
+ int i;
+
+ CYG_TEST_INIT();
+ CYG_TEST_INFO( "Control Thread running" );
+
+ // Go through the 27 possibilitied of resuming the extra threads
+ // 0: not at all
+ // 1: early in the process
+ // 2: later on
+ // which are represented by bits 0-3 and 4-6 resp in the argument to
+ // thread 2 (none set means no resume at all).
+ for ( i = 0; i < 27; i++ ) {
+ static int xx[] = { 0, 1, 16 };
+ int j = i % 3;
+ int k = (i / 3) % 3;
+ int l = (i / 9) % 3;
+
+ int d = xx[j] | (xx[k]<<1) | (xx[l]<<2) ;
+
+ if ( cyg_test_is_simulator && (0 != i && 13 != i && 26 != i) )
+ continue; // 13 is 111 base 3, 26 is 222 base 3
+
+#ifdef PRIORITY_INHERITANCE
+ // If the simple scheme plus relay enhancement, or any other
+ // *complete* scheme, we can run all three ancillary threads no
+ // problem, so no special action here.
+
+#else
+ // If no priority inheritance at all, running threads 1a and 2a is
+ // OK, but not thread 3a; it blocks the world.
+ if ( l ) // Cannot run thread 3a if no
+ break; // priority inheritance at all.
+#endif
+
+ mutex = Cyg_Mutex(); // Reinitialize this
+
+ got_it = 0;
+ t3ran = 0;
+ t3ended = 0;
+ for ( int z = 0; z < 4; z++ ) extras[z] = 0;
+ go_flag = 0;
+
+ new_thread( t1, 0, 5, 1 ); // Slot 1
+ new_thread( t2, d, 10, 1 ); // Slot 2
+ new_thread( t3, 0, 15, 1 ); // Slot 3
+
+ new_thread( extra_thread, 1, 8, j ); // Slot 4
+ new_thread( extra_thread, 2, 12, k ); // Slot 5
+ new_thread( extra_thread, 3, 17, l ); // Slot 6
+
+ {
+ static char *a[] = { "inactive", "run early", "run late" };
+ diag_printf( "\n----- [%2d] New Cycle: 0x%02x, Threads 1a %s, 2a %s, 3a %s -----\n",
+ i, d, a[j], a[k], a[l] );
+ }
+
+ self->suspend();
+
+ kill_threads();
+ mutex.~Cyg_Mutex();
+ }
+ CYG_TEST_EXIT( "Control Thread exit" );
+}
+
+// ------------------------------------------------------------------------
+
+externC void
+cyg_user_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ new_thread( control_thread, 0, 2, 1 );
+}
+
+#else // CYGVAR_KERNEL_COUNTERS_CLOCK &c
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_INFO("Mutex3 test requires:\n"
+ "CYGVAR_KERNEL_COUNTERS_CLOCK &&\n"
+ "(CYGNUM_KERNEL_SCHED_PRIORITIES > 20) &&\n"
+ "!defined(CYGPKG_KERNEL_SMP_SUPPORT)\n");
+ CYG_TEST_NA("Mutex3 test requirements");
+}
+#endif // CYGVAR_KERNEL_COUNTERS_CLOCK &c
+
+
+// ------------------------------------------------------------------------
+// Documentation: enclosed is the design of this test.
+//
+// It has been carefully constructed so that it does NOT use other kernel
+// facilities (aside from delay-task) to test that priority inheritance is
+// working, or not, as intended by the configuration.
+//
+// These notes describe the flow of control in one run of the test with the
+// ancillary tasks optionally interspersed. The details of how those extra
+// tasks are or are not allowed to run are not described.
+//
+//
+//
+// The only change in the test that depends on whether there is inheritance or
+// not is the check in thread 2 on "3-ran" and "got it" flags marked ****
+//
+//
+// volatile &c booleans:
+// "got it" = FALSE
+// "3-ran" = FALSE
+// "3-ended" = FALSE
+// "extras"[3] = FALSE
+//
+// thread 1. prio 5, self-suspend.
+//
+// thread 1a, prio 8, self-suspend.
+//
+// thread 2. prio 10, self-suspend.
+//
+// thread 2a, prio 12, self-suspend.
+//
+// thread 3. prio 15, runs, lock mutex, resume(2)
+//
+// thread 3a, prio 17, self-suspend.
+//
+// 2. runs,
+// 2. resume(3a) +++OPTIONAL
+// 2. resume(2a) +++OPTIONAL
+// 2. resume(1a) +++OPTIONAL
+// [1a lock-fail] thread 3->prio := 8
+//
+// [3. runs maybe, does the looping thing]
+//
+// 2. sleep a while...
+//
+// [2a lock-fail] thread 3->prio := 12
+//
+// [3. runs maybe, does the looping thing]
+//
+// [3a lock-fail] thread 3->prio unchanged
+//
+// [3. runs maybe, does the looping thing]
+//
+// 2. lock scheduler
+// 2. set "go-flag"
+// 2. resume(1)
+// 2. resume(1a) +++OPTIONAL
+// 2. resume(2a) +++OPTIONAL
+// 2. resume(3a) +++OPTIONAL
+// 2. unlock scheduler
+//
+// 1. runs, lock mutex - thread 3 has it locked
+//
+// 2. busy-waits a bit for thread 3 to come out of its delay() loop.
+// This must be a *busy*wait so that 3 can only run via the
+// inherited raised priority.
+//
+// [xa. all do the same: lock mutex, ]
+// [xa. unlock mutex ]
+// [xa. set a flag "extras"[x] to say we are done. ]
+// [xa. exit ]
+//
+//
+//
+// INHERIT
+// -------
+//
+// thread 3->prio := 5
+//
+// 3. runs,
+// 3. set a flag to say "3-ran",
+// 3. loop with a sleep(1) until "go-flag" is set.
+// 3. check "got it" is false,
+// 3. then unlock mutex,
+//
+// thread 3->prio := 15
+//
+// 1. runs, set a flag to say "got it",
+// 1. check "3-ended" flag is false
+// 1. unlock mutex,
+// 1. check "3-ended" flag is still false
+// 1. exit.
+//
+// [1a locks, unlocks, exits]
+//
+// 2. runs, check "3-ran" and "got it" flags are TRUE ****
+// 2. check "3-ended" flag is false
+// 2. sleeps for a while so that...
+//
+// [2a locks, unlocks, exits]
+//
+// 3. runs, set "3-ended" flag,
+// 3. check "3-ran" and "got it" flags
+// 3. exit
+//
+// [3a locks, unlocks, exits]
+//
+// 2. awakens, checks all flags true,
+// 2. check that all "extra" threads that we started have indeed run
+// 2. end of test.
+//
+//
+//
+//
+// NO-INHERIT
+// ----------
+// thread 1 is waiting on the mutex
+//
+// [1a lock-fail]
+//
+// 2. runs, checks that "3-ran" and "got it" flags are FALSE ****
+// 2. check "3-ended" flag is false
+// 2. sleeps for a while so that...
+//
+// [2a. lock-fail]
+//
+// 3. runs, set a flag to say "3-ran",
+// 3. check "got it" is false,
+// 3. then unlock mutex,
+//
+// 1. runs, set a flag to say "got it",
+// 1. check "3-ended" flag is false
+// 1. unlock mutex,
+// 1. check "3-ended" flag is still false
+// 1. exit.
+//
+// [1a locks, unlocks, exits]
+// [2a locks, unlocks, exits]
+//
+// 3. runs, set "3-ended" flag,
+// 3. check "3-ran" and "got it" flags
+// 3. exit
+//
+// [3a locks, unlocks, exits]
+//
+// 2. awakens, checks all flags true,
+// 2. check that all "extra" threads that we started have indeed run
+// 2. end of test.
+//
+//
+// (the end)
+//
+//
+// ------------------------------------------------------------------------
+
+// EOF mutex3.cxx
diff --git a/ecos/packages/kernel/current/tests/philo.cxx b/ecos/packages/kernel/current/tests/philo.cxx
new file mode 100644
index 0000000000..892d0db72a
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/philo.cxx
@@ -0,0 +1,241 @@
+//==========================================================================
+//
+// philo.cxx
+//
+// A test of the dining philosophers problem
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-24
+// Description: A test of the dining philosophers problem
+//####DESCRIPTIONEND####
+//
+
+#include <cyg/kernel/kernel.hxx>
+
+#include <cyg/hal/hal_io.h>
+
+// -------------------------------------------------------------------------
+// Data for the philosophers problem
+
+#define PHILOSOPHERS 15 // number of philosophers
+#define STACKSIZE (2*1024) // size of thread stack
+
+#define NTHREADS PHILOSOPHERS
+#include "testaux.hxx"
+
+// array of chopsticks
+Cyg_Binary_Semaphore chopstick[PHILOSOPHERS];
+
+
+//cyg_thread_entry Philosopher;
+
+// -------------------------------------------------------------------------
+// State recording and display
+
+static char pstate[PHILOSOPHERS+1]; // state vector showing what each
+ // philosopher is doing
+
+Cyg_Mutex state_mutex;
+
+#ifdef CYG_HAL_MN10300_MN103002
+static cyg_count8 eaters = 0;
+#endif
+
+void change_state(int id, char newstate)
+{
+ CYG_INSTRUMENT_USER( 1, 0, 0);
+ state_mutex.lock();
+ CYG_INSTRUMENT_USER( 2, 0, 0);
+
+#ifdef CYG_HAL_MN10300_MN103002
+ if( pstate[id] == 'E' ) eaters--;
+ if( newstate == 'E' ) eaters++;
+// led(eaters);
+#endif
+
+ pstate[id] = newstate;
+
+ diag_write_string(pstate);
+#if 0
+ diag_write_char(' ');
+ diag_write_dec(Cyg_Scheduler::get_thread_switches());
+#endif
+ diag_write_char('\n');
+
+ CYG_INSTRUMENT_USER( 3, 0, 0);
+ state_mutex.unlock();
+ CYG_INSTRUMENT_USER( 4, 0, 0);
+
+}
+
+char get_state( int id)
+{
+ state_mutex.lock();
+
+ char s = pstate[id];
+
+ state_mutex.unlock();
+
+ return s;
+}
+
+// -------------------------------------------------------------------------
+// Thread to behave like a philosopher
+
+void Philosopher( CYG_ADDRESS id )
+{
+ Cyg_Thread *self = Cyg_Thread::self();
+ Cyg_Binary_Semaphore *first_stick = &chopstick[id];
+ Cyg_Binary_Semaphore *second_stick = &chopstick[(id+1)%PHILOSOPHERS];
+#ifdef CYGPKG_INFRA_DEBUG
+ int left_philo = ((id==0)?PHILOSOPHERS:id)-1;
+ int right_philo = (id==PHILOSOPHERS-1)?0:(id+1);
+#endif
+
+ CYG_ASSERT( id >= 0 && id < PHILOSOPHERS, "Bad id");
+
+ // Deadlock avoidance. The easiest way to make the philosophers
+ // behave is to make each pick up the lowest numbered stick
+ // first. This is how it works out anyway for all the philosophers
+ // except the last, who must have his sticks swapped.
+
+ if( id == PHILOSOPHERS-1 )
+ {
+ Cyg_Binary_Semaphore *t = first_stick;
+ first_stick = second_stick;
+ second_stick = t;
+ }
+
+ // The following variable is shared by all philosophers.
+ // It is incremented unprotected, but this does not matter
+ // since it is only present to introduce a little variability
+ // into the think and eat times.
+
+ static int cycle = 0;
+
+ for(;;)
+ {
+ // Think for a bit
+
+ self->delay((id+cycle++)%12); // Cogito ergo sum...
+
+ // I am now hungry, try to get the chopsticks
+
+ change_state(id,'H');
+
+ // Get the first stick
+ CYG_INSTRUMENT_USER( 5, 0, 0);
+ first_stick->wait();
+ CYG_INSTRUMENT_USER( 6, 0, 0);
+
+ // Get the second stick
+ CYG_INSTRUMENT_USER( 7, 0, 0);
+ second_stick->wait();
+ CYG_INSTRUMENT_USER( 8, 0, 0);
+
+ // Got them, now eat
+
+ change_state(id,'E');
+
+ // Check that the world is as I think it is...
+ CYG_ASSERT( !first_stick->posted(), "Not got first stick");
+ CYG_ASSERT( !second_stick->posted(), "Not got second stick");
+ CYG_ASSERT( get_state(left_philo) != 'E', "Left neighbour also eating!!");
+ CYG_ASSERT( get_state(right_philo) != 'E', "Right neighbour also eating!!");
+
+ self->delay((id+cycle++)%6); // munch munch
+
+ // Finished eating, put down sticks.
+
+ change_state(id,'T');
+
+ CYG_INSTRUMENT_USER( 9, 0, 0);
+ first_stick->post();
+ CYG_INSTRUMENT_USER( 10, 0, 0);
+ second_stick->post();
+ CYG_INSTRUMENT_USER( 11, 0, 0);
+
+// Cyg_Scheduler::lock();
+// Cyg_Scheduler::unlock();
+ CYG_INSTRUMENT_USER( 12, 0, 0);
+
+ }
+}
+
+// -------------------------------------------------------------------------
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ diag_init();
+
+ diag_write_string("Philosophers\n");
+ diag_write_string("Started\n");
+
+ // Zero last element in state so it acts like
+ // a string.
+ pstate[PHILOSOPHERS] = 0;
+
+#if 1
+ for( int i = 0; i < PHILOSOPHERS; i++ )
+ {
+ change_state(i,'T'); // starting state
+
+ // Start the philosopher
+ Cyg_Thread *t = new_thread( Philosopher, i );
+
+ // resume it
+ t->resume();
+
+ // and make the matching chopstick present
+ chopstick[i].post();
+ }
+#endif
+
+ // Get the world going
+ Cyg_Scheduler::scheduler.start();
+
+}
+
+// -------------------------------------------------------------------------
+// EOF philo.cxx
diff --git a/ecos/packages/kernel/current/tests/release.cxx b/ecos/packages/kernel/current/tests/release.cxx
new file mode 100644
index 0000000000..e65a46e605
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/release.cxx
@@ -0,0 +1,129 @@
+//==========================================================================
+//
+// release.cxx
+//
+// Thread release test
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1998-04-24
+// Description: Tests the functionality of thread release().
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/mutex.hxx>
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+
+#define NTHREADS 2
+
+#include "testaux.hxx"
+
+static Cyg_Binary_Semaphore s0, s1;
+
+static void entry0( CYG_ADDRWORD data )
+{
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ if (!s0.wait() )
+ {
+ if( self->get_wake_reason() != Cyg_Thread::BREAK )
+ CYG_TEST_FAIL_FINISH("Wake reason not BREAK");
+ }
+ else
+ {
+ CYG_TEST_FAIL_FINISH("Thread not released");
+ }
+
+ s1.post();
+
+ self->exit();
+}
+
+
+static void entry1( CYG_ADDRWORD data )
+{
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ // Give the other thread a chance to wait in SMP systems.
+ for( int i = 0; i < 100; i++ )
+ self->yield();
+
+ thread[0]->release();
+
+ s1.wait();
+
+ CYG_TEST_PASS_FINISH("Release OK");
+
+ Cyg_Thread::self()->exit();
+}
+
+void release_main(void)
+{
+ CYG_TEST_INIT();
+
+ new_thread( entry0, 0);
+ new_thread( entry1, 1);
+
+ thread[0]->set_priority(5);
+ thread[1]->set_priority(6);
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ release_main();
+}
+
+// EOF release.cxx
diff --git a/ecos/packages/kernel/current/tests/sched1.cxx b/ecos/packages/kernel/current/tests/sched1.cxx
new file mode 100644
index 0000000000..6b8865d8ed
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/sched1.cxx
@@ -0,0 +1,111 @@
+//==========================================================================
+//
+// sched1.cxx
+//
+// Sched test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-26
+// Description: Tests some basic sched functions.
+// Omissions:
+// Doesn't test Cyg_Scheduler::get_thread_switches() very well
+// Cyg_SchedThread
+// inherit_priority
+// disinherit_priority
+// Options:
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/sched.hxx> // Cyg_Scheduler::start()
+#include <cyg/kernel/thread.hxx> // Cyg_Thread
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/thread.inl>
+
+#define NTHREADS 2
+
+#include "testaux.hxx"
+
+static void entry0( CYG_ADDRWORD data )
+{
+ CHECK( 0 == Cyg_Scheduler::get_sched_lock() );
+ Cyg_Scheduler::lock(); {
+ CHECK( 1 == Cyg_Scheduler::get_sched_lock() );
+ Cyg_Scheduler::lock(); {
+ CHECK( 2 == Cyg_Scheduler::get_sched_lock() );
+ } Cyg_Scheduler::unlock();
+ } Cyg_Scheduler::unlock();
+ cyg_ucount32 t0=Cyg_Scheduler::get_thread_switches();
+ cyg_ucount32 t1=Cyg_Scheduler::get_thread_switches();
+ CHECK( t1 >= t0 );
+ CHECK( Cyg_Scheduler::get_current_thread() ==
+ Cyg_Thread::self() );
+ CYG_TEST_PASS_FINISH( "Sched 1 OK");
+}
+
+static void entry1( CYG_ADDRWORD data )
+{
+ Cyg_Thread::self()->sleep();
+}
+
+void sched1_main(void)
+{
+ CYG_TEST_INIT();
+
+ new_thread(entry0, 222);
+ new_thread(entry1, 333);
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ sched1_main();
+}
+// EOF sched1.cxx
diff --git a/ecos/packages/kernel/current/tests/smp.cxx b/ecos/packages/kernel/current/tests/smp.cxx
new file mode 100644
index 0000000000..5f35abed41
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/smp.cxx
@@ -0,0 +1,474 @@
+//==========================================================================
+//
+// smp.cxx
+//
+// SMP tests
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: Some basic SMP tests.
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/hal.h>
+
+#if 1
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/mutex.hxx>
+#include <cyg/kernel/sema.hxx>
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/clock.hxx>
+#include <cyg/kernel/clock.inl>
+#endif
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+
+//==========================================================================
+
+#if defined(CYGPKG_KERNEL_SMP_SUPPORT) && \
+ defined(CYGFUN_KERNEL_API_C) && \
+ defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \
+ defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \
+ !defined(CYGPKG_HAL_I386_LINUX) && \
+ !defined(CYGDBG_INFRA_DIAG_USE_DEVICE) && \
+ (CYGNUM_KERNEL_SCHED_PRIORITIES > 12)
+
+//==========================================================================
+
+#define NTHREADS 1
+#include "testaux.hxx"
+
+#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+#define NTHREADS_MAX (CYGNUM_KERNEL_CPU_MAX*3)
+
+static int ncpus = CYGNUM_KERNEL_CPU_MAX;
+static int nthread = NTHREADS_MAX;
+
+static char stacks[NTHREADS_MAX][STACK_SIZE];
+static cyg_thread test_threads[NTHREADS_MAX];
+static cyg_handle_t threads[NTHREADS_MAX];
+
+static volatile cyg_uint32 cpu_run[CYGNUM_KERNEL_CPU_MAX];
+static volatile int failed = false;
+static volatile cyg_uint32 cpu_thread[CYGNUM_KERNEL_CPU_MAX];
+
+static volatile cyg_uint32 slicerun[NTHREADS_MAX][CYGNUM_KERNEL_CPU_MAX];
+
+
+static cyg_mutex_t mx;
+
+
+//==========================================================================
+// Compute a name for a thread
+char *
+thread_name(char *basename, int indx) {
+ return "<<NULL>>"; // Not currently used
+}
+
+//==========================================================================
+
+void
+test_thread_cpu(CYG_ADDRESS id)
+{
+ for(;;)
+ cpu_run[CYG_KERNEL_CPU_THIS()] = true;
+}
+
+//==========================================================================
+// First test: just run as many threads as CPUs and check that we
+// get to run on each CPU.
+
+void run_smp_test_cpus()
+{
+ int i;
+
+ CYG_TEST_INFO( "CPU Test: Check CPUs functional");
+
+ // Init flags.
+ for (i = 0; i < ncpus; i++)
+ cpu_run[i] = false;
+
+ // Set my priority higher than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+
+ for (i = 0; i < ncpus; i++) {
+ cyg_thread_create(10, // Priority - just a number
+ test_thread_cpu, // entry
+ i, // index
+ thread_name("thread", i), // 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( 10 );
+
+ // Delete all the threads
+ for (i = 0; i < ncpus; i++) {
+ cyg_thread_delete(threads[i]);
+ }
+
+ // And check that a thread ran on each CPU
+ for (i = 0; i < ncpus; i++) {
+// CYG_TEST_CHECK( cpu_run[i], "CPU didn't run");
+ if( !cpu_run[i] )
+ {
+ CYG_TEST_INFO( "CPU didn't run" );
+ failed++;
+ }
+ }
+
+ CYG_TEST_INFO( "CPU Test: done");
+}
+
+
+//==========================================================================
+
+void
+test_thread_pri(CYG_ADDRESS id)
+{
+ for(;;)
+ {
+ cpu_thread[CYG_KERNEL_CPU_THIS()] = id;
+ }
+}
+
+//==========================================================================
+// Second test: Run a thread on each CPU and then by manipulating the
+// priorities, get the current thread to migrate to each CPU in turn.
+
+
+void run_smp_test_pri()
+{
+ int i;
+
+ CYG_TEST_INFO( "Pri Test: Check set_priority functionality");
+
+ // Init flags.
+ for (i = 0; i < ncpus; i++)
+ cpu_run[i] = false;
+
+ // Set my priority higher than any I plan to creat
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+
+ for (i = 0; i < ncpus; i++) {
+ cyg_thread_create(10, // Priority - just a number
+ test_thread_pri, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ cyg_thread_resume( threads[i]);
+ }
+
+ cyg_thread_delay( 2 );
+
+ cyg_handle_t cthread = threads[0];
+ cyg_thread_set_priority(cthread, 25);
+
+ // Just wait a while, until the threads have all run for a bit.
+ cyg_thread_delay( 2 );
+
+ for (i = 0; i < ncpus*500; i++)
+ {
+ HAL_SMP_CPU_TYPE cpu = i % CYG_KERNEL_CPU_COUNT();
+
+ if( cpu != CYG_KERNEL_CPU_THIS() )
+ {
+ // At this point we have the current thread running on a
+ // CPU at priority 2, ncpus-1 threads running at priority
+ // 10 and the last thread (cthread) in the run queue at
+ // priority 25.
+
+ // Pick a thread on a different CPU
+ cyg_handle_t dthread;
+
+ do
+ {
+ dthread = threads[cpu_thread[cpu]];
+ } while( dthread == cthread );
+
+ // Change the priority of the victim thread to 20. It is
+ // still higher priority than cthread so it will continue
+ // running.
+
+ cyg_thread_set_priority(dthread, 20);
+
+ // Now change our priority to 15. We are still higher
+ // priority that cthread so we will still run.
+
+ cyg_thread_set_priority(cyg_thread_self(), 15);
+
+ // Finally change the priority of cthread to 10. This will
+ // cause it to preempt us on the current CPU. In turn we
+ // will preempt dthread on its CPU.
+
+ // NOTE: This relies somewhat on the SMP scheduler doing
+ // what we expect here. Specifically, that it will preempt
+ // the current thread with cthread locally. A more
+ // sophisticated scheduler might decide that the most
+ // efficient thing to do is to preempt dthread with
+ // cthread remotely, leaving the current thread where it
+ // is. If we ever bother to implement this, then this test
+ // will need to change.
+
+ cyg_thread_set_priority(cthread, 10);
+
+ // Spin here a while until the scheduler sorts itself out.
+
+ for( int j = 0; j < 100000; j++ );
+
+ // Indicate that we have run on this CPU
+ cpu_run[CYG_KERNEL_CPU_THIS()]++;
+
+ // Restore our priority to 2 and depress dthread to 25 and
+ // make it the new cthread.
+
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+ cyg_thread_set_priority(dthread, 25);
+ cthread = dthread;
+ }
+ }
+
+
+ // Delete all the threads
+ for (i = 0; i < ncpus; i++) {
+ cyg_thread_delete(threads[i]);
+ }
+
+ // And check that a thread ran on each CPU
+ for (i = 0; i < ncpus; i++) {
+// CYG_TEST_CHECK( cpu_run[i], "CPU didn't run");
+ if( !cpu_run[i] )
+ {
+ CYG_TEST_INFO( "CPU didn't run" );
+ failed++;
+ }
+ }
+
+ CYG_TEST_INFO( "PRI Test: done");
+}
+
+//==========================================================================
+
+void
+test_thread_timeslice(CYG_ADDRESS id)
+{
+ for(;;)
+ slicerun[id][CYG_KERNEL_CPU_THIS()]++;
+}
+
+//==========================================================================
+// First test: just run as many threads as CPUs and check that we
+// get to run on each CPU.
+
+void run_smp_test_timeslice()
+{
+ int i;
+
+ CYG_TEST_INFO( "Timeslice Test: Check timeslicing works");
+
+ // Init flags.
+ for (i = 0; i < nthread; i++)
+ for( int 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
+ thread_name("thread", i), // 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( 200 );
+
+ // Delete all the threads
+ for (i = 0; i < nthread; i++) {
+ cyg_thread_suspend(threads[i]);
+ }
+
+
+ // And check that a thread ran on each CPU
+
+ cyg_uint32 cpu_total[ncpus];
+ cyg_uint32 cpu_threads[ncpus];
+ cyg_uint32 thread_total[nthread];
+
+ diag_printf(" Thread ");
+ for( int j = 0; j < ncpus; j++ )
+ {
+ cpu_total[j] = 0;
+ cpu_threads[j] = 0;
+ diag_printf(" CPU %2d",j);
+ }
+ diag_printf(" Total\n");
+ for (i = 0; i < nthread; i++)
+ {
+ thread_total[i] = 0;
+ diag_printf(" %2d ",i);
+ for( int 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(" %8d",slicerun[i][j]);
+ }
+ diag_printf("%8d\n",thread_total[i]);
+ }
+ diag_printf(" Total ");
+ for( int j = 0; j < ncpus; j++ )
+ diag_printf(" %8d",cpu_total[j]);
+ diag_printf("\n");
+ diag_printf("Threads ");
+ for( int j = 0; j < ncpus; j++ )
+ {
+ diag_printf(" %8d",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( "Timeslice Test: done");
+}
+
+
+//==========================================================================
+
+void
+run_smp_tests(CYG_ADDRESS id)
+{
+ cyg_mutex_init( &mx );
+
+ for( int i = 0; i < 100; i++ )
+ {
+ run_smp_test_cpus();
+ run_smp_test_pri();
+ run_smp_test_timeslice();
+ }
+
+ if( failed )
+ CYG_TEST_FAIL_FINISH("SMP tests failed\n");
+
+ CYG_TEST_PASS_FINISH("SMP tests OK");
+}
+
+//==========================================================================
+
+void smp_main( void )
+{
+ CYG_TEST_INIT();
+
+ // Work out how many CPUs we actually have.
+ ncpus = CYG_KERNEL_CPU_COUNT();
+
+ new_thread(run_smp_tests, 0);
+
+ 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
+ smp_main();
+}
+
+//==========================================================================
+
+#else // CYGPKG_KERNEL_SMP_SUPPORT etc.
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_INFO("SMP test requires:\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");
+}
+#endif // CYGPKG_KERNEL_SMP_SUPPORT etc.
+
+//==========================================================================
+// EOF tm_basic.cxx
diff --git a/ecos/packages/kernel/current/tests/stress_threads.c b/ecos/packages/kernel/current/tests/stress_threads.c
new file mode 100644
index 0000000000..daedf7f54b
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/stress_threads.c
@@ -0,0 +1,859 @@
+//==========================================================================
+//
+// stress_threads.cxx
+//
+// Basic thread stress test
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): rosalia
+// Contributors: rosalia, jskov
+// Date: 1999-04-13
+// Description: Very simple thread stress test, with some memory
+// allocation and alarm handling.
+//
+// Notes:
+// If client_makes_request is big, it means that there are made many more
+// client requests than can be serviced. Consequently, clients are wasting
+// CPU time and should be sleeping more.
+//
+// The list of handler invocations show how many threads are running
+// at the same time. The more powerful the CPU, the more the numbers
+// should spread out.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/system.h>
+#include <cyg/infra/testcase.h>
+
+#include <cyg/hal/hal_arch.h>
+
+#if defined(CYGPKG_KERNEL) && defined(CYGPKG_IO) && defined(CYGPKG_ISOINFRA)
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/isoinfra.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+
+#if defined(CYGFUN_KERNEL_API_C)
+
+#include <cyg/kernel/kapi.h>
+
+#ifdef CYGINT_ISO_STDIO_FORMATTED_IO
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(CYGPKG_LIBM)
+
+#include <math.h>
+#include <assert.h>
+
+#include <cyg/kernel/test/stackmon.h>
+
+#if defined(CYGFUN_KERNEL_THREADS_TIMER)
+#if CYGINT_ISO_MALLOC
+
+/* if TIME_LIMIT is defined, it represents the number of seconds this
+ test should last; if it is undefined the test will go forever */
+#define DEATH_TIME_LIMIT 20
+/* #undef DEATH_TIME_LIMIT */
+
+// STACK_SIZE is typical +2kB for printf family calls which use big
+// auto variables. Add more for handler which calls perform_stressful_tasks()
+#define STACK_SIZE (2*1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL)
+#define STACK_SIZE_HANDLER (STACK_SIZE + 30*CYGNUM_HAL_STACK_FRAME_SIZE)
+
+#define N_MAIN 1
+
+// If we have instrumentation enabled, make the execution time in the
+// simulator even shorter that we were going to anyway.
+#ifdef CYGPKG_KERNEL_INSTRUMENT
+#define SIM_DELAY_DIVISOR 100
+#else
+#define SIM_DELAY_DIVISOR 10
+#endif
+
+//-----------------------------------------------------------------------
+// Some targets need to define a smaller number of handlers due to
+// memory restrictions.
+#if defined(CYGMEM_REGION_ram_SIZE) && (CYGMEM_REGION_ram_SIZE < 0x80000)
+#define MAX_HANDLERS 4
+#define N_LISTENERS 1
+#define N_CLIENTS 1
+
+#undef STACK_SIZE
+#undef STACK_SIZE_HANDLER
+#define STACK_SIZE (1024 + CYGNUM_HAL_STACK_SIZE_TYPICAL)
+#define STACK_SIZE_HANDLER (STACK_SIZE + 10*CYGNUM_HAL_STACK_FRAME_SIZE)
+#endif
+
+//-----------------------------------------------------------------------
+// If no target specific definitions, use defaults
+#ifndef MAX_HANDLERS
+#define MAX_HANDLERS 19
+#define N_LISTENERS 4
+#define N_CLIENTS 4
+#endif
+
+/* Allocate priorities in this order. This ensures that handlers
+ (which are the ones using the CPU) get enough CPU time to actually
+ complete their tasks.
+
+ The empty space ensures that if libc main() thread should happen to
+ be in the priority range of the handlers, no handlers are
+ accidently reduced so much in priority to get below
+ listeners/clients. */
+
+#define P_MAIN_PROGRAM 1
+#define P_MAIN_PROGRAM_E (P_MAIN_PROGRAM+N_MAIN)
+
+#define P_BASE_HANDLER (P_MAIN_PROGRAM_E)
+#define P_BASE_HANDLER_E (P_BASE_HANDLER+MAX_HANDLERS)
+
+#define P_BASE_EMPTY (P_BASE_HANDLER_E)
+#define P_BASE_EMPTY_E (P_BASE_EMPTY+2)
+
+#define P_BASE_LISTENER (P_BASE_EMPTY_E)
+#define P_BASE_LISTENER_E (P_BASE_LISTENER+N_LISTENERS)
+
+#define P_BASE_CLIENT (P_BASE_LISTENER_E)
+#define P_BASE_CLIENT_E (P_BASE_CLIENT+N_CLIENTS)
+
+#define P_MAX (P_BASE_CLIENT_E)
+
+/* Ensure there's room for what we request */
+#if (CYGNUM_KERNEL_SCHED_PRIORITIES >= P_MAX)
+
+/* if we use the bitmap scheduler we must make sure we don't use the
+ same priority more than once, so we must store those already in use */
+static volatile char priority_in_use[P_MAX];
+
+/* We may not get the priority we ask for (scheduler may decide to ignore
+ schedule hint). So keep a table of priorities actually assigned to
+ the threads. This information may come in handy for debugging - it's
+ not actively used by the code. */
+static volatile int priority_translation[P_MAX];
+
+/* now declare (and allocate space for) some kernel objects, like the
+ threads we will use */
+cyg_thread main_thread_s;
+cyg_thread handler_thread_s[MAX_HANDLERS];
+cyg_thread listener_thread_s[N_LISTENERS];
+cyg_thread client_thread_s[N_CLIENTS];
+
+/* space for stacks for all threads */
+char main_stack[STACK_SIZE];
+char handler_stack[MAX_HANDLERS][STACK_SIZE_HANDLER];
+char listener_stack[N_LISTENERS][STACK_SIZE];
+char client_stack[N_CLIENTS][STACK_SIZE];
+
+/* now the handles for the threads */
+cyg_handle_t mainH;
+cyg_handle_t handlerH[MAX_HANDLERS];
+cyg_handle_t listenerH[N_LISTENERS];
+cyg_handle_t clientH[N_CLIENTS];
+
+/* space for thread names */
+char thread_name[P_MAX][20];
+
+/* and now variables for the procedure which is the thread */
+cyg_thread_entry_t main_program, client_program, listener_program,
+ handler_program;
+
+/* a few mutexes used in the code */
+cyg_mutex_t client_request_lock, handler_slot_lock, statistics_print_lock,
+ free_handler_lock;
+
+/* global variables with which the handler IDs and thread priorities
+ to free are communicated from handlers to main_program. Access to
+ these are protected by free_handler_lock. An id of -1 means the
+ that the variables are empty. */
+volatile int free_handler_pri = 0;
+volatile int free_handler_id = -1;
+
+/* a global variable with which the client and server coordinate */
+volatile int client_makes_request = 0;
+
+/* if this is true, clients will not make requests */
+volatile int clients_paused = 0;
+
+
+/* indicates that it's time to print out a report */
+volatile int time_to_report = 0;
+/* print status after a delay of this many secs. */
+int time_report_delay;
+
+/*** now application-specific variables ***/
+/* an array that stores whether the handler threads are in use */
+volatile int handler_thread_in_use[MAX_HANDLERS];
+/* total count of active handlers */
+volatile int handler_thread_in_use_count;
+
+
+/***** statistics-gathering variables *****/
+struct s_statistics {
+ /* store the number of times each handler has been invoked */
+ unsigned long handler_invocation_histogram[MAX_HANDLERS];
+
+ /* store how many times malloc has been attempted and how many times
+ it has failed */
+ unsigned long malloc_tries, malloc_failures;
+
+ /* how many threads have been created */
+ unsigned long thread_creations, thread_exits;
+};
+
+struct s_statistics statistics;
+
+/* some function prototypes; those with the sc_ prefix are
+ "statistics-collecting" versions of the cyg_ primitives */
+cyg_addrword_t sc_thread_create(
+ cyg_addrword_t sched_info, /* scheduling info (eg pri) */
+ cyg_thread_entry_t *entry, /* entry point function */
+ cyg_addrword_t entry_data, /* entry data */
+ char *name, /* optional thread name */
+ void *stack_base, /* stack base, NULL = alloc */
+ cyg_ucount32 stack_size, /* stack size, 0 = default */
+ cyg_handle_t *handle, /* returned thread handle */
+ cyg_thread *thread /* put thread here */
+ );
+
+void start_handler(void);
+void stop_handler(int handler_id, int handler_pri);
+void perform_stressful_tasks(void);
+void permute_array(char a[], int size, int seed);
+void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp,
+ cyg_alarm *death_alarm_p, int *killed_p);
+void print_statistics(int print_full);
+
+/* we need to declare the alarm handling function (which is defined
+ below), so that we can pass it to cyg_alarm_initialize() */
+cyg_alarm_t report_alarm_func, death_alarm_func;
+
+/* handle and alarm for the report alarm */
+cyg_handle_t report_alarmH, counterH, system_clockH;
+cyg_alarm report_alarm;
+
+/* main launches all the threads of the test */
+int
+main(void)
+{
+ int i;
+
+ CYG_TEST_INIT();
+ CYG_TEST_INFO("Stress threads test compiled on " __DATE__);
+
+ cyg_mutex_init(&client_request_lock);
+ cyg_mutex_init(&statistics_print_lock);
+ cyg_mutex_init(&free_handler_lock);
+
+ /* initialize statistics */
+ memset(&statistics, 0, sizeof(statistics));
+
+ /* clear priority table */
+ for (i = 0; i < sizeof(priority_in_use); i++)
+ priority_in_use[i] = 0;
+
+ /* initialize main thread */
+ {
+ priority_translation[P_MAIN_PROGRAM] =
+ sc_thread_create(P_MAIN_PROGRAM, main_program, (cyg_addrword_t) 0,
+ "main_program", (void *) main_stack, STACK_SIZE,
+ &mainH, &main_thread_s);
+ priority_in_use[P_MAIN_PROGRAM]++;
+ }
+
+ /* initialize all handler threads to not be in use */
+ for (i = 0; i < MAX_HANDLERS; ++i) {
+ handler_thread_in_use[i] = 0;
+ }
+ handler_thread_in_use_count = 0;
+ for (i = 0; i < N_LISTENERS; ++i) {
+ int prio = P_BASE_LISTENER + i;
+ char* name = &thread_name[prio][0];
+ sprintf(name, "listener-%02d", i);
+ priority_translation[prio] =
+ sc_thread_create(prio, listener_program, (cyg_addrword_t) i,
+ name, (void *) listener_stack[i], STACK_SIZE,
+ &listenerH[i], &listener_thread_s[i]);
+ CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
+ priority_in_use[prio]++;
+ }
+ for (i = 0; i < N_CLIENTS; ++i) {
+ int prio = P_BASE_CLIENT + i;
+ char* name = &thread_name[prio][0];
+ sprintf(name, "client-%02d", i);
+ priority_translation[prio] =
+ sc_thread_create(prio, client_program, (cyg_addrword_t) i,
+ name, (void *) client_stack[i], STACK_SIZE,
+ &(clientH[i]), &client_thread_s[i]);
+ CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
+ priority_in_use[prio]++;
+ }
+
+ cyg_thread_resume(mainH);
+ for (i = 0; i < N_CLIENTS; ++i) {
+ cyg_thread_resume(clientH[i]);
+ }
+ for (i = 0; i < N_LISTENERS; ++i) {
+ cyg_thread_resume(listenerH[i]);
+ }
+
+ /* set up the alarm which gives periodic wakeups to say "time to
+ print a report */
+ system_clockH = cyg_real_time_clock();
+ cyg_clock_to_counter(system_clockH, &counterH);
+
+ cyg_alarm_create(counterH, report_alarm_func,
+ (cyg_addrword_t) 4000,
+ &report_alarmH, &report_alarm);
+ if (cyg_test_is_simulator) {
+ time_report_delay = 2;
+ } else {
+ time_report_delay = 60;
+ }
+
+ cyg_alarm_initialize(report_alarmH, cyg_current_time()+200,
+ time_report_delay*100);
+
+ return 0;
+}
+
+/* main_program() -- frees resources and prints status. */
+void main_program(cyg_addrword_t data)
+{
+#ifdef DEATH_TIME_LIMIT
+ cyg_handle_t deathH;
+ cyg_alarm death_alarm;
+ int is_dead = 0;
+
+ setup_death_alarm(0, &deathH, &death_alarm, &is_dead);
+#endif /* DEATH_TIME_LIMIT */
+
+ for (;;) {
+ int handler_id = -1;
+ int handler_pri = 0;
+
+ cyg_mutex_lock(&free_handler_lock); {
+ // If any handler has left its ID, copy the ID and
+ // priority values to local variables, and free up the
+ // global communication variables again.
+ if (-1 != free_handler_id) {
+ handler_id = free_handler_id;
+ handler_pri = free_handler_pri;
+ free_handler_id = -1;
+ }
+ } cyg_mutex_unlock(&free_handler_lock);
+
+ if (-1 != handler_id) {
+ stop_handler(handler_id, handler_pri);
+ }
+
+ // If it's time to report status or quit, set pause flag and
+ // keep looping until all handlers have stopped.
+ if (time_to_report) {
+ // Pause clients
+ cyg_mutex_lock(&client_request_lock); {
+ clients_paused = 1;
+ } cyg_mutex_unlock(&client_request_lock);
+
+ // When all handlers have stopped, we can print statistics
+ // knowing that all (handler allocated) resources should have
+ // been freed. That is, we should be able to determine leaks.
+ if (0 == handler_thread_in_use_count) {
+ print_statistics(0);
+
+ // We've done the printing now. Resume the system.
+ time_to_report = 0;
+ cyg_mutex_lock(&client_request_lock); {
+ clients_paused = 0;
+ } cyg_mutex_unlock(&client_request_lock);
+ }
+ }
+
+#ifdef DEATH_TIME_LIMIT
+ // Stop test if time.
+ if (is_dead) {
+ // Pause clients
+ cyg_mutex_lock(&client_request_lock); {
+ clients_paused = 1;
+ } cyg_mutex_unlock(&client_request_lock);
+
+ // When all handlers have stopped, we can print statistics
+ // knowing that all (handler allocated) resources should have
+ // been freed. That is, we should be able to determine leaks.
+ if (0 == handler_thread_in_use_count) {
+ print_statistics(1);
+ CYG_TEST_PASS_FINISH("Kernel thread stress test OK");
+ }
+ }
+#endif /* DEATH_TIME_LIMIT */
+
+ cyg_thread_delay(3);
+ }
+}
+
+/* client_program() -- an obnoxious client which makes a lot of requests */
+void client_program(cyg_addrword_t data)
+{
+ int delay;
+
+ system_clockH = cyg_real_time_clock();
+ cyg_clock_to_counter(system_clockH, &counterH);
+
+ for (;;) {
+ delay = (rand() % 20);
+
+ /* now send a request to the server */
+ cyg_mutex_lock(&client_request_lock); {
+ if (0 == clients_paused)
+ client_makes_request++;
+ } cyg_mutex_unlock(&client_request_lock);
+
+ cyg_thread_delay(10+delay);
+ }
+}
+
+/* listener_program() -- listens for a request and spawns a handler to
+ take care of the request */
+void listener_program(cyg_addrword_t data)
+{
+ for (;;) {
+ int make_request = 0;
+ cyg_mutex_lock(&client_request_lock); {
+ if (client_makes_request > 0) {
+ --client_makes_request;
+ make_request = 1;
+ }
+ } cyg_mutex_unlock(&client_request_lock);
+
+ if (make_request)
+ start_handler();
+
+ cyg_thread_delay(2 + (rand() % 10));
+ }
+}
+
+/* handler_program() -- is spawned to handle each incoming request */
+void handler_program(cyg_addrword_t data)
+{
+ /* here is where we perform specific stressful tasks */
+ perform_stressful_tasks();
+
+ cyg_thread_delay(4 + (int) (0.5*log(1.0 + fabs((rand() % 1000000)))));
+
+ {
+ // Loop until the handler id and priority can be communicated to
+ // the main_program.
+ int freed = 0;
+ do {
+ cyg_mutex_lock(&free_handler_lock); {
+ if (-1 == free_handler_id) {
+ free_handler_id = data;
+ free_handler_pri = P_BASE_HANDLER+(int) data;
+ freed = 1;
+ }
+ } cyg_mutex_unlock(&free_handler_lock);
+ if (!freed)
+ cyg_thread_delay(2);
+ } while (!freed);
+ }
+
+ // Then exit.
+ cyg_thread_exit();
+}
+
+/* start a new handler */
+void start_handler(void)
+{
+ int prio;
+ char* name;
+ int handler_slot = 0;
+ int found = 0;
+
+ while (!found) {
+ cyg_mutex_lock(&handler_slot_lock); {
+ for (handler_slot = 0; handler_slot < MAX_HANDLERS;++handler_slot){
+ if (!handler_thread_in_use[handler_slot]) {
+ found = 1;
+ handler_thread_in_use[handler_slot]++;
+ handler_thread_in_use_count++;
+ break;
+ }
+ }
+ } cyg_mutex_unlock(&handler_slot_lock);
+ if (!found)
+ cyg_thread_delay(1);
+ }
+
+ CYG_ASSERT(1 == handler_thread_in_use[handler_slot],
+ "Handler usage count wrong!");
+
+ prio = P_BASE_HANDLER+handler_slot;
+ CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
+ priority_in_use[prio]++;
+
+ name = &thread_name[prio][0];
+ sprintf(name, "handler-%02d/%02d", handler_slot, prio);
+
+ priority_translation[prio] =
+ sc_thread_create(prio, handler_program,
+ (cyg_addrword_t) handler_slot,
+ name, (void *) handler_stack[handler_slot],
+ STACK_SIZE_HANDLER, &handlerH[handler_slot],
+ &handler_thread_s[handler_slot]);
+ cyg_thread_resume(handlerH[handler_slot]);
+ ++statistics.handler_invocation_histogram[handler_slot];
+}
+
+/* free a locked handler thread */
+void stop_handler(int handler_id, int handler_pri)
+{
+ // Finally delete the handler thread. This must be done in a
+ // loop, waiting for the call to return true. If it returns
+ // false, go to sleep for a bit, so the killed thread gets a
+ // chance to run and complete its business.
+ while (!cyg_thread_delete(handlerH[handler_id])) {
+ cyg_thread_delay(1);
+ }
+ ++statistics.thread_exits;
+
+ // Free the handler resources.
+ cyg_mutex_lock(&handler_slot_lock); {
+ handler_thread_in_use[handler_id]--;
+ handler_thread_in_use_count--;
+ priority_in_use[handler_pri]--;
+ CYG_ASSERT(0 == priority_in_use[handler_pri],
+ "Priority not in use!");
+ CYG_ASSERT(0 == handler_thread_in_use[handler_id],
+ "Handler not in use!");
+ CYG_ASSERT(0 <= handler_thread_in_use_count,
+ "Stopped more handlers than was started!");
+ } cyg_mutex_unlock(&handler_slot_lock);
+
+}
+
+
+/* do things which will stress the system */
+void perform_stressful_tasks()
+{
+#define MAX_MALLOCED_SPACES 100 /* do this many mallocs at most */
+#define MALLOCED_BASE_SIZE 1 /* basic size in bytes */
+ char *spaces[MAX_MALLOCED_SPACES];
+ int sizes[MAX_MALLOCED_SPACES];
+ unsigned int i, j, size;
+
+ cyg_uint8 pool_space[10][100];
+ cyg_handle_t mempool_handles[10];
+ cyg_mempool_fix mempool_objects[10];
+
+ /* here I use malloc, which uses the kernel's variable memory pools.
+ note that malloc/free is a bit simple-minded here: it does not
+ try to really fragment things, and it does not try to make the
+ allocation/deallocation concurrent with other thread execution
+ (although I'm about to throw in a yield()) */
+ for (i = 0; i < MAX_MALLOCED_SPACES; ++i) {
+ ++statistics.malloc_tries;
+ size = (i*2+1)*MALLOCED_BASE_SIZE;
+ spaces[i] = (char *) malloc(size);
+ sizes[i] = size;
+
+ if (spaces[i] != NULL) {
+ // Fill with a known value (differs between chunk).
+ for (j = 0; j < size; ++j) {
+ spaces[i][j] = 0x50 | ((j+i) & 0x0f);
+ }
+ }
+
+ if (i % (MAX_MALLOCED_SPACES/10) == 0) {
+ cyg_thread_yield();
+ }
+ if (i % (MAX_MALLOCED_SPACES/15) == 0) {
+ cyg_thread_delay(i % 5);
+ }
+ }
+
+ cyg_thread_delay(5);
+
+ /* now free it all up */
+ for (i = 0; i < MAX_MALLOCED_SPACES; ++i) {
+ if (spaces[i] != NULL) {
+ size = sizes[i];
+ for (j = 0; j < size; ++j) {
+ // Validate chunk data.
+ if ((0x50 | ((j+i) & 0x0f)) != spaces[i][j]) {
+ printf("Bad byte in chunk\n");
+ }
+ spaces[i][j] = 0xAA; /* write a bit pattern */
+ }
+ free(spaces[i]);
+ } else {
+ ++statistics.malloc_failures;
+ }
+ }
+
+ /* now allocate and then free some fixed-size memory pools; for
+ now this is simple-minded because it does not have many threads
+ sharing the memory pools and racing for memory. */
+ for (i = 0; i < 10; ++i) {
+ cyg_mempool_fix_create(pool_space[i], 100, (i+1)*3,
+ &mempool_handles[i], &mempool_objects[i]);
+ }
+
+ for (i = 0; i < 10; ++i) {
+ spaces[i] = cyg_mempool_fix_try_alloc(mempool_handles[i]);
+ }
+
+ for (i = 0; i < 10; ++i) {
+ if (spaces[i]) {
+ cyg_mempool_fix_delete(mempool_handles[i]);
+ }
+ }
+}
+
+/* report_alarm_func() is invoked as an alarm handler, so it should be
+ quick and simple. in this case it sets a global flag which is
+ checked by main_program. */
+void report_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
+{
+ time_to_report = 1;
+}
+
+#ifdef DEATH_TIME_LIMIT
+/* this sets up death alarms. it gets the handle and alarm from the
+ caller, since they must persist for the life of the alarm */
+void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp,
+ cyg_alarm *death_alarm_p, int *killed_p)
+{
+ cyg_handle_t system_clockH, counterH;
+ cyg_resolution_t rtc_res;
+
+ system_clockH = cyg_real_time_clock();
+ cyg_clock_to_counter(system_clockH, &counterH);
+
+ cyg_alarm_create(counterH, death_alarm_func,
+ (cyg_addrword_t) killed_p,
+ deathHp, death_alarm_p);
+ rtc_res = cyg_clock_get_resolution(system_clockH);
+ {
+ cyg_tick_count_t tick_delay;
+ tick_delay = (long long)
+ ((1000000000.0*rtc_res.divisor)
+ *((double)DEATH_TIME_LIMIT)/((double)rtc_res.dividend));
+ if ( cyg_test_is_simulator )
+ tick_delay /= SIM_DELAY_DIVISOR;
+#ifdef CYGPKG_HAL_SYNTH
+ // 20 seconds is a long time compared to the run time of other tests.
+ // Reduce to 10 seconds, allowing more tests to get run.
+ tick_delay /= 2;
+#endif
+
+ cyg_alarm_initialize(*deathHp, cyg_current_time() + tick_delay, 0);
+ }
+}
+#endif
+
+/* death_alarm_func() is the alarm handler that kills the current
+ thread after a specified timeout. It does so by setting a flag the
+ thread is constantly checking. */
+void death_alarm_func(cyg_handle_t alarmH, cyg_addrword_t data)
+{
+ int *killed_p;
+ killed_p = (int *) data;
+ *killed_p = 1;
+}
+
+/* now I write the sc_ versions of the cyg_functions */
+cyg_addrword_t sc_thread_create(
+ cyg_addrword_t sched_info, /* scheduling info (eg pri) */
+ cyg_thread_entry_t *entry, /* entry point function */
+ cyg_addrword_t entry_data, /* entry data */
+ char *name, /* optional thread name */
+ void *stack_base, /* stack base, NULL = alloc */
+ cyg_ucount32 stack_size, /* stack size, 0 = default */
+ cyg_handle_t *handle, /* returned thread handle */
+ cyg_thread *thread /* put thread here */
+ )
+{
+ ++statistics.thread_creations;
+
+ cyg_thread_create(sched_info, entry, entry_data, name,
+ stack_base, stack_size, handle, thread);
+
+ return cyg_thread_get_priority(*handle);
+}
+
+
+#define MINS_HOUR (60)
+#define MINS_DAY (60*24)
+
+void print_statistics(int print_full)
+{
+ int i;
+ static int stat_dumps = 0;
+ static int print_count = 0;
+ static int shift_count = 0;
+ int minutes;
+
+ stat_dumps++;
+
+ // Find number of minutes.
+ minutes = time_report_delay*stat_dumps / 60;
+
+ if (!print_full) {
+ // Return if time/minutes not integer.
+ if ((time_report_delay*stat_dumps % 60) != 0)
+ return;
+
+ // After the first day, only dump stat once per day. Do print
+ // a . on the hour though.
+ if ((minutes > MINS_DAY) && ((minutes % MINS_DAY) != 0)) {
+ if ((minutes % MINS_HOUR) == 0) {
+ printf(".");
+ fflush(stdout);
+ }
+ return;
+ }
+
+ // After the first hour of the first day, only dump stat once
+ // per hour. Do print . each minute though.
+ if ((minutes < MINS_DAY) && (minutes > MINS_HOUR)
+ && ((minutes % MINS_HOUR) != 0)) {
+ printf(".");
+ fflush(stdout);
+ return;
+ }
+ }
+
+ printf("\nState dump %d (%d hours, %d minutes) [numbers >>%d]\n",
+ ++print_count, minutes / MINS_HOUR, minutes % MINS_HOUR,
+ shift_count);
+
+ cyg_mutex_lock(&statistics_print_lock); {
+ //--------------------------------
+ // Information private to this test:
+ printf(" Handler-invocations: ");
+ for (i = 0; i < MAX_HANDLERS; ++i) {
+ printf("%4lu ", statistics.handler_invocation_histogram[i]);
+ }
+ printf("\n");
+ printf(" malloc()-tries/failures: -- %7lu %7lu\n",
+ statistics.malloc_tries, statistics.malloc_failures);
+ printf(" client_makes_request: %d\n", client_makes_request);
+
+ // Check for big numbers and reduce if getting close to overflow
+ if (statistics.malloc_tries > 0x40000000) {
+ shift_count++;
+ for (i = 0; i < MAX_HANDLERS; ++i) {
+ statistics.handler_invocation_histogram[i] >>= 1;
+ }
+ statistics.malloc_tries >>= 1;
+ statistics.malloc_failures >>= 1;
+ }
+ } cyg_mutex_unlock(&statistics_print_lock);
+
+#if CYGINT_ISO_MALLINFO
+ //--------------------------------
+ // System information
+ {
+ struct mallinfo mem_info;
+
+ mem_info = mallinfo();
+
+ printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n",
+ mem_info.arena, mem_info.fordblks, mem_info.maxfree);
+ }
+#endif
+
+ // Dump stack status
+ printf(" Stack usage:\n");
+ cyg_test_dump_interrupt_stack_stats( " Interrupt" );
+ cyg_test_dump_idlethread_stack_stats( " Idle" );
+
+ cyg_test_dump_stack_stats(" Main", main_stack,
+ main_stack + sizeof(main_stack));
+ for (i = 0; i < MAX_HANDLERS; i++) {
+ cyg_test_dump_stack_stats(" Handler", handler_stack[i],
+ handler_stack[i] + sizeof(handler_stack[i]));
+ }
+ for (i = 0; i < N_LISTENERS; i++) {
+ cyg_test_dump_stack_stats(" Listener", listener_stack[i],
+ listener_stack[i] + sizeof(listener_stack[i]));
+ }
+ for (i = 0; i < N_CLIENTS; i++) {
+ cyg_test_dump_stack_stats(" Client", client_stack[i],
+ client_stack[i] + sizeof(client_stack[i]));
+ }
+}
+
+#else /* (CYGNUM_KERNEL_SCHED_PRIORITIES >= */
+/* (N_MAIN+N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) */
+#define N_A_MSG "not enough priorities available"
+#endif /* (CYGNUM_KERNEL_SCHED_PRIORITIES >= */
+/* (N_MAIN+N_CLIENTS+N_LISTENERS+MAX_HANDLERS)) */
+
+#else /* CYGINT_ISO_MALLOC */
+# define N_A_MSG "this test needs malloc"
+#endif /* CYGINT_ISO_MALLOC */
+
+#else /* CYGFUN_KERNEL_THREADS_TIMER */
+# define N_A_MSG "this test needs kernel threads timer"
+#endif /* CYGFUN_KERNEL_THREADS_TIMER */
+
+#else /* CYGPKG_LIBM */
+# define N_A_MSG "this test needs libm"
+#endif /* CYGPKG_LIBM */
+
+#else /* CYGINT_ISO_STDIO_FORMATTED_IO */
+# define N_A_MSG "this test needs stdio formatted I/O"
+#endif /* CYGINT_ISO_STDIO_FORMATTED_IO */
+
+#else // def CYGFUN_KERNEL_API_C
+# define N_A_MSG "this test needs Kernel C API"
+#endif
+
+#else // def CYGPKG_KERNEL && CYGPKG_IO && CYGPKG_ISOINFRA
+# define N_A_MSG "this tests needs Kernel, isoinfra and IO"
+#endif
+
+#ifdef N_A_MSG
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA( N_A_MSG);
+}
+#endif // N_A_MSG
diff --git a/ecos/packages/kernel/current/tests/sync2.cxx b/ecos/packages/kernel/current/tests/sync2.cxx
new file mode 100644
index 0000000000..d6e349a048
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/sync2.cxx
@@ -0,0 +1,201 @@
+//==========================================================================
+//
+// sync2.cxx
+//
+// Sync test 2 -- test of different locking mechanisms
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-18
+// Description:
+// Creates some threads and tests the various synchronization
+// mechanisms. Four threads are created t0..t3. t0 and t3 grab a
+// mutex and check they have exclusive access to shared variable.
+// t0,t1,t2 post each other in a loop with a semaphore so that
+// only one is running at any time. t1,t2,t3 do a similar thing
+// with counting semaphores, except that there are two active
+// threads.
+// Omissions:
+// Doesn't test condition variables
+//
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/mutex.hxx>
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+
+#define NTHREADS 4
+
+#include "testaux.hxx"
+
+static Cyg_Mutex m0;
+static Cyg_Binary_Semaphore s0, s1, s2(1);
+static Cyg_Counting_Semaphore cs0, cs1, cs2, cs3;
+
+static const cyg_ucount16 n = 1000;
+static cyg_ucount8 m0d=99, sd=2, cd0=99, cd1=99;
+
+static void entry0( CYG_ADDRWORD data )
+{
+ for(cyg_ucount16 i=0; i<n; i++) {
+ s2.wait();
+ CHECK( 2 == sd );
+ sd = 0;
+ m0.lock(); {
+ m0d = 0;
+ s0.post();
+ CHECK( 0 == m0d );
+ } m0.unlock();
+ }
+ // wait for 3 explicit posts to indicate threads have stopped.
+ for(cyg_ucount8 i=0; i<3; i++)
+ cs3.wait();
+
+ CHECK( ! s0.posted() );
+ CHECK( ! s1.posted() );
+ CHECK( s2.posted() );
+
+ CHECK( 0 == cs0.peek() );
+ CHECK( 0 == cs1.peek() );
+ CHECK( 0 == cs2.peek() );
+ CHECK( 0 == cs3.peek() );
+
+ CHECK( 0 == cd0 );
+ CHECK( 0 == cd1 );
+ CYG_TEST_PASS_FINISH("Sync 2 OK");
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+static void entry1( CYG_ADDRWORD data )
+{
+ for(cyg_ucount16 i=0; i<n; i++) {
+ s0.wait();
+ CHECK( 0 == sd );
+ sd = 1;
+ cd0 = 1;
+ cs1.post();
+ cd1 = 1;
+ cs1.post();
+ s1.post();
+ cs0.wait();
+ CHECK( 0 == cd0 );
+ cs0.wait();
+ CHECK( 0 == cd1 );
+ }
+ cs3.post();
+ s0.wait();
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+static void entry2( CYG_ADDRWORD data )
+{
+ for(cyg_ucount16 i=0; i<n; i++) {
+ s1.wait();
+ CHECK( 1 == sd );
+ sd = 2;
+ cs1.wait();
+ CHECK( 1 == cd0 );
+ cd0 = 2;
+ cs2.post();
+ s2.post();
+ cs1.wait();
+ CHECK( 1 == cd1 );
+ cd1 = 2;
+ cs2.post();
+ }
+ cs3.post();
+ s1.wait();
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+static void entry3( CYG_ADDRWORD data )
+{
+ for(cyg_ucount16 i=0; i < n*2; i++) {
+ cs2.wait();
+ CHECK( 2 == cd0 || 2 == cd1 );
+ m0.lock(); {
+ m0d = 3;
+ if( 2 == cd0 )
+ cd0 = 0;
+ else {
+ CHECK( 2 == cd1 );
+ cd1 = 0;
+ }
+ cs0.post();
+ CHECK( 3 == m0d );
+ } m0.unlock();
+ }
+ cs3.post();
+ cs1.wait();
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+
+void sync2_main(void)
+{
+ CYG_TEST_INIT();
+
+ new_thread(entry0, 0);
+ new_thread(entry1, 1);
+ new_thread(entry2, 2);
+ new_thread(entry3, 3);
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_PASS_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ sync2_main();
+}
+
+// EOF sync2.cxx
diff --git a/ecos/packages/kernel/current/tests/sync3.cxx b/ecos/packages/kernel/current/tests/sync3.cxx
new file mode 100644
index 0000000000..f2c6e2ec13
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/sync3.cxx
@@ -0,0 +1,232 @@
+//==========================================================================
+//
+// sync3.cxx
+//
+// Sync test 3 -- tests priorities and priority inheritance
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-18
+// Description:
+// Creates mutexes and threads to set up starvation condition.
+// Checks simple priority inheritance cures this.
+//
+// The starvation condition is caused by the highest priority
+// thread, t0 waiting on a mutex which is never released because
+// it is held by t2. t2 never releases it because t1 will be
+// running at a priority level higher than t2 (but lower than t0).
+//
+// With priority inheritance enabled, t2 will inherit its priority
+// from t0 when t0 tries to grab the mutex.
+//
+// Options:
+// CYGIMP_THREAD_PRIORITY
+// CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+// CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_SIMPLE
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/mutex.hxx>
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+
+#if defined(CYGIMP_THREAD_PRIORITY) && \
+ !defined(CYGPKG_KERNEL_SMP_SUPPORT)
+
+// ------------------------------------------------------------------------
+// Manufacture a simpler feature test macro for priority inheritance than
+// the configuration gives us. We have priority inheritance if it is configured
+// as the only protocol, or if it is the default protocol for dynamic protocol
+// choice.
+// FIXME: If we have dynamic protocol choice, we can also set priority inheritance
+// as the protocol to be used on the mutexes we are interested in. At present we
+// do not do this.
+
+#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT
+# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC
+# ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT
+# define PRIORITY_INHERITANCE
+# else
+# undef PRIORITY_INHERITANCE
+# endif
+# else
+# define PRIORITY_INHERITANCE
+# endif
+#else
+# undef PRIORITY_INHERITANCE
+#endif
+
+// ------------------------------------------------------------------------
+
+#define NTHREADS 3
+
+#include "testaux.hxx"
+
+static Cyg_Mutex m0;
+static Cyg_Binary_Semaphore s0, s1, s2;
+
+static cyg_ucount8 m0d = 9;
+
+static void check_priorities_normal()
+{
+ CHECK( 5 == thread[0]->get_priority());
+ CHECK( 6 == thread[1]->get_priority());
+ CHECK( 7 == thread[2]->get_priority());
+}
+
+static void check_priorities_inherited()
+{
+ CHECK( 5 == thread[0]->get_priority());
+ CHECK( 6 == thread[1]->get_priority());
+#ifdef PRIORITY_INHERITANCE
+ CHECK( 5 == thread[2]->get_current_priority());
+#endif
+ CHECK( 7 == thread[2]->get_priority());
+
+}
+
+static void entry0( CYG_ADDRWORD data )
+{
+ s0.wait(); // wait until t2 has gained m0.lock
+ check_priorities_normal();
+ m0.lock(); {
+ check_priorities_normal();
+ CHECK( 2 == m0d );
+ m0d = 0;
+ } m0.unlock();
+ check_priorities_normal();
+#ifdef PRIORITY_INHERITANCE
+ CYG_TEST_PASS_FINISH("Sync 3 OK -- priority inheritance worked");
+#else
+ CYG_TEST_FAIL_FINISH("Sync 3: thread not starved");
+#endif
+ // NOT REACHED
+}
+
+static void entry1( CYG_ADDRWORD data )
+{
+ s1.wait();
+ // The delay below will allow testing of the priority inheritance
+ // mechanism when scheduler does not guarantee to schedule threads
+ // in strict priority order.
+ for ( volatile cyg_ucount32 i=0; i < 100000; i++ )
+ ; // math is hard
+
+#ifdef PRIORITY_INHERITANCE
+ // thread0 should have stopped by this point
+ CYG_TEST_FAIL_FINISH("Sync 3: priority inheritance mechanism failed");
+#else
+ // With strict priority scheduling and no priority inheritance
+ // this is expected to happen.
+ CYG_TEST_PASS_FINISH("Sync 3 OK");
+#endif
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+void entry2( CYG_ADDRWORD data )
+{
+ m0.lock(); {
+ CHECK( 9 == m0d );
+ check_priorities_normal();
+ s0.post(); // Now I have lock on m0, wake t0 then t1
+ check_priorities_inherited();
+ s1.post();
+ check_priorities_inherited();
+ m0d = 2;
+ } m0.unlock();
+ check_priorities_normal();
+ m0.lock(); {
+ check_priorities_normal();
+ CHECK( 0 == m0d );
+ m0d = 21;
+ s2.wait(); // never posted
+ } m0.unlock();
+}
+
+
+
+void sync3_main(void)
+{
+ CYG_TEST_INIT();
+
+ new_thread( entry0, 0);
+ new_thread( entry1, 1);
+ new_thread( entry2, 2);
+
+ thread[0]->set_priority(5);
+ thread[1]->set_priority(6);
+ thread[2]->set_priority(7);
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ sync3_main();
+}
+
+#else // defined(CYGIMP_THREAD_PRIORITY) etc
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_INFO("Sync3 test requires:\n"
+ "defined(CYGIMP_THREAD_PRIORITY) &&\n"
+ "!defined(CYGPKG_KERNEL_SMP_SUPPORT)\n");
+ CYG_TEST_NA("Sync3 test requirements");
+
+}
+
+#endif // defined(CYGIMP_THREAD_PRIORITY) etc
+
+// EOF sync3.cxx
diff --git a/ecos/packages/kernel/current/tests/tcdiag.cxx b/ecos/packages/kernel/current/tests/tcdiag.cxx
new file mode 100644
index 0000000000..ea4d8c648d
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/tcdiag.cxx
@@ -0,0 +1,97 @@
+//==========================================================================
+//
+// tcdiag.cxx
+//
+// Kernel diag test harness.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-17
+// Description: Test harness implementation that uses the kernel's
+// diag channel. This is intended for manual testing
+// of the kernel.
+//####DESCRIPTIONEND####
+
+#include <testcase.h>
+#include <diag.h>
+
+bool cyg_test_is_simulator=false; // infrastructure changes as necessary
+
+void cyg_test_init()
+{
+ diag_init();
+}
+
+void cyg_test_output(int status, char *msg, int line, char *file)
+{
+ char *st;
+
+ switch (status) {
+ case 0:
+ st = "FAIL:";
+ break;
+ case 1:
+ st = "PASS:";
+ break;
+ case 2:
+ st = "EXIT:";
+ break;
+ case 3:
+ st = "INFO:";
+ break;
+ }
+
+ diag_write_string(st);
+ diag_write_char('<');
+ diag_write_string(msg);
+ diag_write_string("> Line: ");
+ diag_write_dec(line);
+ diag_write_string(", File: ");
+ diag_write_string(file);
+ diag_write_char('\n');
+
+}
+
+// This is an appropriate function to set a breakpoint on
+void cyg_test_exit()
+{
+ for(;;)
+ ;
+}
+// EOF tcdiag.cxx
diff --git a/ecos/packages/kernel/current/tests/testaux.h b/ecos/packages/kernel/current/tests/testaux.h
new file mode 100644
index 0000000000..10712c28a6
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/testaux.h
@@ -0,0 +1,62 @@
+#ifndef CYGONCE_KERNEL_TESTS_TESTAUX_H
+#define CYGONCE_KERNEL_TESTS_TESTAUX_H
+
+/*=================================================================
+//
+// testaux.h
+//
+// Auxiliary test header file
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-09
+// Description:
+// Defines some convenience functions to get us going. In
+// particular this file reserves space for NTHREADS threads,
+// which can be created by calls to aux_new_thread()
+// It also defines a CHECK function.
+//
+//####DESCRIPTIONEND####
+*/
+
+#define CHECK(b) CYG_TEST_CHECK(b,#b)
+
+#endif /* ifndef CYGONCE_KERNEL_TESTS_TESTAUX_H */
+
+/* EOF testaux.h */
diff --git a/ecos/packages/kernel/current/tests/testaux.hxx b/ecos/packages/kernel/current/tests/testaux.hxx
new file mode 100644
index 0000000000..b258600433
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/testaux.hxx
@@ -0,0 +1,110 @@
+#ifndef CYGONCE_KERNEL_TESTS_TESTAUX_HXX
+#define CYGONCE_KERNEL_TESTS_TESTAUX_HXX
+
+//==========================================================================
+//
+// testaux.hxx
+//
+// Auxiliary test header file
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-03-09
+// Description:
+// Defines some convenience functions to get us going. In
+// particular this file reserves space for NTHREADS threads,
+// which can be created by calls to aux_new_thread()
+// It also defines a CHECK function.
+//
+//####DESCRIPTIONEND####
+
+
+inline void *operator new(size_t size, void *ptr) { return ptr; };
+
+
+#include <pkgconf/hal.h>
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+externC void
+cyg_hal_invoke_constructors();
+#endif
+
+#ifdef NTHREADS
+
+#ifndef STACKSIZE
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#endif
+
+static Cyg_Thread *thread[NTHREADS];
+
+typedef CYG_WORD64 CYG_ALIGNMENT_TYPE;
+
+static CYG_ALIGNMENT_TYPE thread_obj[NTHREADS] [
+ (sizeof(Cyg_Thread)+sizeof(CYG_ALIGNMENT_TYPE)-1)
+ / sizeof(CYG_ALIGNMENT_TYPE) ];
+
+static CYG_ALIGNMENT_TYPE stack[NTHREADS] [
+ (STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1)
+ / sizeof(CYG_ALIGNMENT_TYPE) ];
+
+static volatile int nthreads = 0;
+
+static Cyg_Thread *new_thread(cyg_thread_entry *entry, CYG_ADDRWORD data)
+{
+ int _nthreads = nthreads++;
+
+ CYG_ASSERT(_nthreads < NTHREADS,
+ "Attempt to create more than NTHREADS threads");
+
+ thread[_nthreads] = new( (void *)&thread_obj[_nthreads] )
+ Cyg_Thread(CYG_SCHED_DEFAULT_INFO,
+ entry, data,
+ NULL, // no name
+ (CYG_ADDRESS)stack[_nthreads], STACKSIZE );
+
+ thread[_nthreads]->resume();
+
+ return thread[_nthreads];
+}
+#endif // defined(NTHREADS)
+
+#define CHECK(b) CYG_TEST_CHECK(b,#b)
+
+#endif // ifndef CYGONCE_KERNEL_TESTS_TESTAUX_HXX
+
+// End of testaux.hxx
diff --git a/ecos/packages/kernel/current/tests/thread0.cxx b/ecos/packages/kernel/current/tests/thread0.cxx
new file mode 100644
index 0000000000..db0209e77e
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/thread0.cxx
@@ -0,0 +1,114 @@
+//==========================================================================
+//
+// thread0.cxx
+//
+// Thread test 0
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-11
+// Description: Limited to checking constructors/destructors
+// Omissions:
+// Thread constructors with 2 or 3 args are not supported at time
+// of writing test.
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/thread.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/thread.inl>
+
+#include "testaux.hxx"
+
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+static char stack[STACKSIZE];
+
+static cyg_thread_entry entry;
+
+static void entry( CYG_ADDRWORD data )
+{
+}
+
+static int *p;
+
+static bool flash( void )
+{
+#if 0 // no facility to allocate stack exists yet.
+ Cyg_Thread t0( entry, 0x111 );
+
+ CYG_ASSERTCLASS(&t0, "error");
+
+ Cyg_Thread t1( entry, (CYG_ADDRWORD)&t0, STACKSIZE );
+
+ CYG_ASSERTCLASS(&t1, "error");
+#endif
+ Cyg_Thread t2( CYG_SCHED_DEFAULT_INFO,
+ entry, (CYG_ADDRWORD)p,
+ "thread t2",
+ (CYG_ADDRESS)stack, STACKSIZE );
+
+ CYG_ASSERTCLASS(&t2, "error");
+
+ return true;
+}
+
+void thread0_main( void )
+{
+ CYG_TEST_INIT();
+
+ CHECK(flash());
+ CHECK(flash());
+
+ CYG_TEST_PASS_FINISH("Thread 0 OK");
+
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ thread0_main();
+}
+// EOF thread0.cxx
diff --git a/ecos/packages/kernel/current/tests/thread1.cxx b/ecos/packages/kernel/current/tests/thread1.cxx
new file mode 100644
index 0000000000..2596a1016a
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/thread1.cxx
@@ -0,0 +1,172 @@
+//==========================================================================
+//
+// thread1.cxx
+//
+// Thread test 1
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-11
+// Description: Tests some basic thread functions.
+// Omissions: Cyg_ThreadTimer
+// Cyg_Thread
+// exit -- not necessarily called
+// yield
+// set_priority
+// get_priority
+// get/set_sleep_reason
+// get/set_wake_reason
+// set/clear_timer
+// Cyg_ThreadQueue
+//
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/thread.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/thread.inl>
+
+#include "testaux.hxx"
+
+#ifdef CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#else
+#define STACKSIZE 2000
+#endif
+
+static char stack[2][STACKSIZE];
+
+static char thread[2][sizeof(Cyg_Thread)];
+
+static Cyg_Thread *pt0,*pt1;
+static cyg_uint16 uid0,uid1;
+
+
+static void entry0( CYG_ADDRWORD data )
+{
+ CHECK( 222 == data );
+
+ uid0 = pt0->get_unique_id();
+
+ pt1->suspend();
+ pt1->resume();
+
+ do {
+ pt0->delay(1);
+ } while( Cyg_Thread::RUNNING == pt1->get_state() );
+
+ CHECK( Cyg_Thread::SLEEPING == pt1->get_state() );
+
+ pt1->wake();
+
+ CHECK( uid0 != uid1 );
+
+ CYG_TEST_PASS_FINISH("Thread 1 OK");
+}
+
+static void entry1( CYG_ADDRWORD data )
+{
+ CHECK( 333 == data );
+
+ uid1 = pt1->get_unique_id();
+
+ Cyg_Thread *self = Cyg_Thread::self();
+
+ CHECK( self == pt1 );
+
+ pt1->sleep();
+ pt1->suspend();
+
+ Cyg_Thread::exit(); // no guarantee this will be called
+}
+
+void thread1_main( void )
+{
+ CYG_TEST_INIT();
+
+ pt0 = new((void *)&thread[0])
+ Cyg_Thread(CYG_SCHED_DEFAULT_INFO,
+ entry0, 222,
+ "thread 0",
+ (CYG_ADDRESS)stack[0], STACKSIZE );
+ pt1 = new((void *)&thread[1])
+ Cyg_Thread(CYG_SCHED_DEFAULT_INFO,
+ entry1, 333,
+ "thread 1",
+ (CYG_ADDRESS)stack[1], STACKSIZE );
+
+ CYG_ASSERTCLASS( pt0, "error" );
+ CYG_ASSERTCLASS( pt1, "error" );
+
+ pt0->resume();
+ pt1->resume();
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+}
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ thread1_main();
+}
+
+#else // ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_NA("Kernel threads timer disabled");
+}
+
+#endif // ifdef CYGFUN_KERNEL_THREADS_TIMER
+
+// EOF thread1.cxx
diff --git a/ecos/packages/kernel/current/tests/thread2.cxx b/ecos/packages/kernel/current/tests/thread2.cxx
new file mode 100644
index 0000000000..e53181987d
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/thread2.cxx
@@ -0,0 +1,236 @@
+//==========================================================================
+//
+// thread2.cxx
+//
+// Thread test 2
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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): dsm
+// Contributors: dsm
+// Date: 1998-02-19
+// Description:
+// tests scheduler & threads & priorities
+// + create multiple threads with various priorities
+// + check highest priority running thread is always running
+// + check next highest runs when highest suspended
+// + check several threads of equal priority share time
+// (only !CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES)
+// + check other threads are starved
+// + check setting priority dynamically causes a thread to
+// become/stay current/non-current
+// Omissions:
+// check yield
+// check can set threads with min and max priority
+// Options:
+// CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES
+// CYGIMP_THREAD_PRIORITY
+// CYGNUM_KERNEL_SCHED_PRIORITIES
+// CYGSEM_KERNEL_SCHED_BITMAP
+// CYGSEM_KERNEL_SCHED_MLQUEUE
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#include <pkgconf/kernel.h>
+
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/mutex.hxx>
+#include <cyg/kernel/sema.hxx>
+
+#include <cyg/infra/testcase.h>
+
+#include <cyg/kernel/sched.inl>
+
+// ------------------------------------------------------------------------
+
+#if defined(CYGIMP_THREAD_PRIORITY) && \
+ !defined(CYGPKG_KERNEL_SMP_SUPPORT)
+
+// ------------------------------------------------------------------------
+
+static Cyg_Counting_Semaphore s0, s1, s2;
+
+static volatile cyg_ucount8 q = 0;
+
+static Cyg_Thread *thread0, *thread1, *thread2;
+
+#define NTHREADS 3
+#include "testaux.hxx"
+
+// ------------------------------------------------------------------------
+
+static void entry0( CYG_ADDRWORD data )
+{
+ CHECK( 0 == q++ );
+ s0.wait();
+ CHECK( 3 == q++ );
+ s1.post();
+ CHECK( 4 == q++ );
+ s0.wait();
+ s0.wait();
+ CYG_TEST_PASS_FINISH("Thread 2 OK");
+}
+
+// ------------------------------------------------------------------------
+
+static void entry1( CYG_ADDRWORD data )
+{
+ CHECK( 1 == q++ );
+ s1.wait();
+ CHECK( 5 == q++ );
+ thread0->set_priority(9);
+ s0.post();
+ CHECK( 6 == q++ );
+ thread2->set_priority(3);
+ CHECK( 8 == q++ );
+ s2.post();
+ CHECK( 12 == q++ );
+ CHECK( 9 == thread0->get_priority() );
+ CHECK( 6 == thread1->get_priority() );
+ CHECK( 7 == thread2->get_priority() );
+ q = 100;
+#if !(CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES) \
+ && defined(CYGSEM_KERNEL_SCHED_TIMESLICE)
+ thread2->set_priority(6);
+ CHECK( 6 == thread1->get_priority() );
+ CHECK( 6 == thread2->get_priority() );
+
+ while ( 100 == q )
+ ;
+ CHECK( 101 == q++ );
+ s1.wait();
+ CHECK( 103 == q++ );
+#endif
+ s0.post();
+ s1.wait();
+}
+
+// ------------------------------------------------------------------------
+
+static void entry2( CYG_ADDRWORD data )
+{
+ CHECK( 2 == q++ );
+ s0.post();
+ CHECK( 7 == q++ );
+ s2.wait();
+ CHECK( 9 == q++ );
+ thread1->set_priority(6);
+ CHECK( 10 == q++ );
+ thread2->set_priority(2);
+ CHECK( 11 == q++ );
+ thread2->set_priority(7);
+
+#if !(CYGINT_KERNEL_SCHEDULER_UNIQUE_PRIORITIES) \
+ && defined(CYGSEM_KERNEL_SCHED_TIMESLICE)
+ CHECK( 6 == thread1->get_priority() );
+ CHECK( 6 == thread2->get_priority() );
+
+ CHECK( 100 == q++ );
+ while ( 101 == q )
+ ;
+ CHECK( 102 == q++ );
+ s1.post();
+#endif
+ s0.post();
+ s2.wait();
+}
+
+
+// ------------------------------------------------------------------------
+
+void thread2_main( void )
+{
+ CYG_TEST_INIT();
+
+ thread0 = new_thread( entry0, 0 );
+ thread1 = new_thread( entry1, 1 );
+ thread2 = new_thread( entry2, 2 );
+
+ thread0->resume();
+ thread1->resume();
+ thread2->resume();
+
+ thread0->set_priority(5);
+ thread1->set_priority(6);
+ thread2->set_priority(7);
+
+ if( 9 >= CYG_THREAD_MIN_PRIORITY )
+ CYG_TEST_FAIL_FINISH("Test requires priorities up to 9");
+
+ if( 2 <= CYG_THREAD_MAX_PRIORITY )
+ CYG_TEST_FAIL_FINISH("Test requires priorities as low as 2");
+
+ Cyg_Scheduler::start();
+
+ CYG_TEST_FAIL_FINISH("Unresolved");
+}
+
+// ------------------------------------------------------------------------
+
+externC void
+cyg_start( void )
+{
+#ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
+ cyg_hal_invoke_constructors();
+#endif
+ thread2_main();
+}
+// ------------------------------------------------------------------------
+
+
+#else // CYGPKG_KERNEL_SMP_SUPPORT etc
+
+// ------------------------------------------------------------------------
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_INFO("Thread2 test requires:\n"
+ "defined(CYGIMP_THREAD_PRIORITY) &&\n"
+ "!defined(CYGPKG_KERNEL_SMP_SUPPORT)\n");
+ CYG_TEST_NA("Thread2 test requirements");
+}
+
+// ------------------------------------------------------------------------
+
+#endif // CYGPKG_KERNEL_SMP_SUPPORT etc
+
+// ------------------------------------------------------------------------
+// EOF thread2.cxx
diff --git a/ecos/packages/kernel/current/tests/thread_gdb.c b/ecos/packages/kernel/current/tests/thread_gdb.c
new file mode 100644
index 0000000000..15ca90a7f7
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/thread_gdb.c
@@ -0,0 +1,413 @@
+//==========================================================================
+//
+// thread_gdb.c
+//
+// A test for thread support in GDB
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: 1998-09-21
+// Description: GDB thread support test.
+//####DESCRIPTIONEND####
+//
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/cyg_ass.h>
+
+#include <cyg/infra/testcase.h>
+
+#if defined(CYGFUN_KERNEL_API_C) && defined(CYGSEM_KERNEL_SCHED_MLQUEUE) &&\
+ (CYGNUM_KERNEL_SCHED_PRIORITIES > 26)
+
+#include <cyg/hal/hal_arch.h> // for CYGNUM_HAL_STACK_SIZE_TYPICAL
+
+// -------------------------------------------------------------------------
+
+#define THREADS 10
+
+#ifdef CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACKSIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#else
+#define STACKSIZE (2*1024)
+#endif
+
+#define CONTROLLER_PRI_HI 0
+#define CONTROLLER_PRI_LO 25
+
+#define WORKER_PRI 3
+#define WORKER_PRI_RANGE 20
+
+
+// -------------------------------------------------------------------------
+
+// array of stacks for threads
+char thread_stack[THREADS][STACKSIZE];
+
+// array of threads.
+cyg_thread thread[THREADS];
+
+cyg_handle_t thread_handle[THREADS];
+
+volatile cyg_uint8 worker_state;
+
+#define WORKER_STATE_WAIT 1
+#define WORKER_STATE_BREAK 2
+#define WORKER_STATE_EXIT 9
+
+cyg_mutex_t worker_mutex;
+cyg_cond_t worker_cv;
+
+cyg_count32 workers_asleep = 0;
+
+cyg_count32 thread_count[THREADS];
+
+cyg_priority_t thread_pri[THREADS];
+
+
+
+// -------------------------------------------------------------------------
+
+extern void breakme(void)
+{
+}
+
+// -------------------------------------------------------------------------
+
+void worker( cyg_addrword_t id )
+{
+ for(;;)
+ {
+ thread_count[id]++;
+ thread_pri[id] = cyg_thread_get_priority( cyg_thread_self() );
+
+ switch( worker_state )
+ {
+ case WORKER_STATE_BREAK:
+ if( 0 == (id % 4) )
+ breakme();
+
+ case WORKER_STATE_WAIT:
+ cyg_mutex_lock( &worker_mutex );
+ workers_asleep++;
+ cyg_cond_wait( &worker_cv );
+ workers_asleep--;
+ cyg_mutex_unlock( &worker_mutex );
+ break;
+
+ case WORKER_STATE_EXIT:
+ cyg_thread_exit();
+
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+
+void controller( cyg_addrword_t id )
+{
+ cyg_priority_t pri;
+ int i;
+
+ cyg_mutex_init( &worker_mutex );
+ cyg_cond_init( &worker_cv, &worker_mutex );
+
+// 1 thread, it is running, it calls BREAKME();
+// +++ Thread status returned:
+// +++ 1 thread, running, is the current one
+
+ breakme();
+
+// Create N more threads; they are all suspended after creation. Adjust
+// the priorities of all the threads to lower than the controlling thread.
+// Make them all be distinct priorities as far as possible. BREAKME();
+// +++ 1 thread, running, + N suspended ones of different prios.
+
+ for( i = 1; i < THREADS; i++ )
+ {
+ pri = CONTROLLER_PRI_HI + 1 + i % WORKER_PRI_RANGE;
+
+ cyg_thread_create(pri, worker, (cyg_addrword_t)i, "worker",
+ (void *)(&thread_stack[i]), STACKSIZE,
+ &thread_handle[i], &thread[i]);
+
+ }
+
+ breakme();
+
+// Adjust the priorities of all the threads to lower than the controlling
+// thread. Make them all be THE SAME priority. BREAKME();
+// +++ 1 thread, running, + N suspended ones of same prio.
+
+ for( i = 1; i < THREADS; i++ )
+ {
+ cyg_thread_set_priority( thread_handle[i], WORKER_PRI );
+ }
+
+ breakme();
+
+// Release all the N threads, BREAKME();
+// +++ 1 thread, running, + N ready ones of same prio.
+
+ for( i = 1; i < THREADS; i++ )
+ {
+ cyg_thread_resume( thread_handle[i] );
+ }
+
+ breakme();
+
+// Adjust the priorities of all the threads, lower than the controlling
+// thread. Make them all be distinct priorities as far as possible.
+// BREAKME();
+// +++ 1 thread, running, + N ready ones of different prios.
+
+ for( i = 1; i < THREADS; i++ )
+ {
+ pri = CONTROLLER_PRI_HI + 1 + i % WORKER_PRI_RANGE;
+
+ cyg_thread_set_priority( thread_handle[i], pri );
+ }
+
+ breakme();
+
+// Command all the N threads to sleep; switch my own priority to lower
+// than theirs so that they all run and sleep, then I get back in and
+// BREAKME();
+// +++ 1 thread, running, + N sleeping ones of different prios.
+
+ worker_state = WORKER_STATE_WAIT;
+
+ cyg_thread_set_priority( thread_handle[0], CONTROLLER_PRI_LO );
+
+ breakme();
+
+// Make them all be THE SAME priority; BREAKME();
+// +++ 1 thread, running, + N sleeping ones of same prio.
+
+ for( i = 1; i < THREADS; i++ )
+ {
+ cyg_thread_set_priority( thread_handle[i], WORKER_PRI );
+ }
+
+ breakme();
+
+// Wake them all up, they'll loop once and sleep again; I get in and
+// BREAKME();
+// +++ 1 thread, running, + N sleeping ones of same prio.
+
+ cyg_cond_broadcast( &worker_cv );
+
+ breakme();
+
+// Adjust the priorities of all the threads, higher than the controlling
+// thread. Make them all be distinct priorities as far as possible.
+// BREAKME();
+// +++ 1 thread, running, + N sleeping ones of different prios.
+
+ for( i = 1; i < THREADS; i++ )
+ {
+ pri = CONTROLLER_PRI_HI + 1 + i % WORKER_PRI_RANGE;
+
+ cyg_thread_set_priority( thread_handle[i], pri );
+ }
+
+ breakme();
+
+// Wake them all up, they'll loop once and sleep again; I get in and
+// BREAKME();
+// +++ 1 thread, running, + N sleeping ones of different prios.
+
+ cyg_cond_broadcast( &worker_cv );
+
+ breakme();
+
+// Set them all the same prio, set me to the same prio, BREAKME();
+// +++ 1 running, + N sleeping, *all* the same prio.
+
+ for( i = 0; i < THREADS; i++ )
+ {
+ cyg_thread_set_priority( thread_handle[i], WORKER_PRI );
+ }
+
+ breakme();
+
+// Wake them all up, they'll loop once and sleep again; I get in and
+// BREAKME(); repeatedly until they have all slept again.
+// +++ 1 running, + some sleeping, some ready, *all* the same prio.
+
+ cyg_cond_broadcast( &worker_cv );
+
+// cyg_thread_yield();
+
+ do
+ {
+ breakme();
+
+ } while( workers_asleep != THREADS-1 );
+
+ breakme();
+
+// Suspend some of the threads, BREAKME();
+// +++ 1 running, + some sleeping, some suspended, *all* the same prio.
+
+ for( i = 1; i < THREADS; i++ )
+ {
+ // suspend every 3rd thread
+ if( 0 == (i % 3) ) cyg_thread_suspend( thread_handle[i] );
+ }
+
+ breakme();
+
+
+// Change the prios all different, change my prio to highest , BREAKME();
+// +++ 1 running, + some sleeping, some suspended, different prios.
+
+ cyg_thread_set_priority( thread_handle[0], CONTROLLER_PRI_HI );
+
+ for( i = 1; i < THREADS; i++ )
+ {
+ pri = CONTROLLER_PRI_HI + 1 + i % WORKER_PRI_RANGE;
+
+ cyg_thread_set_priority( thread_handle[i], pri );
+ }
+
+ breakme();
+
+// Wake up all the threads, BREAKME();
+// +++ 1 running, + some ready, some suspended/ready, different prios.
+
+ cyg_cond_broadcast( &worker_cv );
+
+ breakme();
+
+
+// Change my prio to lowest, let all the threads run, BREAKME().
+// +++ 1 running + some sleeping, some suspended/ready, different prios.
+
+ cyg_thread_set_priority( thread_handle[0], CONTROLLER_PRI_LO );
+
+ breakme();
+
+// Resume all the threads, BREAKME();
+// +++ 1 running, + N ready, different prios.
+
+ for( i = 1; i < THREADS; i++ )
+ {
+ cyg_thread_resume( thread_handle[i] );
+ }
+
+ breakme();
+
+// Command some of the N threads to call BREAKME(); themselves (then sleep
+// again). Change my prio to low, so that they all get to run and hit the
+// breakpoint.
+// +++ A different one running every time, others in a mixture of
+// ready and sleeping states.
+
+ worker_state = WORKER_STATE_BREAK;
+
+ cyg_cond_broadcast( &worker_cv );
+
+ cyg_thread_set_priority( thread_handle[0], CONTROLLER_PRI_LO );
+
+ breakme();
+
+// Command all the threads to exit; switch my own priority to lower
+// than theirs so that they all run and exit, then I get back in and
+// BREAKME();
+// +++ 1 thread, running, + N dormant ones.
+
+ worker_state = WORKER_STATE_EXIT;
+
+ cyg_cond_broadcast( &worker_cv );
+
+ breakme();
+
+#if 0
+
+// Cannot do this yet...
+
+// Destroy some of the N threads to invalidate their IDs. Re-create them
+// with new IDs, so that we get IDs 1,2,4,6,8,11,12,13,14,15 in use instead
+// of 1,2,3,4,5,6,7,8,9, if you see what I mean. Do all the above again.
+// Loop forever, or whatever...
+
+#endif
+
+ breakme();
+
+ CYG_TEST_PASS_FINISH("GDB Thread test OK");
+
+}
+
+// -------------------------------------------------------------------------
+
+externC void
+cyg_start( void )
+{
+
+ CYG_TEST_INIT();
+
+ cyg_thread_create(CONTROLLER_PRI_HI, controller, (cyg_addrword_t)0, "controller",
+ (void *)(&thread_stack[0]), STACKSIZE,
+ &thread_handle[0], &thread[0]);
+
+ // resume it
+ cyg_thread_resume(thread_handle[0]);
+
+
+ // Get the world going
+ cyg_scheduler_start();
+
+ CYG_TEST_FAIL_FINISH("Not reached");
+
+}
+
+#else /* def CYGFUN_KERNEL_API_C */
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_PASS_FINISH("Incorrect configuration for this test");
+}
+#endif /* def CYGFUN_KERNEL_API_C && ... */
+
+// -------------------------------------------------------------------------
+// EOF thread_gdb.c
diff --git a/ecos/packages/kernel/current/tests/timeslice.c b/ecos/packages/kernel/current/tests/timeslice.c
new file mode 100644
index 0000000000..eb61fc488f
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/timeslice.c
@@ -0,0 +1,282 @@
+//==========================================================================
+//
+// timeslice.c
+//
+// Timeslice test
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// 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: A basic 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*5
+
+#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 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( "Timeslice Test: Check timeslicing works");
+
+ // 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( "Timeslice Test: done");
+}
+
+
+//==========================================================================
+
+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("Timeslice test failed\n");
+
+ CYG_TEST_PASS_FINISH("Timeslice test OK");
+}
+
+//==========================================================================
+
+void timeslice_main( void )
+{
+ CYG_TEST_INIT();
+
+ // Work out how many CPUs we actually have.
+ ncpus = CYGNUM_KERNEL_CPU_MAX; //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_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("SMP 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");
+}
+
+#endif // CYGSEM_KERNEL_SCHED_TIMESLICE etc.
+
+//==========================================================================
+// EOF timeslice.c
diff --git a/ecos/packages/kernel/current/tests/tm_basic.cxx b/ecos/packages/kernel/current/tests/tm_basic.cxx
new file mode 100644
index 0000000000..c9e34b5581
--- /dev/null
+++ b/ecos/packages/kernel/current/tests/tm_basic.cxx
@@ -0,0 +1,1880 @@
+//==========================================================================
+//
+// tm_basic.cxx
+//
+// Basic timing test / scaffolding
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003 Gary Thomas
+//
+// 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): gthomas
+// Contributors: gthomas
+// Date: 1998-10-19
+// Description: Very simple kernel timing test
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.h>
+#include <pkgconf/hal.h>
+
+#include <cyg/kernel/sched.hxx>
+#include <cyg/kernel/thread.hxx>
+#include <cyg/kernel/thread.inl>
+#include <cyg/kernel/mutex.hxx>
+#include <cyg/kernel/sema.hxx>
+#include <cyg/kernel/flag.hxx>
+#include <cyg/kernel/sched.inl>
+#include <cyg/kernel/clock.hxx>
+#include <cyg/kernel/clock.inl>
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+
+#include <cyg/kernel/test/stackmon.h>
+#include CYGHWR_MEMORY_LAYOUT_H
+
+// Define this to see the statistics with the first sample datum removed.
+// This can expose the effects of caches on the speed of operations.
+#undef STATS_WITHOUT_FIRST_SAMPLE
+
+#if 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 NTHREADS 1
+#include "testaux.hxx"
+
+// Structure used to keep track of times
+typedef struct fun_times {
+ cyg_uint32 start;
+ cyg_uint32 end;
+} fun_times;
+
+#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM
+
+#if defined(CYGMEM_REGION_ram_SIZE) && !(defined(CYGPKG_HAL_SPARC_LEON3_OPTIONS) || defined(CYGPKG_HAL_SPARC_LEON_OPTIONS))
+#define CYG_THREAD_OVERHEAD (STACK_SIZE+sizeof(cyg_thread)+(sizeof(fun_times)*2))
+#define NTEST_THREADS ((CYGMEM_REGION_ram_SIZE/16)/CYG_THREAD_OVERHEAD)
+#define CYG_MUTEX_OVERHEAD (sizeof(cyg_mutex_t)+sizeof(fun_times))
+#define NMUTEXES ((CYGMEM_REGION_ram_SIZE/16)/CYG_MUTEX_OVERHEAD)
+#define CYG_MBOX_OVERHEAD (sizeof(cyg_mbox)+sizeof(fun_times))
+#define NMBOXES ((CYGMEM_REGION_ram_SIZE/24)/CYG_MBOX_OVERHEAD)
+#define CYG_SEMAPHORE_OVERHEAD (sizeof(cyg_sem_t)+sizeof(fun_times))
+#define NSEMAPHORES ((CYGMEM_REGION_ram_SIZE/16)/CYG_SEMAPHORE_OVERHEAD)
+#define CYG_COUNTER_OVERHEAD (sizeof(cyg_counter)+sizeof(fun_times))
+#define NCOUNTERS ((CYGMEM_REGION_ram_SIZE/24)/CYG_COUNTER_OVERHEAD)
+#define CYG_FLAG_OVERHEAD (sizeof(cyg_flag_t)+sizeof(fun_times))
+#define NFLAGS ((CYGMEM_REGION_ram_SIZE/24)/CYG_FLAG_OVERHEAD)
+#define CYG_ALARM_OVERHEAD (sizeof(cyg_alarm)+sizeof(fun_times))
+#define NALARMS ((CYGMEM_REGION_ram_SIZE/16)/CYG_ALARM_OVERHEAD)
+#else
+// Defaults
+#define NTEST_THREADS 16
+#define NMUTEXES 32
+#define NMBOXES 32
+#define NSEMAPHORES 32
+#define NFLAGS 32
+#define NCOUNTERS 32
+#define NALARMS 32
+#endif
+
+#define NSAMPLES 32
+#define NTHREAD_SWITCHES 128
+#define NSCHEDS 128
+
+#define NSAMPLES_SIM 2
+#define NTEST_THREADS_SIM 2
+#define NTHREAD_SWITCHES_SIM 4
+#define NMUTEXES_SIM 2
+#define NMBOXES_SIM 2
+#define NSEMAPHORES_SIM 2
+#define NSCHEDS_SIM 4
+#define NFLAGS_SIM 2
+#define NCOUNTERS_SIM 2
+#define NALARMS_SIM 2
+
+static int nsamples;
+static int ntest_threads;
+static int nthread_switches;
+static int nmutexes;
+static int nmboxes;
+static int nsemaphores;
+static int nscheds;
+static int nflags;
+static int ncounters;
+static int nalarms;
+
+static char stacks[NTEST_THREADS][STACK_SIZE];
+static cyg_thread test_threads[NTEST_THREADS];
+static cyg_handle_t threads[NTEST_THREADS];
+static int overhead;
+static cyg_sem_t synchro;
+static fun_times thread_ft[NTEST_THREADS];
+
+static fun_times test2_ft[NTHREAD_SWITCHES];
+
+static cyg_mutex_t test_mutexes[NMUTEXES];
+static fun_times mutex_ft[NMUTEXES];
+static cyg_thread mutex_test_thread;
+static cyg_handle_t mutex_test_thread_handle;
+
+static cyg_mbox test_mboxes[NMBOXES];
+static cyg_handle_t test_mbox_handles[NMBOXES];
+static fun_times mbox_ft[NMBOXES];
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+static cyg_thread mbox_test_thread;
+static cyg_handle_t mbox_test_thread_handle;
+#endif
+
+static cyg_sem_t test_semaphores[NSEMAPHORES];
+static fun_times semaphore_ft[NSEMAPHORES];
+static cyg_thread semaphore_test_thread;
+static cyg_handle_t semaphore_test_thread_handle;
+
+static fun_times sched_ft[NSCHEDS];
+
+static cyg_counter test_counters[NCOUNTERS];
+static cyg_handle_t counters[NCOUNTERS];
+static fun_times counter_ft[NCOUNTERS];
+
+static cyg_flag_t test_flags[NFLAGS];
+static fun_times flag_ft[NFLAGS];
+
+static cyg_alarm test_alarms[NALARMS];
+static cyg_handle_t alarms[NALARMS];
+static fun_times alarm_ft[NALARMS];
+
+static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
+static long ns_per_system_clock;
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
+// Data kept by kernel real time clock measuring clock interrupt latency
+extern cyg_tick_count total_clock_latency, total_clock_interrupts;
+extern cyg_int32 min_clock_latency, max_clock_latency;
+extern bool measure_clock_latency;
+#endif
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) && defined(HAL_CLOCK_LATENCY)
+extern cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls;
+extern cyg_int32 min_clock_dsr_latency, max_clock_dsr_latency;
+extern bool measure_clock_latency;
+#endif
+
+void run_sched_tests(void);
+void run_thread_tests(void);
+void run_thread_switch_test(void);
+void run_mutex_tests(void);
+void run_mutex_circuit_test(void);
+void run_mbox_tests(void);
+void run_mbox_circuit_test(void);
+void run_semaphore_tests(void);
+void run_semaphore_circuit_test(void);
+void run_counter_tests(void);
+void run_flag_tests(void);
+void run_alarm_tests(void);
+
+#ifndef max
+#define max(n,m) (m > n ? n : m)
+#endif
+
+// Wait until a clock tick [real time clock] has passed. This should keep it
+// from happening again during a measurement, thus minimizing any fluctuations
+void
+wait_for_tick(void)
+{
+ cyg_tick_count_t tv0, tv1;
+ tv0 = cyg_current_time();
+ while (true) {
+ tv1 = cyg_current_time();
+ if (tv1 != tv0) break;
+ }
+}
+
+// Display a number of ticks as microseconds
+// Note: for improved calculation significance, values are kept in ticks*1000
+void
+show_ticks_in_us(cyg_uint32 ticks)
+{
+ long long ns;
+ ns = (ns_per_system_clock * (long long)ticks) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
+ ns += 5; // for rounding to .01us
+ diag_printf("%5d.%02d", (int)(ns/1000), (int)((ns%1000)/10));
+}
+
+//
+// If the kernel is instrumented to measure clock interrupt latency, these
+// measurements can be drastically perturbed by printing via "diag_printf()"
+// since that code may run with interrupts disabled for long periods.
+//
+// In order to get accurate/reasonable latency figures _for the kernel
+// primitive functions beint tested_, the kernel's latency measurements
+// are suspended while the printing actually takes place.
+//
+// The measurements are reenabled after the printing, thus allowing for
+// fair measurements of the kernel primitives, which are not distorted
+// by the printing mechanisms.
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
+void
+disable_clock_latency_measurement(void)
+{
+ wait_for_tick();
+ measure_clock_latency = false;
+}
+
+void
+enable_clock_latency_measurement(void)
+{
+ wait_for_tick();
+ measure_clock_latency = true;
+}
+
+// Ensure that the measurements are reasonable (no startup anomalies)
+void
+reset_clock_latency_measurement(void)
+{
+ disable_clock_latency_measurement();
+ total_clock_latency = 0;
+ total_clock_interrupts = 0;
+ min_clock_latency = 0x7FFFFFFF;
+ max_clock_latency = 0;
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) && defined(HAL_CLOCK_LATENCY)
+ total_clock_dsr_latency = 0;
+ total_clock_dsr_calls = 0;
+ min_clock_dsr_latency = 0x7FFFFFFF;
+ max_clock_dsr_latency = 0;
+#endif
+ enable_clock_latency_measurement();
+
+}
+#else
+#define disable_clock_latency_measurement()
+#define enable_clock_latency_measurement()
+#define reset_clock_latency_measurement()
+#endif
+
+void
+show_times_hdr(void)
+{
+ disable_clock_latency_measurement();
+ diag_printf("\n");
+ diag_printf(" Confidence\n");
+ diag_printf(" Ave Min Max Var Ave Min Function\n");
+ diag_printf(" ====== ====== ====== ====== ========== ========\n");
+ enable_clock_latency_measurement();
+}
+
+void
+show_times_detail(fun_times ft[], int nsamples, char *title, bool ignore_first)
+{
+ int i, delta, min, max, con_ave, con_min, ave_dev;
+ int start_sample, total_samples;
+ cyg_int32 total, ave;
+
+ if (ignore_first) {
+ start_sample = 1;
+ total_samples = nsamples-1;
+ } else {
+ start_sample = 0;
+ total_samples = nsamples;
+ }
+ total = 0;
+ min = 0x7FFFFFFF;
+ max = 0;
+ for (i = start_sample; i < nsamples; i++) {
+ if (ft[i].end < ft[i].start) {
+ // Clock wrapped around (timer tick)
+ delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
+ } else {
+ delta = ft[i].end - ft[i].start;
+ }
+ delta -= overhead;
+ if (delta < 0) delta = 0;
+ delta *= 1000;
+ total += delta;
+ if (delta < min) min = delta;
+ if (delta > max) max = delta;
+ }
+ ave = total / total_samples;
+ total = 0;
+ ave_dev = 0;
+ for (i = start_sample; i < nsamples; i++) {
+ if (ft[i].end < ft[i].start) {
+ // Clock wrapped around (timer tick)
+ delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
+ } else {
+ delta = ft[i].end - ft[i].start;
+ }
+ delta -= overhead;
+ if (delta < 0) delta = 0;
+ delta *= 1000;
+ delta = delta - ave;
+ if (delta < 0) delta = -delta;
+ ave_dev += delta;
+ }
+ ave_dev /= total_samples;
+ con_ave = 0;
+ con_min = 0;
+ for (i = start_sample; i < nsamples; i++) {
+ if (ft[i].end < ft[i].start) {
+ // Clock wrapped around (timer tick)
+ delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start;
+ } else {
+ delta = ft[i].end - ft[i].start;
+ }
+ delta -= overhead;
+ if (delta < 0) delta = 0;
+ delta *= 1000;
+ if ((delta <= (ave+ave_dev)) && (delta >= (ave-ave_dev))) con_ave++;
+ if ((delta <= (min+ave_dev)) && (delta >= (min-ave_dev))) con_min++;
+ }
+ con_ave = (con_ave * 100) / total_samples;
+ con_min = (con_min * 100) / total_samples;
+ show_ticks_in_us(ave);
+ show_ticks_in_us(min);
+ show_ticks_in_us(max);
+ show_ticks_in_us(ave_dev);
+ disable_clock_latency_measurement();
+ diag_printf(" %3d%% %3d%%", con_ave, con_min);
+ diag_printf(" %s\n", title);
+ enable_clock_latency_measurement();
+}
+
+void
+show_times(fun_times ft[], int nsamples, char *title)
+{
+ show_times_detail(ft, nsamples, title, false);
+#ifdef STATS_WITHOUT_FIRST_SAMPLE
+ show_times_detail(ft, nsamples, "", true);
+#endif
+}
+
+void
+show_test_parameters(void)
+{
+ disable_clock_latency_measurement();
+ diag_printf("\nTesting parameters:\n");
+ diag_printf(" Clock samples: %5d\n", nsamples);
+ diag_printf(" Threads: %5d\n", ntest_threads);
+ diag_printf(" Thread switches: %5d\n", nthread_switches);
+ diag_printf(" Mutexes: %5d\n", nmutexes);
+ diag_printf(" Mailboxes: %5d\n", nmboxes);
+ diag_printf(" Semaphores: %5d\n", nsemaphores);
+ diag_printf(" Scheduler operations: %5d\n", nscheds);
+ diag_printf(" Counters: %5d\n", ncounters);
+ diag_printf(" Flags: %5d\n", nflags);
+ diag_printf(" Alarms: %5d\n", nalarms);
+ diag_printf("\n");
+ enable_clock_latency_measurement();
+}
+
+void
+end_of_test_group(void)
+{
+ disable_clock_latency_measurement();
+ diag_printf("\n");
+ enable_clock_latency_measurement();
+}
+
+// Compute a name for a thread
+char *
+thread_name(char *basename, int indx) {
+ return "<<NULL>>"; // Not currently used
+}
+
+// test0 - null test, never executed
+void
+test0(cyg_uint32 indx)
+{
+#ifndef CYGPKG_KERNEL_SMP_SUPPORT
+ // In SMP, somw of these threads will execute
+ diag_printf("test0.%d executed?\n", indx);
+#endif
+ cyg_thread_exit();
+}
+
+// test1 - empty test, simply exit. Last thread signals parent.
+void
+test1(cyg_uint32 indx)
+{
+ if (indx == (cyg_uint32)(ntest_threads-1)) {
+ cyg_semaphore_post(&synchro); // Signal that last thread is dying
+ }
+ cyg_thread_exit();
+}
+
+// test2 - measure thread switch times
+void
+test2(cyg_uint32 indx)
+{
+ int i;
+ for (i = 0; i < nthread_switches; i++) {
+ if (indx == 0) {
+ HAL_CLOCK_READ(&test2_ft[i].start);
+ } else {
+ HAL_CLOCK_READ(&test2_ft[i].end);
+ }
+ cyg_thread_yield();
+ }
+ if (indx == 1) {
+ cyg_semaphore_post(&synchro);
+ }
+ cyg_thread_exit();
+}
+
+// Full-circuit mutex unlock/lock test
+void
+mutex_test(cyg_uint32 indx)
+{
+ int i;
+ cyg_mutex_lock(&test_mutexes[0]);
+ for (i = 0; i < nmutexes; i++) {
+ cyg_semaphore_wait(&synchro);
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ HAL_CLOCK_READ(&mutex_ft[i].start);
+ cyg_mutex_unlock(&test_mutexes[0]);
+ cyg_mutex_lock(&test_mutexes[0]);
+ cyg_semaphore_post(&synchro);
+ }
+ cyg_thread_exit();
+}
+
+// Full-circuit mbox put/get test
+void
+mbox_test(cyg_uint32 indx)
+{
+ void *item;
+ do {
+ item = cyg_mbox_get(test_mbox_handles[0]);
+ HAL_CLOCK_READ(&mbox_ft[(int)item].end);
+ cyg_semaphore_post(&synchro);
+ } while ((int)item != (nmboxes-1));
+ cyg_thread_exit();
+}
+
+// Full-circuit semaphore post/wait test
+void
+semaphore_test(cyg_uint32 indx)
+{
+ int i;
+ for (i = 0; i < nsemaphores; i++) {
+ cyg_semaphore_wait(&test_semaphores[0]);
+ HAL_CLOCK_READ(&semaphore_ft[i].end);
+ cyg_semaphore_post(&synchro);
+ }
+ cyg_thread_exit();
+}
+
+//
+// This set of tests is used to measure kernel primitives that deal with threads
+//
+void
+run_thread_tests(void)
+{
+ int i;
+ cyg_priority_t prio;
+
+ // Set my priority higher than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_create(10, // Priority - just a number
+ test0, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Create thread");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_yield();
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Yield thread [all suspended]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_suspend(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Suspend [suspended] thread");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_resume(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Resume thread");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_set_priority(threads[i], 11);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Set priority");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ prio = cyg_thread_get_priority(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Get priority");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_kill(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Kill [suspended] thread");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_yield();
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Yield [no other] thread");
+
+ // Set my priority higher than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+
+ // Recreate the test set
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_create(10, // Priority - just a number
+ test0, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ }
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_resume(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Resume [suspended low prio] thread");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_resume(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Resume [runnable low prio] thread");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_suspend(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Suspend [runnable] thread");
+
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_yield();
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Yield [only low prio] thread");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_suspend(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Suspend [runnable->not runnable]");
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_resume(threads[i]);
+ }
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_kill(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Kill [runnable] thread");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_delete(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Destroy [dead] thread");
+
+ // Recreate the test set
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_create(10, // Priority - just a number
+ test0, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ cyg_thread_resume(threads[i]);
+ }
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_delete(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Destroy [runnable] thread");
+
+ // Set my priority lower than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 3);
+
+ // Set up the end-of-threads synchronizer
+ cyg_semaphore_init(&synchro, 0);
+
+ // Recreate the test set
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_create(2, // Priority - just a number
+ test1, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ }
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ntest_threads; i++) {
+ HAL_CLOCK_READ(&thread_ft[i].start);
+ cyg_thread_resume(threads[i]);
+ HAL_CLOCK_READ(&thread_ft[i].end);
+ }
+ show_times(thread_ft, ntest_threads, "Resume [high priority] thread");
+ cyg_semaphore_wait(&synchro); // Wait for all threads to finish
+ // Make sure they are all dead
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_delete(threads[i]);
+ }
+
+ run_thread_switch_test();
+ end_of_test_group();
+}
+
+void
+run_thread_switch_test(void)
+{
+ int i;
+
+ // Set up for thread context switch
+ for (i = 0; i < 2; i++) {
+ cyg_thread_create(10, // Priority - just a number
+ test2, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ cyg_thread_resume(threads[i]);
+ }
+ // Set up the end-of-threads synchronizer
+ cyg_semaphore_init(&synchro, 0);
+ cyg_semaphore_wait(&synchro);
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ show_times(test2_ft, nthread_switches, "Thread switch");
+ // Clean up
+ for (i = 0; i < 2; i++) {
+ cyg_thread_delete(threads[i]);
+ }
+}
+
+void
+run_mutex_tests(void)
+{
+ int i;
+
+ // Mutex primitives
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmutexes; i++) {
+ HAL_CLOCK_READ(&mutex_ft[i].start);
+ cyg_mutex_init(&test_mutexes[i]);
+ HAL_CLOCK_READ(&mutex_ft[i].end);
+ }
+ show_times(mutex_ft, nmutexes, "Init mutex");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmutexes; i++) {
+ HAL_CLOCK_READ(&mutex_ft[i].start);
+ cyg_mutex_lock(&test_mutexes[i]);
+ HAL_CLOCK_READ(&mutex_ft[i].end);
+ }
+ show_times(mutex_ft, nmutexes, "Lock [unlocked] mutex");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmutexes; i++) {
+ HAL_CLOCK_READ(&mutex_ft[i].start);
+ cyg_mutex_unlock(&test_mutexes[i]);
+ HAL_CLOCK_READ(&mutex_ft[i].end);
+ }
+ show_times(mutex_ft, nmutexes, "Unlock [locked] mutex");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmutexes; i++) {
+ HAL_CLOCK_READ(&mutex_ft[i].start);
+ cyg_mutex_trylock(&test_mutexes[i]);
+ HAL_CLOCK_READ(&mutex_ft[i].end);
+ }
+ show_times(mutex_ft, nmutexes, "Trylock [unlocked] mutex");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmutexes; i++) {
+ HAL_CLOCK_READ(&mutex_ft[i].start);
+ cyg_mutex_trylock(&test_mutexes[i]);
+ HAL_CLOCK_READ(&mutex_ft[i].end);
+ }
+ show_times(mutex_ft, nmutexes, "Trylock [locked] mutex");
+
+ // Must unlock mutices before destroying them.
+ for (i = 0; i < nmutexes; i++) {
+ cyg_mutex_unlock(&test_mutexes[i]);
+ }
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmutexes; i++) {
+ HAL_CLOCK_READ(&mutex_ft[i].start);
+ cyg_mutex_destroy(&test_mutexes[i]);
+ HAL_CLOCK_READ(&mutex_ft[i].end);
+ }
+ show_times(mutex_ft, nmutexes, "Destroy mutex");
+ run_mutex_circuit_test();
+ end_of_test_group();
+}
+
+void
+run_mutex_circuit_test(void)
+{
+ int i;
+ // Set my priority lower than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 4);
+ // Set up for full mutex unlock/lock test
+ cyg_mutex_init(&test_mutexes[0]);
+ cyg_semaphore_init(&synchro, 0);
+ cyg_thread_create(3, // Priority - just a number
+ mutex_test, // entry
+ 0, // index
+ thread_name("thread", 0), // Name
+ &stacks[0][0], // Stack
+ STACK_SIZE, // Size
+ &mutex_test_thread_handle, // Handle
+ &mutex_test_thread // Thread data structure
+ );
+ cyg_thread_resume(mutex_test_thread_handle);
+ // Need to raise priority so that this thread will block on the "lock"
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+ for (i = 0; i < nmutexes; i++) {
+ cyg_semaphore_post(&synchro);
+ cyg_mutex_lock(&test_mutexes[0]);
+ HAL_CLOCK_READ(&mutex_ft[i].end);
+ cyg_mutex_unlock(&test_mutexes[0]);
+ cyg_semaphore_wait(&synchro);
+ }
+ cyg_thread_delete(mutex_test_thread_handle);
+ show_times(mutex_ft, nmutexes, "Unlock/Lock mutex");
+}
+
+void
+run_mbox_tests(void)
+{
+ int i, cnt;
+ void *item;
+ // Mailbox primitives
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cyg_mbox_create(&test_mbox_handles[i], &test_mboxes[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Create mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cnt = cyg_mbox_peek(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Peek [empty] mbox");
+
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cyg_mbox_put(test_mbox_handles[i], (void *)i);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Put [first] mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cnt = cyg_mbox_peek(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Peek [1 msg] mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cyg_mbox_put(test_mbox_handles[i], (void *)i);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Put [second] mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cnt = cyg_mbox_peek(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Peek [2 msgs] mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ item = cyg_mbox_get(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Get [first] mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ item = cyg_mbox_get(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Get [second] mbox");
+#endif // ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cyg_mbox_tryput(test_mbox_handles[i], (void *)i);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Tryput [first] mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ item = cyg_mbox_peek_item(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Peek item [non-empty] mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ item = cyg_mbox_tryget(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Tryget [non-empty] mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ item = cyg_mbox_peek_item(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Peek item [empty] mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ item = cyg_mbox_tryget(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Tryget [empty] mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cyg_mbox_waiting_to_get(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Waiting to get mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cyg_mbox_waiting_to_put(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Waiting to put mbox");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nmboxes; i++) {
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cyg_mbox_delete(test_mbox_handles[i]);
+ HAL_CLOCK_READ(&mbox_ft[i].end);
+ }
+ show_times(mbox_ft, nmboxes, "Delete mbox");
+
+ run_mbox_circuit_test();
+ end_of_test_group();
+}
+
+void
+run_mbox_circuit_test(void)
+{
+#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT
+ int i;
+ // Set my priority lower than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 3);
+ // Set up for full mbox put/get test
+ cyg_mbox_create(&test_mbox_handles[0], &test_mboxes[0]);
+ cyg_semaphore_init(&synchro, 0);
+ cyg_thread_create(2, // Priority - just a number
+ mbox_test, // entry
+ 0, // index
+ thread_name("thread", 0), // Name
+ &stacks[0][0], // Stack
+ STACK_SIZE, // Size
+ &mbox_test_thread_handle, // Handle
+ &mbox_test_thread // Thread data structure
+ );
+ cyg_thread_resume(mbox_test_thread_handle);
+ for (i = 0; i < nmboxes; i++) {
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ HAL_CLOCK_READ(&mbox_ft[i].start);
+ cyg_mbox_put(test_mbox_handles[0], (void *)i);
+ cyg_semaphore_wait(&synchro);
+ }
+ cyg_thread_delete(mbox_test_thread_handle);
+ show_times(mbox_ft, nmboxes, "Put/Get mbox");
+#endif
+}
+
+void
+run_semaphore_tests(void)
+{
+ int i;
+ cyg_count32 sem_val;
+ // Semaphore primitives
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nsemaphores; i++) {
+ HAL_CLOCK_READ(&semaphore_ft[i].start);
+ cyg_semaphore_init(&test_semaphores[i], 0);
+ HAL_CLOCK_READ(&semaphore_ft[i].end);
+ }
+ show_times(semaphore_ft, nsemaphores, "Init semaphore");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nsemaphores; i++) {
+ HAL_CLOCK_READ(&semaphore_ft[i].start);
+ cyg_semaphore_post(&test_semaphores[i]);
+ HAL_CLOCK_READ(&semaphore_ft[i].end);
+ }
+ show_times(semaphore_ft, nsemaphores, "Post [0] semaphore");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nsemaphores; i++) {
+ HAL_CLOCK_READ(&semaphore_ft[i].start);
+ cyg_semaphore_wait(&test_semaphores[i]);
+ HAL_CLOCK_READ(&semaphore_ft[i].end);
+ }
+ show_times(semaphore_ft, nsemaphores, "Wait [1] semaphore");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nsemaphores; i++) {
+ HAL_CLOCK_READ(&semaphore_ft[i].start);
+ cyg_semaphore_trywait(&test_semaphores[i]);
+ HAL_CLOCK_READ(&semaphore_ft[i].end);
+ }
+ show_times(semaphore_ft, nsemaphores, "Trywait [0] semaphore");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nsemaphores; i++) {
+ cyg_semaphore_post(&test_semaphores[i]);
+ HAL_CLOCK_READ(&semaphore_ft[i].start);
+ cyg_semaphore_trywait(&test_semaphores[i]);
+ HAL_CLOCK_READ(&semaphore_ft[i].end);
+ }
+ show_times(semaphore_ft, nsemaphores, "Trywait [1] semaphore");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nsemaphores; i++) {
+ HAL_CLOCK_READ(&semaphore_ft[i].start);
+ cyg_semaphore_peek(&test_semaphores[i], &sem_val);
+ HAL_CLOCK_READ(&semaphore_ft[i].end);
+ }
+ show_times(semaphore_ft, nsemaphores, "Peek semaphore");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nsemaphores; i++) {
+ HAL_CLOCK_READ(&semaphore_ft[i].start);
+ cyg_semaphore_destroy(&test_semaphores[i]);
+ HAL_CLOCK_READ(&semaphore_ft[i].end);
+ }
+ show_times(semaphore_ft, nsemaphores, "Destroy semaphore");
+
+ run_semaphore_circuit_test();
+ end_of_test_group();
+}
+
+void
+run_semaphore_circuit_test(void)
+{
+ int i;
+ // Set my priority lower than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 3);
+ // Set up for full semaphore post/wait test
+ cyg_semaphore_init(&test_semaphores[0], 0);
+ cyg_semaphore_init(&synchro, 0);
+ cyg_thread_create(2, // Priority - just a number
+ semaphore_test, // entry
+ 0, // index
+ thread_name("thread", 0), // Name
+ &stacks[0][0], // Stack
+ STACK_SIZE, // Size
+ &semaphore_test_thread_handle, // Handle
+ &semaphore_test_thread // Thread data structure
+ );
+ cyg_thread_resume(semaphore_test_thread_handle);
+ for (i = 0; i < nsemaphores; i++) {
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ HAL_CLOCK_READ(&semaphore_ft[i].start);
+ cyg_semaphore_post(&test_semaphores[0]);
+ cyg_semaphore_wait(&synchro);
+ }
+ cyg_thread_delete(semaphore_test_thread_handle);
+ show_times(semaphore_ft, nsemaphores, "Post/Wait semaphore");
+}
+
+void
+run_counter_tests(void)
+{
+ int i;
+ cyg_tick_count_t val=0;
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ncounters; i++) {
+ HAL_CLOCK_READ(&counter_ft[i].start);
+ cyg_counter_create(&counters[i], &test_counters[i]);
+ HAL_CLOCK_READ(&counter_ft[i].end);
+ }
+ show_times(counter_ft, ncounters, "Create counter");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ncounters; i++) {
+ HAL_CLOCK_READ(&counter_ft[i].start);
+ val = cyg_counter_current_value(counters[i]);
+ HAL_CLOCK_READ(&counter_ft[i].end);
+ }
+ show_times(counter_ft, ncounters, "Get counter value");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ncounters; i++) {
+ HAL_CLOCK_READ(&counter_ft[i].start);
+ cyg_counter_set_value(counters[i], val);
+ HAL_CLOCK_READ(&counter_ft[i].end);
+ }
+ show_times(counter_ft, ncounters, "Set counter value");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ncounters; i++) {
+ HAL_CLOCK_READ(&counter_ft[i].start);
+ cyg_counter_tick(counters[i]);
+ HAL_CLOCK_READ(&counter_ft[i].end);
+ }
+ show_times(counter_ft, ncounters, "Tick counter");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ncounters; i++) {
+ HAL_CLOCK_READ(&counter_ft[i].start);
+ cyg_counter_delete(counters[i]);
+ HAL_CLOCK_READ(&counter_ft[i].end);
+ }
+ show_times(counter_ft, ncounters, "Delete counter");
+ end_of_test_group();
+}
+
+void
+run_flag_tests(void)
+{
+ int i;
+ cyg_flag_value_t val;
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nflags; i++) {
+ HAL_CLOCK_READ(&flag_ft[i].start);
+ cyg_flag_init(&test_flags[i]);
+ HAL_CLOCK_READ(&flag_ft[i].end);
+ }
+ show_times(flag_ft, nflags, "Init flag");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nflags; i++) {
+ HAL_CLOCK_READ(&flag_ft[i].start);
+ cyg_flag_destroy(&test_flags[i]);
+ HAL_CLOCK_READ(&flag_ft[i].end);
+ }
+ show_times(flag_ft, nflags, "Destroy flag");
+
+ // Recreate the flags - reused in the remaining tests
+ for (i = 0; i < nflags; i++) {
+ cyg_flag_init(&test_flags[i]);
+ }
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nflags; i++) {
+ HAL_CLOCK_READ(&flag_ft[i].start);
+ cyg_flag_maskbits(&test_flags[i], 0);
+ HAL_CLOCK_READ(&flag_ft[i].end);
+ }
+ show_times(flag_ft, nflags, "Mask bits in flag");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nflags; i++) {
+ HAL_CLOCK_READ(&flag_ft[i].start);
+ cyg_flag_setbits(&test_flags[i], 0x11);
+ HAL_CLOCK_READ(&flag_ft[i].end);
+ }
+ show_times(flag_ft, nflags, "Set bits in flag [no waiters]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nflags; i++) {
+ cyg_flag_setbits(&test_flags[i], 0x11);
+ HAL_CLOCK_READ(&flag_ft[i].start);
+ cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_AND);
+ HAL_CLOCK_READ(&flag_ft[i].end);
+ }
+ show_times(flag_ft, nflags, "Wait for flag [AND]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nflags; i++) {
+ cyg_flag_setbits(&test_flags[i], 0x11);
+ HAL_CLOCK_READ(&flag_ft[i].start);
+ cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_OR);
+ HAL_CLOCK_READ(&flag_ft[i].end);
+ }
+ show_times(flag_ft, nflags, "Wait for flag [OR]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nflags; i++) {
+ cyg_flag_setbits(&test_flags[i], 0x11);
+ HAL_CLOCK_READ(&flag_ft[i].start);
+ cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_AND|CYG_FLAG_WAITMODE_CLR);
+ HAL_CLOCK_READ(&flag_ft[i].end);
+ }
+ show_times(flag_ft, nflags, "Wait for flag [AND/CLR]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nflags; i++) {
+ cyg_flag_setbits(&test_flags[i], 0x11);
+ HAL_CLOCK_READ(&flag_ft[i].start);
+ cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR);
+ HAL_CLOCK_READ(&flag_ft[i].end);
+ }
+ show_times(flag_ft, nflags, "Wait for flag [OR/CLR]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nflags; i++) {
+ cyg_flag_setbits(&test_flags[i], 0x11);
+ HAL_CLOCK_READ(&flag_ft[i].start);
+ val = cyg_flag_peek(&test_flags[i]);
+ HAL_CLOCK_READ(&flag_ft[i].end);
+ }
+ show_times(flag_ft, nflags, "Peek on flag");
+
+ // Destroy flags - no longer needed
+ for (i = 0; i < nflags; i++) {
+ cyg_flag_destroy(&test_flags[i]);
+ }
+ end_of_test_group();
+}
+
+// Alarm callback function
+void
+alarm_cb(cyg_handle_t alarm, cyg_addrword_t val)
+{
+ // empty call back
+}
+
+// Callback used to test determinancy
+static volatile int alarm_cnt;
+void
+alarm_cb2(cyg_handle_t alarm, cyg_addrword_t indx)
+{
+ if (alarm_cnt == nscheds) return;
+ sched_ft[alarm_cnt].start = 0;
+ HAL_CLOCK_READ(&sched_ft[alarm_cnt++].end);
+ if (alarm_cnt == nscheds) {
+ cyg_semaphore_post(&synchro);
+ }
+}
+
+static void
+alarm_cb3(cyg_handle_t alarm, cyg_addrword_t indx)
+{
+ if (alarm_cnt == nscheds) {
+ cyg_semaphore_post(&synchro);
+ } else {
+ sched_ft[alarm_cnt].start = 0;
+ cyg_thread_resume((cyg_handle_t)indx);
+ }
+}
+
+// Null thread, used to keep scheduler busy
+void
+alarm_test(cyg_uint32 id)
+{
+ while (true) {
+ cyg_thread_yield();
+ }
+}
+
+// Thread that suspends itself at the first opportunity
+void
+alarm_test2(cyg_uint32 id)
+{
+ cyg_handle_t me = cyg_thread_self();
+ while (true) {
+ HAL_CLOCK_READ(&sched_ft[alarm_cnt++].end);
+ cyg_thread_suspend(me);
+ }
+}
+
+void
+run_alarm_tests(void)
+{
+ int i;
+ cyg_tick_count_t init_val, step_val;
+ cyg_handle_t rtc_handle;
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < ncounters; i++) {
+ cyg_counter_create(&counters[i], &test_counters[i]);
+ }
+ for (i = 0; i < nalarms; i++) {
+ HAL_CLOCK_READ(&alarm_ft[i].start);
+ cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[i], &test_alarms[i]);
+ HAL_CLOCK_READ(&alarm_ft[i].end);
+ }
+ show_times(alarm_ft, nalarms, "Create alarm");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ init_val = 0; step_val = 0;
+ for (i = 0; i < nalarms; i++) {
+ HAL_CLOCK_READ(&alarm_ft[i].start);
+ cyg_alarm_initialize(alarms[i], init_val, step_val);
+ HAL_CLOCK_READ(&alarm_ft[i].end);
+ }
+ show_times(alarm_ft, nalarms, "Initialize alarm");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ init_val = 0; step_val = 0;
+ for (i = 0; i < nalarms; i++) {
+ HAL_CLOCK_READ(&alarm_ft[i].start);
+ cyg_alarm_disable(alarms[i]);
+ HAL_CLOCK_READ(&alarm_ft[i].end);
+ }
+ show_times(alarm_ft, nalarms, "Disable alarm");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ init_val = 0; step_val = 0;
+ for (i = 0; i < nalarms; i++) {
+ HAL_CLOCK_READ(&alarm_ft[i].start);
+ cyg_alarm_enable(alarms[i]);
+ HAL_CLOCK_READ(&alarm_ft[i].end);
+ }
+ show_times(alarm_ft, nalarms, "Enable alarm");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nalarms; i++) {
+ HAL_CLOCK_READ(&alarm_ft[i].start);
+ cyg_alarm_delete(alarms[i]);
+ HAL_CLOCK_READ(&alarm_ft[i].end);
+ }
+ show_times(alarm_ft, nalarms, "Delete alarm");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ cyg_counter_create(&counters[0], &test_counters[0]);
+ cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[0], &test_alarms[0]);
+ init_val = 9999; step_val = 9999;
+ cyg_alarm_initialize(alarms[0], init_val, step_val);
+ cyg_alarm_enable(alarms[0]);
+ for (i = 0; i < ncounters; i++) {
+ HAL_CLOCK_READ(&counter_ft[i].start);
+ cyg_counter_tick(counters[0]);
+ HAL_CLOCK_READ(&counter_ft[i].end);
+ }
+ show_times(counter_ft, ncounters, "Tick counter [1 alarm]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ cyg_counter_create(&counters[0], &test_counters[0]);
+ for (i = 0; i < nalarms; i++) {
+ cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[i], &test_alarms[i]);
+ init_val = 9999; step_val = 9999;
+ cyg_alarm_initialize(alarms[i], init_val, step_val);
+ cyg_alarm_enable(alarms[i]);
+ }
+ for (i = 0; i < ncounters; i++) {
+ HAL_CLOCK_READ(&counter_ft[i].start);
+ cyg_counter_tick(counters[0]);
+ HAL_CLOCK_READ(&counter_ft[i].end);
+ }
+ show_times(counter_ft, ncounters, "Tick counter [many alarms]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ cyg_counter_create(&counters[0], &test_counters[0]);
+ cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[0], &test_alarms[0]);
+ init_val = 1; step_val = 1;
+ cyg_alarm_initialize(alarms[0], init_val, step_val);
+ cyg_alarm_enable(alarms[0]);
+ for (i = 0; i < ncounters; i++) {
+ HAL_CLOCK_READ(&counter_ft[i].start);
+ cyg_counter_tick(counters[0]);
+ HAL_CLOCK_READ(&counter_ft[i].end);
+ }
+ show_times(counter_ft, ncounters, "Tick & fire counter [1 alarm]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ cyg_counter_create(&counters[0], &test_counters[0]);
+ for (i = 0; i < nalarms; i++) {
+ cyg_alarm_create(counters[0], alarm_cb, i, &alarms[i], &test_alarms[i]);
+ init_val = 1; step_val = 1;
+ cyg_alarm_initialize(alarms[i], init_val, step_val);
+ cyg_alarm_enable(alarms[i]);
+ }
+ for (i = 0; i < nalarms; i++) {
+ HAL_CLOCK_READ(&alarm_ft[i].start);
+ cyg_counter_tick(counters[0]);
+ HAL_CLOCK_READ(&alarm_ft[i].end);
+ }
+ for (i = 0; i < nalarms; i++) {
+ cyg_alarm_delete(alarms[i]);
+ }
+ show_times(alarm_ft, nalarms, "Tick & fire counters [>1 together]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ cyg_counter_create(&counters[0], &test_counters[0]);
+ for (i = 0; i < nalarms; i++) {
+ cyg_alarm_create(counters[0], alarm_cb, i, &alarms[i], &test_alarms[i]);
+ init_val = i+1; step_val = nalarms+1;
+ cyg_alarm_initialize(alarms[i], init_val, step_val);
+ cyg_alarm_enable(alarms[i]);
+ }
+ for (i = 0; i < nalarms; i++) {
+ HAL_CLOCK_READ(&alarm_ft[i].start);
+ cyg_counter_tick(counters[0]);
+ HAL_CLOCK_READ(&alarm_ft[i].end);
+ }
+ for (i = 0; i < nalarms; i++) {
+ cyg_alarm_delete(alarms[i]);
+ }
+ show_times(alarm_ft, nalarms, "Tick & fire counters [>1 separately]");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle);
+ cyg_alarm_create(rtc_handle, alarm_cb2, 0, &alarms[0], &test_alarms[0]);
+ init_val = 5; step_val = 5; alarm_cnt = 0;
+ cyg_alarm_initialize(alarms[0], init_val, step_val);
+ cyg_semaphore_init(&synchro, 0);
+ cyg_alarm_enable(alarms[0]);
+ cyg_semaphore_wait(&synchro);
+ cyg_alarm_disable(alarms[0]);
+ cyg_alarm_delete(alarms[0]);
+ show_times(sched_ft, nscheds, "Alarm latency [0 threads]");
+
+ // Set my priority higher than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+ for (i = 0; i < 2; i++) {
+ cyg_thread_create(10, // Priority - just a number
+ alarm_test, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ cyg_thread_resume(threads[i]);
+ }
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle);
+ cyg_alarm_create(rtc_handle, alarm_cb2, 0, &alarms[0], &test_alarms[0]);
+ init_val = 5; step_val = 5; alarm_cnt = 0;
+ cyg_alarm_initialize(alarms[0], init_val, step_val);
+ cyg_semaphore_init(&synchro, 0);
+ cyg_alarm_enable(alarms[0]);
+ cyg_semaphore_wait(&synchro);
+ cyg_alarm_disable(alarms[0]);
+ cyg_alarm_delete(alarms[0]);
+ show_times(sched_ft, nscheds, "Alarm latency [2 threads]");
+ for (i = 0; i < 2; i++) {
+ cyg_thread_suspend(threads[i]);
+ cyg_thread_delete(threads[i]);
+ }
+
+ // Set my priority higher than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_create(10, // Priority - just a number
+ alarm_test, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ cyg_thread_resume(threads[i]);
+ }
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle);
+ cyg_alarm_create(rtc_handle, alarm_cb2, 0, &alarms[0], &test_alarms[0]);
+ init_val = 5; step_val = 5; alarm_cnt = 0;
+ cyg_alarm_initialize(alarms[0], init_val, step_val);
+ cyg_semaphore_init(&synchro, 0);
+ cyg_alarm_enable(alarms[0]);
+ cyg_semaphore_wait(&synchro);
+ cyg_alarm_disable(alarms[0]);
+ cyg_alarm_delete(alarms[0]);
+ show_times(sched_ft, nscheds, "Alarm latency [many threads]");
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_suspend(threads[i]);
+ cyg_thread_delete(threads[i]);
+ }
+
+ // Set my priority higher than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+ cyg_thread_create(10, // Priority - just a number
+ alarm_test2, // entry
+ i, // index
+ thread_name("thread", 0), // Name
+ &stacks[0][0], // Stack
+ STACK_SIZE, // Size
+ &threads[0], // Handle
+ &test_threads[0] // Thread data structure
+ );
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle);
+ cyg_alarm_create(rtc_handle, alarm_cb3, threads[0], &alarms[0],
+ &test_alarms[0]);
+ init_val = 5; step_val = 5; alarm_cnt = 0;
+ cyg_alarm_initialize(alarms[0], init_val, step_val);
+ cyg_semaphore_init(&synchro, 0);
+ cyg_alarm_enable(alarms[0]);
+ cyg_semaphore_wait(&synchro);
+ cyg_alarm_disable(alarms[0]);
+ cyg_alarm_delete(alarms[0]);
+ show_times(sched_ft, nscheds, "Alarm -> thread resume latency");
+ cyg_thread_suspend(threads[0]);
+ cyg_thread_delete(threads[0]);
+
+ end_of_test_group();
+}
+
+void
+run_sched_tests(void)
+{
+ int i;
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nscheds; i++) {
+ HAL_CLOCK_READ(&sched_ft[i].start);
+ cyg_scheduler_lock();
+ HAL_CLOCK_READ(&sched_ft[i].end);
+ cyg_scheduler_unlock();
+ }
+ show_times(sched_ft, nscheds, "Scheduler lock");
+
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nscheds; i++) {
+ cyg_scheduler_lock();
+ HAL_CLOCK_READ(&sched_ft[i].start);
+ cyg_scheduler_unlock();
+ HAL_CLOCK_READ(&sched_ft[i].end);
+ }
+ show_times(sched_ft, nscheds, "Scheduler unlock [0 threads]");
+
+ // Set my priority higher than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+ for (i = 0; i < 1; i++) {
+ cyg_thread_create(10, // Priority - just a number
+ test0, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ }
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nscheds; i++) {
+ cyg_scheduler_lock();
+ HAL_CLOCK_READ(&sched_ft[i].start);
+ cyg_scheduler_unlock();
+ HAL_CLOCK_READ(&sched_ft[i].end);
+ }
+ show_times(sched_ft, nscheds, "Scheduler unlock [1 suspended]");
+ for (i = 0; i < 1; i++) {
+ cyg_thread_delete(threads[i]);
+ }
+
+ // Set my priority higher than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_create(10, // Priority - just a number
+ test0, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ }
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nscheds; i++) {
+ cyg_scheduler_lock();
+ HAL_CLOCK_READ(&sched_ft[i].start);
+ cyg_scheduler_unlock();
+ HAL_CLOCK_READ(&sched_ft[i].end);
+ }
+ show_times(sched_ft, nscheds, "Scheduler unlock [many suspended]");
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_delete(threads[i]);
+ }
+
+ // Set my priority higher than any I plan to create
+ cyg_thread_set_priority(cyg_thread_self(), 2);
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_create(10, // Priority - just a number
+ test0, // entry
+ i, // index
+ thread_name("thread", i), // Name
+ &stacks[i][0], // Stack
+ STACK_SIZE, // Size
+ &threads[i], // Handle
+ &test_threads[i] // Thread data structure
+ );
+ cyg_thread_resume(threads[i]);
+ }
+ wait_for_tick(); // Wait until the next clock tick to minimize aberations
+ for (i = 0; i < nscheds; i++) {
+ cyg_scheduler_lock();
+ HAL_CLOCK_READ(&sched_ft[i].start);
+ cyg_scheduler_unlock();
+ HAL_CLOCK_READ(&sched_ft[i].end);
+ }
+ show_times(sched_ft, nscheds, "Scheduler unlock [many low prio]");
+ for (i = 0; i < ntest_threads; i++) {
+ cyg_thread_delete(threads[i]);
+ }
+ end_of_test_group();
+}
+
+static void
+_run_all_tests(CYG_ADDRESS id)
+{
+ int i, j;
+ cyg_uint32 tv[nsamples], tv0, tv1;
+ cyg_uint32 min_stack, max_stack, total_stack, actual_stack;
+ cyg_tick_count_t ticks, tick0, tick1;
+#ifdef CYG_SCHEDULER_LOCK_TIMINGS
+ cyg_uint32 lock_ave, lock_max;
+#endif
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
+ cyg_int32 clock_ave;
+#endif
+
+ disable_clock_latency_measurement();
+
+#ifndef CYGPKG_KERNEL_SMP_SUPPORT
+ cyg_test_dump_thread_stack_stats( "Startup, main stack", thread[0] );
+ cyg_test_dump_interrupt_stack_stats( "Startup" );
+ cyg_test_dump_idlethread_stack_stats( "Startup" );
+ cyg_test_clear_interrupt_stack();
+#endif
+
+ diag_printf("\neCos Kernel Timings\n");
+ diag_printf("Notes: all times are in microseconds (.000001) unless otherwise stated\n");
+#ifdef STATS_WITHOUT_FIRST_SAMPLE
+ diag_printf(" second line of results have first sample removed\n");
+#endif
+
+ cyg_thread_delay(2); // Make sure the clock is actually running
+
+ ns_per_system_clock = 1000000/rtc_resolution[1];
+
+ wait_for_tick();
+ for (i = 0; i < nsamples; i++) {
+ HAL_CLOCK_READ(&tv[i]);
+ }
+ tv0 = 0;
+ for (i = 1; i < nsamples; i++) {
+ tv0 += tv[i] - tv[i-1];
+ }
+ end_of_test_group();
+
+ overhead = tv0 / (nsamples-1);
+ diag_printf("Reading the hardware clock takes %d 'ticks' overhead\n", overhead);
+ diag_printf("... this value will be factored out of all other measurements\n");
+
+ // Try and measure how long the clock interrupt handling takes
+ for (i = 0; i < nsamples; i++) {
+ tick0 = cyg_current_time();
+ while (true) {
+ tick1 = cyg_current_time();
+ if (tick0 != tick1) break;
+ }
+ HAL_CLOCK_READ(&tv[i]);
+ }
+ tv1 = 0;
+ for (i = 0; i < nsamples; i++) {
+ tv1 += tv[i] * 1000;
+ }
+ tv1 = tv1 / nsamples;
+ tv1 -= overhead; // Adjust out the cost of getting the timer value
+ diag_printf("Clock interrupt took");
+ show_ticks_in_us(tv1);
+ diag_printf(" microseconds (%d raw clock ticks)\n", tv1/1000);
+ enable_clock_latency_measurement();
+
+ ticks = cyg_current_time();
+
+ show_test_parameters();
+ show_times_hdr();
+
+ reset_clock_latency_measurement();
+
+ run_thread_tests();
+ run_sched_tests();
+ run_mutex_tests();
+ run_mbox_tests();
+ run_semaphore_tests();
+ run_counter_tests();
+ run_flag_tests();
+ run_alarm_tests();
+
+#ifdef CYG_SCHEDULER_LOCK_TIMINGS
+ Cyg_Scheduler::get_lock_times(&lock_ave, &lock_max);
+ diag_printf("\nMax lock:");
+ show_ticks_in_us(lock_max);
+ diag_printf(", Ave lock:");
+ show_ticks_in_us(lock_ave);
+ diag_printf("\n");
+#endif
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY)
+ // Display latency figures in same format as all other numbers
+ disable_clock_latency_measurement();
+ clock_ave = (total_clock_latency*1000) / total_clock_interrupts;
+ show_ticks_in_us(clock_ave);
+ show_ticks_in_us(min_clock_latency*1000);
+ show_ticks_in_us(max_clock_latency*1000);
+ show_ticks_in_us(0);
+ diag_printf(" Clock/interrupt latency\n\n");
+ enable_clock_latency_measurement();
+#endif
+
+#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) && defined(HAL_CLOCK_LATENCY)
+ disable_clock_latency_measurement();
+ clock_ave = (total_clock_dsr_latency*1000) / total_clock_dsr_calls;
+ show_ticks_in_us(clock_ave);
+ show_ticks_in_us(min_clock_dsr_latency*1000);
+ show_ticks_in_us(max_clock_dsr_latency*1000);
+ show_ticks_in_us(0);
+ diag_printf(" Clock DSR latency\n\n");
+ enable_clock_latency_measurement();
+#endif
+
+#ifndef CYGPKG_KERNEL_SMP_SUPPORT
+ disable_clock_latency_measurement();
+ min_stack = STACK_SIZE;
+ max_stack = 0;
+ total_stack = 0;
+ for (i = 0; i < (int)NTEST_THREADS; i++) {
+ for (j = 0; j < STACK_SIZE; j++) {
+ if (stacks[i][j]) break;
+ }
+ actual_stack = STACK_SIZE-j;
+ if (actual_stack < min_stack) min_stack = actual_stack;
+ if (actual_stack > max_stack) max_stack = actual_stack;
+ total_stack += actual_stack;
+ }
+ for (j = 0; j < STACKSIZE; j++) {
+ if (((char *)stack[0])[j]) break;
+ }
+ diag_printf("%5ld %5d %5d (main stack: %5d) Thread stack used (%d total)\n",
+ (unsigned long) total_stack/NTEST_THREADS, min_stack, max_stack,
+ STACKSIZE - j, STACK_SIZE);
+
+ cyg_test_dump_thread_stack_stats( "All done, main stack", thread[0] );
+ cyg_test_dump_interrupt_stack_stats( "All done" );
+ cyg_test_dump_idlethread_stack_stats( "All done" );
+#endif
+
+ enable_clock_latency_measurement();
+
+ ticks = cyg_current_time();
+ diag_printf("\nTiming complete - %d ms total\n\n", (int)((ticks*ns_per_system_clock)/1000));
+}
+
+void
+run_all_tests(CYG_ADDRESS id)
+{
+#if CYGNUM_TESTS_RUN_COUNT < 0
+ while (1)
+#else
+ int i;
+ for (i = 0; i < CYGNUM_TESTS_RUN_COUNT; i++)
+#endif
+ _run_all_tests(id);
+ CYG_TEST_PASS_FINISH("Basic timing OK");
+}
+
+void tm_basic_main( void )
+{
+ CYG_TEST_INIT();
+
+ if (cyg_test_is_simulator) {
+ nsamples = NSAMPLES_SIM;
+ ntest_threads = NTEST_THREADS_SIM;
+ nthread_switches = NTHREAD_SWITCHES_SIM;
+ nmutexes = NMUTEXES_SIM;
+ nmboxes = NMBOXES_SIM;
+ nsemaphores = NSEMAPHORES_SIM;
+ nscheds = NSCHEDS_SIM;
+ nflags = NFLAGS_SIM;
+ ncounters = NCOUNTERS_SIM;
+ nalarms = NALARMS_SIM;
+ } else {
+ nsamples = NSAMPLES;
+ ntest_threads = NTEST_THREADS;
+ nthread_switches = NTHREAD_SWITCHES;
+ nmutexes = NMUTEXES;
+ nmboxes = NMBOXES;
+ nsemaphores = NSEMAPHORES;
+ nscheds = NSCHEDS;
+ nflags = NFLAGS;
+ ncounters = NCOUNTERS;
+ nalarms = NALARMS;
+ }
+
+ // Sanity
+#ifdef WORKHORSE_TEST
+ ntest_threads = max(512, ntest_threads);
+ nmutexes = max(1024, nmutexes);
+ nsemaphores = max(1024, nsemaphores);
+ nmboxes = max(1024, nmboxes);
+ ncounters = max(1024, ncounters);
+ nalarms = max(1024, nalarms);
+#else
+ ntest_threads = max(64, ntest_threads);
+ nmutexes = max(32, nmutexes);
+ nsemaphores = max(32, nsemaphores);
+ nmboxes = max(32, nmboxes);
+ ncounters = max(32, ncounters);
+ nflags = max(32, nflags);
+ nalarms = max(32, nalarms);
+#endif
+
+ new_thread(run_all_tests, 0);
+
+ Cyg_Scheduler::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
+ tm_basic_main();
+}
+
+#else // CYGFUN_KERNEL_API_C
+
+externC void
+cyg_start( void )
+{
+ CYG_TEST_INIT();
+ CYG_TEST_INFO("Timing tests require:\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("Timing tests requirements");
+}
+#endif // CYGFUN_KERNEL_API_C, etc.
+
+// EOF tm_basic.cxx
diff --git a/ecos/packages/kernel/current/tests_smp/README.SPLASH2 b/ecos/packages/kernel/current/tests_smp/README.SPLASH2
new file mode 100644
index 0000000000..7fee72c9f0
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/README.SPLASH2
@@ -0,0 +1,349 @@
+Date: Oct 19, 1994
+
+This is the directory for the second release of the Stanford Parallel
+Applications for Shared-Memory (SPLASH-2) programs. For further
+information contact splash@mojave.stanford.edu.
+
+PLEASE NOTE: Due to our limited resources, we will be unable to spend
+much time answering questions about the applications.
+
+splash.tar contains the tared version of all the files. Grabbing this
+file will get you everything you need. We also keep the files
+individually untared for partial retrieval. The splash.tar file is not
+compressed, but the large files in it are. We attempted to compress the
+splash.tar file to reduce the file size further, but this resulted in
+a negative compression ratio.
+
+
+DIFFERENCES BETWEEN SPLASH AND SPLASH-2:
+----------------------------------------
+
+The SPLASH-2 suite contains two types of codes: full applications and
+kernels. Each of the codes utilizes the Argonne National Laboratories
+(ANL) parmacs macros for parallel constructs. Unlike the codes in the
+original SPLASH release, each of the codes assumes the use of a
+"lightweight threads" model (which we hereafter refer to as the "threads"
+model) in which child processes share the same virtual address space as
+their parent process. In order for the codes to function correctly,
+the CREATE macro should call the proper Unix system routine (e.g. "sproc"
+in the Silicon Graphics IRIX operating system) instead of the "fork"
+routine that was used for SPLASH. The difference is that processes
+created with the Unix fork command receive their own private copies of
+all global variables. In the threads model, child processes share the
+same virtual address space, and hence all global data. Some of the
+codes function correctly when the Unix "fork" command is used for child
+process creation as well. Comments in the code header denote those
+applications which function correctly with "fork."
+
+
+MACROS:
+-------
+
+Macros for the previous release of the SPLASH application suite can be
+obtained via anonymous ftp to www-flash.stanford.edu. The macros are
+contained in the pub/old_splash/splash/macros subdirectory. HOWEVER,
+THE MACRO FILES MUST BE MODIFIED IN ORDER TO BE USED WITH SPLASH-2 CODES.
+The CREATE macros must be changed so that they call the proper process
+creation routine (See DIFFERENCES section above) instead of "fork."
+
+In this macros subdirectory, macros and sample makefiles are provided
+for three machines:
+
+Encore Multimax (CMU Mach 2.5: C and Fortran)
+SGI 4D/240 (IRIX System V Release 3.3: C only)
+Alliant FX/8 (Alliant Rev. 5.0: C and Fortran)
+
+These macros work for us with the above operating systems. Unfortunately,
+our limited resources prevent us from supporting them in any way or
+even fielding questions about them. If they don't work for you, please
+contact Argonne National Labs for a version that will. An e-mail address
+to try might be monitor-users-request@mcs.anl.gov. An excerpt from
+a message, received from Argonne, concerning obtaining the macros follows:
+
+"The parmacs package is in the public domain. Approximately 15 people at
+Argonne (or associated with Argonne or students) have worked on the
+parmacs package at one time or another. The parmacs package is
+implemented via macros using the M4 macropreprocessor (standard on most
+Unix systems). Current distribution of the software is somewhat ad hoc.
+Most C versions can be obtained from netlib (send electronic mail to
+netlib@ornl.gov with the message send index from parmacs). Fortran
+versions have been emailed directly or sent on tape. The primary
+documentation for the parmacs package is the book ``Portable Programs for
+Parallel Processors'' by Lusk, et al, Holt, Rinehart, and Winston 1987."
+
+The makefiles provided in the individual program directories specify
+a null macro set that will turn the parallel programs into sequential
+ones. Note that we do not have a null macro set for FORTRAN.
+
+
+CODE ENHANCEMENTS:
+------------------
+
+All of the codes are designed for shared address space multiprocessors
+with physically distributed main memory. For these types of machines,
+process migration and poor data distribution can decrease performance
+to suboptimal levels. In the applications, comments indicating potential
+enhancements can be found which will improve performance. Each potential
+enhancement is denoted by a comment beginning with "POSSIBLE ENHANCEMENT".
+The potential enhancements which we identify are:
+
+ (1) Data Distribution
+
+ Comments are placed in the code indicating where directives should
+ be placed so that data can be migrated to the local memories of
+ nodes, thus allowing for remote communication to be minimized.
+
+ (2) Process-to-Processor Assignment
+
+ Comments are placed in the code indicating where directives should
+ be placed so that processes can be "pinned" to processors,
+ preventing them from migrating from processor to processor.
+
+In addition, to facilitate simulation studies, we note points in the
+codes where statistics gathering routines should be turned on so that
+cold-start and initialization effects can be avoided.
+
+As previously mentioned, processes are assumed to be created through calls
+to a "threads" model creation routine. One important side effect is that
+this model causes all global variables to be shared (whereas the fork model
+causes all processes to get their own private copy of global variables).
+In order to mimic the behavior of global variables in the fork model, many
+of the applications provide arrays of structures that can be accessed by
+process ID, such as:
+
+ struct per_process_info {
+ char pad[PAD_LENGTH];
+ unsigned start_time;
+ unsigned end_time;
+ char pad[PAD_LENGTH];
+ } PPI[MAX_PROCS];
+
+In these structures, padding is inserted to ensure that the structure
+information associated with each process can be placed on a different
+page of memory, and can thus be explicitly migrated to that processor's
+local memory system. We follow this strategy for certain variables since
+these data really belong to a process and should be allocated in its local
+memory. A programming model that had the ability to declare global private
+data would have automatically ensured that these data were private, and
+that false sharing did not occur across different structures in the
+array. However, since the threads model does not provide this capability,
+it is provided by explicitly introducing arrays of structures with padding.
+The padding constants used in the programs (PAD_LENGTH in this example)
+can easily be changed to suit the particular characteristics of a given
+system. The actual data that is manipulated by individual applications
+(e.g. grid points, particle data, etc) is not padded, however.
+
+Finally, for some applications we provide less-optimized versions of the
+codes. The less-optimized versions utilize data structures that lead to
+simpler implementations, but which do not allow for optimal data
+distribution (and can thus generate false-sharing).
+
+
+REPORT:
+-------
+
+A report will be put together shortly describing the structure, function,
+and performance characteristics of each application. The report will be
+similar to the original SPLASH report (see the original report for the
+issues discussed). The report will provide quantitative data (for two
+different cache line size) for characteristics such as working set size
+and miss rates (local versus remote, etc.). In addition, the report
+will discuss cache behavior and synchronization behavior of the
+applications as well. In the mean time, each application directory has
+a README file that describes how to run each application. In addition,
+most applications have comments in their headers describing how to run
+each application.
+
+
+README FILES:
+-------------
+
+Each application has an associated README file. It is VERY important to
+read these files carefully, as they discuss the important parameters to
+supply for each application, as well as other issues involved in running
+the programs. In each README file, we discuss the impact of explicitly
+distributing data on the Stanford DASH Multiprocessor. Unless otherwise
+specified, we assume that the default data distribution mechanism is
+through round-robin page allocation.
+
+
+PROBLEM SIZES:
+--------------
+
+For each application, the README file describes a recommended problem
+size that is a reasonable base problem size that both can be simulated
+and is not too small for reality on a machine with up to 64 processors.
+For the purposes of studying algorithm performance, the parameters
+associated with each application can be varied. However, for the
+purposes of comparing machine architectures, the README files describe
+which parameters can be varied, and which should remain constant (or at
+their default values) for comparability. If the specific "base"
+parameters that are specified are not used, then results which are
+reported should explicitly state which parameters were changed, what
+their new values are, and address why they were changed.
+
+
+CORE PROGRAMS:
+--------------
+
+Since the number of programs has increased over SPLASH, and since not
+everyone may be able to use all the programs in a given study, we
+identify some of the programs as "core" programs that should be used
+in most studies for comparability. In the currently available set, these
+core programs include:
+
+(1) Ocean Simulation
+(2) Hierarchical Radiosity
+(3) Water Simulation with Spatial data structure
+(4) Barnes-Hut
+(5) FFT
+(6) Blocked Sparse Cholesky Factorization
+(7) Radix Sort
+
+The less optimized versions of the programs, when provided, should be
+used only in addition to these.
+
+
+MAILING LIST:
+-------------
+
+Please send a note to splash@mojave.stanford.edu if you have copied over
+the programs, so that we can put you on a mailing list for update reports.
+
+
+AUTHORSHIP:
+-----------
+
+The applications provided in the SPLASH-2 suite were developed by a number
+of people. The report lists authors primarily responsible for the
+development of each application code. The codes were made ready for
+distribution and the README files were prepared by Steven Cameron Woo and
+Jaswinder Pal Singh.
+
+
+CODE CHANGES:
+-------------
+
+If modifications are made to the codes which improve their performance,
+we would like to hear about them. Please send email to
+splash@mojave.stanford.edu detailing the changes.
+
+
+UPDATE REPORTS:
+---------------
+
+Watch this file for information regarding changes to codes and additions
+to the application suite.
+
+
+CHANGES:
+-------
+
+10-21-94: Ocean code, contiguous partitions, line 247 of slave1.C changed
+ from
+
+ t2a[0][0] = hh3*t2a[0][0]+hh1*psi[procid][1][0][0];
+
+ to
+
+ t2a[0][0] = hh3*t2a[0][0]+hh1*t2c[0][0];
+
+ This change does not affect correctness; it is an optimization
+ that was performed elsewhere in the code but overlooked here.
+
+11-01-94: Barnes, file code_io.C, line 55 changed from
+
+ in_real(instr, tnow);
+
+ to
+
+ in_real(instr, &tnow);
+
+11-01-94: Raytrace, file main.C, lines 216-223 changed from
+
+ if ((pid == 0) || (dostats))
+ CLOCK(end);
+
+ gm->partime[0] = (end - begin) & 0x7FFFFFFF;
+ if (pid == 0) gm->par_start_time = begin;
+
+/* printf("Process %ld elapsed time %lu.\n", pid, lapsed); */
+
+ }
+
+ to
+
+ if ((pid == 0) || (dostats)) {
+ CLOCK(end);
+ gm->partime[pid] = (end - begin) & 0x7FFFFFFF;
+ if (pid == 0) gm->par_start_time = begin;
+ }
+
+11-13-94: Raytrace, file memory.C
+
+ The use of the word MAIN_INITENV in a comment in memory.c causes
+ m4 to expand this macro, and some implementations may get confused
+ and generate the wrong C code.
+
+11-13-94: Radiosity, file rad_main.C
+
+ rad_main.C uses the macro CREATE_LITE. All three instances of
+ CREATE_LITE should be changed to CREATE.
+
+11-13-94: Water-spatial and Water-nsquared, file makefile
+
+ makefiles were changed so that the compilation phases included the
+ CFLAGS options instead of the CCOPTS options, which did not exist.
+
+11-17-94: FMM, file particle.C
+
+ Comment regarding data distribution of particle_array data
+ structure is incorrect. Round-robin allocation should be used.
+
+11-18-94: OCEAN, contiguous partitions, files main.C and linkup.C
+
+ Eliminated a problem which caused non-doubleword aligned
+ accesses to doublewords for the uniprocessor case.
+
+ main.C: Added lines 467-471:
+
+ if (nprocs%2 == 1) { /* To make sure that the actual data
+ starts double word aligned, add an extra
+ pointer */
+ d_size += sizeof(double ***);
+ }
+
+ Added same lines in file linkup.C at line numbers 100 and 159.
+
+07-30-95: RADIX has been changed. A tree-structured parallel prefix
+ computation is now used instead of a linear one.
+
+ LU had been modified. A comment describing how to distribute
+ data (one of the POSSIBLE ENHANCEMENTS) was incorrect for the
+ contiguous_blocks version of LU. Also, a modification was made
+ that reduces false sharing at line 206 of lu.C:
+
+ last_malloc[i] = (double *) (((unsigned) last_malloc[i]) + PAGE_SIZE -
+ ((unsigned) last_malloc[i]) % PAGE_SIZE);
+
+ A subdirectory shmem_files was added under the codes directory.
+ This directory contains a file that can be compiled on SGI machines
+ which replaces the libsgi.a file distributed in the original SPLASH
+ release.
+
+09-26-95: Fixed a bug in LU. Line 201 was changed from
+
+ last_malloc[i] = (double *) G_MALLOC(proc_bytes[i])
+
+ to
+
+ last_malloc[i] = (double *) G_MALLOC(proc_bytes[i] + PAGE_SIZE)
+
+ Fixed similar bugs in WATER-NSQUARED and WATER-SPATIAL. Both
+ codes needed a barrier added into the mdmain.C files. In both
+ codes, the line
+
+ BARRIER(gl->start, NumProcs);
+
+ was added. In WATER-NSQUARED, it was added in mdmain.C at line
+ 84. In WATER-SPATIAL, it was added in mdmain.C at line 107.
diff --git a/ecos/packages/kernel/current/tests_smp/README.fft b/ecos/packages/kernel/current/tests_smp/README.fft
new file mode 100644
index 0000000000..3de85e9239
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/README.fft
@@ -0,0 +1,62 @@
+GENERAL INFORMATION:
+
+The FFT program is a complex, one-dimensional version of the "Six-Step"
+FFT described in
+
+Bailey, D. H. FFTs in External or Hierarchical Memory.
+ Journal of Supercomputing, 4(1):23-35, March 1990.
+
+Specific optimizations in this implementation include: (1) Performing
+staggered, blocked transposes that exploit cache-line reuse; (2) The
+roots of unity data structure is arranged and distributed for only local
+accesses during application of the roots of unity step; (3) A small set of
+roots of unity elements are replicated locally at each processor for
+computation of the 1D FFTs; and (4) The matrix data structures are padded
+to reduce cache mapping conflicts. The algorithm used in this
+implementation is described in:
+
+Woo, S. C., Singh, J. P., and Hennessy, J. L. The Performance Advantages
+ of Integrating Block Data Transfer in Cache-Coherent Multiprocessors.
+ Proceedings of the 6th International Conference on Architectural
+ Support for Programming Languages and Operating Systems (ASPLOS-VI),
+ October 1994.
+
+This program works under both the Unix FORK and SPROC models.
+
+RUNNING THE PROGRAM:
+
+To see how to run the program, please see the comment at the top of the
+file fft.C, or run the application with the "-h" command line option.
+Four command-line parameters MUST be specified: The number of points
+to transform, the number of processors, the log base 2 of the cache
+line size, and the number of cache lines.
+
+The number of complex data points to be transformed and the number of
+processors being used can be varied according to the following rules.
+The number of data points must be an even power of 2 (2**16, 2**18,
+etc). The command-line option "-mM" specifies the even power of two (M),
+so for 65,536 data points, the command line option is "-m16." The number
+of processors must be a power of 2.
+
+The main data structures are padded to reduce cache mapping conflicts.
+The constant PAGE_SIZE should be changed to reflect the page size (in
+bytes) of the target system. In addition, the program uses a blocking
+technique to exploit cache line reuse. Both the log base 2 of the cache
+line size and the number of cache lines in the cache should be specified
+at the command line in order to allow the blocking algorithm to work
+effectively.
+
+BASE PROBLEM SIZE:
+
+The base problem size for an upto-64 processor machine is 65,536 complex
+data points (M=16). The PAGE_SIZE constant should be changed to reflect
+the page size (in bytes) of the target system. In addition, the log base
+2 of the cache line size, the number of cache lines, and the number of
+processors must be specified.
+
+DATA DISTRIBUTION:
+
+Our "POSSIBLE ENHANCEMENT" comments in the source code tell where one
+might want to distribute data and how. Data distribution has an impact
+on performance on the Stanford DASH multiprocessor.
+
diff --git a/ecos/packages/kernel/current/tests_smp/README.lu b/ecos/packages/kernel/current/tests_smp/README.lu
new file mode 100644
index 0000000000..cce3108fb6
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/README.lu
@@ -0,0 +1,55 @@
+GENERAL INFORMATION:
+
+The LU program factors a dense matrix into the product of a lower
+triangular and an upper triangular matrix. The factorization uses
+blocking to exploit temporal locality on individual submatrix elements.
+The algorithm used in this implementation is described in
+
+Woo, S. C., Singh, J. P., and Hennessy, J. L. The Performance Advantages
+ of Integrating Block Data Transfer in Cache-Coherent Multiprocessors.
+ Proceedings of the 6th International Conference on Architectural
+ Support for Programming Languages and Operating Systems (ASPLOS-VI),
+ October 1994.
+
+Two implementations are provided in the SPLASH-2 distribution:
+
+ (1) Non-contiguous block allocation
+
+ This implementation (contained in the non_contiguous_blocks
+ subdirectory) implements the matrix to be factored with a
+ two-dimensional array. This data structure prevents blocks from
+ being allocated contiguously, but leads to a conceptually simple
+ programming implementation.
+
+ (2) Contiguous block allocation
+
+ This implementation (contained in the contiguous_blocks
+ subdirectory) implements the matrix to be factored as an array
+ of blocks. This data structure allows blocks to be allocated
+ contiguously and entirely in the local memory of processors that
+ "own" them, thus enhancing data locality properties.
+
+These programs work under both the Unix FORK and SPROC models.
+
+RUNNING THE PROGRAM:
+
+To see how to run the program, please see the comment at the top of the
+file lu.C, or run the application with the "-h" command line option.
+Three parameters may be specified on the command line, of which the
+ones that are normally changed are the matrix size and the number of
+processors. It is suggested that the block size be kept at the value
+B=16, since this value works well in practice. If this parameter is
+changed, the new value should be reported in any results that are
+presented.
+
+BASE PROBLEM SIZE:
+
+The base problem size for an upto-64 processor machine is a 512x512 matrix
+with a block size of B=16.
+
+DATA DISTRIBUTION:
+
+Our "POSSIBLE ENHANCEMENT" comments in the source code tell where one
+might want to distribute data and how. Data distribution has a small
+impact on performance on the Stanford DASH multiprocessor.
+
diff --git a/ecos/packages/kernel/current/tests_smp/README.radix b/ecos/packages/kernel/current/tests_smp/README.radix
new file mode 100644
index 0000000000..3cd5b8026f
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/README.radix
@@ -0,0 +1,44 @@
+GENERAL INFORMATION:
+
+The RADIX program implements an integer radix sort based on the method
+described in:
+
+Blelloch, G. E., et. al. A Comparison of Sorting Algorithms for the
+ Connection Machine CM-2. In Symposium on Parallel Algorithms and
+ Architectures, pp. 3-16, July 1991.
+
+A description of this implementation can be found in:
+
+Woo, S. C., Singh, J. P., and Hennessy, J. L. The Performance Advantages
+ of Integrating Message Passing in Cache-Coherent Multiprocessors.
+ Technical Report CSL-TR-93-593, Stanford University, December 1993.
+
+This program works under both the Unix FORK and SPROC models.
+
+RUNNING THE PROGRAM:
+
+To see how to run the program, please see the comment at the top of the
+file radix.C, or run the application with the "-h" command line option.
+Four command line parameters can be specified, of which the ones which
+would normally be changed are the number of keys to sort, the radix
+for sorting, and the number of processors. The radix used for sorting
+must be a power of 2. Optional command line parameters allow timing
+information to be printed out at the end of the program, testing to
+make sure all keys are sorted correctly, and keys to be printed out
+in sorted order.
+
+BASE PROBLEM SIZE:
+
+The base problem size for an upto-64 processor machine is 256k (262,144)
+keys to be sorted and a radix of 1024. The default values should be
+used for other parameters (except the number of processors, which can
+be varied). For larger problems, the number of keys can also be
+increased by factors of 2. Any changes to these parameters should be
+reported when results are presented.
+
+DATA DISTRIBUTION:
+
+Our "POSSIBLE ENHANCEMENT" comments in the source code tell where one
+might want to distribute data and how. Data distribution has an impact
+on performance on the Stanford DASH multiprocessor.
+
diff --git a/ecos/packages/kernel/current/tests_smp/SPLASH2.POSTING b/ecos/packages/kernel/current/tests_smp/SPLASH2.POSTING
new file mode 100644
index 0000000000..29dc8aed27
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/SPLASH2.POSTING
@@ -0,0 +1,124 @@
+We are pleased to announce the release of the SPLASH-2 suite of
+multiprocessor applications. SPLASH-2 is the successor to the SPLASH
+suite that we previously released, and the programs in it are also
+written assuming a coherent shared address space communication model.
+SPLASH-2 contains several new applications, as well as improved versions
+of applications from SPLASH. The suite is currently available via
+anonymous ftp to
+
+ www-flash.stanford.edu (in the pub/splash2 subdirectory)
+
+and via the World-Wide-Web at
+
+ http://www-flash.stanford.edu/apps/SPLASH/
+
+Several programs are currently available, and a few others will be added
+shortly. The programs fall into two categories: full applications and
+kernels. Additionally, we designate some of these as "core programs"
+(see below). The applications and kernels currently available in the
+SPLASH-2 suite include:
+
+Applications:
+ Ocean Simulation
+ Ray Tracer
+ Hierarchical Radiosity
+ Volume Renderer
+ Water Simulation with Spatial Data Structure
+ Water Simulation without Spatial Data Structure
+ Barnes-Hut (gravitational N-body simulation)
+ Adaptive Fast Multipole (gravitational N-body simulation)
+
+Kernels:
+ FFT
+ Blocked LU Decomposition
+ Blocked Sparse Cholesky Factorization
+ Radix Sort
+
+Programs that will appear soon include:
+
+ PSIM4 - Particle Dynamics Simulation (full application)
+ Conjugate Gradient (kernel)
+ LocusRoute (standard cell router from SPLASH)
+ Protein Structure Prediction
+ Protein Sequencing
+ Parallel Probabilistic Inference
+
+In some cases, we provide both well-optimized and less-optimized versions
+of the programs. For both the Ocean simulation and the Blocked LU
+Decomposition kernel, less optimized versions of the codes are currently
+available.
+
+There are important differences between applications in the SPLASH-2 suite
+and applications in the SPLASH suite. These differences are noted in the
+README.SPLASH2 file in the pub/splash2 directory. It is *VERY IMPORTANT*
+that you read the README.SPLASH2 file, as well as the individual README
+files in the program directories, before using the SPLASH-2 programs.
+These files describe how to run the programs, provide commented annotations
+about how to distribute data on a machine with physically distributed main
+memory, and provides guidelines on the baseline problem sizes to use when
+studying architectural interactions through simulation.
+
+Complete documentation of SPLASH2, including a detailed characterization
+of performance as well as memory system interactions and synchronization
+behavior, will appear in the SPLASH2 report that is currently being
+written.
+
+
+OPTIMIZATION STRATEGY:
+----------------------
+
+For each application and kernel, we note potential features or
+enhancements that are typically machine-specific. These potential
+enhancements are encapsulated within comments in the code starting with
+the string "POSSIBLE ENHANCEMENT." The potential enhancements which we
+identify are:
+
+ (1) Data Distribution
+
+ We note where data migration routines should be called in order to
+ enhance locality of data access. We do not distribute data by
+ default as different machines implement migration routines in
+ different ways, and on some machines this is not relevant.
+
+ (2) Process-to-Processor Assignment
+
+ We note where calls can be made to "pin" processes to specific
+ processors so that process migration can be avoided. We do not
+ do this by default, since different machines implement this
+ feature in different ways.
+
+In addition, to facilitate simulation studies, we note points in the
+codes where statistics gathering routines should be turned on so that
+cold-start and initialization effects can be avoided.
+
+For two programs (Ocean and LU), we provide less-optimized versions of
+the codes. The less-optimized versions utilize data structures that
+lead to simpler implementations, but which do not allow for optimal data
+distribution (and can generate false-sharing).
+
+
+CORE PROGRAMS:
+--------------
+
+Since the number of programs has increased over SPLASH, and since not
+everyone may be able to use all the programs in a given study, we
+identify some of the programs as "core" programs that should be used
+in most studies for comparability. In the currently available set,
+these core programs include:
+
+(1) Ocean Simulation
+(2) Hierarchical Radiosity
+(3) Water Simulation with Spatial data structure
+(4) Barnes-Hut
+(5) FFT
+(6) Blocked Sparse Cholesky Factorization
+(7) Radix Sort
+
+The less optimized versions of the programs, when available, should be
+used only in addition to these.
+
+The base problem sizes that we recommend are provided in the README files
+for individual applications. Please use at least these for experiments
+with upto 64 processors. If changes are made to these base parameters
+for further experimentation, these changes should be explicitly stated
+in any results that are presented.
diff --git a/ecos/packages/kernel/current/tests_smp/c.m4.ecos b/ecos/packages/kernel/current/tests_smp/c.m4.ecos
new file mode 100644
index 0000000000..6b94263c89
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/c.m4.ecos
@@ -0,0 +1,290 @@
+divert(-1)
+define(NEWPROC,) dnl
+define(ENDLAB, 5283) dnl
+
+define(BARRIER, `{
+/*---------------------------------*/
+ LOCK( ( $1[0].lock ) );
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),$3,$1[0].count[0],$1[0].queue[0].count);
+ }
+ if ( $1[0].count[0] < ($2 -1) ) {
+ $1[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),$3,$1[0].count[0],$1[0].queue[0].count);
+ }
+ UNLOCK( $1[0].lock );
+ SEMWAIT( $1[0].queue[0] );
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),$3,$1[0].count[0],$1[0].queue[0].count);
+ }
+ if ( $1[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),$3,$1[0].count[0],$1[0].queue[0].count);
+ }
+
+ UNLOCK( $1[0].lock );
+
+ } else {
+ ( $1[0].count[0] )-- ;
+ //UNLOCK( $1[0].count_lock[0] );
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),$3,$1[0].count[0],$1[0].queue[0].count);
+ }
+ SEMPOST( $1[0].queue[0] );
+ }
+
+/*---------------------------------*/
+}')
+
+
+define(BARDEC, `DECVAR($1,1,1,)')
+define(BARINIT, `{MONINIT($1,1,1)}')
+
+define(GSDEC, `/*##########*/
+int ($1);')
+define(GSINIT, `/*##########*/
+{ ($1) = 0; }')
+define(GETSUB, `/*##########*/
+{
+ if (($1)<=($3))
+ ($2) = ($1)++;
+ else {
+ ($2) = -1;
+ ($1) = 0;
+ }
+}')
+
+define(NU_GSDEC, `int ($1);')
+define(NU_GSINIT, `{ ($1) = 0; }')
+define(NU_GETSUB, `GETSUB($1,$2,$3,$4)')
+
+define(ADEC, `int ($1);')
+define(AINIT, `{/*##########*/;}')
+define(PROBEND, `{/*##########*/;}')
+
+define(LOCKDEC, `cyg_spinlock_t $1;')
+define(LOCKINIT, `cyg_spinlock_init( &$1,0 );')
+define(LOCK, `cyg_spinlock_spin(&$1);')
+define(UNLOCK, `cyg_spinlock_clear(&$1);')
+
+define(SEMINIT, `{ cyg_semaphore_init(&$1,$2);}')
+define(SEMWAIT, `{ cyg_semaphore_wait(&$1);}')
+define(SEMPOST, `{ cyg_semaphore_post(&$1);}')
+define(SEMDEC, ` cyg_sem_t $1;')
+
+define(NLOCKDEC, `int ($1);')
+define(NLOCKINIT, `{/*##########*/;}')
+define(NLOCK, `{/*##########*/;}')
+define(NUNLOCK, `{/*##########*/;}')
+
+define(ALOCKDEC, `DECVAR($1,0,$2)')
+define(ALOCKINIT, `{ MONINIT($1,0,$2);}')
+define(ALOCK, `{ MENTER($1,$2);}')
+define(AULOCK, `{ MEXIT($1,$2);}')
+
+
+define(PAUSEDEC, ` ')
+define(PAUSEINIT, `{/*##########*/;}')
+define(CLEARPAUSE, `{/*##########*/;}')
+define(SETPAUSE, `{/*##########*/;}')
+define(EVENT, `{/*##########*/;}')
+define(WAITPAUSE, `{/*##########*/;}')
+define(PAUSE, `{/*##########*/;}')
+
+define(AUG_ON, ` ')
+define(AUG_OFF, ` ')
+define(TRACE_ON, ` ')
+define(TRACE_OFF, ` ')
+define(REF_TRACE_ON, ` ')
+define(REF_TRACE_OFF, ` ')
+define(DYN_TRACE_ON, `;')
+define(DYN_TRACE_OFF, `;')
+define(DYN_REF_TRACE_ON, `;')
+define(DYN_REF_TRACE_OFF, `;')
+define(DYN_SIM_ON, `;')
+define(DYN_SIM_OFF, `;')
+define(DYN_SCHED_ON, `;')
+define(DYN_SCHED_OFF, `;')
+define(AUG_SET_LOLIMIT, `;')
+define(AUG_SET_HILIMIT, `;')
+
+define(MENTER, `LOCK($1[$2].lock);')
+define(DELAY, `{$1[$3].count[$2]++;
+ UNLOCK($1[$3].lock)
+ SEMWAIT($1[$3].queue[$2]);}')
+define(CONTINUE, `{
+ if ($1[$3].count[$2]) {
+ ($1[$3].count[$2])--;
+ SEMPOST($1[$3].queue[$2])
+ } else
+ UNLOCK($1[$3].lock)
+ goto `L'ENDLAB;
+`LGO'ENDLAB: ;
+}')
+define(MEXIT, `{
+ UNLOCK($1[$2].lock); `L'ENDLAB: ;
+ define(`ENDLAB', eval(ENDLAB+1))
+}')
+
+define(WAIT_FOR_END, `{
+;}')
+
+/* create(<procedure>)*/
+define(CREATE,`
+{
+ /*---------------------------------------*/
+ stack[i] = calloc(STACK_SIZE, 1);
+ cyg_thread_create(10, // Priority - just a number
+ $1, // entry
+ 0, // index
+ "slave", // Name
+ stack[i], // Stack
+ STACK_SIZE, // Size
+ &threadh[i], // Handle
+ &thread[i] // Thread data structure
+ );
+ cyg_thread_resume( threadh[i] );
+ /*---------------------------------------*/
+}
+')
+
+define(MAIN_INITENV, `{;}')
+define(MAIN_END, `
+{
+ diag_printf("FP test end\n");
+ return 0;
+}
+')
+define(MAIN_ENV,`
+/*---------------------------------------*/
+#include <pkgconf/system.h>
+#include <pkgconf/infra.h>
+#include <pkgconf/kernel.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/testcase.h>
+#include <pkgconf/isoinfra.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_smp.h>
+#include <cyg/kernel/kapi.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+int smp_cyg_test_main(int argc, char **argv);
+
+void smp_cyg_test_main_call(void *p) {
+ smp_cyg_test_main(smp_cyg_test_argc, smp_cyg_test_argv);
+}
+
+
+/* #define STACK_SIZE 0x1b000 */
+#define STACK_SIZE 8192
+static cyg_thread smp_cyg_test_thread;
+static char smp_cyg_test_stack[STACK_SIZE];
+static cyg_handle_t smp_cyg_test_threadh;
+
+
+
+cyg_handle_t threadh[64];
+char *stack[64];
+cyg_thread thread[64];
+
+
+externC void cyg_user_start( void )
+{
+ CYG_TEST_INIT();
+
+ diag_printf("Starting test app\n");
+
+ cyg_thread_create(10, // Priority - just a number
+ smp_cyg_test_main_call, // entry
+ 0, // index
+ "smp test", // Name
+ smp_cyg_test_stack, // Stack
+ STACK_SIZE, // Size
+ &smp_cyg_test_threadh, // Handle
+ &smp_cyg_test_thread // Thread data structure
+ );
+ cyg_thread_resume( smp_cyg_test_threadh );
+ /*cyg_scheduler_start();*/
+}
+
+
+/*---------------------------------------*/
+')
+
+define(ENV, ` ')
+define(EXTERN_ENV, `
+
+#include <pkgconf/system.h>
+#include <pkgconf/infra.h>
+#include <pkgconf/kernel.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/testcase.h>
+#include <pkgconf/isoinfra.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/kernel/kapi.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+ ')
+
+define(G_MALLOC, `calloc($1, 1);')
+define(G_FREE, `;')
+define(G_MALLOC_F, `malloc($1);')
+define(NU_MALLOC, `malloc($1);')
+define(NU_FREE, `;')
+define(NU_MALLOC_F, `malloc($1)')
+
+define(GET_HOME, `{($1) = 0;}')
+define(GET_PID, `{($1) = 0;}')
+define(AUG_DELAY, `{sleep ($1);}')
+define(ST_LOG, `{;}')
+define(SET_HOME, `{;}')
+
+/* clock(<clock_val>)*/
+define(CLOCK, `{
+ ($1) = cyg_current_time()*10;
+}
+')
+divert(0)
+
+
+
+define(DECVAR,`
+/*---------------------------------------*/
+struct $1TYP {
+ LOCKDEC(lock);
+ ifelse(eval($2 > 0),1,int count[$2];,)
+ ifelse(eval($2 > 0),1, SEMDEC(queue[$2]);,)
+ $4
+ } $1[$3];
+/*---------------------------------------*/
+ '
+)
+
+define(MONINIT, `{
+/*---------------------------------------*/
+ int mon_dum1,mon_dum2;
+ ifelse(eval($2 > 0),1,
+ for (mon_dum1=0; mon_dum1 < $3; mon_dum1++)
+ for (mon_dum2=0; mon_dum2 < $2; mon_dum2++) {
+ $1[mon_dum1].count[mon_dum2] = 0;
+ SEMINIT($1[mon_dum1].queue[mon_dum2],0);
+ },,)
+ for (mon_dum1=0; mon_dum1 < $3; mon_dum1++) {
+ LOCKINIT($1[mon_dum1].lock);
+ }
+/*---------------------------------------*/
+}')
+
+
+
+
diff --git a/ecos/packages/kernel/current/tests_smp/fft.C b/ecos/packages/kernel/current/tests_smp/fft.C
new file mode 100644
index 0000000000..e2b0f979af
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/fft.C
@@ -0,0 +1,1057 @@
+/*************************************************************************/
+/* */
+/* Copyright (c) 1994 Stanford University */
+/* */
+/* All rights reserved. */
+/* */
+/* Permission is given to use, copy, and modify this software for any */
+/* non-commercial purpose as long as this copyright notice is not */
+/* removed. All other uses, including redistribution in whole or in */
+/* part, are forbidden without prior written permission. */
+/* */
+/* This software is provided with absolutely no warranty and no */
+/* support. */
+/* */
+/*************************************************************************/
+
+/*************************************************************************/
+/* */
+/* Perform 1D fast Fourier transform using six-step FFT method */
+/* */
+/* 1) Performs staggered, blocked transposes for cache-line reuse */
+/* 2) Roots of unity rearranged and distributed for only local */
+/* accesses during application of roots of unity */
+/* 3) Small set of roots of unity elements replicated locally for */
+/* 1D FFTs (less than root N elements replicated at each node) */
+/* 4) Matrix data structures are padded to reduce cache mapping */
+/* conflicts */
+/* */
+/* Command line options: */
+/* */
+/* -mM : M = even integer; 2**M total complex data points transformed. */
+/* -pP : P = number of processors; Must be a power of 2. */
+/* -nN : N = number of cache lines. */
+/* -lL : L = Log base 2 of cache line length in bytes. */
+/* -s : Print individual processor timing statistics. */
+/* -t : Perform FFT and inverse FFT. Test output by comparing the */
+/* integral of the original data to the integral of the data */
+/* that results from performing the FFT and inverse FFT. */
+/* -o : Print out complex data points. */
+/* -h : Print out command line options. */
+/* */
+/* Note: This version works under both the FORK and SPROC models */
+/* */
+/*************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <tests_smp/getopt.h>
+
+#define MAXRAND 2147483647
+#define PAGE_SIZE 4096
+#define NUM_CACHE_LINES 65536
+#define LOG2_LINE_SIZE 4
+#define PI 3.1416
+#define DEFAULT_M 10
+#define DEFAULT_P 1
+
+#include <tests_smp/fft_arg.c>
+
+MAIN_ENV
+
+#define SWAP(a,b) {double tmp; tmp=a; a=b; b=tmp;}
+
+struct GlobalMemory {
+ int id;
+ LOCKDEC(idlock)
+ BARDEC(start)
+ int *transtimes;
+ int *totaltimes;
+ int starttime;
+ int finishtime;
+ int initdonetime;
+} *Global;
+
+int dbg_on = 0;
+
+int P = DEFAULT_P;
+int M = DEFAULT_M;
+int N; /* N = 2^M */
+int rootN; /* rootN = N^1/2 */
+double *x; /* x is the original time-domain data */
+double *trans; /* trans is used as scratch space */
+double *umain; /* umain is roots of unity for 1D FFTs */
+double *umain2; /* umain2 is entire roots of unity matrix */
+int test_result = 0;
+int doprint = 0;
+int dostats = 0;
+int transtime = 0;
+int transtime2 = 0;
+int avgtranstime = 0;
+int avgcomptime = 0;
+unsigned int transstart = 0;
+unsigned int transend = 0;
+int maxtotal=0;
+int mintotal=0;
+double maxfrac=0;
+double minfrac=0;
+double avgfractime=0;
+int orig_num_lines = NUM_CACHE_LINES; /* number of cache lines */
+int num_cache_lines = NUM_CACHE_LINES; /* number of cache lines */
+int log2_line_size = LOG2_LINE_SIZE;
+int line_size;
+int rowsperproc;
+double ck1;
+double ck3; /* checksums for testing answer */
+int pad_length;
+
+void SlaveStart();
+double TouchArray(double *,double *,double *,double *,int,int,int,int);
+void FFT1D(int,int,int,double *,double *,double *,double *,int,int *,int,
+ int,int,int,int,int,int,struct GlobalMemory *);
+double CheckSum();
+double drand48();
+int log_2(int);
+void printerr(char *);
+volatile int thread_array[4] = {0, 0, 0, 0};
+
+int smp_cyg_test_main(int argc, char **argv)
+{
+ int i;
+ int j;
+ int c;
+ extern char *optarg;
+ int m1;
+ int factor;
+ int pages;
+ unsigned int start;
+ //memset (thread_array,0,sizeof(thread_array));
+
+ CLOCK(start);
+
+
+// extern Cyg_Mempool_dlmalloc *cygmem_memalloc_heaps[ 2 ];
+// cygmem_memalloc_heaps[0].
+
+
+ // printf("<cpu%d> thread %d Arguments (%d): ",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),argc);
+// for (i = 0;i < argc;i++){
+// printf("%s ",argv[i]);
+// }
+// printf("\n");
+
+ while ((c = getopt(argc, argv, "p:m:n:l:stoh")) != -1) {
+ switch(c) {
+ case 'p': P = atoi(optarg);
+ P = HAL_SMP_CPU_MAX;
+ if (P < 1) {
+ printerr("P must be >= 1\n");
+ exit(-1);
+ }
+ if (log_2(P) == -1) {
+ printerr("P must be a power of 2\n");
+ exit(-1);
+ }
+ break;
+ case 'm': M = atoi(optarg);
+ m1 = M/2;
+ if (2*m1 != M) {
+ printerr("M must be even\n");
+ exit(-1);
+ }
+ break;
+ case 'n': num_cache_lines = atoi(optarg);
+ orig_num_lines = num_cache_lines;
+ if (num_cache_lines < 1) {
+ printerr("Number of cache lines must be >= 1\n");
+ exit(-1);
+ }
+ break;
+ case 'l': log2_line_size = atoi(optarg);
+ if (log2_line_size < 0) {
+ printerr("Log base 2 of cache line length in bytes must be >= 0\n");
+ exit(-1);
+ }
+ break;
+ case 's': dostats = !dostats;
+ break;
+ case 't': test_result = !test_result;
+ break;
+ case 'o': doprint = !doprint;
+ break;
+ case 'h': printf("Usage: FFT <options>\n\n");
+ printf("options:\n");
+ printf(" -mM : M = even integer; 2**M total complex data points transformed.\n");
+ printf(" -pP : P = number of processors; Must be a power of 2.\n");
+ printf(" -nN : N = number of cache lines.\n");
+ printf(" -lL : L = Log base 2 of cache line length in bytes.\n");
+ printf(" -s : Print individual processor timing statistics.\n");
+ printf(" -t : Perform FFT and inverse FFT. Test output by comparing the\n");
+ printf(" integral of the original data to the integral of the data that\n");
+ printf(" results from performing the FFT and inverse FFT.\n");
+ printf(" -o : Print out complex data points.\n");
+ printf(" -h : Print out command line options.\n\n");
+ printf("Default: FFT -m%1d -p%1d -n%1d -l%1d\n",
+ DEFAULT_M,DEFAULT_P,NUM_CACHE_LINES,LOG2_LINE_SIZE);
+ exit(0);
+ break;
+ }
+ }
+
+ if (P > 64) {
+ printf("Maximal 64 processes\n");
+ exit(0);
+ }
+
+ MAIN_INITENV(,80000000);
+
+ N = 1<<M;
+ rootN = 1<<(M/2);
+ rowsperproc = rootN/P;
+ if (rowsperproc == 0) {
+ printerr("Matrix not large enough. 2**(M/2) must be >= P\n");
+ exit(-1);
+ }
+
+ line_size = 1 << log2_line_size;
+ if (line_size < 2*sizeof(double)) {
+ printf("WARNING: Each element is a complex double (%d bytes)\n",2*sizeof(double));
+ printf(" => Less than one element per cache line\n");
+ printf(" Computing transpose blocking factor\n");
+ factor = (2*sizeof(double)) / line_size;
+ num_cache_lines = orig_num_lines / factor;
+ }
+ if (line_size <= 2*sizeof(double)) {
+ pad_length = 1;
+ } else {
+ pad_length = line_size / (2*sizeof(double));
+ }
+
+ if (rowsperproc * rootN * 2 * sizeof(double) >= PAGE_SIZE) {
+ pages = (2 * pad_length * sizeof(double) * rowsperproc) / PAGE_SIZE;
+ if (pages * PAGE_SIZE != 2 * pad_length * sizeof(double) * rowsperproc) {
+ pages ++;
+ }
+ pad_length = (pages * PAGE_SIZE) / (2 * sizeof(double) * rowsperproc);
+ } else {
+ pad_length = (PAGE_SIZE - (rowsperproc * rootN * 2 * sizeof(double))) /
+
+ (2 * sizeof(double) * rowsperproc);
+ if (pad_length * (2 * sizeof(double) * rowsperproc) !=
+ (PAGE_SIZE - (rowsperproc * rootN * 2 * sizeof(double)))) {
+ printerr("Padding algorithm unsuccessful\n");
+ exit(-1);
+ }
+ }
+
+ Global = (struct GlobalMemory *) G_MALLOC(sizeof(struct GlobalMemory));
+ if (Global == NULL) {
+ printf("Could not malloc memory for Global (%d)\n",sizeof(struct GlobalMemory));
+ exit(-1);
+ }
+
+
+ x = (double *) G_MALLOC(2*(N+rootN*pad_length)*sizeof(double)+PAGE_SIZE);
+ trans = (double *) G_MALLOC(2*(N+rootN*pad_length)*sizeof(double)+PAGE_SIZE);
+ umain = (double *) G_MALLOC(2*rootN*sizeof(double));
+ umain2 = (double *) G_MALLOC(2*(N+rootN*pad_length)*sizeof(double)+PAGE_SIZE);
+
+
+ Global->transtimes = (int *) G_MALLOC(P*sizeof(int));
+ Global->totaltimes = (int *) G_MALLOC(P*sizeof(int));
+ if (x == NULL) {
+ printerr("Could not malloc memory for x\n");
+ exit(-1);
+ } else if (trans == NULL) {
+ printerr("Could not malloc memory for trans\n");
+ exit(-1);
+ } else if (umain == NULL) {
+ printerr("Could not malloc memory for umain\n");
+ exit(-1);
+ } else if (umain2 == NULL) {
+ printerr("Could not malloc memory for umain2\n");
+ exit(-1);
+ }
+
+ x = (double *) (((unsigned) x) + PAGE_SIZE - ((unsigned) x) % PAGE_SIZE);
+ trans = (double *) (((unsigned) trans) + PAGE_SIZE - ((unsigned) trans) % PAGE_SIZE);
+ umain2 = (double *) (((unsigned) umain2) + PAGE_SIZE - ((unsigned) umain2) % PAGE_SIZE);
+
+/* In order to optimize data distribution, the data structures x, trans,
+ and umain2 have been aligned so that each begins on a page boundary.
+ This ensures that the amount of padding calculated by the program is
+ such that each processor's partition ends on a page boundary, thus
+ ensuring that all data from these structures that are needed by a
+ processor can be allocated to its local memory */
+
+/* POSSIBLE ENHANCEMENT: Here is where one might distribute the x,
+ trans, and umain2 data structures across physically distributed
+ memories as desired.
+
+ One way to place data is as follows:
+
+ double *base;
+ int i;
+
+ i = ((N/P)+(rootN/P)*pad_length)*2;
+ base = &(x[0]);
+ for (j=0;j<P;j++) {
+ Place all addresses x such that (base <= x < base+i) on node j
+ base += i;
+ }
+
+ The trans and umain2 data structures can be placed in a similar manner.
+
+ */
+
+ printf("\n");
+ printf("FFT with Blocking Transpose\n");
+ printf(" %d Complex Doubles\n",N);
+ printf(" %d Threads\n",P);
+ if (num_cache_lines != orig_num_lines) {
+ printf(" %d Cache lines\n",orig_num_lines);
+ printf(" %d Cache lines for blocking transpose\n",num_cache_lines);
+ } else {
+ printf(" %d Cache lines\n",num_cache_lines);
+ }
+ printf(" %d Byte line size\n",(1 << log2_line_size));
+ printf(" %d Bytes per page\n",PAGE_SIZE);
+ printf("\n");
+
+ BARINIT(Global->start);
+ LOCKINIT(Global->idlock);
+ Global->id = 0;
+ InitX(N, x); /* place random values in x */
+
+ if (test_result) {
+ ck1 = CheckSum(N, x);
+ }
+ if (doprint) {
+ printf("Original data values:\n");
+ PrintArray(N, x);
+ }
+
+ InitU(N,umain); /* initialize u arrays*/
+ InitU2(N,umain2,rootN);
+
+ /* fire off P processes */
+ for (i=1; i<P; i++) {
+ CREATE(SlaveStart,thread_array[i]);
+ }
+
+ SlaveStart();
+
+ for (i=1; i<P; i++) {
+ while(!thread_array[i]) {};
+ }
+
+ if (doprint) {
+ if (test_result) {
+ printf("Data values after inverse FFT:\n");
+ } else {
+ printf("Data values after FFT:\n");
+ }
+ PrintArray(N, x);
+ }
+
+ transtime = Global->transtimes[0];
+ printf("\n");
+ printf(" PROCESS STATISTICS\n");
+ printf(" Computation Transpose Transpose\n");
+ printf(" Proc Time Time Fraction\n");
+ printf(" 0 %10d %10d %8.5f\n",
+ Global->totaltimes[0],Global->transtimes[0],
+ ((double)Global->transtimes[0])/Global->totaltimes[0]);
+ if (dostats) {
+ transtime2 = Global->transtimes[0];
+ avgtranstime = Global->transtimes[0];
+ avgcomptime = Global->totaltimes[0];
+ maxtotal = Global->totaltimes[0];
+ mintotal = Global->totaltimes[0];
+ maxfrac = ((double)Global->transtimes[0])/Global->totaltimes[0];
+ minfrac = ((double)Global->transtimes[0])/Global->totaltimes[0];
+ avgfractime = ((double)Global->transtimes[0])/Global->totaltimes[0];
+ for (i=1;i<P;i++) {
+ if (Global->transtimes[i] > transtime) {
+ transtime = Global->transtimes[i];
+ }
+ if (Global->transtimes[i] < transtime2) {
+ transtime2 = Global->transtimes[i];
+ }
+ if (Global->totaltimes[i] > maxtotal) {
+ maxtotal = Global->totaltimes[i];
+ }
+ if (Global->totaltimes[i] < mintotal) {
+ mintotal = Global->totaltimes[i];
+ }
+ if (((double)Global->transtimes[i])/Global->totaltimes[i] > maxfrac) {
+ maxfrac = ((double)Global->transtimes[i])/Global->totaltimes[i];
+ }
+ if (((double)Global->transtimes[i])/Global->totaltimes[i] < minfrac) {
+ minfrac = ((double)Global->transtimes[i])/Global->totaltimes[i];
+ }
+ printf(" %3d %10d %10d %f\n",
+ i,Global->totaltimes[i],Global->transtimes[i],
+ ((double)Global->transtimes[i])/Global->totaltimes[i]);
+ avgtranstime += Global->transtimes[i];
+ avgcomptime += Global->totaltimes[i];
+ avgfractime += ((double)Global->transtimes[i])/Global->totaltimes[i];
+ }
+ printf(" Avg %10f %10f %f\n",
+ ((double) avgcomptime)/P,((double) avgtranstime)/P,avgfractime/P);
+ printf(" Max %10d %10d %f\n",
+ maxtotal,transtime,maxfrac);
+ printf(" Min %10d %10d %f\n",
+ mintotal,transtime2,minfrac);
+ }
+ Global->starttime = start;
+ printf("\n");
+ printf(" TIMING INFORMATION\n");
+ printf("Start time : %16d\n",
+ Global->starttime);
+ printf("Initialization finish time : %16d\n",
+ Global->initdonetime);
+ printf("Overall finish time : %16d\n",
+ Global->finishtime);
+ printf("Total time with initialization : %16d\n",
+ Global->finishtime-Global->starttime);
+ printf("Total time without initialization : %16d\n",
+ Global->finishtime-Global->initdonetime);
+ printf("Overall transpose time : %16d\n",
+ transtime);
+ printf("Overall transpose fraction : %f\n",
+ ((double) transtime)/(Global->finishtime-Global->initdonetime));
+ printf("\n");
+
+ if (test_result) {
+ ck3 = CheckSum(N, x);
+ printf(" INVERSE FFT TEST RESULTS\n");
+ printf("Checksum difference is %f (%f, %f)\n",
+ ck1-ck3, ck1, ck3);
+ if (fabs(ck1-ck3) < 0.001) {
+ printf("TEST PASSED\n");
+ } else {
+ printf("TEST FAILED\n");
+ }
+ }
+
+ MAIN_END;
+}
+
+
+void SlaveStart()
+{
+ int i;
+ int j;
+ int MyNum;
+ double error;
+ double *upriv;
+ int initdone;
+ int finish;
+ int l_transtime=0;
+ int MyFirst;
+ int MyLast;
+
+ LOCK(Global->idlock);
+ MyNum = Global->id;
+ Global->id++;
+#ifdef FFT_DBG
+ printf("Slave %d started\n",MyNum);
+#endif
+ UNLOCK(Global->idlock);
+
+
+/* POSSIBLE ENHANCEMENT: Here is where one might pin processes to
+ processors to avoid migration */
+
+ BARRIER(Global->start, P, 1);
+#ifdef FFT_DBG
+ LOCK(Global->idlock); printf("Slave %d left barrier 1\n",MyNum); UNLOCK(Global->idlock);
+#endif
+
+ upriv = (double *) malloc(2*(rootN-1)*sizeof(double));
+ if (upriv == NULL) {
+ printf("Proc %d could not malloc memory for upriv\n",MyNum);
+ exit(-1);
+ }
+ for (i=0;i<2*(rootN-1);i++) {
+ upriv[i] = umain[i];
+ }
+
+ MyFirst = rootN*MyNum/P;
+ MyLast = rootN*(MyNum+1)/P;
+
+ TouchArray(x, trans, umain2, upriv, N, MyNum, MyFirst, MyLast);
+
+ BARRIER(Global->start, P, 2);
+#ifdef FFT_DBG
+ LOCK(Global->idlock); printf("Slave %d left barrier 2\n",MyNum); UNLOCK(Global->idlock);
+#endif
+
+/* POSSIBLE ENHANCEMENT: Here is where one might reset the
+ statistics that one is measuring about the parallel execution */
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(initdone);
+ }
+
+ /* perform forward FFT */
+ FFT1D(1, M, N, x, trans, upriv, umain2, MyNum, &l_transtime, MyFirst,
+ MyLast, pad_length, P, test_result, doprint, dostats, Global);
+
+ /* perform backward FFT */
+ if (test_result) {
+ FFT1D(-1, M, N, x, trans, upriv, umain2, MyNum, &l_transtime, MyFirst,
+ MyLast, pad_length, P, test_result, doprint, dostats, Global);
+ }
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(finish);
+ Global->transtimes[MyNum] = l_transtime;
+ Global->totaltimes[MyNum] = finish-initdone;
+ }
+ if (MyNum == 0) {
+ Global->finishtime = finish;
+ Global->initdonetime = initdone;
+ }
+
+ thread_array[MyNum] = 1;
+}
+
+
+double TouchArray(x, scratch, u, upriv, N, MyNum, MyFirst, MyLast)
+
+double *x;
+double *scratch;
+double *u;
+double *upriv;
+int N;
+int MyNum;
+int MyFirst;
+int MyLast;
+
+{
+ int i,j,k;
+ double tot = 0.0;
+
+ /* touch my data */
+ for (j=0;j<2*(rootN-1);j++) {
+ tot += upriv[j];
+ }
+ for (j=MyFirst; j<MyLast; j++) {
+ k = j * (rootN + pad_length);
+ for (i=0;i<rootN;i++) {
+ tot += x[2*(k+i)] + x[2*(k+i)+1] +
+ scratch[2*(k+i)] + scratch[2*(k+i)+1] +
+ u[2*(k+i)] + u[2*(k+i)+1];
+ }
+ }
+ return tot;
+}
+
+
+double CheckSum(N, x)
+
+int N;
+double *x;
+
+{
+ int i,j,k;
+ double cks;
+
+ cks = 0.0;
+ for (j=0; j<rootN; j++) {
+ k = j * (rootN + pad_length);
+ for (i=0;i<rootN;i++) {
+ cks += x[2*(k+i)] + x[2*(k+i)+1];
+ }
+ }
+
+ return(cks);
+}
+
+
+InitX(N, x)
+
+int N;
+double *x;
+
+{
+ int i,j,k;
+
+ srand(0);
+ for (j=0; j<rootN; j++) {
+ k = j * (rootN + pad_length);
+ for (i=0;i<rootN;i++) {
+ x[2*(k+i)] = rand()/MAXRAND;
+ x[2*(k+i)+1] = rand()/MAXRAND;
+ }
+ }
+}
+
+
+InitU(N, u)
+
+int N;
+double *u;
+
+{
+ int q;
+ int j;
+ int base;
+ int n1;
+
+ for (q=0; 1<<q<N; q++) {
+ n1 = 1<<q;
+ base = n1-1;
+ for (j=0; j<n1; j++) {
+ if (base+j > rootN-1) {
+ return;
+ }
+ u[2*(base+j)] = cos(2.0*PI*j/(2*n1));
+ u[2*(base+j)+1] = -sin(2.0*PI*j/(2*n1));
+ }
+ }
+}
+
+
+InitU2(N, u, n1)
+
+int N;
+double *u;
+int n1;
+
+{
+ int i,j,k;
+ int base;
+
+ for (j=0; j<n1; j++) {
+ k = j*(rootN+pad_length);
+ for (i=0; i<n1; i++) {
+ u[2*(k+i)] = cos(2.0*PI*i*j/(N));
+ u[2*(k+i)+1] = -sin(2.0*PI*i*j/(N));
+ }
+ }
+}
+
+
+BitReverse(M, k)
+
+int M;
+int k;
+
+{
+ int i;
+ int j;
+ int tmp;
+
+ j = 0;
+ tmp = k;
+ for (i=0; i<M; i++) {
+ j = 2*j + (tmp&0x1);
+ tmp = tmp>>1;
+ }
+ return(j);
+}
+
+
+void FFT1D(direction, M, N, x, scratch, upriv, umain2, MyNum, l_transtime,
+ MyFirst, MyLast, pad_length, P, test_result, doprint, dostats,
+ Global)
+
+int direction;
+int M;
+int N;
+int *l_transtime;
+double *x;
+double *upriv;
+double *scratch;
+double *umain2;
+int MyFirst;
+int MyLast;
+int pad_length;
+int P;
+int test_result;
+int doprint;
+int dostats;
+struct GlobalMemory *Global;
+
+{
+ int i;
+ int j;
+ int m1;
+ int n1;
+ int flag = 0;
+ unsigned int clocktime1;
+ unsigned int clocktime2;
+
+ m1 = M/2;
+ n1 = 1<<m1;
+
+ BARRIER(Global->start, P, 3);
+#ifdef FFT_DBG
+ LOCK(Global->idlock); printf("Slave %d left barrier 3\n",MyNum); UNLOCK(Global->idlock);
+#endif
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(clocktime1);
+ }
+
+ /* transpose from x into scratch */
+ Transpose(n1, x, scratch, MyNum, MyFirst, MyLast, pad_length);
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(clocktime2);
+ *l_transtime += (clocktime2-clocktime1);
+ }
+
+ /* do n1 1D FFTs on columns */
+ for (j=MyFirst; j<MyLast; j++) {
+ FFT1DOnce(direction, m1, n1, upriv, &scratch[2*j*(n1+pad_length)]);
+ TwiddleOneCol(direction, n1, N, j, umain2, &scratch[2*j*(n1+pad_length)],
+ pad_length);
+ }
+
+ BARRIER(Global->start, P, 4);
+#ifdef FFT_DBG
+ LOCK(Global->idlock); printf("Slave %d left barrier 4\n",MyNum); UNLOCK(Global->idlock);
+#endif
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(clocktime1);
+ }
+ /* transpose */
+ Transpose(n1, scratch, x, MyNum, MyFirst, MyLast, pad_length);
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(clocktime2);
+ *l_transtime += (clocktime2-clocktime1);
+ }
+
+ /* do n1 1D FFTs on columns again */
+ for (j=MyFirst; j<MyLast; j++) {
+ FFT1DOnce(direction, m1, n1, upriv, &x[2*j*(n1+pad_length)]);
+ if (direction == -1)
+ Scale(n1, N, &x[2*j*(n1+pad_length)]);
+ }
+
+ BARRIER(Global->start, P, 5);
+#ifdef FFT_DBG
+ LOCK(Global->idlock); printf("Slave %d left barrier 5\n",MyNum); UNLOCK(Global->idlock);
+#endif
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(clocktime1);
+ }
+
+ /* transpose back */
+ Transpose(n1, x, scratch, MyNum, MyFirst, MyLast, pad_length);
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(clocktime2);
+ *l_transtime += (clocktime2-clocktime1);
+ }
+
+ BARRIER(Global->start, P, 6);
+#ifdef FFT_DBG
+ LOCK(Global->idlock); printf("Slave %d left barrier 6\n",MyNum); UNLOCK(Global->idlock);
+#endif
+
+ /* copy columns from scratch to x */
+ if ((test_result) || (doprint)) {
+ for (j=MyFirst; j<MyLast; j++) {
+ CopyColumn(n1, &scratch[2*j*(n1+pad_length)], &x[2*j*(n1+pad_length)]);
+ }
+ }
+
+ BARRIER(Global->start, P, 7);
+}
+
+
+TwiddleOneCol(direction, n1, N, j, u, x, pad_length)
+
+int direction;
+int n1;
+int N;
+int j;
+double *u;
+double *x;
+int pad_length;
+
+{
+ int i;
+ double omega_r;
+ double omega_c;
+ double x_r;
+ double x_c;
+ double r1;
+ double c1;
+ double r2;
+ double c2;
+
+ for (i=0; i<n1; i++) {
+ omega_r = u[2*(j*(n1+pad_length)+i)];
+ omega_c = direction*u[2*(j*(n1+pad_length)+i)+1];
+ x_r = x[2*i];
+ x_c = x[2*i+1];
+ x[2*i] = omega_r*x_r - omega_c*x_c;
+ x[2*i+1] = omega_r*x_c + omega_c*x_r;
+ }
+}
+
+
+Scale(n1, N, x)
+
+int n1;
+int N;
+double *x;
+
+{
+ int i;
+
+ for (i=0; i<n1; i++) {
+ x[2*i] /= N;
+ x[2*i+1] /= N;
+ }
+}
+
+
+Transpose(n1, src, dest, MyNum, MyFirst, MyLast, pad_length)
+
+int n1;
+double *src;
+double *dest;
+int MyNum;
+int MyFirst;
+int MyLast;
+int pad_length;
+
+{
+ int i;
+ int j;
+ int k;
+ int l;
+ int m;
+ int blksize;
+ int numblks;
+ int firstfirst;
+ int h_off;
+ int v_off;
+ int v;
+ int h;
+ int n1p;
+ int row_count;
+
+ blksize = MyLast-MyFirst;
+ numblks = (2*blksize)/num_cache_lines;
+ if (numblks * num_cache_lines != 2 * blksize) {
+ numblks ++;
+ }
+ blksize = blksize / numblks;
+ firstfirst = MyFirst;
+ row_count = n1/P;
+ n1p = n1+pad_length;
+ for (l=MyNum+1;l<P;l++) {
+ v_off = l*row_count;
+ for (k=0; k<numblks; k++) {
+ h_off = firstfirst;
+ for (m=0; m<numblks; m++) {
+ for (i=0; i<blksize; i++) {
+ v = v_off + i;
+ for (j=0; j<blksize; j++) {
+ h = h_off + j;
+ dest[2*(h*n1p+v)] = src[2*(v*n1p+h)];
+ dest[2*(h*n1p+v)+1] = src[2*(v*n1p+h)+1];
+ }
+ }
+ h_off += blksize;
+ }
+ v_off+=blksize;
+ }
+ }
+
+ for (l=0;l<MyNum;l++) {
+ v_off = l*row_count;
+ for (k=0; k<numblks; k++) {
+ h_off = firstfirst;
+ for (m=0; m<numblks; m++) {
+ for (i=0; i<blksize; i++) {
+ v = v_off + i;
+ for (j=0; j<blksize; j++) {
+ h = h_off + j;
+ dest[2*(h*n1p+v)] = src[2*(v*n1p+h)];
+ dest[2*(h*n1p+v)+1] = src[2*(v*n1p+h)+1];
+ }
+ }
+ h_off += blksize;
+ }
+ v_off+=blksize;
+ }
+ }
+
+ v_off = MyNum*row_count;
+ for (k=0; k<numblks; k++) {
+ h_off = firstfirst;
+ for (m=0; m<numblks; m++) {
+ for (i=0; i<blksize; i++) {
+ v = v_off + i;
+ for (j=0; j<blksize; j++) {
+ h = h_off + j;
+ dest[2*(h*n1p+v)] = src[2*(v*n1p+h)];
+ dest[2*(h*n1p+v)+1] = src[2*(v*n1p+h)+1];
+ }
+ }
+ h_off += blksize;
+ }
+ v_off+=blksize;
+ }
+}
+
+
+CopyColumn(n1, src, dest)
+
+int n1;
+double *src;
+double *dest;
+
+{
+ int i;
+
+ for (i=0; i<n1; i++) {
+ dest[2*i] = src[2*i];
+ dest[2*i+1] = src[2*i+1];
+ }
+}
+
+
+Reverse(N, M, x)
+
+int N;
+int M;
+double *x;
+
+{
+ int j, k;
+
+ for (k=0; k<N; k++) {
+ j = BitReverse(M, k);
+ if (j > k) {
+ SWAP(x[2*j], x[2*k]);
+ SWAP(x[2*j+1], x[2*k+1]);
+ }
+ }
+}
+
+
+FFT1DOnce(direction, M, N, u, x)
+
+int direction;
+int M;
+int N;
+double *u;
+double *x;
+
+{
+ int j;
+ int k;
+ int q;
+ int L;
+ int r;
+ int Lstar;
+ double *u1;
+ double *x1;
+ double *x2;
+ double omega_r;
+ double omega_c;
+ double tau_r;
+ double tau_c;
+ double x_r;
+ double x_c;
+
+ Reverse(N, M, x);
+
+ for (q=1; q<=M; q++) {
+ L = 1<<q; r = N/L; Lstar = L/2;
+ u1 = &u[2*(Lstar-1)];
+ for (k=0; k<r; k++) {
+ x1 = &x[2*(k*L)];
+ x2 = &x[2*(k*L+Lstar)];
+ for (j=0; j<Lstar; j++) {
+ omega_r = u1[2*j];
+ omega_c = direction*u1[2*j+1];
+ x_r = x2[2*j];
+ x_c = x2[2*j+1];
+ tau_r = omega_r*x_r - omega_c*x_c;
+ tau_c = omega_r*x_c + omega_c*x_r;
+ x_r = x1[2*j];
+ x_c = x1[2*j+1];
+ x2[2*j] = x_r - tau_r;
+ x2[2*j+1] = x_c - tau_c;
+ x1[2*j] = x_r + tau_r;
+ x1[2*j+1] = x_c + tau_c;
+ }
+ }
+ }
+}
+
+
+PrintArray(N, x)
+
+int N;
+double *x;
+
+{
+ int i, j, k;
+
+ for (i=0; i<rootN; i++) {
+ k = i*(rootN+pad_length);
+ for (j=0; j<rootN; j++) {
+ printf(" %4.2f %4.2f", x[2*(k+j)], x[2*(k+j)+1]);
+ if (i*rootN+j != N-1) {
+ printf(",");
+ }
+ if ((i*rootN+j+1) % 8 == 0) {
+ printf("\n");
+ }
+ }
+ }
+ printf("\n");
+ printf("\n");
+}
+
+
+void printerr(s)
+
+char *s;
+
+{
+ printf("ERROR: %s\n",s);
+}
+
+
+int log_2(number)
+
+int number;
+
+{
+ int cumulative = 1;
+ int out = 0;
+ int done = 0;
+
+ while ((cumulative < number) && (!done) && (out < 50)) {
+ if (cumulative == number) {
+ done = 1;
+ } else {
+ cumulative = cumulative * 2;
+ out ++;
+ }
+ }
+
+ if (cumulative == number) {
+ return(out);
+ } else {
+ return(-1);
+ }
+}
+
+#include <tests_smp/getopt.c>
diff --git a/ecos/packages/kernel/current/tests_smp/fft.c b/ecos/packages/kernel/current/tests_smp/fft.c
new file mode 100644
index 0000000000..0222677c33
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/fft.c
@@ -0,0 +1,1460 @@
+
+
+
+
+
+
+
+
+
+
+
+/*************************************************************************/
+/* */
+/* Copyright (c) 1994 Stanford University */
+/* */
+/* All rights reserved. */
+/* */
+/* Permission is given to use, copy, and modify this software for any */
+/* non-commercial purpose as long as this copyright notice is not */
+/* removed. All other uses, including redistribution in whole or in */
+/* part, are forbidden without prior written permission. */
+/* */
+/* This software is provided with absolutely no warranty and no */
+/* support. */
+/* */
+/*************************************************************************/
+
+/*************************************************************************/
+/* */
+/* Perform 1D fast Fourier transform using six-step FFT method */
+/* */
+/* 1) Performs staggered, blocked transposes for cache-line reuse */
+/* 2) Roots of unity rearranged and distributed for only local */
+/* accesses during application of roots of unity */
+/* 3) Small set of roots of unity elements replicated locally for */
+/* 1D FFTs (less than root N elements replicated at each node) */
+/* 4) Matrix data structures are padded to reduce cache mapping */
+/* conflicts */
+/* */
+/* Command line options: */
+/* */
+/* -mM : M = even integer; 2**M total complex data points transformed. */
+/* -pP : P = number of processors; Must be a power of 2. */
+/* -nN : N = number of cache lines. */
+/* -lL : L = Log base 2 of cache line length in bytes. */
+/* -s : Print individual processor timing statistics. */
+/* -t : Perform FFT and inverse FFT. Test output by comparing the */
+/* integral of the original data to the integral of the data */
+/* that results from performing the FFT and inverse FFT. */
+/* -o : Print out complex data points. */
+/* -h : Print out command line options. */
+/* */
+/* Note: This version works under both the FORK and SPROC models */
+/* */
+/*************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <tests_smp/getopt.h>
+
+#define MAXRAND 2147483647
+#define PAGE_SIZE 4096
+#define NUM_CACHE_LINES 65536
+#define LOG2_LINE_SIZE 4
+#define PI 3.1416
+#define DEFAULT_M 10
+#define DEFAULT_P 1
+
+#include <tests_smp/fft_arg.c>
+
+
+/*---------------------------------------*/
+#include <pkgconf/system.h>
+#include <pkgconf/infra.h>
+#include <pkgconf/kernel.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/testcase.h>
+#include <pkgconf/isoinfra.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_smp.h>
+#include <cyg/kernel/kapi.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+int smp_cyg_test_main(int argc, char **argv);
+
+void smp_cyg_test_main_call(void *p) {
+ smp_cyg_test_main(smp_cyg_test_argc, smp_cyg_test_argv);
+}
+
+
+/* #define STACK_SIZE 0x1b000 */
+#define STACK_SIZE 8192
+static cyg_thread smp_cyg_test_thread;
+static char smp_cyg_test_stack[STACK_SIZE];
+static cyg_handle_t smp_cyg_test_threadh;
+
+
+
+cyg_handle_t threadh[64];
+char *stack[64];
+cyg_thread thread[64];
+
+
+externC void cyg_user_start( void )
+{
+ CYG_TEST_INIT();
+
+ diag_printf("Starting test app\n");
+
+ cyg_thread_create(10, // Priority - just a number
+ smp_cyg_test_main_call, // entry
+ 0, // index
+ "smp test", // Name
+ smp_cyg_test_stack, // Stack
+ STACK_SIZE, // Size
+ &smp_cyg_test_threadh, // Handle
+ &smp_cyg_test_thread // Thread data structure
+ );
+ cyg_thread_resume( smp_cyg_test_threadh );
+ /*cyg_scheduler_start();*/
+}
+
+
+/*---------------------------------------*/
+
+
+#define SWAP(a,b) {double tmp; tmp=a; a=b; b=tmp;}
+
+struct GlobalMemory {
+ int id;
+ cyg_spinlock_t idlock;
+
+/*---------------------------------------*/
+struct startTYP {
+ cyg_spinlock_t lock;;
+ int count[1];
+ cyg_sem_t queue[1];;
+
+ } start[1];
+/*---------------------------------------*/
+
+
+ int *transtimes;
+ int *totaltimes;
+ int starttime;
+ int finishtime;
+ int initdonetime;
+} *Global;
+
+int dbg_on = 0;
+
+int P = DEFAULT_P;
+int M = DEFAULT_M;
+int N; /* N = 2^M */
+int rootN; /* rootN = N^1/2 */
+double *x; /* x is the original time-domain data */
+double *trans; /* trans is used as scratch space */
+double *umain; /* umain is roots of unity for 1D FFTs */
+double *umain2; /* umain2 is entire roots of unity matrix */
+int test_result = 0;
+int doprint = 0;
+int dostats = 0;
+int transtime = 0;
+int transtime2 = 0;
+int avgtranstime = 0;
+int avgcomptime = 0;
+unsigned int transstart = 0;
+unsigned int transend = 0;
+int maxtotal=0;
+int mintotal=0;
+double maxfrac=0;
+double minfrac=0;
+double avgfractime=0;
+int orig_num_lines = NUM_CACHE_LINES; /* number of cache lines */
+int num_cache_lines = NUM_CACHE_LINES; /* number of cache lines */
+int log2_line_size = LOG2_LINE_SIZE;
+int line_size;
+int rowsperproc;
+double ck1;
+double ck3; /* checksums for testing answer */
+int pad_length;
+
+void SlaveStart();
+double TouchArray(double *,double *,double *,double *,int,int,int,int);
+void FFT1D(int,int,int,double *,double *,double *,double *,int,int *,int,
+ int,int,int,int,int,int,struct GlobalMemory *);
+double CheckSum();
+double drand48();
+int log_2(int);
+void printerr(char *);
+volatile int thread_array[4] = {0, 0, 0, 0};
+
+int smp_cyg_test_main(int argc, char **argv)
+{
+ int i;
+ int j;
+ int c;
+ extern char *optarg;
+ int m1;
+ int factor;
+ int pages;
+ unsigned int start;
+ //memset (thread_array,0,sizeof(thread_array));
+
+ {
+ (start) = cyg_current_time()*10;
+}
+;
+
+
+// extern Cyg_Mempool_dlmalloc *cygmem_memalloc_heaps[ 2 ];
+// cygmem_memalloc_heaps[0].
+
+
+ // printf("<cpu%d> thread %d Arguments (%d): ",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),argc);
+// for (i = 0;i < argc;i++){
+// printf("%s ",argv[i]);
+// }
+// printf("\n");
+
+ while ((c = getopt(argc, argv, "p:m:n:l:stoh")) != -1) {
+ switch(c) {
+ case 'p': P = atoi(optarg);
+ P = HAL_SMP_CPU_MAX;
+ if (P < 1) {
+ printerr("P must be >= 1\n");
+ exit(-1);
+ }
+ if (log_2(P) == -1) {
+ printerr("P must be a power of 2\n");
+ exit(-1);
+ }
+ break;
+ case 'm': M = atoi(optarg);
+ m1 = M/2;
+ if (2*m1 != M) {
+ printerr("M must be even\n");
+ exit(-1);
+ }
+ break;
+ case 'n': num_cache_lines = atoi(optarg);
+ orig_num_lines = num_cache_lines;
+ if (num_cache_lines < 1) {
+ printerr("Number of cache lines must be >= 1\n");
+ exit(-1);
+ }
+ break;
+ case 'l': log2_line_size = atoi(optarg);
+ if (log2_line_size < 0) {
+ printerr("Log base 2 of cache line length in bytes must be >= 0\n");
+ exit(-1);
+ }
+ break;
+ case 's': dostats = !dostats;
+ break;
+ case 't': test_result = !test_result;
+ break;
+ case 'o': doprint = !doprint;
+ break;
+ case 'h': printf("Usage: FFT <options>\n\n");
+ printf("options:\n");
+ printf(" -mM : M = even integer; 2**M total complex data points transformed.\n");
+ printf(" -pP : P = number of processors; Must be a power of 2.\n");
+ printf(" -nN : N = number of cache lines.\n");
+ printf(" -lL : L = Log base 2 of cache line length in bytes.\n");
+ printf(" -s : Print individual processor timing statistics.\n");
+ printf(" -t : Perform FFT and inverse FFT. Test output by comparing the\n");
+ printf(" integral of the original data to the integral of the data that\n");
+ printf(" results from performing the FFT and inverse FFT.\n");
+ printf(" -o : Print out complex data points.\n");
+ printf(" -h : Print out command line options.\n\n");
+ printf("Default: FFT -m%1d -p%1d -n%1d -l%1d\n",
+ DEFAULT_M,DEFAULT_P,NUM_CACHE_LINES,LOG2_LINE_SIZE);
+ exit(0);
+ break;
+ }
+ }
+
+ if (P > 64) {
+ printf("Maximal 64 processes\n");
+ exit(0);
+ }
+
+ {;};
+
+ N = 1<<M;
+ rootN = 1<<(M/2);
+ rowsperproc = rootN/P;
+ if (rowsperproc == 0) {
+ printerr("Matrix not large enough. 2**(M/2) must be >= P\n");
+ exit(-1);
+ }
+
+ line_size = 1 << log2_line_size;
+ if (line_size < 2*sizeof(double)) {
+ printf("WARNING: Each element is a complex double (%d bytes)\n",2*sizeof(double));
+ printf(" => Less than one element per cache line\n");
+ printf(" Computing transpose blocking factor\n");
+ factor = (2*sizeof(double)) / line_size;
+ num_cache_lines = orig_num_lines / factor;
+ }
+ if (line_size <= 2*sizeof(double)) {
+ pad_length = 1;
+ } else {
+ pad_length = line_size / (2*sizeof(double));
+ }
+
+ if (rowsperproc * rootN * 2 * sizeof(double) >= PAGE_SIZE) {
+ pages = (2 * pad_length * sizeof(double) * rowsperproc) / PAGE_SIZE;
+ if (pages * PAGE_SIZE != 2 * pad_length * sizeof(double) * rowsperproc) {
+ pages ++;
+ }
+ pad_length = (pages * PAGE_SIZE) / (2 * sizeof(double) * rowsperproc);
+ } else {
+ pad_length = (PAGE_SIZE - (rowsperproc * rootN * 2 * sizeof(double))) /
+
+ (2 * sizeof(double) * rowsperproc);
+ if (pad_length * (2 * sizeof(double) * rowsperproc) !=
+ (PAGE_SIZE - (rowsperproc * rootN * 2 * sizeof(double)))) {
+ printerr("Padding algorithm unsuccessful\n");
+ exit(-1);
+ }
+ }
+
+ Global = (struct GlobalMemory *) calloc(sizeof(struct GlobalMemory), 1);;
+ if (Global == NULL) {
+ printf("Could not malloc memory for Global (%d)\n",sizeof(struct GlobalMemory));
+ exit(-1);
+ }
+
+
+ x = (double *) calloc(2*(N+rootN*pad_length)*sizeof(double)+PAGE_SIZE, 1);;
+ trans = (double *) calloc(2*(N+rootN*pad_length)*sizeof(double)+PAGE_SIZE, 1);;
+ umain = (double *) calloc(2*rootN*sizeof(double), 1);;
+ umain2 = (double *) calloc(2*(N+rootN*pad_length)*sizeof(double)+PAGE_SIZE, 1);;
+
+
+ Global->transtimes = (int *) calloc(P*sizeof(int), 1);;
+ Global->totaltimes = (int *) calloc(P*sizeof(int), 1);;
+ if (x == NULL) {
+ printerr("Could not malloc memory for x\n");
+ exit(-1);
+ } else if (trans == NULL) {
+ printerr("Could not malloc memory for trans\n");
+ exit(-1);
+ } else if (umain == NULL) {
+ printerr("Could not malloc memory for umain\n");
+ exit(-1);
+ } else if (umain2 == NULL) {
+ printerr("Could not malloc memory for umain2\n");
+ exit(-1);
+ }
+
+ x = (double *) (((unsigned) x) + PAGE_SIZE - ((unsigned) x) % PAGE_SIZE);
+ trans = (double *) (((unsigned) trans) + PAGE_SIZE - ((unsigned) trans) % PAGE_SIZE);
+ umain2 = (double *) (((unsigned) umain2) + PAGE_SIZE - ((unsigned) umain2) % PAGE_SIZE);
+
+/* In order to optimize data distribution, the data structures x, trans,
+ and umain2 have been aligned so that each begins on a page boundary.
+ This ensures that the amount of padding calculated by the program is
+ such that each processor's partition ends on a page boundary, thus
+ ensuring that all data from these structures that are needed by a
+ processor can be allocated to its local memory */
+
+/* POSSIBLE ENHANCEMENT: Here is where one might distribute the x,
+ trans, and umain2 data structures across physically distributed
+ memories as desired.
+
+ One way to place data is as follows:
+
+ double *base;
+ int i;
+
+ i = ((N/P)+(rootN/P)*pad_length)*2;
+ base = &(x[0]);
+ for (j=0;j<P;j++) {
+ Place all addresses x such that (base <= x < base+i) on node j
+ base += i;
+ }
+
+ The trans and umain2 data structures can be placed in a similar manner.
+
+ */
+
+ printf("\n");
+ printf("FFT with Blocking Transpose\n");
+ printf(" %d Complex Doubles\n",N);
+ printf(" %d Threads\n",P);
+ if (num_cache_lines != orig_num_lines) {
+ printf(" %d Cache lines\n",orig_num_lines);
+ printf(" %d Cache lines for blocking transpose\n",num_cache_lines);
+ } else {
+ printf(" %d Cache lines\n",num_cache_lines);
+ }
+ printf(" %d Byte line size\n",(1 << log2_line_size));
+ printf(" %d Bytes per page\n",PAGE_SIZE);
+ printf("\n");
+
+ {{
+/*---------------------------------------*/
+ int mon_dum1,mon_dum2;
+ for (mon_dum1=0; mon_dum1 < 1; mon_dum1++)
+ for (mon_dum2=0; mon_dum2 < 1; mon_dum2++) {
+ Global->start[mon_dum1].count[mon_dum2] = 0;
+ { cyg_semaphore_init(&Global->start[mon_dum1].queue[mon_dum2],0);};
+ }
+ for (mon_dum1=0; mon_dum1 < 1; mon_dum1++) {
+ cyg_spinlock_init( &Global->start[mon_dum1].lock,0 );;
+ }
+/*---------------------------------------*/
+}};
+ cyg_spinlock_init( &Global->idlock,0 );;
+ Global->id = 0;
+ InitX(N, x); /* place random values in x */
+
+ if (test_result) {
+ ck1 = CheckSum(N, x);
+ }
+ if (doprint) {
+ printf("Original data values:\n");
+ PrintArray(N, x);
+ }
+
+ InitU(N,umain); /* initialize u arrays*/
+ InitU2(N,umain2,rootN);
+
+ /* fire off P processes */
+ for (i=1; i<P; i++) {
+
+{
+ /*---------------------------------------*/
+ stack[i] = calloc(STACK_SIZE, 1);
+ cyg_thread_create(10, // Priority - just a number
+ SlaveStart, // entry
+ 0, // index
+ "slave", // Name
+ stack[i], // Stack
+ STACK_SIZE, // Size
+ &threadh[i], // Handle
+ &thread[i] // Thread data structure
+ );
+ cyg_thread_resume( threadh[i] );
+ /*---------------------------------------*/
+}
+;
+ }
+
+ SlaveStart();
+
+ for (i=1; i<P; i++) {
+ while(!thread_array[i]) {};
+ }
+
+ if (doprint) {
+ if (test_result) {
+ printf("Data values after inverse FFT:\n");
+ } else {
+ printf("Data values after FFT:\n");
+ }
+ PrintArray(N, x);
+ }
+
+ transtime = Global->transtimes[0];
+ printf("\n");
+ printf(" PROCESS STATISTICS\n");
+ printf(" Computation Transpose Transpose\n");
+ printf(" Proc Time Time Fraction\n");
+ printf(" 0 %10d %10d %8.5f\n",
+ Global->totaltimes[0],Global->transtimes[0],
+ ((double)Global->transtimes[0])/Global->totaltimes[0]);
+ if (dostats) {
+ transtime2 = Global->transtimes[0];
+ avgtranstime = Global->transtimes[0];
+ avgcomptime = Global->totaltimes[0];
+ maxtotal = Global->totaltimes[0];
+ mintotal = Global->totaltimes[0];
+ maxfrac = ((double)Global->transtimes[0])/Global->totaltimes[0];
+ minfrac = ((double)Global->transtimes[0])/Global->totaltimes[0];
+ avgfractime = ((double)Global->transtimes[0])/Global->totaltimes[0];
+ for (i=1;i<P;i++) {
+ if (Global->transtimes[i] > transtime) {
+ transtime = Global->transtimes[i];
+ }
+ if (Global->transtimes[i] < transtime2) {
+ transtime2 = Global->transtimes[i];
+ }
+ if (Global->totaltimes[i] > maxtotal) {
+ maxtotal = Global->totaltimes[i];
+ }
+ if (Global->totaltimes[i] < mintotal) {
+ mintotal = Global->totaltimes[i];
+ }
+ if (((double)Global->transtimes[i])/Global->totaltimes[i] > maxfrac) {
+ maxfrac = ((double)Global->transtimes[i])/Global->totaltimes[i];
+ }
+ if (((double)Global->transtimes[i])/Global->totaltimes[i] < minfrac) {
+ minfrac = ((double)Global->transtimes[i])/Global->totaltimes[i];
+ }
+ printf(" %3d %10d %10d %f\n",
+ i,Global->totaltimes[i],Global->transtimes[i],
+ ((double)Global->transtimes[i])/Global->totaltimes[i]);
+ avgtranstime += Global->transtimes[i];
+ avgcomptime += Global->totaltimes[i];
+ avgfractime += ((double)Global->transtimes[i])/Global->totaltimes[i];
+ }
+ printf(" Avg %10f %10f %f\n",
+ ((double) avgcomptime)/P,((double) avgtranstime)/P,avgfractime/P);
+ printf(" Max %10d %10d %f\n",
+ maxtotal,transtime,maxfrac);
+ printf(" Min %10d %10d %f\n",
+ mintotal,transtime2,minfrac);
+ }
+ Global->starttime = start;
+ printf("\n");
+ printf(" TIMING INFORMATION\n");
+ printf("Start time : %16d\n",
+ Global->starttime);
+ printf("Initialization finish time : %16d\n",
+ Global->initdonetime);
+ printf("Overall finish time : %16d\n",
+ Global->finishtime);
+ printf("Total time with initialization : %16d\n",
+ Global->finishtime-Global->starttime);
+ printf("Total time without initialization : %16d\n",
+ Global->finishtime-Global->initdonetime);
+ printf("Overall transpose time : %16d\n",
+ transtime);
+ printf("Overall transpose fraction : %f\n",
+ ((double) transtime)/(Global->finishtime-Global->initdonetime));
+ printf("\n");
+
+ if (test_result) {
+ ck3 = CheckSum(N, x);
+ printf(" INVERSE FFT TEST RESULTS\n");
+ printf("Checksum difference is %f (%f, %f)\n",
+ ck1-ck3, ck1, ck3);
+ if (fabs(ck1-ck3) < 0.001) {
+ printf("TEST PASSED\n");
+ } else {
+ printf("TEST FAILED\n");
+ }
+ }
+
+
+{
+ diag_printf("FP test end\n");
+ return 0;
+}
+;
+}
+
+
+void SlaveStart()
+{
+ int i;
+ int j;
+ int MyNum;
+ double error;
+ double *upriv;
+ int initdone;
+ int finish;
+ int l_transtime=0;
+ int MyFirst;
+ int MyLast;
+
+ cyg_spinlock_spin(&Global->idlock);;
+ MyNum = Global->id;
+ Global->id++;
+#ifdef FFT_DBG
+ printf("Slave %d started\n",MyNum);
+#endif
+ cyg_spinlock_clear(&Global->idlock);;
+
+
+/* POSSIBLE ENHANCEMENT: Here is where one might pin processes to
+ processors to avoid migration */
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+#ifdef FFT_DBG
+ cyg_spinlock_spin(&Global->idlock);; printf("Slave %d left barrier 1\n",MyNum); cyg_spinlock_clear(&Global->idlock);;
+#endif
+
+ upriv = (double *) malloc(2*(rootN-1)*sizeof(double));
+ if (upriv == NULL) {
+ printf("Proc %d could not malloc memory for upriv\n",MyNum);
+ exit(-1);
+ }
+ for (i=0;i<2*(rootN-1);i++) {
+ upriv[i] = umain[i];
+ }
+
+ MyFirst = rootN*MyNum/P;
+ MyLast = rootN*(MyNum+1)/P;
+
+ TouchArray(x, trans, umain2, upriv, N, MyNum, MyFirst, MyLast);
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+#ifdef FFT_DBG
+ cyg_spinlock_spin(&Global->idlock);; printf("Slave %d left barrier 2\n",MyNum); cyg_spinlock_clear(&Global->idlock);;
+#endif
+
+/* POSSIBLE ENHANCEMENT: Here is where one might reset the
+ statistics that one is measuring about the parallel execution */
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (initdone) = cyg_current_time()*10;
+}
+;
+ }
+
+ /* perform forward FFT */
+ FFT1D(1, M, N, x, trans, upriv, umain2, MyNum, &l_transtime, MyFirst,
+ MyLast, pad_length, P, test_result, doprint, dostats, Global);
+
+ /* perform backward FFT */
+ if (test_result) {
+ FFT1D(-1, M, N, x, trans, upriv, umain2, MyNum, &l_transtime, MyFirst,
+ MyLast, pad_length, P, test_result, doprint, dostats, Global);
+ }
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (finish) = cyg_current_time()*10;
+}
+;
+ Global->transtimes[MyNum] = l_transtime;
+ Global->totaltimes[MyNum] = finish-initdone;
+ }
+ if (MyNum == 0) {
+ Global->finishtime = finish;
+ Global->initdonetime = initdone;
+ }
+
+ thread_array[MyNum] = 1;
+}
+
+
+double TouchArray(x, scratch, u, upriv, N, MyNum, MyFirst, MyLast)
+
+double *x;
+double *scratch;
+double *u;
+double *upriv;
+int N;
+int MyNum;
+int MyFirst;
+int MyLast;
+
+{
+ int i,j,k;
+ double tot = 0.0;
+
+ /* touch my data */
+ for (j=0;j<2*(rootN-1);j++) {
+ tot += upriv[j];
+ }
+ for (j=MyFirst; j<MyLast; j++) {
+ k = j * (rootN + pad_length);
+ for (i=0;i<rootN;i++) {
+ tot += x[2*(k+i)] + x[2*(k+i)+1] +
+ scratch[2*(k+i)] + scratch[2*(k+i)+1] +
+ u[2*(k+i)] + u[2*(k+i)+1];
+ }
+ }
+ return tot;
+}
+
+
+double CheckSum(N, x)
+
+int N;
+double *x;
+
+{
+ int i,j,k;
+ double cks;
+
+ cks = 0.0;
+ for (j=0; j<rootN; j++) {
+ k = j * (rootN + pad_length);
+ for (i=0;i<rootN;i++) {
+ cks += x[2*(k+i)] + x[2*(k+i)+1];
+ }
+ }
+
+ return(cks);
+}
+
+
+InitX(N, x)
+
+int N;
+double *x;
+
+{
+ int i,j,k;
+
+ srand(0);
+ for (j=0; j<rootN; j++) {
+ k = j * (rootN + pad_length);
+ for (i=0;i<rootN;i++) {
+ x[2*(k+i)] = rand()/MAXRAND;
+ x[2*(k+i)+1] = rand()/MAXRAND;
+ }
+ }
+}
+
+
+InitU(N, u)
+
+int N;
+double *u;
+
+{
+ int q;
+ int j;
+ int base;
+ int n1;
+
+ for (q=0; 1<<q<N; q++) {
+ n1 = 1<<q;
+ base = n1-1;
+ for (j=0; j<n1; j++) {
+ if (base+j > rootN-1) {
+ return;
+ }
+ u[2*(base+j)] = cos(2.0*PI*j/(2*n1));
+ u[2*(base+j)+1] = -sin(2.0*PI*j/(2*n1));
+ }
+ }
+}
+
+
+InitU2(N, u, n1)
+
+int N;
+double *u;
+int n1;
+
+{
+ int i,j,k;
+ int base;
+
+ for (j=0; j<n1; j++) {
+ k = j*(rootN+pad_length);
+ for (i=0; i<n1; i++) {
+ u[2*(k+i)] = cos(2.0*PI*i*j/(N));
+ u[2*(k+i)+1] = -sin(2.0*PI*i*j/(N));
+ }
+ }
+}
+
+
+BitReverse(M, k)
+
+int M;
+int k;
+
+{
+ int i;
+ int j;
+ int tmp;
+
+ j = 0;
+ tmp = k;
+ for (i=0; i<M; i++) {
+ j = 2*j + (tmp&0x1);
+ tmp = tmp>>1;
+ }
+ return(j);
+}
+
+
+void FFT1D(direction, M, N, x, scratch, upriv, umain2, MyNum, l_transtime,
+ MyFirst, MyLast, pad_length, P, test_result, doprint, dostats,
+ Global)
+
+int direction;
+int M;
+int N;
+int *l_transtime;
+double *x;
+double *upriv;
+double *scratch;
+double *umain2;
+int MyFirst;
+int MyLast;
+int pad_length;
+int P;
+int test_result;
+int doprint;
+int dostats;
+struct GlobalMemory *Global;
+
+{
+ int i;
+ int j;
+ int m1;
+ int n1;
+ int flag = 0;
+ unsigned int clocktime1;
+ unsigned int clocktime2;
+
+ m1 = M/2;
+ n1 = 1<<m1;
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+#ifdef FFT_DBG
+ cyg_spinlock_spin(&Global->idlock);; printf("Slave %d left barrier 3\n",MyNum); cyg_spinlock_clear(&Global->idlock);;
+#endif
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (clocktime1) = cyg_current_time()*10;
+}
+;
+ }
+
+ /* transpose from x into scratch */
+ Transpose(n1, x, scratch, MyNum, MyFirst, MyLast, pad_length);
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (clocktime2) = cyg_current_time()*10;
+}
+;
+ *l_transtime += (clocktime2-clocktime1);
+ }
+
+ /* do n1 1D FFTs on columns */
+ for (j=MyFirst; j<MyLast; j++) {
+ FFT1DOnce(direction, m1, n1, upriv, &scratch[2*j*(n1+pad_length)]);
+ TwiddleOneCol(direction, n1, N, j, umain2, &scratch[2*j*(n1+pad_length)],
+ pad_length);
+ }
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+#ifdef FFT_DBG
+ cyg_spinlock_spin(&Global->idlock);; printf("Slave %d left barrier 4\n",MyNum); cyg_spinlock_clear(&Global->idlock);;
+#endif
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (clocktime1) = cyg_current_time()*10;
+}
+;
+ }
+ /* transpose */
+ Transpose(n1, scratch, x, MyNum, MyFirst, MyLast, pad_length);
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (clocktime2) = cyg_current_time()*10;
+}
+;
+ *l_transtime += (clocktime2-clocktime1);
+ }
+
+ /* do n1 1D FFTs on columns again */
+ for (j=MyFirst; j<MyLast; j++) {
+ FFT1DOnce(direction, m1, n1, upriv, &x[2*j*(n1+pad_length)]);
+ if (direction == -1)
+ Scale(n1, N, &x[2*j*(n1+pad_length)]);
+ }
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+#ifdef FFT_DBG
+ cyg_spinlock_spin(&Global->idlock);; printf("Slave %d left barrier 5\n",MyNum); cyg_spinlock_clear(&Global->idlock);;
+#endif
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (clocktime1) = cyg_current_time()*10;
+}
+;
+ }
+
+ /* transpose back */
+ Transpose(n1, x, scratch, MyNum, MyFirst, MyLast, pad_length);
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (clocktime2) = cyg_current_time()*10;
+}
+;
+ *l_transtime += (clocktime2-clocktime1);
+ }
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),6,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),6,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),6,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),6,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),6,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+#ifdef FFT_DBG
+ cyg_spinlock_spin(&Global->idlock);; printf("Slave %d left barrier 6\n",MyNum); cyg_spinlock_clear(&Global->idlock);;
+#endif
+
+ /* copy columns from scratch to x */
+ if ((test_result) || (doprint)) {
+ for (j=MyFirst; j<MyLast; j++) {
+ CopyColumn(n1, &scratch[2*j*(n1+pad_length)], &x[2*j*(n1+pad_length)]);
+ }
+ }
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),7,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),7,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),7,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),7,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),7,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+}
+
+
+TwiddleOneCol(direction, n1, N, j, u, x, pad_length)
+
+int direction;
+int n1;
+int N;
+int j;
+double *u;
+double *x;
+int pad_length;
+
+{
+ int i;
+ double omega_r;
+ double omega_c;
+ double x_r;
+ double x_c;
+ double r1;
+ double c1;
+ double r2;
+ double c2;
+
+ for (i=0; i<n1; i++) {
+ omega_r = u[2*(j*(n1+pad_length)+i)];
+ omega_c = direction*u[2*(j*(n1+pad_length)+i)+1];
+ x_r = x[2*i];
+ x_c = x[2*i+1];
+ x[2*i] = omega_r*x_r - omega_c*x_c;
+ x[2*i+1] = omega_r*x_c + omega_c*x_r;
+ }
+}
+
+
+Scale(n1, N, x)
+
+int n1;
+int N;
+double *x;
+
+{
+ int i;
+
+ for (i=0; i<n1; i++) {
+ x[2*i] /= N;
+ x[2*i+1] /= N;
+ }
+}
+
+
+Transpose(n1, src, dest, MyNum, MyFirst, MyLast, pad_length)
+
+int n1;
+double *src;
+double *dest;
+int MyNum;
+int MyFirst;
+int MyLast;
+int pad_length;
+
+{
+ int i;
+ int j;
+ int k;
+ int l;
+ int m;
+ int blksize;
+ int numblks;
+ int firstfirst;
+ int h_off;
+ int v_off;
+ int v;
+ int h;
+ int n1p;
+ int row_count;
+
+ blksize = MyLast-MyFirst;
+ numblks = (2*blksize)/num_cache_lines;
+ if (numblks * num_cache_lines != 2 * blksize) {
+ numblks ++;
+ }
+ blksize = blksize / numblks;
+ firstfirst = MyFirst;
+ row_count = n1/P;
+ n1p = n1+pad_length;
+ for (l=MyNum+1;l<P;l++) {
+ v_off = l*row_count;
+ for (k=0; k<numblks; k++) {
+ h_off = firstfirst;
+ for (m=0; m<numblks; m++) {
+ for (i=0; i<blksize; i++) {
+ v = v_off + i;
+ for (j=0; j<blksize; j++) {
+ h = h_off + j;
+ dest[2*(h*n1p+v)] = src[2*(v*n1p+h)];
+ dest[2*(h*n1p+v)+1] = src[2*(v*n1p+h)+1];
+ }
+ }
+ h_off += blksize;
+ }
+ v_off+=blksize;
+ }
+ }
+
+ for (l=0;l<MyNum;l++) {
+ v_off = l*row_count;
+ for (k=0; k<numblks; k++) {
+ h_off = firstfirst;
+ for (m=0; m<numblks; m++) {
+ for (i=0; i<blksize; i++) {
+ v = v_off + i;
+ for (j=0; j<blksize; j++) {
+ h = h_off + j;
+ dest[2*(h*n1p+v)] = src[2*(v*n1p+h)];
+ dest[2*(h*n1p+v)+1] = src[2*(v*n1p+h)+1];
+ }
+ }
+ h_off += blksize;
+ }
+ v_off+=blksize;
+ }
+ }
+
+ v_off = MyNum*row_count;
+ for (k=0; k<numblks; k++) {
+ h_off = firstfirst;
+ for (m=0; m<numblks; m++) {
+ for (i=0; i<blksize; i++) {
+ v = v_off + i;
+ for (j=0; j<blksize; j++) {
+ h = h_off + j;
+ dest[2*(h*n1p+v)] = src[2*(v*n1p+h)];
+ dest[2*(h*n1p+v)+1] = src[2*(v*n1p+h)+1];
+ }
+ }
+ h_off += blksize;
+ }
+ v_off+=blksize;
+ }
+}
+
+
+CopyColumn(n1, src, dest)
+
+int n1;
+double *src;
+double *dest;
+
+{
+ int i;
+
+ for (i=0; i<n1; i++) {
+ dest[2*i] = src[2*i];
+ dest[2*i+1] = src[2*i+1];
+ }
+}
+
+
+Reverse(N, M, x)
+
+int N;
+int M;
+double *x;
+
+{
+ int j, k;
+
+ for (k=0; k<N; k++) {
+ j = BitReverse(M, k);
+ if (j > k) {
+ SWAP(x[2*j], x[2*k]);
+ SWAP(x[2*j+1], x[2*k+1]);
+ }
+ }
+}
+
+
+FFT1DOnce(direction, M, N, u, x)
+
+int direction;
+int M;
+int N;
+double *u;
+double *x;
+
+{
+ int j;
+ int k;
+ int q;
+ int L;
+ int r;
+ int Lstar;
+ double *u1;
+ double *x1;
+ double *x2;
+ double omega_r;
+ double omega_c;
+ double tau_r;
+ double tau_c;
+ double x_r;
+ double x_c;
+
+ Reverse(N, M, x);
+
+ for (q=1; q<=M; q++) {
+ L = 1<<q; r = N/L; Lstar = L/2;
+ u1 = &u[2*(Lstar-1)];
+ for (k=0; k<r; k++) {
+ x1 = &x[2*(k*L)];
+ x2 = &x[2*(k*L+Lstar)];
+ for (j=0; j<Lstar; j++) {
+ omega_r = u1[2*j];
+ omega_c = direction*u1[2*j+1];
+ x_r = x2[2*j];
+ x_c = x2[2*j+1];
+ tau_r = omega_r*x_r - omega_c*x_c;
+ tau_c = omega_r*x_c + omega_c*x_r;
+ x_r = x1[2*j];
+ x_c = x1[2*j+1];
+ x2[2*j] = x_r - tau_r;
+ x2[2*j+1] = x_c - tau_c;
+ x1[2*j] = x_r + tau_r;
+ x1[2*j+1] = x_c + tau_c;
+ }
+ }
+ }
+}
+
+
+PrintArray(N, x)
+
+int N;
+double *x;
+
+{
+ int i, j, k;
+
+ for (i=0; i<rootN; i++) {
+ k = i*(rootN+pad_length);
+ for (j=0; j<rootN; j++) {
+ printf(" %4.2f %4.2f", x[2*(k+j)], x[2*(k+j)+1]);
+ if (i*rootN+j != N-1) {
+ printf(",");
+ }
+ if ((i*rootN+j+1) % 8 == 0) {
+ printf("\n");
+ }
+ }
+ }
+ printf("\n");
+ printf("\n");
+}
+
+
+void printerr(s)
+
+char *s;
+
+{
+ printf("ERROR: %s\n",s);
+}
+
+
+int log_2(number)
+
+int number;
+
+{
+ int cumulative = 1;
+ int out = 0;
+ int done = 0;
+
+ while ((cumulative < number) && (!done) && (out < 50)) {
+ if (cumulative == number) {
+ done = 1;
+ } else {
+ cumulative = cumulative * 2;
+ out ++;
+ }
+ }
+
+ if (cumulative == number) {
+ return(out);
+ } else {
+ return(-1);
+ }
+}
+
+#include <tests_smp/getopt.c>
diff --git a/ecos/packages/kernel/current/tests_smp/fft_arg.c b/ecos/packages/kernel/current/tests_smp/fft_arg.c
new file mode 100644
index 0000000000..acf764a06d
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/fft_arg.c
@@ -0,0 +1,18 @@
+
+//___________________________________________
+#define smp_cyg_test_argc 11
+char *_cyg_argv[] = {
+ "fft.exe",
+ "-s",
+ "-t",
+ "-l",
+ "5",
+ "-n",
+ "256",
+ "-p",
+ "2", /* not used, using HAL_SMP_CPU_MAX */
+ "-m",
+ "16"
+};
+#define smp_cyg_test_argv &_cyg_argv
+//'''''''''''''''''''''''''''''''''''''''''''
diff --git a/ecos/packages/kernel/current/tests_smp/getopt.c b/ecos/packages/kernel/current/tests_smp/getopt.c
new file mode 100644
index 0000000000..7645ec44d6
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/getopt.c
@@ -0,0 +1,654 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+ Free Software Foundation, Inc.
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef __STDC__
+# ifndef const
+# define const
+# endif
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#endif /* GNU C library. */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+ long-named option. Because this is not POSIX.2 compliant, it is
+ being phased out. */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+#define BAD_OPTION '\0'
+int optopt = BAD_OPTION;
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+static int
+my_strlen (str)
+ const char *str;
+{
+ int n = 0;
+ while (*str++)
+ n++;
+ return n;
+}
+
+static char *
+my_index (str, chr)
+ const char *str;
+ int chr;
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved.
+
+ To perform the swap, we first reverse the order of all elements. So
+ all options now come before all non options, but they are in the
+ wrong order. So we put back the options and non options in original
+ order by reversing them again. For example:
+ original input: a b c -x -y
+ reverse all: -y -x c b a
+ reverse options: -x -y c b a
+ reverse non options: -x -y a b c
+*/
+
+#if __STDC__ || defined(PROTO)
+static void exchange (char **argv);
+#endif
+
+static void
+exchange (argv)
+ char **argv;
+{
+ char *temp, **first, **last;
+
+ /* Reverse all the elements [first_nonopt, optind) */
+ first = &argv[first_nonopt];
+ last = &argv[optind-1];
+ while (first < last) {
+ temp = *first; *first = *last; *last = temp; first++; last--;
+ }
+ /* Put back the options in order */
+ first = &argv[first_nonopt];
+ first_nonopt += (optind - last_nonopt);
+ last = &argv[first_nonopt - 1];
+ while (first < last) {
+ temp = *first; *first = *last; *last = temp; first++; last--;
+ }
+
+ /* Put back the non options in order */
+ first = &argv[first_nonopt];
+ last_nonopt = optind;
+ last = &argv[last_nonopt-1];
+ while (first < last) {
+ temp = *first; *first = *last; *last = temp; first++; last--;
+ }
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return BAD_OPTION after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return BAD_OPTION.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+ const struct option *longopts;
+ int *longind;
+ int long_only;
+{
+ int option_index;
+
+ optarg = 0;
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (optind == 0)
+ {
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (getenv ("POSIXLY_CORRECT") != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+ }
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Now skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+ && (longopts == NULL
+ || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif /* GETOPT_COMPAT */
+ )
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ if (longopts != NULL
+ && ((argv[optind][0] == '-'
+ && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ ))
+ {
+ const struct option *p;
+ char *s = nextchar;
+ int exact = 0;
+ int ambig = 0;
+ const struct option *pfound = NULL;
+ int indfound = 0;
+
+ while (*s && *s != '=')
+ s++;
+
+ /* Test all options for either exact match or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name;
+ p++, option_index++)
+ if (!strncmp (p->name, nextchar, s - nextchar))
+ {
+ if (s - nextchar == my_strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += my_strlen (nextchar);
+ optind++;
+ return BAD_OPTION;
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*s)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = s + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += my_strlen (nextchar);
+ return BAD_OPTION;
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += my_strlen (nextchar);
+ return optstring[0] == ':' ? ':' : BAD_OPTION;
+ }
+ }
+ nextchar += my_strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+ || argv[optind][0] == '+'
+#endif /* GETOPT_COMPAT */
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return BAD_OPTION;
+ }
+ }
+
+ /* Look at and handle the next option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+#if 0
+ if (c < 040 || c >= 0177)
+ fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+ argv[0], c);
+ else
+ fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+ }
+ optopt = c;
+ return BAD_OPTION;
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = 0;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+#if 0
+ fprintf (stderr, "%s: option `-%c' requires an argument\n",
+ argv[0], c);
+#else
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+#endif
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = BAD_OPTION;
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char *const *argv;
+ const char *options;
+ const struct option *long_options;
+ int *opt_index;
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+
diff --git a/ecos/packages/kernel/current/tests_smp/getopt.h b/ecos/packages/kernel/current/tests_smp/getopt.h
new file mode 100644
index 0000000000..3c0b2930a6
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/getopt.h
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+//#define printf diag_printf
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+ of `struct option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ no_argument (or 0) if the option does not take an argument,
+ required_argument (or 1) if the option requires an argument,
+ optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `getopt'
+ returns the contents of the `val' field. */
+
+struct option
+{
+#if __STDC__
+ const char *name;
+#else
+ char *name;
+#endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'. */
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+#if __STDC__ || defined(PROTO)
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int _getopt_internal (int argc, char *const *argv,
+ const char *shortopts,
+ const struct option *longopts, int *longind,
+ int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/ecos/packages/kernel/current/tests_smp/lu.C b/ecos/packages/kernel/current/tests_smp/lu.C
new file mode 100644
index 0000000000..9a46678260
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/lu.C
@@ -0,0 +1,788 @@
+/*************************************************************************/
+/* */
+/* Copyright (c) 1994 Stanford University */
+/* */
+/* All rights reserved. */
+/* */
+/* Permission is given to use, copy, and modify this software for any */
+/* non-commercial purpose as long as this copyright notice is not */
+/* removed. All other uses, including redistribution in whole or in */
+/* part, are forbidden without prior written permission. */
+/* */
+/* This software is provided with absolutely no warranty and no */
+/* support. */
+/* */
+/*************************************************************************/
+
+/*************************************************************************/
+/* */
+/* Parallel dense blocked LU factorization (no pivoting) */
+/* */
+/* This version contains one dimensional arrays in which the matrix */
+/* to be factored is stored. */
+/* */
+/* Command line options: */
+/* */
+/* -nN : Decompose NxN matrix. */
+/* -pP : P = number of processors. */
+/* -bB : Use a block size of B. BxB elements should fit in cache for */
+/* good performance. Small block sizes (B=8, B=16) work well. */
+/* -s : Print individual processor timing statistics. */
+/* -t : Test output. */
+/* -o : Print out matrix values. */
+/* -h : Print out command line options. */
+/* */
+/* Note: This version works under both the FORK and SPROC models */
+/* */
+/*************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <tests_smp/getopt.h>
+
+#include <tests_smp/lu_arg.c>
+
+MAIN_ENV
+
+#define MAXRAND 2147483647
+#define DEFAULT_N 128
+#define DEFAULT_P 1
+#define DEFAULT_B 16
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+struct GlobalMemory {
+ double *t_in_fac;
+ double *t_in_solve;
+ double *t_in_mod;
+ double *t_in_bar;
+ double *completion;
+ unsigned int starttime;
+ unsigned int rf;
+ unsigned int rs;
+ unsigned int done;
+ int id;
+ BARDEC(start)
+ LOCKDEC(idlock)
+} *Global;
+
+struct LocalCopies {
+ double t_in_fac;
+ double t_in_solve;
+ double t_in_mod;
+ double t_in_bar;
+};
+
+int dbg_on = 0;
+int n = DEFAULT_N; /* The size of the matrix */
+int P = DEFAULT_P; /* Number of processors */
+int block_size = DEFAULT_B; /* Block dimension */
+int nblocks; /* Number of blocks in each dimension */
+int num_rows; /* Number of processors per row of processor grid */
+int num_cols; /* Number of processors per col of processor grid */
+double *a; /* a = lu; l and u both placed back in a */
+double *rhs;
+int *proc_bytes; /* Bytes to malloc per processor to hold blocks
+ of A*/
+int test_result = 0; /* Test result of factorization? */
+int doprint = 0; /* Print out matrix values? */
+int dostats = 0; /* Print out individual processor statistics? */
+
+void SlaveStart();
+void OneSolve(int, int, double *, int, int);
+void lu0(double *,int, int);
+void bdiv(double *, double *, int, int, int, int);
+void bmodd(double *, double*, int, int, int, int);
+void bmod(double *, double *, double *, int, int, int, int);
+void daxpy(double *, double *, int, double);
+int BlockOwner(int, int);
+void lu(int, int, int, struct LocalCopies *, int);
+void InitA(double *);
+double TouchA(int, int);
+void PrintA();
+void CheckResult(int, double *, double *);
+void printerr(char *);
+volatile cyg_thread *thread_array[64];
+
+
+int smp_cyg_test_main(argc, argv)
+
+int argc;
+char **argv;
+
+{
+ int i, j;
+ int ch;
+ extern char *optarg;
+ int MyNum=0;
+ double mint, maxt, avgt;
+ double min_fac, min_solve, min_mod, min_bar;
+ double max_fac, max_solve, max_mod, max_bar;
+ double avg_fac, avg_solve, avg_mod, avg_bar;
+ int proc_num;
+ unsigned int start;
+
+ memset (thread_array,0,sizeof(thread_array));
+
+ CLOCK(start);
+
+ while ((ch = getopt(argc, argv, "n:p:b:cstoh")) != -1) {
+ switch(ch) {
+ case 'n': n = atoi(optarg); break;
+ case 'p': P = atoi(optarg);
+ P = HAL_SMP_CPU_MAX; break;
+ case 'b': block_size = atoi(optarg); break;
+ case 's': dostats = 1; break;
+ case 't': test_result = !test_result; break;
+ case 'o': doprint = !doprint; break;
+ case 'h': diag_printf("Usage: LU <options>\n\n");
+ diag_printf("options:\n");
+ diag_printf(" -nN : Decompose NxN matrix.\n");
+ diag_printf(" -pP : P = number of processors.\n");
+ diag_printf(" -bB : Use a block size of B. BxB elements should fit in cache for \n");
+ diag_printf(" good performance. Small block sizes (B=8, B=16) work well.\n");
+ diag_printf(" -c : Copy non-locally allocated blocks to local memory before use.\n");
+ diag_printf(" -s : Print individual processor timing statistics.\n");
+ diag_printf(" -t : Test output.\n");
+ diag_printf(" -o : Print out matrix values.\n");
+ diag_printf(" -h : Print out command line options.\n\n");
+ diag_printf("Default: LU -n%1d -p%1d -b%1d\n",
+ DEFAULT_N,DEFAULT_P,DEFAULT_B);
+ exit(0);
+ break;
+ }
+ }
+ if (P > 64) {
+ printf("Maximal 64 processes\n");
+ exit(0);
+ }
+
+ MAIN_INITENV(,150000000)
+
+ diag_printf("\n");
+ diag_printf("Blocked Dense LU Factorization\n");
+ diag_printf(" %d by %d Matrix\n",n,n);
+ diag_printf(" %d Processors\n",P);
+ diag_printf(" %d by %d Element Blocks\n",block_size,block_size);
+ diag_printf("\n");
+ diag_printf("\n");
+
+ num_rows = (int) sqrt((double) P);
+ for (;;) {
+ num_cols = P/num_rows;
+ if (num_rows*num_cols == P)
+ break;
+ num_rows--;
+ }
+ nblocks = n/block_size;
+ if (block_size * nblocks != n) {
+ nblocks++;
+ }
+
+ a = (double *) G_MALLOC(n*n*sizeof(double));
+ rhs = (double *) G_MALLOC(n*sizeof(double));
+
+ Global = (struct GlobalMemory *) G_MALLOC(sizeof(struct GlobalMemory));
+ Global->t_in_fac = (double *) G_MALLOC(P*sizeof(double));
+ Global->t_in_mod = (double *) G_MALLOC(P*sizeof(double));
+ Global->t_in_solve = (double *) G_MALLOC(P*sizeof(double));
+ Global->t_in_bar = (double *) G_MALLOC(P*sizeof(double));
+ Global->completion = (double *) G_MALLOC(P*sizeof(double));
+
+ if (Global == NULL) {
+ printerr("Could not malloc memory for Global\n");
+ exit(-1);
+ } else if (Global->t_in_fac == NULL) {
+ printerr("Could not malloc memory for Global->t_in_fac\n");
+ exit(-1);
+ } else if (Global->t_in_mod == NULL) {
+ printerr("Could not malloc memory for Global->t_in_mod\n");
+ exit(-1);
+ } else if (Global->t_in_solve == NULL) {
+ printerr("Could not malloc memory for Global->t_in_solve\n");
+ exit(-1);
+ } else if (Global->t_in_bar == NULL) {
+ printerr("Could not malloc memory for Global->t_in_bar\n");
+ exit(-1);
+ } else if (Global->completion == NULL) {
+ printerr("Could not malloc memory for Global->completion\n");
+ exit(-1);
+ }
+
+/* POSSIBLE ENHANCEMENT: Here is where one might distribute the a
+ matrix data across physically distributed memories in a
+ round-robin fashion as desired. */
+
+ BARINIT(Global->start);
+ LOCKINIT(Global->idlock);
+ Global->id = 0;
+
+ for (i=1; i<P; i++) {
+ CREATE(SlaveStart,thread_array[i])
+ }
+
+ InitA(rhs);
+ if (doprint) {
+ diag_printf("Matrix before decomposition:\n");
+ PrintA();
+ }
+
+
+ SlaveStart(MyNum);
+
+ for (i=1; i<P; i++) {
+ while(thread_array[i]) {};
+ }
+
+ if (doprint) {
+ diag_printf("\nMatrix after decomposition:\n");
+ PrintA();
+ }
+
+ if (dostats) {
+ maxt = avgt = mint = Global->completion[0];
+ for (i=1; i<P; i++) {
+ if (Global->completion[i] > maxt) {
+ maxt = Global->completion[i];
+ }
+ if (Global->completion[i] < mint) {
+ mint = Global->completion[i];
+ }
+ avgt += Global->completion[i];
+ }
+ avgt = avgt / P;
+
+ min_fac = max_fac = avg_fac = Global->t_in_fac[0];
+ min_solve = max_solve = avg_solve = Global->t_in_solve[0];
+ min_mod = max_mod = avg_mod = Global->t_in_mod[0];
+ min_bar = max_bar = avg_bar = Global->t_in_bar[0];
+
+ for (i=1; i<P; i++) {
+ if (Global->t_in_fac[i] > max_fac) {
+ max_fac = Global->t_in_fac[i];
+ }
+ if (Global->t_in_fac[i] < min_fac) {
+ min_fac = Global->t_in_fac[i];
+ }
+ if (Global->t_in_solve[i] > max_solve) {
+ max_solve = Global->t_in_solve[i];
+ }
+ if (Global->t_in_solve[i] < min_solve) {
+ min_solve = Global->t_in_solve[i];
+ }
+ if (Global->t_in_mod[i] > max_mod) {
+ max_mod = Global->t_in_mod[i];
+ }
+ if (Global->t_in_mod[i] < min_mod) {
+ min_mod = Global->t_in_mod[i];
+ }
+ if (Global->t_in_bar[i] > max_bar) {
+ max_bar = Global->t_in_bar[i];
+ }
+ if (Global->t_in_bar[i] < min_bar) {
+ min_bar = Global->t_in_bar[i];
+ }
+ avg_fac += Global->t_in_fac[i];
+ avg_solve += Global->t_in_solve[i];
+ avg_mod += Global->t_in_mod[i];
+ avg_bar += Global->t_in_bar[i];
+ }
+ avg_fac = avg_fac/P;
+ avg_solve = avg_solve/P;
+ avg_mod = avg_mod/P;
+ avg_bar = avg_bar/P;
+ }
+ diag_printf(" PROCESS STATISTICS\n");
+ diag_printf(" Total Diagonal Perimeter Interior Barrier\n");
+ diag_printf(" Proc Time Time Time Time Time\n");
+ diag_printf(" 0 %10.0f %10.0f %10.0f %10.0f %10.0f\n",
+ Global->completion[0],Global->t_in_fac[0],
+ Global->t_in_solve[0],Global->t_in_mod[0],
+ Global->t_in_bar[0]);
+ if (dostats) {
+ for (i=1; i<P; i++) {
+ diag_printf(" %3d %10.0f %10.0f %10.0f %10.0f %10.0f\n",
+ i,Global->completion[i],Global->t_in_fac[i],
+ Global->t_in_solve[i],Global->t_in_mod[i],
+ Global->t_in_bar[i]);
+ }
+ diag_printf(" Avg %10.0f %10.0f %10.0f %10.0f %10.0f\n",
+ avgt,avg_fac,avg_solve,avg_mod,avg_bar);
+ diag_printf(" Min %10.0f %10.0f %10.0f %10.0f %10.0f\n",
+ mint,min_fac,min_solve,min_mod,min_bar);
+ diag_printf(" Max %10.0f %10.0f %10.0f %10.0f %10.0f\n",
+ maxt,max_fac,max_solve,max_mod,max_bar);
+ }
+ diag_printf("\n");
+ Global->starttime = start;
+ diag_printf(" TIMING INFORMATION\n");
+ diag_printf("Start time : %16d\n",
+ Global->starttime);
+ diag_printf("Initialization finish time : %16d\n",
+ Global->rs);
+ diag_printf("Overall finish time : %16d\n",
+ Global->rf);
+ diag_printf("Total time with initialization : %16d\n",
+ Global->rf-Global->starttime);
+ diag_printf("Total time without initialization : %16d\n",
+ Global->rf-Global->rs);
+ diag_printf("\n");
+
+ if (test_result) {
+ diag_printf(" TESTING RESULTS\n");
+ CheckResult(n, a, rhs);
+ }
+
+ MAIN_END;
+}
+
+void SlaveStart()
+
+{
+ int i;
+ int j;
+ int cluster;
+ int max_block;
+ int MyNum;
+
+ LOCK(Global->idlock)
+ MyNum = Global->id;
+ Global->id ++;
+ UNLOCK(Global->idlock)
+
+/* POSSIBLE ENHANCEMENT: Here is where one might pin processes to
+ processors to avoid migration */
+
+ diag_printf("Slave start\n");
+
+ OneSolve(n, block_size, a, MyNum, dostats);
+
+ thread_array[MyNum] = 0;
+
+}
+
+
+void OneSolve(n, block_size, a, MyNum, dostats)
+
+double *a;
+int n;
+int block_size;
+int MyNum;
+int dostats;
+
+{
+ unsigned int i;
+ unsigned int myrs;
+ unsigned int myrf;
+ unsigned int mydone;
+ struct LocalCopies *lc;
+
+ lc = (struct LocalCopies *) malloc(sizeof(struct LocalCopies));
+ if (lc == NULL) {
+ diag_printf("Proc %d could not malloc memory for lc\n",MyNum);
+ exit(-1);
+ }
+ lc->t_in_fac = 0.0;
+ lc->t_in_solve = 0.0;
+ lc->t_in_mod = 0.0;
+ lc->t_in_bar = 0.0;
+
+ /* barrier to ensure all initialization is done */
+ BARRIER(Global->start, P, 1);
+
+ /* to remove cold-start misses, all processors begin by touching a[] */
+ TouchA(block_size, MyNum);
+
+ BARRIER(Global->start, P, 2);
+
+/* POSSIBLE ENHANCEMENT: Here is where one might reset the
+ statistics that one is measuring about the parallel execution */
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(myrs);
+ }
+
+ diag_printf("Start calc\n");
+ lu(n, block_size, MyNum, lc, dostats);
+ diag_printf("End calc\n");
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(mydone);
+ }
+
+ BARRIER(Global->start, P, 3);
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(myrf);
+ Global->t_in_fac[MyNum] = lc->t_in_fac;
+ Global->t_in_solve[MyNum] = lc->t_in_solve;
+ Global->t_in_mod[MyNum] = lc->t_in_mod;
+ Global->t_in_bar[MyNum] = lc->t_in_bar;
+ Global->completion[MyNum] = mydone-myrs;
+ }
+ if (MyNum == 0) {
+ Global->rs = myrs;
+ Global->done = mydone;
+ Global->rf = myrf;
+ }
+}
+
+
+void lu0(a, n, stride)
+
+double *a;
+int n;
+int stride;
+
+{
+ int j;
+ int k;
+ int length;
+ double alpha;
+
+ for (k=0; k<n; k++) {
+ /* modify subsequent columns */
+ for (j=k+1; j<n; j++) {
+ a[k+j*stride] /= a[k+k*stride];
+ alpha = -a[k+j*stride];
+ length = n-k-1;
+ daxpy(&a[k+1+j*stride], &a[k+1+k*stride], n-k-1, alpha);
+ }
+ }
+}
+
+
+void bdiv(a, diag, stride_a, stride_diag, dimi, dimk)
+
+double *a;
+double *diag;
+int stride_a;
+int stride_diag;
+int dimi;
+int dimk;
+
+{
+ int j;
+ int k;
+ double alpha;
+
+ for (k=0; k<dimk; k++) {
+ for (j=k+1; j<dimk; j++) {
+ alpha = -diag[k+j*stride_diag];
+ daxpy(&a[j*stride_a], &a[k*stride_a], dimi, alpha);
+ }
+ }
+}
+
+
+void bmodd(a, c, dimi, dimj, stride_a, stride_c)
+
+double *a;
+double *c;
+int dimi;
+int dimj;
+int stride_a;
+int stride_c;
+
+{
+ int i;
+ int j;
+ int k;
+ int length;
+ double alpha;
+
+ for (k=0; k<dimi; k++)
+ for (j=0; j<dimj; j++) {
+ c[k+j*stride_c] /= a[k+k*stride_a];
+ alpha = -c[k+j*stride_c];
+ length = dimi - k - 1;
+ daxpy(&c[k+1+j*stride_c], &a[k+1+k*stride_a], dimi-k-1, alpha);
+ }
+}
+
+
+void bmod(a, b, c, dimi, dimj, dimk, stride)
+
+double *a;
+double *b;
+double *c;
+int dimi;
+int dimj;
+int dimk;
+int stride;
+
+{
+ int i;
+ int j;
+ int k;
+ double alpha;
+
+ for (k=0; k<dimk; k++) {
+ for (j=0; j<dimj; j++) {
+ alpha = -b[k+j*stride];
+ daxpy(&c[j*stride], &a[k*stride], dimi, alpha);
+ }
+ }
+}
+
+
+void daxpy(a, b, n, alpha)
+
+double *a;
+double *b;
+double alpha;
+int n;
+
+{
+ int i;
+
+ for (i=0; i<n; i++) {
+ a[i] += alpha*b[i];
+ }
+}
+
+
+int BlockOwner(I, J)
+
+int I;
+int J;
+
+{
+ return((I%num_cols) + (J%num_rows)*num_cols);
+}
+
+
+void lu(n, bs, MyNum, lc, dostats)
+
+int n;
+int bs;
+int MyNum;
+struct LocalCopies *lc;
+int dostats;
+
+{
+ int i, il, j, jl, k, kl;
+ int I, J, K;
+ double *A, *B, *C, *D;
+ int dimI, dimJ, dimK;
+ int strI;
+ unsigned int t1, t2, t3, t4, t11, t22;
+ int diagowner;
+ int colowner;
+
+ strI = n;
+ for (k=0, K=0; k<n; k+=bs, K++) {
+ kl = k+bs;
+ if (kl>n) {
+ kl = n;
+ }
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(t1);
+ }
+
+ /* factor diagonal block */
+ diagowner = BlockOwner(K, K);
+ if (diagowner == MyNum) {
+ A = &(a[k+k*n]);
+ lu0(A, kl-k, strI);
+ }
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(t11);
+ }
+
+ BARRIER(Global->start, P, 4);
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(t2);
+ }
+
+ /* divide column k by diagonal block */
+ D = &(a[k+k*n]);
+ for (i=kl, I=K+1; i<n; i+=bs, I++) {
+ if (BlockOwner(I, K) == MyNum) { /* parcel out blocks */
+ il = i + bs;
+ if (il > n) {
+ il = n;
+ }
+ A = &(a[i+k*n]);
+ bdiv(A, D, strI, n, il-i, kl-k);
+ }
+ }
+ /* modify row k by diagonal block */
+ for (j=kl, J=K+1; j<n; j+=bs, J++) {
+ if (BlockOwner(K, J) == MyNum) { /* parcel out blocks */
+ jl = j+bs;
+ if (jl > n) {
+ jl = n;
+ }
+ A = &(a[k+j*n]);
+ bmodd(D, A, kl-k, jl-j, n, strI);
+ }
+ }
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(t22);
+ }
+
+ BARRIER(Global->start, P, 5);
+
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(t3);
+ }
+
+ /* modify subsequent block columns */
+ for (i=kl, I=K+1; i<n; i+=bs, I++) {
+ il = i+bs;
+ if (il > n) {
+ il = n;
+ }
+ colowner = BlockOwner(I,K);
+ A = &(a[i+k*n]);
+ for (j=kl, J=K+1; j<n; j+=bs, J++) {
+ jl = j + bs;
+ if (jl > n) {
+ jl = n;
+ }
+ if (BlockOwner(I, J) == MyNum) { /* parcel out blocks */
+ B = &(a[k+j*n]);
+ C = &(a[i+j*n]);
+ bmod(A, B, C, il-i, jl-j, kl-k, n);
+ }
+ }
+ }
+ if ((MyNum == 0) || (dostats)) {
+ CLOCK(t4);
+ lc->t_in_fac += (t11-t1);
+ lc->t_in_solve += (t22-t2);
+ lc->t_in_mod += (t4-t3);
+ lc->t_in_bar += (t2-t11) + (t3-t22);
+ }
+ }
+}
+
+
+void InitA(rhs)
+
+double *rhs;
+
+{
+ int i, j;
+
+ srand(1);
+ for (j=0; j<n; j++) {
+ for (i=0; i<n; i++) {
+ a[i+j*n] = (double) rand()/MAXRAND;
+ if (i == j) {
+ a[i+j*n] *= 10;
+ }
+ }
+ }
+
+ for (j=0; j<n; j++) {
+ rhs[j] = 0.0;
+ }
+ for (j=0; j<n; j++) {
+ for (i=0; i<n; i++) {
+ rhs[i] += a[i+j*n];
+ }
+ }
+}
+
+
+double TouchA(bs, MyNum)
+
+int bs;
+int MyNum;
+
+{
+ int i, j, I, J;
+ double tot = 0.0;
+
+ for (J=0; J*bs<n; J++) {
+ for (I=0; I*bs<n; I++) {
+ if (BlockOwner(I, J) == MyNum) {
+ for (j=J*bs; j<(J+1)*bs && j<n; j++) {
+ for (i=I*bs; i<(I+1)*bs && i<n; i++) {
+ tot += a[i+j*n];
+ }
+ }
+ }
+ }
+ }
+ return(tot);
+}
+
+
+void PrintA()
+{
+ int i, j;
+
+ for (i=0; i<n; i++) {
+ for (j=0; j<n; j++) {
+ diag_printf("%8.1f ", a[i+j*n]);
+ }
+ diag_printf("\n");
+ }
+}
+
+
+void CheckResult(n, a, rhs)
+
+int n;
+double *a;
+double *rhs;
+
+{
+ int i, j, bogus = 0;
+ double *y, diff, max_diff;
+
+ y = (double *) malloc(n*sizeof(double));
+ if (y == NULL) {
+ printerr("Could not malloc memory for y\n");
+ exit(-1);
+ }
+ for (j=0; j<n; j++) {
+ y[j] = rhs[j];
+ }
+ for (j=0; j<n; j++) {
+ y[j] = y[j]/a[j+j*n];
+ for (i=j+1; i<n; i++) {
+ y[i] -= a[i+j*n]*y[j];
+ }
+ }
+
+ for (j=n-1; j>=0; j--) {
+ for (i=0; i<j; i++) {
+ y[i] -= a[i+j*n]*y[j];
+ }
+ }
+
+ max_diff = 0.0;
+ for (j=0; j<n; j++) {
+ diff = y[j] - 1.0;
+ if (fabs(diff) > 0.00001) {
+ bogus = 1;
+ max_diff = diff;
+ }
+ }
+ if (bogus) {
+ diag_printf("TEST FAILED: (%.5f diff)\n", max_diff);
+ } else {
+ diag_printf("TEST PASSED\n");
+ }
+ free(y);
+}
+
+
+void printerr(s)
+
+char *s;
+
+{
+ diag_printf("ERROR: %s\n",s);
+}
+
+
+#include <tests_smp/getopt.c>
diff --git a/ecos/packages/kernel/current/tests_smp/lu.c b/ecos/packages/kernel/current/tests_smp/lu.c
new file mode 100644
index 0000000000..9527c41ab3
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/lu.c
@@ -0,0 +1,1118 @@
+
+
+
+
+
+
+
+
+
+
+
+/*************************************************************************/
+/* */
+/* Copyright (c) 1994 Stanford University */
+/* */
+/* All rights reserved. */
+/* */
+/* Permission is given to use, copy, and modify this software for any */
+/* non-commercial purpose as long as this copyright notice is not */
+/* removed. All other uses, including redistribution in whole or in */
+/* part, are forbidden without prior written permission. */
+/* */
+/* This software is provided with absolutely no warranty and no */
+/* support. */
+/* */
+/*************************************************************************/
+
+/*************************************************************************/
+/* */
+/* Parallel dense blocked LU factorization (no pivoting) */
+/* */
+/* This version contains one dimensional arrays in which the matrix */
+/* to be factored is stored. */
+/* */
+/* Command line options: */
+/* */
+/* -nN : Decompose NxN matrix. */
+/* -pP : P = number of processors. */
+/* -bB : Use a block size of B. BxB elements should fit in cache for */
+/* good performance. Small block sizes (B=8, B=16) work well. */
+/* -s : Print individual processor timing statistics. */
+/* -t : Test output. */
+/* -o : Print out matrix values. */
+/* -h : Print out command line options. */
+/* */
+/* Note: This version works under both the FORK and SPROC models */
+/* */
+/*************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <tests_smp/getopt.h>
+
+#include <tests_smp/lu_arg.c>
+
+
+/*---------------------------------------*/
+#include <pkgconf/system.h>
+#include <pkgconf/infra.h>
+#include <pkgconf/kernel.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/testcase.h>
+#include <pkgconf/isoinfra.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_smp.h>
+#include <cyg/kernel/kapi.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+int smp_cyg_test_main(int argc, char **argv);
+
+void smp_cyg_test_main_call(void *p) {
+ smp_cyg_test_main(smp_cyg_test_argc, smp_cyg_test_argv);
+}
+
+
+/* #define STACK_SIZE 0x1b000 */
+#define STACK_SIZE 8192
+static cyg_thread smp_cyg_test_thread;
+static char smp_cyg_test_stack[STACK_SIZE];
+static cyg_handle_t smp_cyg_test_threadh;
+
+
+
+cyg_handle_t threadh[64];
+char *stack[64];
+cyg_thread thread[64];
+
+
+externC void cyg_user_start( void )
+{
+ CYG_TEST_INIT();
+
+ diag_printf("Starting test app\n");
+
+ cyg_thread_create(10, // Priority - just a number
+ smp_cyg_test_main_call, // entry
+ 0, // index
+ "smp test", // Name
+ smp_cyg_test_stack, // Stack
+ STACK_SIZE, // Size
+ &smp_cyg_test_threadh, // Handle
+ &smp_cyg_test_thread // Thread data structure
+ );
+ cyg_thread_resume( smp_cyg_test_threadh );
+ /*cyg_scheduler_start();*/
+}
+
+
+/*---------------------------------------*/
+
+
+#define MAXRAND 2147483647
+#define DEFAULT_N 128
+#define DEFAULT_P 1
+#define DEFAULT_B 16
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+struct GlobalMemory {
+ double *t_in_fac;
+ double *t_in_solve;
+ double *t_in_mod;
+ double *t_in_bar;
+ double *completion;
+ unsigned int starttime;
+ unsigned int rf;
+ unsigned int rs;
+ unsigned int done;
+ int id;
+
+/*---------------------------------------*/
+struct startTYP {
+ cyg_spinlock_t lock;;
+ int count[1];
+ cyg_sem_t queue[1];;
+
+ } start[1];
+/*---------------------------------------*/
+
+
+ cyg_spinlock_t idlock;
+} *Global;
+
+struct LocalCopies {
+ double t_in_fac;
+ double t_in_solve;
+ double t_in_mod;
+ double t_in_bar;
+};
+
+int dbg_on = 0;
+int n = DEFAULT_N; /* The size of the matrix */
+int P = DEFAULT_P; /* Number of processors */
+int block_size = DEFAULT_B; /* Block dimension */
+int nblocks; /* Number of blocks in each dimension */
+int num_rows; /* Number of processors per row of processor grid */
+int num_cols; /* Number of processors per col of processor grid */
+double *a; /* a = lu; l and u both placed back in a */
+double *rhs;
+int *proc_bytes; /* Bytes to malloc per processor to hold blocks
+ of A*/
+int test_result = 0; /* Test result of factorization? */
+int doprint = 0; /* Print out matrix values? */
+int dostats = 0; /* Print out individual processor statistics? */
+
+void SlaveStart();
+void OneSolve(int, int, double *, int, int);
+void lu0(double *,int, int);
+void bdiv(double *, double *, int, int, int, int);
+void bmodd(double *, double*, int, int, int, int);
+void bmod(double *, double *, double *, int, int, int, int);
+void daxpy(double *, double *, int, double);
+int BlockOwner(int, int);
+void lu(int, int, int, struct LocalCopies *, int);
+void InitA(double *);
+double TouchA(int, int);
+void PrintA();
+void CheckResult(int, double *, double *);
+void printerr(char *);
+volatile cyg_thread *thread_array[64];
+
+
+int smp_cyg_test_main(argc, argv)
+
+int argc;
+char **argv;
+
+{
+ int i, j;
+ int ch;
+ extern char *optarg;
+ int MyNum=0;
+ double mint, maxt, avgt;
+ double min_fac, min_solve, min_mod, min_bar;
+ double max_fac, max_solve, max_mod, max_bar;
+ double avg_fac, avg_solve, avg_mod, avg_bar;
+ int proc_num;
+ unsigned int start;
+
+ memset (thread_array,0,sizeof(thread_array));
+
+ {
+ (start) = cyg_current_time()*10;
+}
+;
+
+ while ((ch = getopt(argc, argv, "n:p:b:cstoh")) != -1) {
+ switch(ch) {
+ case 'n': n = atoi(optarg); break;
+ case 'p': P = atoi(optarg);
+ P = HAL_SMP_CPU_MAX; break;
+ case 'b': block_size = atoi(optarg); break;
+ case 's': dostats = 1; break;
+ case 't': test_result = !test_result; break;
+ case 'o': doprint = !doprint; break;
+ case 'h': diag_printf("Usage: LU <options>\n\n");
+ diag_printf("options:\n");
+ diag_printf(" -nN : Decompose NxN matrix.\n");
+ diag_printf(" -pP : P = number of processors.\n");
+ diag_printf(" -bB : Use a block size of B. BxB elements should fit in cache for \n");
+ diag_printf(" good performance. Small block sizes (B=8, B=16) work well.\n");
+ diag_printf(" -c : Copy non-locally allocated blocks to local memory before use.\n");
+ diag_printf(" -s : Print individual processor timing statistics.\n");
+ diag_printf(" -t : Test output.\n");
+ diag_printf(" -o : Print out matrix values.\n");
+ diag_printf(" -h : Print out command line options.\n\n");
+ diag_printf("Default: LU -n%1d -p%1d -b%1d\n",
+ DEFAULT_N,DEFAULT_P,DEFAULT_B);
+ exit(0);
+ break;
+ }
+ }
+ if (P > 64) {
+ printf("Maximal 64 processes\n");
+ exit(0);
+ }
+
+ {;}
+
+ diag_printf("\n");
+ diag_printf("Blocked Dense LU Factorization\n");
+ diag_printf(" %d by %d Matrix\n",n,n);
+ diag_printf(" %d Processors\n",P);
+ diag_printf(" %d by %d Element Blocks\n",block_size,block_size);
+ diag_printf("\n");
+ diag_printf("\n");
+
+ num_rows = (int) sqrt((double) P);
+ for (;;) {
+ num_cols = P/num_rows;
+ if (num_rows*num_cols == P)
+ break;
+ num_rows--;
+ }
+ nblocks = n/block_size;
+ if (block_size * nblocks != n) {
+ nblocks++;
+ }
+
+ a = (double *) calloc(n*n*sizeof(double), 1);;
+ rhs = (double *) calloc(n*sizeof(double), 1);;
+
+ Global = (struct GlobalMemory *) calloc(sizeof(struct GlobalMemory), 1);;
+ Global->t_in_fac = (double *) calloc(P*sizeof(double), 1);;
+ Global->t_in_mod = (double *) calloc(P*sizeof(double), 1);;
+ Global->t_in_solve = (double *) calloc(P*sizeof(double), 1);;
+ Global->t_in_bar = (double *) calloc(P*sizeof(double), 1);;
+ Global->completion = (double *) calloc(P*sizeof(double), 1);;
+
+ if (Global == NULL) {
+ printerr("Could not malloc memory for Global\n");
+ exit(-1);
+ } else if (Global->t_in_fac == NULL) {
+ printerr("Could not malloc memory for Global->t_in_fac\n");
+ exit(-1);
+ } else if (Global->t_in_mod == NULL) {
+ printerr("Could not malloc memory for Global->t_in_mod\n");
+ exit(-1);
+ } else if (Global->t_in_solve == NULL) {
+ printerr("Could not malloc memory for Global->t_in_solve\n");
+ exit(-1);
+ } else if (Global->t_in_bar == NULL) {
+ printerr("Could not malloc memory for Global->t_in_bar\n");
+ exit(-1);
+ } else if (Global->completion == NULL) {
+ printerr("Could not malloc memory for Global->completion\n");
+ exit(-1);
+ }
+
+/* POSSIBLE ENHANCEMENT: Here is where one might distribute the a
+ matrix data across physically distributed memories in a
+ round-robin fashion as desired. */
+
+ {{
+/*---------------------------------------*/
+ int mon_dum1,mon_dum2;
+ for (mon_dum1=0; mon_dum1 < 1; mon_dum1++)
+ for (mon_dum2=0; mon_dum2 < 1; mon_dum2++) {
+ Global->start[mon_dum1].count[mon_dum2] = 0;
+ { cyg_semaphore_init(&Global->start[mon_dum1].queue[mon_dum2],0);};
+ }
+ for (mon_dum1=0; mon_dum1 < 1; mon_dum1++) {
+ cyg_spinlock_init( &Global->start[mon_dum1].lock,0 );;
+ }
+/*---------------------------------------*/
+}};
+ cyg_spinlock_init( &Global->idlock,0 );;
+ Global->id = 0;
+
+ for (i=1; i<P; i++) {
+
+{
+ /*---------------------------------------*/
+ stack[i] = calloc(STACK_SIZE, 1);
+ cyg_thread_create(10, // Priority - just a number
+ SlaveStart, // entry
+ 0, // index
+ "slave", // Name
+ stack[i], // Stack
+ STACK_SIZE, // Size
+ &threadh[i], // Handle
+ &thread[i] // Thread data structure
+ );
+ cyg_thread_resume( threadh[i] );
+ /*---------------------------------------*/
+}
+
+ }
+
+ InitA(rhs);
+ if (doprint) {
+ diag_printf("Matrix before decomposition:\n");
+ PrintA();
+ }
+
+
+ SlaveStart(MyNum);
+
+ for (i=1; i<P; i++) {
+ while(thread_array[i]) {};
+ }
+
+ if (doprint) {
+ diag_printf("\nMatrix after decomposition:\n");
+ PrintA();
+ }
+
+ if (dostats) {
+ maxt = avgt = mint = Global->completion[0];
+ for (i=1; i<P; i++) {
+ if (Global->completion[i] > maxt) {
+ maxt = Global->completion[i];
+ }
+ if (Global->completion[i] < mint) {
+ mint = Global->completion[i];
+ }
+ avgt += Global->completion[i];
+ }
+ avgt = avgt / P;
+
+ min_fac = max_fac = avg_fac = Global->t_in_fac[0];
+ min_solve = max_solve = avg_solve = Global->t_in_solve[0];
+ min_mod = max_mod = avg_mod = Global->t_in_mod[0];
+ min_bar = max_bar = avg_bar = Global->t_in_bar[0];
+
+ for (i=1; i<P; i++) {
+ if (Global->t_in_fac[i] > max_fac) {
+ max_fac = Global->t_in_fac[i];
+ }
+ if (Global->t_in_fac[i] < min_fac) {
+ min_fac = Global->t_in_fac[i];
+ }
+ if (Global->t_in_solve[i] > max_solve) {
+ max_solve = Global->t_in_solve[i];
+ }
+ if (Global->t_in_solve[i] < min_solve) {
+ min_solve = Global->t_in_solve[i];
+ }
+ if (Global->t_in_mod[i] > max_mod) {
+ max_mod = Global->t_in_mod[i];
+ }
+ if (Global->t_in_mod[i] < min_mod) {
+ min_mod = Global->t_in_mod[i];
+ }
+ if (Global->t_in_bar[i] > max_bar) {
+ max_bar = Global->t_in_bar[i];
+ }
+ if (Global->t_in_bar[i] < min_bar) {
+ min_bar = Global->t_in_bar[i];
+ }
+ avg_fac += Global->t_in_fac[i];
+ avg_solve += Global->t_in_solve[i];
+ avg_mod += Global->t_in_mod[i];
+ avg_bar += Global->t_in_bar[i];
+ }
+ avg_fac = avg_fac/P;
+ avg_solve = avg_solve/P;
+ avg_mod = avg_mod/P;
+ avg_bar = avg_bar/P;
+ }
+ diag_printf(" PROCESS STATISTICS\n");
+ diag_printf(" Total Diagonal Perimeter Interior Barrier\n");
+ diag_printf(" Proc Time Time Time Time Time\n");
+ diag_printf(" 0 %10.0f %10.0f %10.0f %10.0f %10.0f\n",
+ Global->completion[0],Global->t_in_fac[0],
+ Global->t_in_solve[0],Global->t_in_mod[0],
+ Global->t_in_bar[0]);
+ if (dostats) {
+ for (i=1; i<P; i++) {
+ diag_printf(" %3d %10.0f %10.0f %10.0f %10.0f %10.0f\n",
+ i,Global->completion[i],Global->t_in_fac[i],
+ Global->t_in_solve[i],Global->t_in_mod[i],
+ Global->t_in_bar[i]);
+ }
+ diag_printf(" Avg %10.0f %10.0f %10.0f %10.0f %10.0f\n",
+ avgt,avg_fac,avg_solve,avg_mod,avg_bar);
+ diag_printf(" Min %10.0f %10.0f %10.0f %10.0f %10.0f\n",
+ mint,min_fac,min_solve,min_mod,min_bar);
+ diag_printf(" Max %10.0f %10.0f %10.0f %10.0f %10.0f\n",
+ maxt,max_fac,max_solve,max_mod,max_bar);
+ }
+ diag_printf("\n");
+ Global->starttime = start;
+ diag_printf(" TIMING INFORMATION\n");
+ diag_printf("Start time : %16d\n",
+ Global->starttime);
+ diag_printf("Initialization finish time : %16d\n",
+ Global->rs);
+ diag_printf("Overall finish time : %16d\n",
+ Global->rf);
+ diag_printf("Total time with initialization : %16d\n",
+ Global->rf-Global->starttime);
+ diag_printf("Total time without initialization : %16d\n",
+ Global->rf-Global->rs);
+ diag_printf("\n");
+
+ if (test_result) {
+ diag_printf(" TESTING RESULTS\n");
+ CheckResult(n, a, rhs);
+ }
+
+
+{
+ diag_printf("FP test end\n");
+ return 0;
+}
+;
+}
+
+void SlaveStart()
+
+{
+ int i;
+ int j;
+ int cluster;
+ int max_block;
+ int MyNum;
+
+ cyg_spinlock_spin(&Global->idlock);
+ MyNum = Global->id;
+ Global->id ++;
+ cyg_spinlock_clear(&Global->idlock);
+
+/* POSSIBLE ENHANCEMENT: Here is where one might pin processes to
+ processors to avoid migration */
+
+ diag_printf("Slave start\n");
+
+ OneSolve(n, block_size, a, MyNum, dostats);
+
+ thread_array[MyNum] = 0;
+
+}
+
+
+void OneSolve(n, block_size, a, MyNum, dostats)
+
+double *a;
+int n;
+int block_size;
+int MyNum;
+int dostats;
+
+{
+ unsigned int i;
+ unsigned int myrs;
+ unsigned int myrf;
+ unsigned int mydone;
+ struct LocalCopies *lc;
+
+ lc = (struct LocalCopies *) malloc(sizeof(struct LocalCopies));
+ if (lc == NULL) {
+ diag_printf("Proc %d could not malloc memory for lc\n",MyNum);
+ exit(-1);
+ }
+ lc->t_in_fac = 0.0;
+ lc->t_in_solve = 0.0;
+ lc->t_in_mod = 0.0;
+ lc->t_in_bar = 0.0;
+
+ /* barrier to ensure all initialization is done */
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+
+ /* to remove cold-start misses, all processors begin by touching a[] */
+ TouchA(block_size, MyNum);
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+
+/* POSSIBLE ENHANCEMENT: Here is where one might reset the
+ statistics that one is measuring about the parallel execution */
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (myrs) = cyg_current_time()*10;
+}
+;
+ }
+
+ diag_printf("Start calc\n");
+ lu(n, block_size, MyNum, lc, dostats);
+ diag_printf("End calc\n");
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (mydone) = cyg_current_time()*10;
+}
+;
+ }
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (myrf) = cyg_current_time()*10;
+}
+;
+ Global->t_in_fac[MyNum] = lc->t_in_fac;
+ Global->t_in_solve[MyNum] = lc->t_in_solve;
+ Global->t_in_mod[MyNum] = lc->t_in_mod;
+ Global->t_in_bar[MyNum] = lc->t_in_bar;
+ Global->completion[MyNum] = mydone-myrs;
+ }
+ if (MyNum == 0) {
+ Global->rs = myrs;
+ Global->done = mydone;
+ Global->rf = myrf;
+ }
+}
+
+
+void lu0(a, n, stride)
+
+double *a;
+int n;
+int stride;
+
+{
+ int j;
+ int k;
+ int length;
+ double alpha;
+
+ for (k=0; k<n; k++) {
+ /* modify subsequent columns */
+ for (j=k+1; j<n; j++) {
+ a[k+j*stride] /= a[k+k*stride];
+ alpha = -a[k+j*stride];
+ length = n-k-1;
+ daxpy(&a[k+1+j*stride], &a[k+1+k*stride], n-k-1, alpha);
+ }
+ }
+}
+
+
+void bdiv(a, diag, stride_a, stride_diag, dimi, dimk)
+
+double *a;
+double *diag;
+int stride_a;
+int stride_diag;
+int dimi;
+int dimk;
+
+{
+ int j;
+ int k;
+ double alpha;
+
+ for (k=0; k<dimk; k++) {
+ for (j=k+1; j<dimk; j++) {
+ alpha = -diag[k+j*stride_diag];
+ daxpy(&a[j*stride_a], &a[k*stride_a], dimi, alpha);
+ }
+ }
+}
+
+
+void bmodd(a, c, dimi, dimj, stride_a, stride_c)
+
+double *a;
+double *c;
+int dimi;
+int dimj;
+int stride_a;
+int stride_c;
+
+{
+ int i;
+ int j;
+ int k;
+ int length;
+ double alpha;
+
+ for (k=0; k<dimi; k++)
+ for (j=0; j<dimj; j++) {
+ c[k+j*stride_c] /= a[k+k*stride_a];
+ alpha = -c[k+j*stride_c];
+ length = dimi - k - 1;
+ daxpy(&c[k+1+j*stride_c], &a[k+1+k*stride_a], dimi-k-1, alpha);
+ }
+}
+
+
+void bmod(a, b, c, dimi, dimj, dimk, stride)
+
+double *a;
+double *b;
+double *c;
+int dimi;
+int dimj;
+int dimk;
+int stride;
+
+{
+ int i;
+ int j;
+ int k;
+ double alpha;
+
+ for (k=0; k<dimk; k++) {
+ for (j=0; j<dimj; j++) {
+ alpha = -b[k+j*stride];
+ daxpy(&c[j*stride], &a[k*stride], dimi, alpha);
+ }
+ }
+}
+
+
+void daxpy(a, b, n, alpha)
+
+double *a;
+double *b;
+double alpha;
+int n;
+
+{
+ int i;
+
+ for (i=0; i<n; i++) {
+ a[i] += alpha*b[i];
+ }
+}
+
+
+int BlockOwner(I, J)
+
+int I;
+int J;
+
+{
+ return((I%num_cols) + (J%num_rows)*num_cols);
+}
+
+
+void lu(n, bs, MyNum, lc, dostats)
+
+int n;
+int bs;
+int MyNum;
+struct LocalCopies *lc;
+int dostats;
+
+{
+ int i, il, j, jl, k, kl;
+ int I, J, K;
+ double *A, *B, *C, *D;
+ int dimI, dimJ, dimK;
+ int strI;
+ unsigned int t1, t2, t3, t4, t11, t22;
+ int diagowner;
+ int colowner;
+
+ strI = n;
+ for (k=0, K=0; k<n; k+=bs, K++) {
+ kl = k+bs;
+ if (kl>n) {
+ kl = n;
+ }
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (t1) = cyg_current_time()*10;
+}
+;
+ }
+
+ /* factor diagonal block */
+ diagowner = BlockOwner(K, K);
+ if (diagowner == MyNum) {
+ A = &(a[k+k*n]);
+ lu0(A, kl-k, strI);
+ }
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (t11) = cyg_current_time()*10;
+}
+;
+ }
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (t2) = cyg_current_time()*10;
+}
+;
+ }
+
+ /* divide column k by diagonal block */
+ D = &(a[k+k*n]);
+ for (i=kl, I=K+1; i<n; i+=bs, I++) {
+ if (BlockOwner(I, K) == MyNum) { /* parcel out blocks */
+ il = i + bs;
+ if (il > n) {
+ il = n;
+ }
+ A = &(a[i+k*n]);
+ bdiv(A, D, strI, n, il-i, kl-k);
+ }
+ }
+ /* modify row k by diagonal block */
+ for (j=kl, J=K+1; j<n; j+=bs, J++) {
+ if (BlockOwner(K, J) == MyNum) { /* parcel out blocks */
+ jl = j+bs;
+ if (jl > n) {
+ jl = n;
+ }
+ A = &(a[k+j*n]);
+ bmodd(D, A, kl-k, jl-j, n, strI);
+ }
+ }
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (t22) = cyg_current_time()*10;
+}
+;
+ }
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( Global->start[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] < (P -1) ) {
+ Global->start[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&Global->start[0].lock );;
+ { cyg_semaphore_wait(&Global->start[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ if ( Global->start[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&Global->start[0].lock );;
+
+ } else {
+ ( Global->start[0].count[0] )-- ;
+ //cyg_spinlock_clear(&Global->start[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,Global->start[0].count[0],Global->start[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&Global->start[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (t3) = cyg_current_time()*10;
+}
+;
+ }
+
+ /* modify subsequent block columns */
+ for (i=kl, I=K+1; i<n; i+=bs, I++) {
+ il = i+bs;
+ if (il > n) {
+ il = n;
+ }
+ colowner = BlockOwner(I,K);
+ A = &(a[i+k*n]);
+ for (j=kl, J=K+1; j<n; j+=bs, J++) {
+ jl = j + bs;
+ if (jl > n) {
+ jl = n;
+ }
+ if (BlockOwner(I, J) == MyNum) { /* parcel out blocks */
+ B = &(a[k+j*n]);
+ C = &(a[i+j*n]);
+ bmod(A, B, C, il-i, jl-j, kl-k, n);
+ }
+ }
+ }
+ if ((MyNum == 0) || (dostats)) {
+ {
+ (t4) = cyg_current_time()*10;
+}
+;
+ lc->t_in_fac += (t11-t1);
+ lc->t_in_solve += (t22-t2);
+ lc->t_in_mod += (t4-t3);
+ lc->t_in_bar += (t2-t11) + (t3-t22);
+ }
+ }
+}
+
+
+void InitA(rhs)
+
+double *rhs;
+
+{
+ int i, j;
+
+ srand(1);
+ for (j=0; j<n; j++) {
+ for (i=0; i<n; i++) {
+ a[i+j*n] = (double) rand()/MAXRAND;
+ if (i == j) {
+ a[i+j*n] *= 10;
+ }
+ }
+ }
+
+ for (j=0; j<n; j++) {
+ rhs[j] = 0.0;
+ }
+ for (j=0; j<n; j++) {
+ for (i=0; i<n; i++) {
+ rhs[i] += a[i+j*n];
+ }
+ }
+}
+
+
+double TouchA(bs, MyNum)
+
+int bs;
+int MyNum;
+
+{
+ int i, j, I, J;
+ double tot = 0.0;
+
+ for (J=0; J*bs<n; J++) {
+ for (I=0; I*bs<n; I++) {
+ if (BlockOwner(I, J) == MyNum) {
+ for (j=J*bs; j<(J+1)*bs && j<n; j++) {
+ for (i=I*bs; i<(I+1)*bs && i<n; i++) {
+ tot += a[i+j*n];
+ }
+ }
+ }
+ }
+ }
+ return(tot);
+}
+
+
+void PrintA()
+{
+ int i, j;
+
+ for (i=0; i<n; i++) {
+ for (j=0; j<n; j++) {
+ diag_printf("%8.1f ", a[i+j*n]);
+ }
+ diag_printf("\n");
+ }
+}
+
+
+void CheckResult(n, a, rhs)
+
+int n;
+double *a;
+double *rhs;
+
+{
+ int i, j, bogus = 0;
+ double *y, diff, max_diff;
+
+ y = (double *) malloc(n*sizeof(double));
+ if (y == NULL) {
+ printerr("Could not malloc memory for y\n");
+ exit(-1);
+ }
+ for (j=0; j<n; j++) {
+ y[j] = rhs[j];
+ }
+ for (j=0; j<n; j++) {
+ y[j] = y[j]/a[j+j*n];
+ for (i=j+1; i<n; i++) {
+ y[i] -= a[i+j*n]*y[j];
+ }
+ }
+
+ for (j=n-1; j>=0; j--) {
+ for (i=0; i<j; i++) {
+ y[i] -= a[i+j*n]*y[j];
+ }
+ }
+
+ max_diff = 0.0;
+ for (j=0; j<n; j++) {
+ diff = y[j] - 1.0;
+ if (fabs(diff) > 0.00001) {
+ bogus = 1;
+ max_diff = diff;
+ }
+ }
+ if (bogus) {
+ diag_printf("TEST FAILED: (%.5f diff)\n", max_diff);
+ } else {
+ diag_printf("TEST PASSED\n");
+ }
+ free(y);
+}
+
+
+void printerr(s)
+
+char *s;
+
+{
+ diag_printf("ERROR: %s\n",s);
+}
+
+
+#include <tests_smp/getopt.c>
diff --git a/ecos/packages/kernel/current/tests_smp/lu_arg.c b/ecos/packages/kernel/current/tests_smp/lu_arg.c
new file mode 100644
index 0000000000..fb02575185
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/lu_arg.c
@@ -0,0 +1,12 @@
+//___________________________________________
+#define _str_HAL_SMP_CPU_MAX(x) #x
+#define smp_cyg_test_argc 5
+char *_cyg_argv[] = {
+ "fft.exe",
+ "-p",
+ "2", /* not used, using HAL_SMP_CPU_MAX */
+ "-n",
+ "64"
+};
+#define smp_cyg_test_argv &_cyg_argv
+//'''''''''''''''''''''''''''''''''''''''''''
diff --git a/ecos/packages/kernel/current/tests_smp/makefile b/ecos/packages/kernel/current/tests_smp/makefile
new file mode 100644
index 0000000000..2c6df8b3d8
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/makefile
@@ -0,0 +1,13 @@
+MACROS = c.m4.ecos
+
+all: fft.c radix.c lu.c
+
+fft.c: fft.C $(MACROS)
+ m4 $(MACROS) fft.C > fft.c
+
+radix.c: radix.C $(MACROS)
+ m4 $(MACROS) radix.C > radix.c
+
+lu.c: lu.C $(MACROS)
+ m4 $(MACROS) lu.C > lu.c
+
diff --git a/ecos/packages/kernel/current/tests_smp/radix.C b/ecos/packages/kernel/current/tests_smp/radix.C
new file mode 100644
index 0000000000..b23dd6d356
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/radix.C
@@ -0,0 +1,909 @@
+/*************************************************************************/
+/* */
+/* Copyright (c) 1994 Stanford University */
+/* */
+/* All rights reserved. */
+/* */
+/* Permission is given to use, copy, and modify this software for any */
+/* non-commercial purpose as long as this copyright notice is not */
+/* removed. All other uses, including redistribution in whole or in */
+/* part, are forbidden without prior written permission. */
+/* */
+/* This software is provided with absolutely no warranty and no */
+/* support. */
+/* */
+/*************************************************************************/
+
+/*************************************************************************/
+/* */
+/* Integer radix sort of non-negative integers. */
+/* */
+/* Command line options: */
+/* */
+/* -pP : P = number of processors. */
+/* -rR : R = radix for sorting. Must be power of 2. */
+/* -nN : N = number of keys to sort. */
+/* -mM : M = maximum key value. Integer keys k will be generated such */
+/* that 0 <= k <= M. */
+/* -s : Print individual processor timing statistics. */
+/* -t : Check to make sure all keys are sorted correctly. */
+/* -o : Print out sorted keys. */
+/* -h : Print out command line options. */
+/* */
+/* Default: RADIX -p1 -n262144 -r1024 -m524288 */
+/* */
+/* Note: This version works under both the FORK and SPROC models */
+/* */
+/*************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <tests_smp/getopt.h>
+
+#define DEFAULT_P 1
+#define DEFAULT_N 262144
+#define DEFAULT_R 1024
+#define DEFAULT_M 524288
+#define MAX_PROCESSORS 64
+#define RADIX_S 8388608.0e0
+#define RADIX 70368744177664.0e0
+#define SEED 314159265.0e0
+#define RATIO 1220703125.0e0
+#define PAGE_SIZE 4096
+#define PAGE_MASK (~(PAGE_SIZE-1))
+#define MAX_RADIX 4096
+
+#include <tests_smp/radix_arg.c>
+
+MAIN_ENV
+
+struct prefix_node {
+ int densities[MAX_RADIX];
+ int ranks[MAX_RADIX];
+ PAUSEDEC(done)
+ char pad[PAGE_SIZE];
+};
+
+struct global_memory {
+ int Index; /* process ID */
+ LOCKDEC(lock_Index) /* for fetch and add to get ID */
+ LOCKDEC(rank_lock) /* for fetch and add to get ID */
+ ALOCKDEC(section_lock,MAX_PROCESSORS) /* key locks */
+ BARDEC(barrier_rank) /* for ranking process */
+ BARDEC(barrier_key) /* for key sorting process */
+ double *ranktime;
+ double *sorttime;
+ double *totaltime;
+ int final;
+ unsigned int starttime;
+ unsigned int rs;
+ unsigned int rf;
+ struct prefix_node prefix_tree[2 * MAX_PROCESSORS];
+} *global;
+
+struct global_private {
+ char pad[PAGE_SIZE];
+ int *rank_ff; /* overall processor ranks */
+} gp[MAX_PROCESSORS];
+
+int *key[2]; /* sort from one index into the other */
+int **rank_me; /* individual processor ranks */
+int *key_partition; /* keys a processor works on */
+int *rank_partition; /* ranks a processor works on */
+
+int number_of_processors = DEFAULT_P;
+int max_num_digits;
+int radix = DEFAULT_R;
+int num_keys = DEFAULT_N;
+int max_key = DEFAULT_M;
+int log2_radix;
+int log2_keys;
+int dostats = 0;
+int test_result = 0;
+int doprint = 0;
+volatile cyg_thread *thread_array[64];
+
+int dbg_on = 0;
+double ran_num_init(unsigned int,double,double);
+double product_mod_46(double,double);
+int get_max_digits(int);
+int get_log2_radix(int);
+int get_log2_keys(int);
+void slave_sort();
+int log_2(int);
+void printerr(char *);
+void init(int,int,int);
+void test_sort(int);
+void printout();
+
+
+int smp_cyg_test_main(argc, argv)
+
+int argc;
+char **argv;
+
+{
+ int i;
+ int p;
+ int quotient;
+ int remainder;
+ int sum_i;
+ int sum_f;
+ int mistake=0;
+ int size;
+ int **temp;
+ int **temp2;
+ int *a;
+ int c;
+ int n1;
+ extern char *optarg;
+ double mint, maxt, avgt;
+ double minrank, maxrank, avgrank;
+ double minsort, maxsort, avgsort;
+ unsigned int start;
+ int done = 0;
+ int start_p;
+ int end_p;
+ int level;
+ int index;
+ int base;
+ int offset;
+ int toffset;
+
+
+ memset (thread_array,0,sizeof(thread_array));
+
+ CLOCK(start)
+
+ while ((c = getopt(argc, argv, "p:r:n:m:stoh")) != -1) {
+ switch(c) {
+ case 'p': number_of_processors = atoi(optarg);
+ number_of_processors = HAL_SMP_CPU_MAX;
+ if (number_of_processors < 1) {
+ printerr("P must be >= 1\n");
+ exit(-1);
+ }
+ if (number_of_processors > MAX_PROCESSORS) {
+ printerr("Maximum processors (MAX_PROCESSORS) exceeded\n");
+ exit(-1);
+ }
+ break;
+ case 'r': radix = atoi(optarg);
+ if (radix < 1) {
+ printerr("Radix must be a power of 2 greater than 0\n");
+ exit(-1);
+ }
+ log2_radix = log_2(radix);
+ if (log2_radix == -1) {
+ printerr("Radix must be a power of 2\n");
+ exit(-1);
+ }
+ break;
+ case 'n': num_keys = atoi(optarg);
+ if (num_keys < 1) {
+ printerr("Number of keys must be >= 1\n");
+ exit(-1);
+ }
+ break;
+ case 'm': max_key = atoi(optarg);
+ if (max_key < 1) {
+ printerr("Maximum key must be >= 1\n");
+ exit(-1);
+ }
+ break;
+ case 's': dostats = !dostats;
+ break;
+ case 't': test_result = !test_result;
+ break;
+ case 'o': doprint = !doprint;
+ break;
+ case 'h': diag_printf("Usage: RADIX <options>\n\n");
+ diag_printf(" -pP : P = number of processors.\n");
+ diag_printf(" -rR : R = radix for sorting. Must be power of 2.\n");
+ diag_printf(" -nN : N = number of keys to sort.\n");
+ diag_printf(" -mM : M = maximum key value. Integer keys k will be generated such\n");
+ diag_printf(" that 0 <= k <= M.\n");
+ diag_printf(" -s : Print individual processor timing statistics.\n");
+ diag_printf(" -t : Check to make sure all keys are sorted correctly.\n");
+ diag_printf(" -o : Print out sorted keys.\n");
+ diag_printf(" -h : Print out command line options.\n\n");
+ diag_printf("Default: RADIX -p%1d -n%1d -r%1d -m%1d\n",
+ DEFAULT_P,DEFAULT_N,DEFAULT_R,DEFAULT_M);
+ exit(0);
+ }
+ }
+
+ if (number_of_processors > 64) {
+ printf("Maximal 64 processes\n");
+ exit(0);
+ }
+
+ MAIN_INITENV(,80000000)
+
+ log2_radix = log_2(radix);
+ log2_keys = log_2(num_keys);
+ global = (struct global_memory *) G_MALLOC(sizeof(struct global_memory))
+ key[0] = (int *) G_MALLOC(num_keys*sizeof(int));
+ key[1] = (int *) G_MALLOC(num_keys*sizeof(int));
+ key_partition = (int *) G_MALLOC((number_of_processors+1)*sizeof(int));
+ rank_partition = (int *) G_MALLOC((number_of_processors+1)*sizeof(int));
+
+ if ((global == NULL)) {
+ diag_printf("ERROR: Cannot malloc enough memory %d\n",sizeof(struct global_memory));
+ }
+
+ global->ranktime = (double *) G_MALLOC(number_of_processors*sizeof(double));
+ global->sorttime = (double *) G_MALLOC(number_of_processors*sizeof(double));
+ global->totaltime = (double *) G_MALLOC(number_of_processors*sizeof(double));
+ size = number_of_processors*(radix*sizeof(int)+sizeof(int *));
+ rank_me = (int **) G_MALLOC(size);
+
+ if ((global == NULL) || (key[0] == NULL) || (key[1] == NULL) ||
+ (key_partition == NULL) || (rank_partition == NULL) ||
+ (rank_me == NULL)) {
+ diag_printf("ERROR: Cannot malloc enough memory\n");
+ exit(-1);
+ }
+
+ temp = rank_me;
+ temp2 = temp + number_of_processors;
+ a = (int *) temp2;
+ for (i=0;i<number_of_processors;i++) {
+ *temp = (int *) a;
+ temp++;
+ a += radix;
+ }
+ for (i=0;i<number_of_processors;i++) {
+ gp[i].rank_ff = (int *) G_MALLOC(radix*sizeof(int)+PAGE_SIZE);
+ }
+ LOCKINIT(global->lock_Index)
+ LOCKINIT(global->rank_lock)
+ ALOCKINIT(global->section_lock,MAX_PROCESSORS)
+ BARINIT(global->barrier_rank)
+ BARINIT(global->barrier_key)
+
+ for (i=0; i<2*number_of_processors; i++) {
+ PAUSEINIT(global->prefix_tree[i].done);
+ }
+
+ global->Index = 0;
+ max_num_digits = get_max_digits(max_key);
+ diag_printf("\n");
+ diag_printf("Integer Radix Sort\n");
+ diag_printf(" %d Keys\n",num_keys);
+ diag_printf(" %d Processors\n",number_of_processors);
+ diag_printf(" Radix = %d\n",radix);
+ diag_printf(" Max key = %d\n",max_key);
+ diag_printf("\n");
+
+ quotient = num_keys / number_of_processors;
+ remainder = num_keys % number_of_processors;
+ sum_i = 0;
+ sum_f = 0;
+ p = 0;
+ diag_printf("key_partition\n",max_key);
+ while (sum_i < num_keys) {
+ key_partition[p] = sum_i;
+ p++;
+ sum_i = sum_i + quotient;
+ sum_f = sum_f + remainder;
+ sum_i = sum_i + sum_f / number_of_processors;
+ sum_f = sum_f % number_of_processors;
+ }
+ key_partition[p] = num_keys;
+
+ quotient = radix / number_of_processors;
+ remainder = radix % number_of_processors;
+ sum_i = 0;
+ sum_f = 0;
+ p = 0;
+ diag_printf("rank_partition\n",max_key);
+ while (sum_i < radix) {
+ rank_partition[p] = sum_i;
+ p++;
+ sum_i = sum_i + quotient;
+ sum_f = sum_f + remainder;
+ sum_i = sum_i + sum_f / number_of_processors;
+ sum_f = sum_f % number_of_processors;
+ }
+ rank_partition[p] = radix;
+
+/* POSSIBLE ENHANCEMENT: Here is where one might distribute the key,
+ rank_me, rank, and gp data structures across physically
+ distributed memories as desired.
+
+ One way to place data is as follows:
+
+ for (i=0;i<number_of_processors;i++) {
+ Place all addresses x such that:
+ &(key[0][key_partition[i]]) <= x < &(key[0][key_partition[i+1]])
+ on node i
+ &(key[1][key_partition[i]]) <= x < &(key[1][key_partition[i+1]])
+ on node i
+ &(rank_me[i][0]) <= x < &(rank_me[i][radix-1]) on node i
+ &(gp[i]) <= x < &(gp[i+1]) on node i
+ &(gp[i].rank_ff[0]) <= x < &(gp[i].rank_ff[radix]) on node i
+ }
+ start_p = 0;
+ i = 0;
+
+ for (toffset = 0; toffset < number_of_processors; toffset ++) {
+ offset = toffset;
+ level = number_of_processors >> 1;
+ base = number_of_processors;
+ while ((offset & 0x1) != 0) {
+ offset >>= 1;
+ index = base + offset;
+ Place all addresses x such that:
+ &(global->prefix_tree[index]) <= x <
+ &(global->prefix_tree[index + 1]) on node toffset
+ base += level;
+ level >>= 1;
+ }
+ } */
+
+ /* Fill the random-number array. */
+
+ for (i = 1; i < number_of_processors; i++) {
+ CREATE(slave_sort,thread_array[i])
+ }
+
+ slave_sort();
+
+ for (i = 1; i < number_of_processors; i++) {
+ while(thread_array[i]) {};
+ }
+
+ diag_printf("\n");
+ diag_printf(" PROCESS STATISTICS\n");
+ diag_printf(" Total Rank Sort\n");
+ diag_printf(" Proc Time Time Time\n");
+ diag_printf(" 0 %10.0f %10.0f %10.0f\n",
+ global->totaltime[0],global->ranktime[0],
+ global->sorttime[0]);
+ if (dostats) {
+ maxt = avgt = mint = global->totaltime[0];
+ maxrank = avgrank = minrank = global->ranktime[0];
+ maxsort = avgsort = minsort = global->sorttime[0];
+ for (i=1; i<number_of_processors; i++) {
+ if (global->totaltime[i] > maxt) {
+ maxt = global->totaltime[i];
+ }
+ if (global->totaltime[i] < mint) {
+ mint = global->totaltime[i];
+ }
+ if (global->ranktime[i] > maxrank) {
+ maxrank = global->ranktime[i];
+ }
+ if (global->ranktime[i] < minrank) {
+ minrank = global->ranktime[i];
+ }
+ if (global->sorttime[i] > maxsort) {
+ maxsort = global->sorttime[i];
+ }
+ if (global->sorttime[i] < minsort) {
+ minsort = global->sorttime[i];
+ }
+ avgt += global->totaltime[i];
+ avgrank += global->ranktime[i];
+ avgsort += global->sorttime[i];
+ }
+ avgt = avgt / number_of_processors;
+ avgrank = avgrank / number_of_processors;
+ avgsort = avgsort / number_of_processors;
+ for (i=1; i<number_of_processors; i++) {
+ diag_printf(" %3d %10.0f %10.0f %10.0f\n",
+ i,global->totaltime[i],global->ranktime[i],
+ global->sorttime[i]);
+ }
+ diag_printf(" Avg %10.0f %10.0f %10.0f\n",avgt,avgrank,avgsort);
+ diag_printf(" Min %10.0f %10.0f %10.0f\n",mint,minrank,minsort);
+ diag_printf(" Max %10.0f %10.0f %10.0f\n",maxt,maxrank,maxsort);
+ diag_printf("\n");
+ }
+
+ diag_printf("\n");
+ global->starttime = start;
+ diag_printf(" TIMING INFORMATION\n");
+ diag_printf("Start time : %16d\n",
+ global->starttime);
+ diag_printf("Initialization finish time : %16d\n",
+ global->rs);
+ diag_printf("Overall finish time : %16d\n",
+ global->rf);
+ diag_printf("Total time with initialization : %16d\n",
+ global->rf-global->starttime);
+ diag_printf("Total time without initialization : %16d\n",
+ global->rf-global->rs);
+ diag_printf("\n");
+
+ if (doprint) {
+ printout();
+ }
+ if (test_result) {
+ test_sort(global->final);
+ }
+
+ MAIN_END;
+}
+
+void slave_sort()
+{
+ int i, j, k, kk, Ind;
+ int MyNum;
+ int this_key;
+ int tmp;
+ int last_key;
+ int loopnum;
+ double ran_num;
+ double sum;
+ int shiftnum;
+ int bb;
+ int my_key;
+ int key_start;
+ int key_stop;
+ int rank_start;
+ int rank_stop;
+ int from=0;
+ int to=1;
+ int *key_density; /* individual processor key densities */
+ unsigned int time1;
+ unsigned int time2;
+ unsigned int time3;
+ unsigned int time4;
+ unsigned int time5;
+ unsigned int time6;
+ double ranktime=0;
+ double sorttime=0;
+ int *key_from;
+ int *key_to;
+ int *rank_me_mynum;
+ int *rank_me_i;
+ int *rank_ff_mynum;
+ int stats;
+ struct prefix_node* n;
+ struct prefix_node* r;
+ struct prefix_node* l;
+ struct prefix_node* my_node;
+ struct prefix_node* their_node;
+ volatile int* prefx;
+ int index;
+ int level;
+ int base;
+ int offset;
+
+ diag_printf("SlaveSort %d\n",cyg_hal_get_current_threadid());
+
+ stats = dostats;
+
+ LOCK(global->lock_Index)
+ MyNum = global->Index;
+ global->Index++;
+ UNLOCK(global->lock_Index)
+
+/* POSSIBLE ENHANCEMENT: Here is where one might pin processes to
+ processors to avoid migration */
+
+ key_density = (int *) malloc(radix*sizeof(int));
+
+ /* Fill the random-number array. */
+
+ key_start = key_partition[MyNum];
+ key_stop = key_partition[MyNum + 1];
+ rank_start = rank_partition[MyNum];
+ rank_stop = rank_partition[MyNum + 1];
+ if (rank_stop == radix) {
+ rank_stop--;
+ }
+
+ diag_printf("init %d, %d-%d\n",cyg_hal_get_current_threadid(),key_start,key_stop);
+ init(key_start,key_stop,from);
+
+ BARRIER(global->barrier_key, number_of_processors, 1 )
+
+/* POSSIBLE ENHANCEMENT: Here is where one might reset the
+ statistics that one is measuring about the parallel execution */
+
+ BARRIER(global->barrier_key, number_of_processors, 2)
+
+ if ((MyNum == 0) || (stats)) {
+ CLOCK(time1)
+ }
+
+/* Do 1 iteration per digit. */
+
+ rank_me_mynum = rank_me[MyNum];
+ rank_ff_mynum = gp[MyNum].rank_ff;
+ for (loopnum=0;loopnum<max_num_digits;loopnum++) {
+ shiftnum = (loopnum * log2_radix);
+ bb = (radix-1) << shiftnum;
+
+/* generate histograms based on one digit */
+
+ if ((MyNum == 0) || (stats)) {
+ CLOCK(time2)
+ }
+
+ for (i = 0; i < radix; i++) {
+ rank_me_mynum[i] = 0;
+ }
+ key_from = (int *) key[from];
+ key_to = (int *) key[to];
+ for (i=key_start;i<key_stop;i++) {
+ my_key = key_from[i] & bb;
+ my_key = my_key >> shiftnum;
+ rank_me_mynum[my_key]++;
+ }
+ key_density[0] = rank_me_mynum[0];
+ for (i=1;i<radix;i++) {
+ key_density[i] = key_density[i-1] + rank_me_mynum[i];
+ }
+
+ BARRIER(global->barrier_rank, number_of_processors,3)
+
+ n = &(global->prefix_tree[MyNum]);
+ for (i = 0; i < radix; i++) {
+ n->densities[i] = key_density[i];
+ n->ranks[i] = rank_me_mynum[i];
+ }
+ offset = MyNum;
+ level = number_of_processors >> 1;
+ base = number_of_processors;
+ if ((MyNum & 0x1) == 0) {
+ SETPAUSE(global->prefix_tree[base + (offset >> 1)].done);
+ }
+ while ((offset & 0x1) != 0) {
+ offset >>= 1;
+ r = n;
+ l = n - 1;
+ index = base + offset;
+ n = &(global->prefix_tree[index]);
+ WAITPAUSE(n->done);
+ CLEARPAUSE(n->done);
+ if (offset != (level - 1)) {
+ for (i = 0; i < radix; i++) {
+ n->densities[i] = r->densities[i] + l->densities[i];
+ n->ranks[i] = r->ranks[i] + l->ranks[i];
+ }
+ } else {
+ for (i = 0; i < radix; i++) {
+ n->densities[i] = r->densities[i] + l->densities[i];
+ }
+ }
+ base += level;
+ level >>= 1;
+ if ((offset & 0x1) == 0) {
+ SETPAUSE(global->prefix_tree[base + (offset >> 1)].done);
+ }
+ }
+ BARRIER(global->barrier_rank, number_of_processors,4);
+
+ if (MyNum != (number_of_processors - 1)) {
+ offset = MyNum;
+ level = number_of_processors;
+ base = 0;
+ while ((offset & 0x1) != 0) {
+ offset >>= 1;
+ base += level;
+ level >>= 1;
+ }
+ my_node = &(global->prefix_tree[base + offset]);
+ offset >>= 1;
+ base += level;
+ level >>= 1;
+ while ((offset & 0x1) != 0) {
+ offset >>= 1;
+ base += level;
+ level >>= 1;
+ }
+ their_node = &(global->prefix_tree[base + offset]);
+ WAITPAUSE(my_node->done);
+ CLEARPAUSE(my_node->done);
+ for (i = 0; i < radix; i++) {
+ my_node->densities[i] = their_node->densities[i];
+ }
+ } else {
+ my_node = &(global->prefix_tree[(2 * number_of_processors) - 2]);
+ }
+ offset = MyNum;
+ level = number_of_processors;
+ base = 0;
+ while ((offset & 0x1) != 0) {
+ SETPAUSE(global->prefix_tree[base + offset - 1].done);
+ offset >>= 1;
+ base += level;
+ level >>= 1;
+ }
+ offset = MyNum;
+ level = number_of_processors;
+ base = 0;
+ for(i = 0; i < radix; i++) {
+ rank_ff_mynum[i] = 0;
+ }
+ while (offset != 0) {
+ if ((offset & 0x1) != 0) {
+ /* Add ranks of node to your left at this level */
+ l = &(global->prefix_tree[base + offset - 1]);
+ for (i = 0; i < radix; i++) {
+ rank_ff_mynum[i] += l->ranks[i];
+ }
+ }
+ base += level;
+ level >>= 1;
+ offset >>= 1;
+ }
+ for (i = 1; i < radix; i++) {
+ rank_ff_mynum[i] += my_node->densities[i - 1];
+ }
+
+ if ((MyNum == 0) || (stats)) {
+ CLOCK(time3);
+ }
+
+ BARRIER(global->barrier_rank, number_of_processors,5);
+
+ if ((MyNum == 0) || (stats)) {
+ CLOCK(time4);
+ }
+
+ /* put it in order according to this digit */
+
+ for (i = key_start; i < key_stop; i++) {
+ this_key = key_from[i] & bb;
+ this_key = this_key >> shiftnum;
+ tmp = rank_ff_mynum[this_key];
+ key_to[tmp] = key_from[i];
+ rank_ff_mynum[this_key]++;
+ } /* i */
+
+ if ((MyNum == 0) || (stats)) {
+ CLOCK(time5);
+ }
+
+ if (loopnum != max_num_digits-1) {
+ from = from ^ 0x1;
+ to = to ^ 0x1;
+ }
+
+ BARRIER(global->barrier_rank, number_of_processors, 6)
+
+ if ((MyNum == 0) || (stats)) {
+ ranktime += (time3 - time2);
+ sorttime += (time5 - time4);
+ }
+ } /* for */
+
+ BARRIER(global->barrier_rank, number_of_processors, 7)
+ if ((MyNum == 0) || (stats)) {
+ CLOCK(time6)
+ global->ranktime[MyNum] = ranktime;
+ global->sorttime[MyNum] = sorttime;
+ global->totaltime[MyNum] = time6-time1;
+ }
+ if (MyNum == 0) {
+ global->rs = time1;
+ global->rf = time6;
+ global->final = to;
+ }
+
+ thread_array[MyNum] = 0;
+}
+
+double product_mod_46(t1, t2) /* product_mod_46() returns the product
+ (mod 2^46) of t1 and t2. */
+double t1;
+double t2;
+
+{
+ double a1;
+ double b1;
+ double a2;
+ double b2;
+
+ a1 = (double)((int)(t1 / RADIX_S)); /* Decompose the arguments. */
+ a2 = t1 - a1 * RADIX_S;
+ b1 = (double)((int)(t2 / RADIX_S));
+ b2 = t2 - b1 * RADIX_S;
+ t1 = a1 * b2 + a2 * b1; /* Multiply the arguments. */
+ t2 = (double)((int)(t1 / RADIX_S));
+ t2 = t1 - t2 * RADIX_S;
+ t1 = t2 * RADIX_S + a2 * b2;
+ t2 = (double)((int)(t1 / RADIX));
+
+ return (t1 - t2 * RADIX); /* Return the product. */
+}
+
+double ran_num_init(k, b, t) /* finds the (k)th random number,
+ given the seed, b, and the ratio, t. */
+unsigned int k;
+double b;
+double t;
+
+{
+ unsigned int j;
+
+ while (k != 0) { /* while() is executed m times
+ such that 2^m > k. */
+ j = k >> 1;
+ if ((j << 1) != k) {
+ b = product_mod_46(b, t);
+ }
+ t = product_mod_46(t, t);
+ k = j;
+ }
+
+ return b;
+}
+
+int get_max_digits(max_key)
+
+int max_key;
+
+{
+ int done = 0;
+ int temp = 1;
+ int key_val;
+
+ key_val = max_key;
+ while (!done) {
+ key_val = key_val / radix;
+ if (key_val == 0) {
+ done = 1;
+ } else {
+ temp ++;
+ }
+ }
+ return temp;
+}
+
+int get_log2_radix(rad)
+
+int rad;
+
+{
+ int cumulative=1;
+ int out;
+
+ for (out = 0; out < 20; out++) {
+ if (cumulative == rad) {
+ return(out);
+ } else {
+ cumulative = cumulative * 2;
+ }
+ }
+ diag_printf("ERROR: Radix %d not a power of 2\n", rad);
+ exit(-1);
+}
+
+int get_log2_keys(num_keys)
+
+int num_keys;
+
+{
+ int cumulative=1;
+ int out;
+
+ for (out = 0; out < 30; out++) {
+ if (cumulative == num_keys) {
+ return(out);
+ } else {
+ cumulative = cumulative * 2;
+ }
+ }
+ diag_printf("ERROR: Number of keys %d not a power of 2\n", num_keys);
+ exit(-1);
+}
+
+int log_2(number)
+
+int number;
+
+{
+ int cumulative = 1;
+ int out = 0;
+ int done = 0;
+
+ while ((cumulative < number) && (!done) && (out < 50)) {
+ if (cumulative == number) {
+ done = 1;
+ } else {
+ cumulative = cumulative * 2;
+ out ++;
+ }
+ }
+
+ if (cumulative == number) {
+ return(out);
+ } else {
+ return(-1);
+ }
+}
+
+void printerr(s)
+
+char *s;
+
+{
+ diag_printf("ERROR: %s\n",s);
+}
+
+void init(key_start,key_stop,from)
+
+int key_start;
+int key_stop;
+int from;
+
+{
+ double ran_num;
+ double sum;
+ int tmp;
+ int i;
+ int *key_from;
+
+ ran_num = ran_num_init((key_start << 2) + 1, SEED, RATIO);
+ sum = ran_num / RADIX;
+ key_from = (int *) key[from];
+ for (i = key_start; i < key_stop; i++) {
+ ran_num = product_mod_46(ran_num, RATIO);
+ sum = sum + ran_num / RADIX;
+ ran_num = product_mod_46(ran_num, RATIO);
+ sum = sum + ran_num / RADIX;
+ ran_num = product_mod_46(ran_num, RATIO);
+ sum = sum + ran_num / RADIX;
+ key_from[i] = (int) ((sum / 4.0) * max_key);
+ tmp = (int) ((key_from[i])/100);
+ ran_num = product_mod_46(ran_num, RATIO);
+ sum = ran_num / RADIX;
+ }
+
+}
+
+void test_sort(final)
+
+int final;
+
+{
+ int i;
+ int mistake = 0;
+ int *key_final;
+
+ diag_printf("\n");
+ diag_printf(" TESTING RESULTS\n");
+ key_final = key[final];
+ for (i = 0; i < num_keys-1; i++) {
+ if (key_final[i] > key_final[i + 1]) {
+ diag_printf("error with key %d, value %d %d \n",
+ i,key_final[i],key_final[i + 1]);
+ mistake++;
+ }
+ }
+
+ if (mistake) {
+ diag_printf("FAILED: %d keys out of place.\n", mistake);
+ } else {
+ diag_printf("PASSED: All keys in place.\n");
+ }
+ diag_printf("\n");
+}
+
+void printout()
+
+{
+ int i;
+ int mistake;
+ int *key_final;
+
+ key_final = (int *) key[global->final];
+ diag_printf("\n");
+ diag_printf(" SORTED KEY VALUES\n");
+ diag_printf("%8d ",key_final[0]);
+ for (i = 0; i < num_keys-1; i++) {
+ diag_printf("%8d ",key_final[i+1]);
+ if ((i+2)%5 == 0) {
+ diag_printf("\n");
+ }
+ }
+ diag_printf("\n");
+}
+
+#include <tests_smp/getopt.c>
diff --git a/ecos/packages/kernel/current/tests_smp/radix.c b/ecos/packages/kernel/current/tests_smp/radix.c
new file mode 100644
index 0000000000..00a14fe9fb
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/radix.c
@@ -0,0 +1,1346 @@
+
+
+
+
+
+
+
+
+
+
+
+/*************************************************************************/
+/* */
+/* Copyright (c) 1994 Stanford University */
+/* */
+/* All rights reserved. */
+/* */
+/* Permission is given to use, copy, and modify this software for any */
+/* non-commercial purpose as long as this copyright notice is not */
+/* removed. All other uses, including redistribution in whole or in */
+/* part, are forbidden without prior written permission. */
+/* */
+/* This software is provided with absolutely no warranty and no */
+/* support. */
+/* */
+/*************************************************************************/
+
+/*************************************************************************/
+/* */
+/* Integer radix sort of non-negative integers. */
+/* */
+/* Command line options: */
+/* */
+/* -pP : P = number of processors. */
+/* -rR : R = radix for sorting. Must be power of 2. */
+/* -nN : N = number of keys to sort. */
+/* -mM : M = maximum key value. Integer keys k will be generated such */
+/* that 0 <= k <= M. */
+/* -s : Print individual processor timing statistics. */
+/* -t : Check to make sure all keys are sorted correctly. */
+/* -o : Print out sorted keys. */
+/* -h : Print out command line options. */
+/* */
+/* Default: RADIX -p1 -n262144 -r1024 -m524288 */
+/* */
+/* Note: This version works under both the FORK and SPROC models */
+/* */
+/*************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <tests_smp/getopt.h>
+
+#define DEFAULT_P 1
+#define DEFAULT_N 262144
+#define DEFAULT_R 1024
+#define DEFAULT_M 524288
+#define MAX_PROCESSORS 64
+#define RADIX_S 8388608.0e0
+#define RADIX 70368744177664.0e0
+#define SEED 314159265.0e0
+#define RATIO 1220703125.0e0
+#define PAGE_SIZE 4096
+#define PAGE_MASK (~(PAGE_SIZE-1))
+#define MAX_RADIX 4096
+
+#include <tests_smp/radix_arg.c>
+
+
+/*---------------------------------------*/
+#include <pkgconf/system.h>
+#include <pkgconf/infra.h>
+#include <pkgconf/kernel.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/testcase.h>
+#include <pkgconf/isoinfra.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/hal/hal_smp.h>
+#include <cyg/kernel/kapi.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+int smp_cyg_test_main(int argc, char **argv);
+
+void smp_cyg_test_main_call(void *p) {
+ smp_cyg_test_main(smp_cyg_test_argc, smp_cyg_test_argv);
+}
+
+
+/* #define STACK_SIZE 0x1b000 */
+#define STACK_SIZE 8192
+static cyg_thread smp_cyg_test_thread;
+static char smp_cyg_test_stack[STACK_SIZE];
+static cyg_handle_t smp_cyg_test_threadh;
+
+
+
+cyg_handle_t threadh[64];
+char *stack[64];
+cyg_thread thread[64];
+
+
+externC void cyg_user_start( void )
+{
+ CYG_TEST_INIT();
+
+ diag_printf("Starting test app\n");
+
+ cyg_thread_create(10, // Priority - just a number
+ smp_cyg_test_main_call, // entry
+ 0, // index
+ "smp test", // Name
+ smp_cyg_test_stack, // Stack
+ STACK_SIZE, // Size
+ &smp_cyg_test_threadh, // Handle
+ &smp_cyg_test_thread // Thread data structure
+ );
+ cyg_thread_resume( smp_cyg_test_threadh );
+ /*cyg_scheduler_start();*/
+}
+
+
+/*---------------------------------------*/
+
+
+struct prefix_node {
+ int densities[MAX_RADIX];
+ int ranks[MAX_RADIX];
+
+ char pad[PAGE_SIZE];
+};
+
+struct global_memory {
+ int Index; /* process ID */
+ cyg_spinlock_t lock_Index; /* for fetch and add to get ID */
+ cyg_spinlock_t rank_lock; /* for fetch and add to get ID */
+
+/*---------------------------------------*/
+struct section_lockTYP {
+ cyg_spinlock_t lock;;
+
+
+
+ } section_lock[MAX_PROCESSORS];
+/*---------------------------------------*/
+
+ /* key locks */
+
+/*---------------------------------------*/
+struct barrier_rankTYP {
+ cyg_spinlock_t lock;;
+ int count[1];
+ cyg_sem_t queue[1];;
+
+ } barrier_rank[1];
+/*---------------------------------------*/
+
+ /* for ranking process */
+
+/*---------------------------------------*/
+struct barrier_keyTYP {
+ cyg_spinlock_t lock;;
+ int count[1];
+ cyg_sem_t queue[1];;
+
+ } barrier_key[1];
+/*---------------------------------------*/
+
+ /* for key sorting process */
+ double *ranktime;
+ double *sorttime;
+ double *totaltime;
+ int final;
+ unsigned int starttime;
+ unsigned int rs;
+ unsigned int rf;
+ struct prefix_node prefix_tree[2 * MAX_PROCESSORS];
+} *global;
+
+struct global_private {
+ char pad[PAGE_SIZE];
+ int *rank_ff; /* overall processor ranks */
+} gp[MAX_PROCESSORS];
+
+int *key[2]; /* sort from one index into the other */
+int **rank_me; /* individual processor ranks */
+int *key_partition; /* keys a processor works on */
+int *rank_partition; /* ranks a processor works on */
+
+int number_of_processors = DEFAULT_P;
+int max_num_digits;
+int radix = DEFAULT_R;
+int num_keys = DEFAULT_N;
+int max_key = DEFAULT_M;
+int log2_radix;
+int log2_keys;
+int dostats = 0;
+int test_result = 0;
+int doprint = 0;
+volatile cyg_thread *thread_array[64];
+
+int dbg_on = 0;
+double ran_num_init(unsigned int,double,double);
+double product_mod_46(double,double);
+int get_max_digits(int);
+int get_log2_radix(int);
+int get_log2_keys(int);
+void slave_sort();
+int log_2(int);
+void printerr(char *);
+void init(int,int,int);
+void test_sort(int);
+void printout();
+
+
+int smp_cyg_test_main(argc, argv)
+
+int argc;
+char **argv;
+
+{
+ int i;
+ int p;
+ int quotient;
+ int remainder;
+ int sum_i;
+ int sum_f;
+ int mistake=0;
+ int size;
+ int **temp;
+ int **temp2;
+ int *a;
+ int c;
+ int n1;
+ extern char *optarg;
+ double mint, maxt, avgt;
+ double minrank, maxrank, avgrank;
+ double minsort, maxsort, avgsort;
+ unsigned int start;
+ int done = 0;
+ int start_p;
+ int end_p;
+ int level;
+ int index;
+ int base;
+ int offset;
+ int toffset;
+
+
+ memset (thread_array,0,sizeof(thread_array));
+
+ {
+ (start) = cyg_current_time()*10;
+}
+
+
+ while ((c = getopt(argc, argv, "p:r:n:m:stoh")) != -1) {
+ switch(c) {
+ case 'p': number_of_processors = atoi(optarg);
+ number_of_processors = HAL_SMP_CPU_MAX;
+ if (number_of_processors < 1) {
+ printerr("P must be >= 1\n");
+ exit(-1);
+ }
+ if (number_of_processors > MAX_PROCESSORS) {
+ printerr("Maximum processors (MAX_PROCESSORS) exceeded\n");
+ exit(-1);
+ }
+ break;
+ case 'r': radix = atoi(optarg);
+ if (radix < 1) {
+ printerr("Radix must be a power of 2 greater than 0\n");
+ exit(-1);
+ }
+ log2_radix = log_2(radix);
+ if (log2_radix == -1) {
+ printerr("Radix must be a power of 2\n");
+ exit(-1);
+ }
+ break;
+ case 'n': num_keys = atoi(optarg);
+ if (num_keys < 1) {
+ printerr("Number of keys must be >= 1\n");
+ exit(-1);
+ }
+ break;
+ case 'm': max_key = atoi(optarg);
+ if (max_key < 1) {
+ printerr("Maximum key must be >= 1\n");
+ exit(-1);
+ }
+ break;
+ case 's': dostats = !dostats;
+ break;
+ case 't': test_result = !test_result;
+ break;
+ case 'o': doprint = !doprint;
+ break;
+ case 'h': diag_printf("Usage: RADIX <options>\n\n");
+ diag_printf(" -pP : P = number of processors.\n");
+ diag_printf(" -rR : R = radix for sorting. Must be power of 2.\n");
+ diag_printf(" -nN : N = number of keys to sort.\n");
+ diag_printf(" -mM : M = maximum key value. Integer keys k will be generated such\n");
+ diag_printf(" that 0 <= k <= M.\n");
+ diag_printf(" -s : Print individual processor timing statistics.\n");
+ diag_printf(" -t : Check to make sure all keys are sorted correctly.\n");
+ diag_printf(" -o : Print out sorted keys.\n");
+ diag_printf(" -h : Print out command line options.\n\n");
+ diag_printf("Default: RADIX -p%1d -n%1d -r%1d -m%1d\n",
+ DEFAULT_P,DEFAULT_N,DEFAULT_R,DEFAULT_M);
+ exit(0);
+ }
+ }
+
+ if (number_of_processors > 64) {
+ printf("Maximal 64 processes\n");
+ exit(0);
+ }
+
+ {;}
+
+ log2_radix = log_2(radix);
+ log2_keys = log_2(num_keys);
+ global = (struct global_memory *) calloc(sizeof(struct global_memory), 1);
+ key[0] = (int *) calloc(num_keys*sizeof(int), 1);;
+ key[1] = (int *) calloc(num_keys*sizeof(int), 1);;
+ key_partition = (int *) calloc((number_of_processors+1)*sizeof(int), 1);;
+ rank_partition = (int *) calloc((number_of_processors+1)*sizeof(int), 1);;
+
+ if ((global == NULL)) {
+ diag_printf("ERROR: Cannot malloc enough memory %d\n",sizeof(struct global_memory));
+ }
+
+ global->ranktime = (double *) calloc(number_of_processors*sizeof(double), 1);;
+ global->sorttime = (double *) calloc(number_of_processors*sizeof(double), 1);;
+ global->totaltime = (double *) calloc(number_of_processors*sizeof(double), 1);;
+ size = number_of_processors*(radix*sizeof(int)+sizeof(int *));
+ rank_me = (int **) calloc(size, 1);;
+
+ if ((global == NULL) || (key[0] == NULL) || (key[1] == NULL) ||
+ (key_partition == NULL) || (rank_partition == NULL) ||
+ (rank_me == NULL)) {
+ diag_printf("ERROR: Cannot malloc enough memory\n");
+ exit(-1);
+ }
+
+ temp = rank_me;
+ temp2 = temp + number_of_processors;
+ a = (int *) temp2;
+ for (i=0;i<number_of_processors;i++) {
+ *temp = (int *) a;
+ temp++;
+ a += radix;
+ }
+ for (i=0;i<number_of_processors;i++) {
+ gp[i].rank_ff = (int *) calloc(radix*sizeof(int)+PAGE_SIZE, 1);;
+ }
+ cyg_spinlock_init( &global->lock_Index,0 );
+ cyg_spinlock_init( &global->rank_lock,0 );
+ { {
+/*---------------------------------------*/
+ int mon_dum1,mon_dum2;
+
+ for (mon_dum1=0; mon_dum1 < MAX_PROCESSORS; mon_dum1++) {
+ cyg_spinlock_init( &global->section_lock[mon_dum1].lock,0 );;
+ }
+/*---------------------------------------*/
+};}
+ {{
+/*---------------------------------------*/
+ int mon_dum1,mon_dum2;
+ for (mon_dum1=0; mon_dum1 < 1; mon_dum1++)
+ for (mon_dum2=0; mon_dum2 < 1; mon_dum2++) {
+ global->barrier_rank[mon_dum1].count[mon_dum2] = 0;
+ { cyg_semaphore_init(&global->barrier_rank[mon_dum1].queue[mon_dum2],0);};
+ }
+ for (mon_dum1=0; mon_dum1 < 1; mon_dum1++) {
+ cyg_spinlock_init( &global->barrier_rank[mon_dum1].lock,0 );;
+ }
+/*---------------------------------------*/
+}}
+ {{
+/*---------------------------------------*/
+ int mon_dum1,mon_dum2;
+ for (mon_dum1=0; mon_dum1 < 1; mon_dum1++)
+ for (mon_dum2=0; mon_dum2 < 1; mon_dum2++) {
+ global->barrier_key[mon_dum1].count[mon_dum2] = 0;
+ { cyg_semaphore_init(&global->barrier_key[mon_dum1].queue[mon_dum2],0);};
+ }
+ for (mon_dum1=0; mon_dum1 < 1; mon_dum1++) {
+ cyg_spinlock_init( &global->barrier_key[mon_dum1].lock,0 );;
+ }
+/*---------------------------------------*/
+}}
+
+ for (i=0; i<2*number_of_processors; i++) {
+ {/*##########*/;};
+ }
+
+ global->Index = 0;
+ max_num_digits = get_max_digits(max_key);
+ diag_printf("\n");
+ diag_printf("Integer Radix Sort\n");
+ diag_printf(" %d Keys\n",num_keys);
+ diag_printf(" %d Processors\n",number_of_processors);
+ diag_printf(" Radix = %d\n",radix);
+ diag_printf(" Max key = %d\n",max_key);
+ diag_printf("\n");
+
+ quotient = num_keys / number_of_processors;
+ remainder = num_keys % number_of_processors;
+ sum_i = 0;
+ sum_f = 0;
+ p = 0;
+ diag_printf("key_partition\n",max_key);
+ while (sum_i < num_keys) {
+ key_partition[p] = sum_i;
+ p++;
+ sum_i = sum_i + quotient;
+ sum_f = sum_f + remainder;
+ sum_i = sum_i + sum_f / number_of_processors;
+ sum_f = sum_f % number_of_processors;
+ }
+ key_partition[p] = num_keys;
+
+ quotient = radix / number_of_processors;
+ remainder = radix % number_of_processors;
+ sum_i = 0;
+ sum_f = 0;
+ p = 0;
+ diag_printf("rank_partition\n",max_key);
+ while (sum_i < radix) {
+ rank_partition[p] = sum_i;
+ p++;
+ sum_i = sum_i + quotient;
+ sum_f = sum_f + remainder;
+ sum_i = sum_i + sum_f / number_of_processors;
+ sum_f = sum_f % number_of_processors;
+ }
+ rank_partition[p] = radix;
+
+/* POSSIBLE ENHANCEMENT: Here is where one might distribute the key,
+ rank_me, rank, and gp data structures across physically
+ distributed memories as desired.
+
+ One way to place data is as follows:
+
+ for (i=0;i<number_of_processors;i++) {
+ Place all addresses x such that:
+ &(key[0][key_partition[i]]) <= x < &(key[0][key_partition[i+1]])
+ on node i
+ &(key[1][key_partition[i]]) <= x < &(key[1][key_partition[i+1]])
+ on node i
+ &(rank_me[i][0]) <= x < &(rank_me[i][radix-1]) on node i
+ &(gp[i]) <= x < &(gp[i+1]) on node i
+ &(gp[i].rank_ff[0]) <= x < &(gp[i].rank_ff[radix]) on node i
+ }
+ start_p = 0;
+ i = 0;
+
+ for (toffset = 0; toffset < number_of_processors; toffset ++) {
+ offset = toffset;
+ level = number_of_processors >> 1;
+ base = number_of_processors;
+ while ((offset & 0x1) != 0) {
+ offset >>= 1;
+ index = base + offset;
+ Place all addresses x such that:
+ &(global->prefix_tree[index]) <= x <
+ &(global->prefix_tree[index + 1]) on node toffset
+ base += level;
+ level >>= 1;
+ }
+ } */
+
+ /* Fill the random-number array. */
+
+ for (i = 1; i < number_of_processors; i++) {
+
+{
+ /*---------------------------------------*/
+ stack[i] = calloc(STACK_SIZE, 1);
+ cyg_thread_create(10, // Priority - just a number
+ slave_sort, // entry
+ 0, // index
+ "slave", // Name
+ stack[i], // Stack
+ STACK_SIZE, // Size
+ &threadh[i], // Handle
+ &thread[i] // Thread data structure
+ );
+ cyg_thread_resume( threadh[i] );
+ /*---------------------------------------*/
+}
+
+ }
+
+ slave_sort();
+
+ for (i = 1; i < number_of_processors; i++) {
+ while(thread_array[i]) {};
+ }
+
+ diag_printf("\n");
+ diag_printf(" PROCESS STATISTICS\n");
+ diag_printf(" Total Rank Sort\n");
+ diag_printf(" Proc Time Time Time\n");
+ diag_printf(" 0 %10.0f %10.0f %10.0f\n",
+ global->totaltime[0],global->ranktime[0],
+ global->sorttime[0]);
+ if (dostats) {
+ maxt = avgt = mint = global->totaltime[0];
+ maxrank = avgrank = minrank = global->ranktime[0];
+ maxsort = avgsort = minsort = global->sorttime[0];
+ for (i=1; i<number_of_processors; i++) {
+ if (global->totaltime[i] > maxt) {
+ maxt = global->totaltime[i];
+ }
+ if (global->totaltime[i] < mint) {
+ mint = global->totaltime[i];
+ }
+ if (global->ranktime[i] > maxrank) {
+ maxrank = global->ranktime[i];
+ }
+ if (global->ranktime[i] < minrank) {
+ minrank = global->ranktime[i];
+ }
+ if (global->sorttime[i] > maxsort) {
+ maxsort = global->sorttime[i];
+ }
+ if (global->sorttime[i] < minsort) {
+ minsort = global->sorttime[i];
+ }
+ avgt += global->totaltime[i];
+ avgrank += global->ranktime[i];
+ avgsort += global->sorttime[i];
+ }
+ avgt = avgt / number_of_processors;
+ avgrank = avgrank / number_of_processors;
+ avgsort = avgsort / number_of_processors;
+ for (i=1; i<number_of_processors; i++) {
+ diag_printf(" %3d %10.0f %10.0f %10.0f\n",
+ i,global->totaltime[i],global->ranktime[i],
+ global->sorttime[i]);
+ }
+ diag_printf(" Avg %10.0f %10.0f %10.0f\n",avgt,avgrank,avgsort);
+ diag_printf(" Min %10.0f %10.0f %10.0f\n",mint,minrank,minsort);
+ diag_printf(" Max %10.0f %10.0f %10.0f\n",maxt,maxrank,maxsort);
+ diag_printf("\n");
+ }
+
+ diag_printf("\n");
+ global->starttime = start;
+ diag_printf(" TIMING INFORMATION\n");
+ diag_printf("Start time : %16d\n",
+ global->starttime);
+ diag_printf("Initialization finish time : %16d\n",
+ global->rs);
+ diag_printf("Overall finish time : %16d\n",
+ global->rf);
+ diag_printf("Total time with initialization : %16d\n",
+ global->rf-global->starttime);
+ diag_printf("Total time without initialization : %16d\n",
+ global->rf-global->rs);
+ diag_printf("\n");
+
+ if (doprint) {
+ printout();
+ }
+ if (test_result) {
+ test_sort(global->final);
+ }
+
+
+{
+ diag_printf("FP test end\n");
+ return 0;
+}
+;
+}
+
+void slave_sort()
+{
+ int i, j, k, kk, Ind;
+ int MyNum;
+ int this_key;
+ int tmp;
+ int last_key;
+ int loopnum;
+ double ran_num;
+ double sum;
+ int shiftnum;
+ int bb;
+ int my_key;
+ int key_start;
+ int key_stop;
+ int rank_start;
+ int rank_stop;
+ int from=0;
+ int to=1;
+ int *key_density; /* individual processor key densities */
+ unsigned int time1;
+ unsigned int time2;
+ unsigned int time3;
+ unsigned int time4;
+ unsigned int time5;
+ unsigned int time6;
+ double ranktime=0;
+ double sorttime=0;
+ int *key_from;
+ int *key_to;
+ int *rank_me_mynum;
+ int *rank_me_i;
+ int *rank_ff_mynum;
+ int stats;
+ struct prefix_node* n;
+ struct prefix_node* r;
+ struct prefix_node* l;
+ struct prefix_node* my_node;
+ struct prefix_node* their_node;
+ volatile int* prefx;
+ int index;
+ int level;
+ int base;
+ int offset;
+
+ diag_printf("SlaveSort %d\n",cyg_hal_get_current_threadid());
+
+ stats = dostats;
+
+ cyg_spinlock_spin(&global->lock_Index);
+ MyNum = global->Index;
+ global->Index++;
+ cyg_spinlock_clear(&global->lock_Index);
+
+/* POSSIBLE ENHANCEMENT: Here is where one might pin processes to
+ processors to avoid migration */
+
+ key_density = (int *) malloc(radix*sizeof(int));
+
+ /* Fill the random-number array. */
+
+ key_start = key_partition[MyNum];
+ key_stop = key_partition[MyNum + 1];
+ rank_start = rank_partition[MyNum];
+ rank_stop = rank_partition[MyNum + 1];
+ if (rank_stop == radix) {
+ rank_stop--;
+ }
+
+ diag_printf("init %d, %d-%d\n",cyg_hal_get_current_threadid(),key_start,key_stop);
+ init(key_start,key_stop,from);
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( global->barrier_key[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1 ,global->barrier_key[0].count[0],global->barrier_key[0].queue[0].count);
+ }
+ if ( global->barrier_key[0].count[0] < (number_of_processors -1) ) {
+ global->barrier_key[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1 ,global->barrier_key[0].count[0],global->barrier_key[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&global->barrier_key[0].lock );;
+ { cyg_semaphore_wait(&global->barrier_key[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1 ,global->barrier_key[0].count[0],global->barrier_key[0].queue[0].count);
+ }
+ if ( global->barrier_key[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1 ,global->barrier_key[0].count[0],global->barrier_key[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&global->barrier_key[0].lock );;
+
+ } else {
+ ( global->barrier_key[0].count[0] )-- ;
+ //cyg_spinlock_clear(&global->barrier_key[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),1 ,global->barrier_key[0].count[0],global->barrier_key[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&global->barrier_key[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+}
+
+/* POSSIBLE ENHANCEMENT: Here is where one might reset the
+ statistics that one is measuring about the parallel execution */
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( global->barrier_key[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,global->barrier_key[0].count[0],global->barrier_key[0].queue[0].count);
+ }
+ if ( global->barrier_key[0].count[0] < (number_of_processors -1) ) {
+ global->barrier_key[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,global->barrier_key[0].count[0],global->barrier_key[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&global->barrier_key[0].lock );;
+ { cyg_semaphore_wait(&global->barrier_key[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,global->barrier_key[0].count[0],global->barrier_key[0].queue[0].count);
+ }
+ if ( global->barrier_key[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,global->barrier_key[0].count[0],global->barrier_key[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&global->barrier_key[0].lock );;
+
+ } else {
+ ( global->barrier_key[0].count[0] )-- ;
+ //cyg_spinlock_clear(&global->barrier_key[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),2,global->barrier_key[0].count[0],global->barrier_key[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&global->barrier_key[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+}
+
+ if ((MyNum == 0) || (stats)) {
+ {
+ (time1) = cyg_current_time()*10;
+}
+
+ }
+
+/* Do 1 iteration per digit. */
+
+ rank_me_mynum = rank_me[MyNum];
+ rank_ff_mynum = gp[MyNum].rank_ff;
+ for (loopnum=0;loopnum<max_num_digits;loopnum++) {
+ shiftnum = (loopnum * log2_radix);
+ bb = (radix-1) << shiftnum;
+
+/* generate histograms based on one digit */
+
+ if ((MyNum == 0) || (stats)) {
+ {
+ (time2) = cyg_current_time()*10;
+}
+
+ }
+
+ for (i = 0; i < radix; i++) {
+ rank_me_mynum[i] = 0;
+ }
+ key_from = (int *) key[from];
+ key_to = (int *) key[to];
+ for (i=key_start;i<key_stop;i++) {
+ my_key = key_from[i] & bb;
+ my_key = my_key >> shiftnum;
+ rank_me_mynum[my_key]++;
+ }
+ key_density[0] = rank_me_mynum[0];
+ for (i=1;i<radix;i++) {
+ key_density[i] = key_density[i-1] + rank_me_mynum[i];
+ }
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( global->barrier_rank[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ if ( global->barrier_rank[0].count[0] < (number_of_processors -1) ) {
+ global->barrier_rank[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&global->barrier_rank[0].lock );;
+ { cyg_semaphore_wait(&global->barrier_rank[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ if ( global->barrier_rank[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&global->barrier_rank[0].lock );;
+
+ } else {
+ ( global->barrier_rank[0].count[0] )-- ;
+ //cyg_spinlock_clear(&global->barrier_rank[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),3,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&global->barrier_rank[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+}
+
+ n = &(global->prefix_tree[MyNum]);
+ for (i = 0; i < radix; i++) {
+ n->densities[i] = key_density[i];
+ n->ranks[i] = rank_me_mynum[i];
+ }
+ offset = MyNum;
+ level = number_of_processors >> 1;
+ base = number_of_processors;
+ if ((MyNum & 0x1) == 0) {
+ {/*##########*/;};
+ }
+ while ((offset & 0x1) != 0) {
+ offset >>= 1;
+ r = n;
+ l = n - 1;
+ index = base + offset;
+ n = &(global->prefix_tree[index]);
+ {/*##########*/;};
+ {/*##########*/;};
+ if (offset != (level - 1)) {
+ for (i = 0; i < radix; i++) {
+ n->densities[i] = r->densities[i] + l->densities[i];
+ n->ranks[i] = r->ranks[i] + l->ranks[i];
+ }
+ } else {
+ for (i = 0; i < radix; i++) {
+ n->densities[i] = r->densities[i] + l->densities[i];
+ }
+ }
+ base += level;
+ level >>= 1;
+ if ((offset & 0x1) == 0) {
+ {/*##########*/;};
+ }
+ }
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( global->barrier_rank[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ if ( global->barrier_rank[0].count[0] < (number_of_processors -1) ) {
+ global->barrier_rank[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&global->barrier_rank[0].lock );;
+ { cyg_semaphore_wait(&global->barrier_rank[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ if ( global->barrier_rank[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&global->barrier_rank[0].lock );;
+
+ } else {
+ ( global->barrier_rank[0].count[0] )-- ;
+ //cyg_spinlock_clear(&global->barrier_rank[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),4,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&global->barrier_rank[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+
+ if (MyNum != (number_of_processors - 1)) {
+ offset = MyNum;
+ level = number_of_processors;
+ base = 0;
+ while ((offset & 0x1) != 0) {
+ offset >>= 1;
+ base += level;
+ level >>= 1;
+ }
+ my_node = &(global->prefix_tree[base + offset]);
+ offset >>= 1;
+ base += level;
+ level >>= 1;
+ while ((offset & 0x1) != 0) {
+ offset >>= 1;
+ base += level;
+ level >>= 1;
+ }
+ their_node = &(global->prefix_tree[base + offset]);
+ {/*##########*/;};
+ {/*##########*/;};
+ for (i = 0; i < radix; i++) {
+ my_node->densities[i] = their_node->densities[i];
+ }
+ } else {
+ my_node = &(global->prefix_tree[(2 * number_of_processors) - 2]);
+ }
+ offset = MyNum;
+ level = number_of_processors;
+ base = 0;
+ while ((offset & 0x1) != 0) {
+ {/*##########*/;};
+ offset >>= 1;
+ base += level;
+ level >>= 1;
+ }
+ offset = MyNum;
+ level = number_of_processors;
+ base = 0;
+ for(i = 0; i < radix; i++) {
+ rank_ff_mynum[i] = 0;
+ }
+ while (offset != 0) {
+ if ((offset & 0x1) != 0) {
+ /* Add ranks of node to your left at this level */
+ l = &(global->prefix_tree[base + offset - 1]);
+ for (i = 0; i < radix; i++) {
+ rank_ff_mynum[i] += l->ranks[i];
+ }
+ }
+ base += level;
+ level >>= 1;
+ offset >>= 1;
+ }
+ for (i = 1; i < radix; i++) {
+ rank_ff_mynum[i] += my_node->densities[i - 1];
+ }
+
+ if ((MyNum == 0) || (stats)) {
+ {
+ (time3) = cyg_current_time()*10;
+}
+;
+ }
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( global->barrier_rank[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ if ( global->barrier_rank[0].count[0] < (number_of_processors -1) ) {
+ global->barrier_rank[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&global->barrier_rank[0].lock );;
+ { cyg_semaphore_wait(&global->barrier_rank[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ if ( global->barrier_rank[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&global->barrier_rank[0].lock );;
+
+ } else {
+ ( global->barrier_rank[0].count[0] )-- ;
+ //cyg_spinlock_clear(&global->barrier_rank[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),5,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&global->barrier_rank[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+};
+
+ if ((MyNum == 0) || (stats)) {
+ {
+ (time4) = cyg_current_time()*10;
+}
+;
+ }
+
+ /* put it in order according to this digit */
+
+ for (i = key_start; i < key_stop; i++) {
+ this_key = key_from[i] & bb;
+ this_key = this_key >> shiftnum;
+ tmp = rank_ff_mynum[this_key];
+ key_to[tmp] = key_from[i];
+ rank_ff_mynum[this_key]++;
+ } /* i */
+
+ if ((MyNum == 0) || (stats)) {
+ {
+ (time5) = cyg_current_time()*10;
+}
+;
+ }
+
+ if (loopnum != max_num_digits-1) {
+ from = from ^ 0x1;
+ to = to ^ 0x1;
+ }
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( global->barrier_rank[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),6,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ if ( global->barrier_rank[0].count[0] < (number_of_processors -1) ) {
+ global->barrier_rank[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),6,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&global->barrier_rank[0].lock );;
+ { cyg_semaphore_wait(&global->barrier_rank[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),6,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ if ( global->barrier_rank[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),6,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&global->barrier_rank[0].lock );;
+
+ } else {
+ ( global->barrier_rank[0].count[0] )-- ;
+ //cyg_spinlock_clear(&global->barrier_rank[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),6,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&global->barrier_rank[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+}
+
+ if ((MyNum == 0) || (stats)) {
+ ranktime += (time3 - time2);
+ sorttime += (time5 - time4);
+ }
+ } /* for */
+
+ {
+/*---------------------------------*/
+ cyg_spinlock_spin(&( global->barrier_rank[0].lock ) );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: >b (%d:%d:%d): Enter barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),7,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ if ( global->barrier_rank[0].count[0] < (number_of_processors -1) ) {
+ global->barrier_rank[0].count[0]++;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ?b (%d:%d:%d): Wait\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),7,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ cyg_spinlock_clear(&global->barrier_rank[0].lock );;
+ { cyg_semaphore_wait(&global->barrier_rank[0].queue[0] );};
+ }
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: <b (%d:%d:%d): Exit barrier\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),7,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ if ( global->barrier_rank[0].count[0] == 0 ) {
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: ^b (%d:%d:%d): unlock barrier \n-----------\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),7,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+
+ cyg_spinlock_clear(&global->barrier_rank[0].lock );;
+
+ } else {
+ ( global->barrier_rank[0].count[0] )-- ;
+ //cyg_spinlock_clear(&global->barrier_rank[0].count_lock[0] );;
+
+ if (dbg_on) {
+ diag_printf("<cpu%d> thread %d: @b (%d:%d:%d): unlock queue\n",cyg_hal_get_current_cpuid(),cyg_hal_get_current_threadid(),7,global->barrier_rank[0].count[0],global->barrier_rank[0].queue[0].count);
+ }
+ { cyg_semaphore_post(&global->barrier_rank[0].queue[0] );};
+ }
+
+/*---------------------------------*/
+}
+ if ((MyNum == 0) || (stats)) {
+ {
+ (time6) = cyg_current_time()*10;
+}
+
+ global->ranktime[MyNum] = ranktime;
+ global->sorttime[MyNum] = sorttime;
+ global->totaltime[MyNum] = time6-time1;
+ }
+ if (MyNum == 0) {
+ global->rs = time1;
+ global->rf = time6;
+ global->final = to;
+ }
+
+ thread_array[MyNum] = 0;
+}
+
+double product_mod_46(t1, t2) /* product_mod_46() returns the product
+ (mod 2^46) of t1 and t2. */
+double t1;
+double t2;
+
+{
+ double a1;
+ double b1;
+ double a2;
+ double b2;
+
+ a1 = (double)((int)(t1 / RADIX_S)); /* Decompose the arguments. */
+ a2 = t1 - a1 * RADIX_S;
+ b1 = (double)((int)(t2 / RADIX_S));
+ b2 = t2 - b1 * RADIX_S;
+ t1 = a1 * b2 + a2 * b1; /* Multiply the arguments. */
+ t2 = (double)((int)(t1 / RADIX_S));
+ t2 = t1 - t2 * RADIX_S;
+ t1 = t2 * RADIX_S + a2 * b2;
+ t2 = (double)((int)(t1 / RADIX));
+
+ return (t1 - t2 * RADIX); /* Return the product. */
+}
+
+double ran_num_init(k, b, t) /* finds the (k)th random number,
+ given the seed, b, and the ratio, t. */
+unsigned int k;
+double b;
+double t;
+
+{
+ unsigned int j;
+
+ while (k != 0) { /* while() is executed m times
+ such that 2^m > k. */
+ j = k >> 1;
+ if ((j << 1) != k) {
+ b = product_mod_46(b, t);
+ }
+ t = product_mod_46(t, t);
+ k = j;
+ }
+
+ return b;
+}
+
+int get_max_digits(max_key)
+
+int max_key;
+
+{
+ int done = 0;
+ int temp = 1;
+ int key_val;
+
+ key_val = max_key;
+ while (!done) {
+ key_val = key_val / radix;
+ if (key_val == 0) {
+ done = 1;
+ } else {
+ temp ++;
+ }
+ }
+ return temp;
+}
+
+int get_log2_radix(rad)
+
+int rad;
+
+{
+ int cumulative=1;
+ int out;
+
+ for (out = 0; out < 20; out++) {
+ if (cumulative == rad) {
+ return(out);
+ } else {
+ cumulative = cumulative * 2;
+ }
+ }
+ diag_printf("ERROR: Radix %d not a power of 2\n", rad);
+ exit(-1);
+}
+
+int get_log2_keys(num_keys)
+
+int num_keys;
+
+{
+ int cumulative=1;
+ int out;
+
+ for (out = 0; out < 30; out++) {
+ if (cumulative == num_keys) {
+ return(out);
+ } else {
+ cumulative = cumulative * 2;
+ }
+ }
+ diag_printf("ERROR: Number of keys %d not a power of 2\n", num_keys);
+ exit(-1);
+}
+
+int log_2(number)
+
+int number;
+
+{
+ int cumulative = 1;
+ int out = 0;
+ int done = 0;
+
+ while ((cumulative < number) && (!done) && (out < 50)) {
+ if (cumulative == number) {
+ done = 1;
+ } else {
+ cumulative = cumulative * 2;
+ out ++;
+ }
+ }
+
+ if (cumulative == number) {
+ return(out);
+ } else {
+ return(-1);
+ }
+}
+
+void printerr(s)
+
+char *s;
+
+{
+ diag_printf("ERROR: %s\n",s);
+}
+
+void init(key_start,key_stop,from)
+
+int key_start;
+int key_stop;
+int from;
+
+{
+ double ran_num;
+ double sum;
+ int tmp;
+ int i;
+ int *key_from;
+
+ ran_num = ran_num_init((key_start << 2) + 1, SEED, RATIO);
+ sum = ran_num / RADIX;
+ key_from = (int *) key[from];
+ for (i = key_start; i < key_stop; i++) {
+ ran_num = product_mod_46(ran_num, RATIO);
+ sum = sum + ran_num / RADIX;
+ ran_num = product_mod_46(ran_num, RATIO);
+ sum = sum + ran_num / RADIX;
+ ran_num = product_mod_46(ran_num, RATIO);
+ sum = sum + ran_num / RADIX;
+ key_from[i] = (int) ((sum / 4.0) * max_key);
+ tmp = (int) ((key_from[i])/100);
+ ran_num = product_mod_46(ran_num, RATIO);
+ sum = ran_num / RADIX;
+ }
+
+}
+
+void test_sort(final)
+
+int final;
+
+{
+ int i;
+ int mistake = 0;
+ int *key_final;
+
+ diag_printf("\n");
+ diag_printf(" TESTING RESULTS\n");
+ key_final = key[final];
+ for (i = 0; i < num_keys-1; i++) {
+ if (key_final[i] > key_final[i + 1]) {
+ diag_printf("error with key %d, value %d %d \n",
+ i,key_final[i],key_final[i + 1]);
+ mistake++;
+ }
+ }
+
+ if (mistake) {
+ diag_printf("FAILED: %d keys out of place.\n", mistake);
+ } else {
+ diag_printf("PASSED: All keys in place.\n");
+ }
+ diag_printf("\n");
+}
+
+void printout()
+
+{
+ int i;
+ int mistake;
+ int *key_final;
+
+ key_final = (int *) key[global->final];
+ diag_printf("\n");
+ diag_printf(" SORTED KEY VALUES\n");
+ diag_printf("%8d ",key_final[0]);
+ for (i = 0; i < num_keys-1; i++) {
+ diag_printf("%8d ",key_final[i+1]);
+ if ((i+2)%5 == 0) {
+ diag_printf("\n");
+ }
+ }
+ diag_printf("\n");
+}
+
+#include <tests_smp/getopt.c>
diff --git a/ecos/packages/kernel/current/tests_smp/radix_arg.c b/ecos/packages/kernel/current/tests_smp/radix_arg.c
new file mode 100644
index 0000000000..6858edd616
--- /dev/null
+++ b/ecos/packages/kernel/current/tests_smp/radix_arg.c
@@ -0,0 +1,12 @@
+//___________________________________________
+#define _str_HAL_SMP_CPU_MAX(x) #x
+#define smp_cyg_test_argc 5
+char *_cyg_argv[] = {
+ "radix.exe",
+ "-p",
+ "2", /* not used, using HAL_SMP_CPU_MAX */
+ "-m",
+ "10"
+};
+#define smp_cyg_test_argv &_cyg_argv
+//'''''''''''''''''''''''''''''''''''''''''''