This patch addresses some issues with the mailbox implementation raised by the following two threads:
http://ecos.sourceware.org/ml/ecos-devel/2006-08/msg00004.html http://ecos.sourceware.org/ml/ecos-discuss/2006-08/msg00170.html The first pointed out a possible race condition with CYG_ASSERTCLASS() if it is called without the scheduler lock claimed. The solution has been to move all CYG_ASSERTCLASS() calls to places where the scheduler lock is claimed. The second raised some problems with the use of mailboxes in LWIP. It is not clear what the issue there was, I cannot see any obvious problems with the mailbox implementation. However, it did highlight the fact that the wrong mailbox implementation is being used by default. There are two implementations, a straightforward one (mboxt) that works the same way as most other eCos synchronization primitives, and a UITRON-compatible implementation (mboxt2). The main difference is in the way that a new message is assigned to a waiting thread, and how multiple threads interact (I won't go into gory details here unless someone wants me to). For some reason the CDL option that causes the mboxt implementation to be selected by default was missing, causing the mboxt2 implementation to be used all the time. Before looking at this I would have sworn that mboxt was the default implementation. I have therefore added the option and set it to select the mboxt implementation, which is what should have been happening all along. It also appears that using mboxt also solves the problems that were reported for LWIP. However: switching from mboxt2 to mboxt does introduce a slight change in semantics for mailboxes. It only affects mailboxes that have multiple threads attempting to get messages simultaneously. I believe it is reasonable to commit this since it doesn't violate the specified behaviour, and it results in using a slightly smaller implementation. It has required a change to the test programs, but that's because they attempt to track mailbox behaviour in an unsynchronized way. Before committing this, I think we need to come to a consensus as to whether this difference in behaviour is in fact significant. Index: compat/uitron/current/ChangeLog =================================================================== RCS file: /cvs/ecos/ecos/packages/compat/uitron/current/ChangeLog,v retrieving revision 1.25 diff -u -5 -r1.25 ChangeLog --- compat/uitron/current/ChangeLog 3 Aug 2005 21:02:31 -0000 1.25 +++ compat/uitron/current/ChangeLog 8 Sep 2006 10:17:10 -0000 @@ -1,5 +1,10 @@ +2006-09-07 Nick Garnett <[EMAIL PROTECTED]> + + * cdl/uitron.cdl: Add reqirement for UITRON conformant mailbox + implementation to CYGIMP_UITRON_STRICT_CONFORMANCE. + 2005-08-02 Andrew Lunn <[EMAIL PROTECTED]> * tests/test2.c (task1): Cast to fix compiler warning. 2003-02-24 Jonathan Larmour <[EMAIL PROTECTED]> @@ -844,10 +849,11 @@ //=========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2006 eCosCentric Ltd. // // 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. // @@ -867,11 +873,8 @@ // 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#### //=========================================================================== Index: compat/uitron/current/cdl/uitron.cdl =================================================================== RCS file: /cvs/ecos/ecos/packages/compat/uitron/current/cdl/uitron.cdl,v retrieving revision 1.7 diff -u -5 -r1.7 uitron.cdl --- compat/uitron/current/cdl/uitron.cdl 24 Feb 2003 14:08:52 -0000 1.7 +++ compat/uitron/current/cdl/uitron.cdl 8 Sep 2006 10:17:10 -0000 @@ -7,10 +7,11 @@ # ==================================================================== #####ECOSGPLCOPYRIGHTBEGIN#### ## ------------------------------------------- ## This file is part of eCos, the Embedded Configurable Operating System. ## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +## Copyright (C) 2006 eCosCentric Ltd. ## ## 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. ## @@ -30,13 +31,10 @@ ## 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#### # @@ -74,10 +72,11 @@ default_value 0 requires CYGVAR_KERNEL_COUNTERS_CLOCK requires CYGSEM_KERNEL_SCHED_MLQUEUE requires !CYGSEM_KERNEL_SCHED_TIMESLICE requires CYGFUN_KERNEL_THREADS_TIMER + requires !CYGIMP_MBOX_USE_MBOXT_PLAIN implements CYGINT_UITRON_CONFORMANCE description " Require the rest of the system configuration to match the needs of strict uITRON standards conformance. This option can only be set if the rest of the system is Index: kernel/current/ChangeLog =================================================================== RCS file: /cvs/ecos/ecos/packages/kernel/current/ChangeLog,v retrieving revision 1.138 diff -u -5 -r1.138 ChangeLog --- kernel/current/ChangeLog 21 Aug 2006 17:13:45 -0000 1.138 +++ kernel/current/ChangeLog 8 Sep 2006 10:17:30 -0000 @@ -1,5 +1,22 @@ +2006-09-07 Nick Garnett <[EMAIL PROTECTED]> + + * cdl/synch.cdl: Added CYGIMP_MBOX_USE_MBOXT_PLAIN option. This is + tested in various placed but was not actually defined. It now is + and defaults to 1 so that the plain version of mail boxes is + selected. + + * include/mboxt.inl: + * include/mboxt2.inl: Moved various CYG_ASSERTCLASS() calls to be + within scheduler locked regions. Race conditions could have caused + them to fail before. + + * tests/mbox1.cxx: + * tests/kmbox1.cxx: Updated tests to work with mboxt + implementation. This requires thread 1 to run at lower priority + than thread 0. + 2006-08-21 Jonathan Larmour <[EMAIL PROTECTED]> * doc/kernel.sgml: Use reinterpret_cast, not static cast Thanks to Tony Garland for the report in bug 1000299. Index: kernel/current/cdl/synch.cdl =================================================================== RCS file: /cvs/ecos/ecos/packages/kernel/current/cdl/synch.cdl,v retrieving revision 1.8 diff -u -5 -r1.8 synch.cdl --- kernel/current/cdl/synch.cdl 24 Feb 2003 14:06:55 -0000 1.8 +++ kernel/current/cdl/synch.cdl 8 Sep 2006 10:17:31 -0000 @@ -7,10 +7,11 @@ # ==================================================================== #####ECOSGPLCOPYRIGHTBEGIN#### ## ------------------------------------------- ## This file is part of eCos, the Embedded Configurable Operating System. ## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +## Copyright (C) 2006 eCosCentric Ltd. ## ## 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. ## @@ -30,13 +31,10 @@ ## 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#### # @@ -139,10 +137,20 @@ display "Number of protocols selected" } } +cdl_option CYGIMP_MBOX_USE_MBOXT_PLAIN { + display "Use mboxt_plain mbox implementation" + default_value 1 + description " + Use the plain mboxt implementation instead of the mboxt2 + implementation. The mboxt2 version is designed to provide + semantics compatible with UITRON, the plain implementation + is adquate in most other situations." +} + 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 " Index: kernel/current/include/mboxt.inl =================================================================== RCS file: /cvs/ecos/ecos/packages/kernel/current/include/mboxt.inl,v retrieving revision 1.7 diff -u -5 -r1.7 mboxt.inl --- kernel/current/include/mboxt.inl 23 May 2002 23:06:48 -0000 1.7 +++ kernel/current/include/mboxt.inl 8 Sep 2006 10:17:31 -0000 @@ -9,10 +9,11 @@ //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2006 eCosCentric Ltd. // // 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. // @@ -32,13 +33,10 @@ // 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#### // @@ -221,15 +219,15 @@ self->sleep(); get_threadq.enqueue( self ); CYG_INSTRUMENT_MBOXT(WAIT, this, count); + CYG_ASSERTCLASS( this, "Bad this pointer"); + // 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; @@ -257,14 +255,15 @@ #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT wakeup_waiter( put_threadq ); #endif } + CYG_ASSERTCLASS( this, "Bad this pointer"); + // Unlock the scheduler and maybe switch threads Cyg_Scheduler::unlock(); - CYG_ASSERTCLASS( this, "Bad this pointer"); CYG_REPORT_RETVAL( result ); return result; } @@ -307,11 +306,11 @@ 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"); @@ -353,14 +352,15 @@ #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT wakeup_waiter( put_threadq ); #endif } + CYG_ASSERTCLASS( this, "Bad this pointer"); + // 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 @@ -371,15 +371,15 @@ 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_ASSERTCLASS( this, "Bad this pointer"); + 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 ) { @@ -406,15 +406,15 @@ 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_ASSERTCLASS( this, "Bad this pointer"); + 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 ) Index: kernel/current/include/mboxt2.inl =================================================================== RCS file: /cvs/ecos/ecos/packages/kernel/current/include/mboxt2.inl,v retrieving revision 1.7 diff -u -5 -r1.7 mboxt2.inl --- kernel/current/include/mboxt2.inl 23 May 2002 23:06:48 -0000 1.7 +++ kernel/current/include/mboxt2.inl 8 Sep 2006 10:17:32 -0000 @@ -9,10 +9,11 @@ //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2006 eCosCentric Ltd. // // 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. // @@ -32,13 +33,10 @@ // 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#### // @@ -259,25 +257,28 @@ #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT wakeup_putter(); #endif + CYG_ASSERTCLASS( this, "Bad this pointer"); + // 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); - + + CYG_ASSERTCLASS( this, "Bad this pointer"); + // Unlock scheduler and allow other threads to run Cyg_Scheduler::unlock_reschedule(); cyg_bool result = true; switch( self->get_wake_reason() ) @@ -292,11 +293,11 @@ break; default: break; } - CYG_ASSERTCLASS( this, "Bad this pointer"); + CYG_REPORT_RETVAL( result ); return result; } @@ -331,14 +332,15 @@ #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT wakeup_putter(); #endif + CYG_ASSERTCLASS( this, "Bad this pointer"); + // 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 @@ -354,18 +356,18 @@ get_threadq.enqueue( self ); CYG_INSTRUMENT_MBOXT(WAIT, this, count); } + CYG_ASSERTCLASS( this, "Bad this pointer"); + // 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; @@ -397,15 +399,15 @@ 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_ASSERTCLASS( this, "Bad this pointer"); + 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 ) { @@ -432,15 +434,15 @@ 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_ASSERTCLASS( this, "Bad this pointer"); + 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 ) @@ -478,15 +480,15 @@ self->sleep(); put_threadq.enqueue( self ); CYG_INSTRUMENT_MBOXT(WAIT, this, count); + CYG_ASSERTCLASS( this, "Bad this pointer"); + // 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: @@ -504,12 +506,12 @@ return result; } if ( !get_threadq.empty() ) { wakeup_winner( item ); - Cyg_Scheduler::unlock(); // unlock, maybe switch threads CYG_ASSERTCLASS( this, "Bad this pointer"); + Cyg_Scheduler::unlock(); // unlock, maybe switch threads CYG_REPORT_RETVAL( true ); return true; } cyg_count32 in = base + (count++); @@ -566,10 +568,12 @@ put_threadq.enqueue( self ); CYG_INSTRUMENT_MBOXT(WAIT, this, count); } + CYG_ASSERTCLASS( this, "Bad this pointer"); + // 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(); @@ -593,20 +597,19 @@ 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_Scheduler::unlock(); // unlock, maybe switch threads CYG_REPORT_RETVAL( true ); return true; } cyg_count32 in = base + (count++); @@ -617,13 +620,14 @@ 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_ASSERTCLASS( this, "Bad this pointer"); CYG_REPORT_RETVAL( true ); return true; } #endif // CYGFUN_KERNEL_THREADS_TIMER #endif // CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT Index: kernel/current/tests/kmbox1.c =================================================================== RCS file: /cvs/ecos/ecos/packages/kernel/current/tests/kmbox1.c,v retrieving revision 1.6 diff -u -5 -r1.6 kmbox1.c --- kernel/current/tests/kmbox1.c 23 May 2002 23:07:00 -0000 1.6 +++ kernel/current/tests/kmbox1.c 8 Sep 2006 10:17:32 -0000 @@ -7,10 +7,11 @@ //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2006 eCosCentric Ltd. // // 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. // @@ -30,13 +31,10 @@ // 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#### // @@ -185,11 +183,11 @@ 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", + cyg_thread_create(5, 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 ); Index: kernel/current/tests/mbox1.cxx =================================================================== RCS file: /cvs/ecos/ecos/packages/kernel/current/tests/mbox1.cxx,v retrieving revision 1.7 diff -u -5 -r1.7 mbox1.cxx --- kernel/current/tests/mbox1.cxx 23 May 2002 23:07:01 -0000 1.7 +++ kernel/current/tests/mbox1.cxx 8 Sep 2006 10:17:32 -0000 @@ -7,10 +7,11 @@ //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2006 eCosCentric Ltd. // // 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. // @@ -30,13 +31,10 @@ // 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#### // @@ -74,10 +72,12 @@ static void entry0( CYG_ADDRWORD data ) { cyg_count8 u,i; + Cyg_Thread::self()->set_priority(4); + 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); @@ -149,10 +149,13 @@ } static void entry1( CYG_ADDRWORD data ) { cyg_count8 i; + + Cyg_Thread::self()->set_priority(5); + i = (cyg_count8)m1.get(); CYG_TEST_CHECK(1==q++, "bad synchronization"); m0.PUT((void *)3); // wake t0 #ifdef CYGFUN_KERNEL_THREADS_TIMER -- Nick Garnett eCos Kernel Architect http://www.ecoscentric.com The eCos and RedBoot experts
