]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/compat/uitron/v2_0/tests/testintr.cxx
Initial revision
[karo-tx-redboot.git] / packages / compat / uitron / v2_0 / tests / testintr.cxx
1 //===========================================================================
2 //
3 //      testintr.c
4 //
5 //      uITRON "C" test program for ixxx_yyy interrupt safe operators
6 //
7 //===========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //===========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):   hmt
44 // Contributors:hmt
45 // Date:        1998-08-20
46 // Purpose:     uITRON API testing
47 // Description: 
48 //
49 //####DESCRIPTIONEND####
50 //
51 //===========================================================================
52
53 #include <pkgconf/system.h>
54 #include <pkgconf/uitron.h>             // uITRON setup CYGNUM_UITRON_SEMAS
55                                         // CYGPKG_UITRON et al
56 #include <cyg/infra/testcase.h>         // testing infrastructure
57
58 #ifdef CYGPKG_UITRON                    // we DO want the uITRON package
59
60 #ifdef CYGSEM_KERNEL_SCHED_MLQUEUE      // we DO want prioritized threads
61
62 #ifdef CYGFUN_KERNEL_THREADS_TIMER      // we DO want timout-able calls
63
64 #ifdef CYGVAR_KERNEL_COUNTERS_CLOCK     // we DO want the realtime clock
65
66 // we're OK if it's C++ or neither of those two is defined:
67 #if defined( __cplusplus ) || \
68     (!defined( CYGIMP_UITRON_INLINE_FUNCS ) && \
69      !defined( CYGIMP_UITRON_CPP_OUTLINE_FUNCS) )
70
71 // =================== TEST CONFIGURATION ===================
72 #if \
73     /* test configuration for enough tasks */                      \
74     (CYGNUM_UITRON_TASKS >= 4)                                  && \
75     (CYGNUM_UITRON_TASKS < 90)                                  && \
76     (CYGNUM_UITRON_START_TASKS == 1)                            && \
77     ( !defined(CYGPKG_UITRON_TASKS_CREATE_DELETE) ||               \
78       CYGNUM_UITRON_TASKS_INITIALLY >= 4             )          && \
79                                                                    \
80     /* the end of the large #if statement */                       \
81     1 
82
83 // ============================ END ============================
84
85 #include <cyg/hal/hal_arch.h>
86 #include <cyg/hal/hal_intr.h>
87
88 #include <cyg/infra/diag.h>
89
90 #include <cyg/compat/uitron/uit_func.h> // uITRON
91 #include <cyg/compat/uitron/uit_ifnc.h> // uITRON interrupt funcs
92
93 void set_interrupt_number( void );
94
95 unsigned int clock_interrupt = 0;
96
97 externC void
98 cyg_package_start( void )
99 {
100     CYG_TEST_INIT();
101     CYG_TEST_INFO( "Calling cyg_uitron_start()" );
102     set_interrupt_number();
103     cyg_uitron_start();
104 }
105
106 extern "C" {
107     void task1( unsigned int arg );
108     void task2( unsigned int arg );
109     void task3( unsigned int arg );
110     void task4( unsigned int arg );
111 }
112
113 volatile int intercom = 0;
114 INT scratch = 0;
115
116 // Plan: replace (by direct intervention) the ISR and DSR of the regular
117 // timer interrupt; be sure to ack the clock intr using the appropriate hal
118 // macros.
119 // 
120 // The new ISR(s) will simply use the interrupt-safe signalling functions
121 // to control a 2nd task.  Main task will check on the state thereof.
122 //
123 // We must test the ixxx_yyy() funcs with the scheduler already locked
124 // also, by direct sched calls on the KAPI.  This must verify that the
125 // signal only happens when the scheduler unlocks.
126 // 
127 // The 4 producer ops are:
128 //     iwup_tsk ( ID tskid );
129 //     isig_sem ( ID semid );
130 //     iset_flg ( ID flgid, UINT setptn );
131 //     isnd_msg ( ID mbxid, T_MSG *pk_msg );
132 //
133 // and return macros are:
134 //     ret_wup( ID tskid );
135 //     ret_int();
136 //
137 // These ISRs perform the producer ops on all available objects in turn.
138 // Tasks 2-4
139 // Semas 1-4
140 // Flags 1-4 with marching bit data; they'll all be set to 0x1ff eventually
141 // Mboxes 1-4 with an arbitrary pointer
142
143 enum {
144     NOTHING = 0,
145     SLP,
146     SEM,
147     FLG,
148     MBX,
149     EXIT
150 };
151
152 #define ACK_CLOCK() CYG_MACRO_START                             \
153     HAL_CLOCK_RESET( CYGNUM_HAL_INTERRUPT_RTC,                  \
154                      CYGNUM_KERNEL_COUNTERS_RTC_PERIOD );       \
155     HAL_INTERRUPT_ACKNOWLEDGE( CYGNUM_HAL_INTERRUPT_RTC );      \
156 CYG_MACRO_END
157
158 #define CHECK_TID() CYG_MACRO_START                     \
159     int my_tid;                                         \
160     ER ercd;                                            \
161     ercd = get_tid( &my_tid );                          \
162     CYG_TEST_CHECK( E_OK == ercd, "get_tid bad ercd" ); \
163     CYG_TEST_CHECK( 0 == my_tid, "tid not 0 in ISR" );  \
164 CYG_MACRO_END
165
166
167 unsigned int
168 isr_wup_tsk( unsigned int vector, unsigned int data )
169 {
170     // Hit TASKS in range 2..4
171     static int wtid = 2;
172     ACK_CLOCK();
173     CHECK_TID();
174     iwup_tsk( wtid );
175     wtid++;
176     if ( 5 == wtid ) wtid = 2;
177     ret_int();
178 }
179
180 unsigned int
181 isr_ret_wup( unsigned int vector, unsigned int data )
182 {
183     // Hit TASKS in range 2..4
184     static int rwid = 2;
185     ACK_CLOCK();
186     CHECK_TID();
187     rwid++;
188     if ( 6 == rwid ) rwid = 3;
189     ret_wup( rwid - 1 );
190 }
191
192 unsigned int
193 isr_sig_sem( unsigned int vector, unsigned int data )
194 {
195     // Hit SEMAS in range 1..3
196     static int ssid = 1;
197     ACK_CLOCK();
198     CHECK_TID();
199     isig_sem( ssid );
200     ssid++;
201     if ( ssid == 4 ) ssid = 1;
202     ret_int();
203 }
204
205 unsigned int
206 isr_set_flg( unsigned int vector, unsigned int data )
207 {
208     // Hit FLAGS in range 1..4
209     static int sfid = 1;
210     static int sfdata = 0xff;
211     ACK_CLOCK();
212     CHECK_TID();
213     iset_flg( sfid, sfdata );
214     sfid++;
215     if ( sfid == 5 ) sfid = 1;
216 //    sfdata <<= 1;
217 //    if ( sfdata == 0x20 ) sfdata = 1; // so that eventually all 0x1f set
218     ret_int();
219 }
220
221 unsigned int
222 isr_snd_msg( unsigned int vector, unsigned int data )
223 {
224     // Hit MBOXES in range 1..4
225     static int smid = 1;
226     ACK_CLOCK();
227     CHECK_TID();
228     isnd_msg( smid, (T_MSG *)&smid );
229     smid++;
230     if ( smid == 5 ) smid = 1;
231     ret_int();
232 }
233
234
235 void attach_isr( unsigned int (*isr)(unsigned int, unsigned int) );
236 void detach_isr( unsigned int (*isr)(unsigned int, unsigned int) );
237
238 void lock_sched( void );
239 void unlock_sched( void );
240
241 volatile int count = -1;
242
243 /*
244 #define BIGDELAY  50000000
245 #define SMALLDELAY (BIGDELAY/SMALLLOOPS)
246 #define SMALLLOOPS 3
247
248 #define xxxLONGDELAY()                                     \
249 do {                                                    \
250     int i;                                              \
251     for ( i = 0; i < BIGDELAY; i++ )                    \
252         if ( wakeups[ 4 ] > prewups[ 4 ] + 99 ) break;  \
253 } while ( 0 )
254    
255 #define xxxDELAYLOCKSCHED()                                        \
256 do {                                                            \
257     int i,j;                                                    \
258     for ( j = 0; j < SMALLLOOPS; j++ ) {                        \
259         lock_sched();                                           \
260         for ( i = 0; i < SMALLDELAY; i++ )                      \
261             if ( wakeups[ 4 ] > prewups[ 4 ] + 99 ) break;      \
262         unlock_sched();                                         \
263         if ( wakeups[ 4 ] > prewups[ 4 ] + 99 ) break;          \
264     }                                                           \
265 } while ( 0 )
266 */
267
268 #define SMALLDELAYHW  (5000000)
269 #define EVENTSHW      (     20)
270 #define SMALLDELAYSIM ( 100000)
271 #define EVENTSSIM     (      4)
272
273 #define SMALLDELAY (smalldelay)
274 #define EVENTS     (events)
275
276 static int smalldelay = SMALLDELAYHW;
277 static int events     = EVENTSHW;
278
279 #define LONGDELAY() do {                                        \
280     count = 0;                                                  \
281     do count++; while ( wakeups[ 4 ] < prewups[ 4 ] + EVENTS ); \
282 } while ( 0 )
283
284
285 #define DELAYLOCKSCHED()                                              \
286 do {                                                                  \
287     count = 0;                                                        \
288     int i;                                                            \
289     do {                                                              \
290         lock_sched();                                                 \
291         for ( i = 0; i < SMALLDELAY; i++ ) {                          \
292             count++;                                                  \
293             if ( wakeups[ 4 ] >= prewups[ 4 ] + EVENTS )              \
294                 break;                                                \
295         }                                                             \
296         unlock_sched();                                               \
297         CYG_TEST_INFO("  [Still iterating, please wait....]  ");      \
298     } while ( wakeups[ 4 ] < prewups[ 4 ] + EVENTS );                 \
299 } while ( 0 )
300
301 #define DELAY()                                 \
302 if ( 1 & loops )                                \
303     DELAYLOCKSCHED();                           \
304 else                                            \
305     LONGDELAY();
306     
307
308 volatile int wakeups[ 5 ] = { 0,0,0,0,0 };
309 volatile int prewups[ 5 ] = { 0,0,0,0,0 };
310
311
312 void task1( unsigned int arg )
313 {
314     ER ercd;
315     int loops;
316
317     CYG_TEST_INFO( "Task 1 running" );
318
319     if ( cyg_test_is_simulator ) {
320         // take less time
321         events     = EVENTSSIM;
322     }
323
324
325     // First test that dis_int() and ena_int() work for the clock interrupt
326 #ifdef CYGSEM_UITRON_BAD_PARAMS_RETURN_ERRORS
327     ercd = ena_int( 123456789 ); // Hope this is large enough to error
328     CYG_TEST_CHECK( E_PAR == ercd, "ena_int bad ercd !E_PAR" );
329     ercd = dis_int( 123456789 );
330     CYG_TEST_CHECK( E_PAR == ercd, "dis_int bad ercd !E_PAR" );
331 #endif
332
333     // This may take too long on a sim...
334     // On the synthetic target this test cannot run reliably - the
335     // loop counting assumes exclusive access to the processor.
336 #ifndef CYGPKG_HAL_SYNTH    
337     if ( ! cyg_test_is_simulator ) {
338         SYSTIME t1, t2;
339
340         CYG_TEST_INFO( "Testing masking of clock interrupt" );
341
342         ercd = get_tim( &t1 );
343         CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
344
345         // Wait for a tick. This loop acts as a synchronizer for the loop
346         // below, ensuring that it starts just after a tick.
347         for ( loops = 0; loops < 10000000; loops++ ) {
348             ercd = get_tim( &t2 );
349             CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
350             if ( t2 != t1 )
351                 break;
352         }
353         // Wait for next tick. Reset loops counter so we get the
354         // approximate loop count of one clock tick.
355         for ( loops = 0; loops < 10000000; loops++ ) {
356             ercd = get_tim( &t1 );
357             CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
358             if ( t2 != t1 )
359                 break;
360         }
361
362         // save how many loops could be executed in one tick. Multiply
363         // with 3 : we run loops in pairs below and add the time of
364         // one extra to avoid small variations to trigger failures.
365         intercom = loops * 3;
366
367         ercd = ena_int( clock_interrupt ); // was initialized already
368         CYG_TEST_CHECK( E_OK == ercd, "ena_int bad ercd" );
369
370         ercd = get_tim( &t1 );
371         CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
372
373         // Wait for a tick
374         for ( loops = intercom; loops > 0; loops-- ) {
375             ercd = get_tim( &t2 );
376             CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
377             if ( t2 != t1 )
378                 break;
379         }
380         CYG_TEST_CHECK( 0 < loops, "No first tick" );
381         // and a second one
382         for (                 ; loops > 0; loops-- ) {
383             ercd = get_tim( &t1 );
384             CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
385             if ( t2 != t1 )
386                 break;
387         }
388         CYG_TEST_CHECK( 0 < loops, "No second tick" );
389         
390         // The PowerPC cannot disable the timer interrupt (separately).
391 #ifndef CYGPKG_HAL_POWERPC
392         ercd = dis_int( clock_interrupt ); // was initialized already
393         CYG_TEST_CHECK( E_OK == ercd, "dis_int bad ercd" );
394
395         ercd = get_tim( &t1 );
396         CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
397
398         // Wait for a tick (should not happen)
399         for ( loops = intercom; loops > 0; loops-- ) {
400             ercd = get_tim( &t2 );
401             CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
402             if ( t2 != t1 )
403                 break;
404         }
405         CYG_TEST_CHECK( 0 == loops, "A tick occured - should be masked" );
406         CYG_TEST_CHECK( t1 == t2, "Times are different" );
407
408         // Now enable it again and ensure all is well:
409         ercd = ena_int( clock_interrupt );
410         CYG_TEST_CHECK( E_OK == ercd, "ena_int bad ercd" );
411 #endif
412         
413         ercd = get_tim( &t1 );
414         CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
415
416         // Wait for a tick
417         for ( loops = intercom; loops > 0; loops-- ) {
418             ercd = get_tim( &t2 );
419             CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
420             if ( t2 != t1 )
421                 break;
422         }
423         CYG_TEST_CHECK( 0 < loops, "No first tick" );
424         // and a second one
425         for (                 ; loops > 0; loops-- ) {
426             ercd = get_tim( &t1 );
427             CYG_TEST_CHECK( E_OK == ercd, "get_tim bad ercd" );
428             if ( t2 != t1 )
429                 break;
430         }
431         CYG_TEST_CHECK( 0 < loops, "No second tick" );
432
433         CYG_TEST_PASS( "dis_int(), ena_int() OK" );
434     }
435 #endif
436     
437     intercom = 0;
438
439     ercd = get_tid( &scratch );
440     CYG_TEST_CHECK( E_OK == ercd, "get_tid bad ercd" );
441     CYG_TEST_CHECK( 1 == scratch, "tid not 1" );
442
443     // start all other tasks (our prio is 1 by default)
444     ercd = sta_tsk( 2, 222 );
445     CYG_TEST_CHECK( E_OK == ercd, "sta_tsk 2 bad ercd" );
446     ercd = sta_tsk( 3, 333 );
447     CYG_TEST_CHECK( E_OK == ercd, "sta_tsk 3 bad ercd" );
448     ercd = sta_tsk( 4, 444 );
449     CYG_TEST_CHECK( E_OK == ercd, "sta_tsk 4 bad ercd" );
450     // drop pri of other tasks all to 5
451     ercd = chg_pri( 2, 5 );
452     CYG_TEST_CHECK( E_OK == ercd, "chg_pri 2 bad ercd" );
453     ercd = chg_pri( 3, 5 );
454     CYG_TEST_CHECK( E_OK == ercd, "chg_pri 3 bad ercd" );
455     ercd = chg_pri( 4, 5 );
456     CYG_TEST_CHECK( E_OK == ercd, "chg_pri 4 bad ercd" );
457
458     // Test sleep/wakeup
459     intercom = SLP;
460     // Drop our prio to lower; they will run in turn until asleep
461     ercd = chg_pri( 1, 6 );
462     CYG_TEST_CHECK( E_OK == ercd, "chg_pri 1 (self) bad ercd" );
463     
464     loops = 4;
465     do {
466
467         if ( 1 & loops )
468             CYG_TEST_INFO( " (toggling scheduler lock) " );
469         else
470             CYG_TEST_INFO( " (unlocked scheduler) " );
471
472
473         CYG_TEST_CHECK(          0 == wakeups[0], "init: Wakeups[0] hit" );
474         CYG_TEST_CHECK(          0 == wakeups[1], "init: Wakeups[1] hit" );
475         CYG_TEST_CHECK( prewups[2] == wakeups[2], "init: Wakeups[2] hit" );
476         CYG_TEST_CHECK( prewups[3] == wakeups[3], "init: Wakeups[3] hit" );
477         CYG_TEST_CHECK( prewups[4] == wakeups[4], "init: Wakeups[4] hit" );
478
479         // -------- TIMERS AND TIMESLICING DISABLED ---------
480         // install an isr that will wake them all up in turn
481         attach_isr( isr_wup_tsk );
482         DELAY();
483         detach_isr( isr_wup_tsk );
484         // -------- timers and timeslicing ENABLED ---------
485         
486         CYG_TEST_CHECK(         0 == wakeups[0], "iwup_tsk: Wakeups[0] hit" );
487         CYG_TEST_CHECK(         0 == wakeups[1], "iwup_tsk: Wakeups[1] hit" );
488         CYG_TEST_CHECK( prewups[2] < wakeups[2], "iwup_tsk: Wakeups[2] not hit" );
489         CYG_TEST_CHECK( prewups[3] < wakeups[3], "iwup_tsk: Wakeups[3] not hit" );
490         CYG_TEST_CHECK( prewups[4] < wakeups[4], "iwup_tsk: Wakeups[4] not hit" );
491         diag_printf( "INFO:<(fg loops %10d) thread wakeups : %2d %2d %2d >\n", count,
492                      wakeups[2] - prewups[2],
493                      wakeups[3] - prewups[3],
494                      wakeups[4] - prewups[4] );
495         prewups[2] = wakeups[2];
496         prewups[3] = wakeups[3];
497         prewups[4] = wakeups[4];
498         
499         // -------- TIMERS AND TIMESLICING DISABLED ---------
500         // install an isr that will wake them all up in turn
501         attach_isr( isr_ret_wup );
502         DELAY();
503         detach_isr( isr_ret_wup );
504         // -------- timers and timeslicing ENABLED ---------
505         
506         CYG_TEST_CHECK(         0 == wakeups[0], "ret_wup: Wakeups[0] hit" );
507         CYG_TEST_CHECK(         0 == wakeups[1], "ret_wup: Wakeups[1] hit" );
508         CYG_TEST_CHECK( prewups[2] < wakeups[2], "ret_wup: Wakeups[2] not hit" );
509         CYG_TEST_CHECK( prewups[3] < wakeups[3], "ret_wup: Wakeups[3] not hit" );
510         CYG_TEST_CHECK( prewups[4] < wakeups[4], "ret_wup: Wakeups[4] not hit" );
511         diag_printf( "INFO:<(fg loops %10d) thread ret_wups: %2d %2d %2d >\n", count,
512                      wakeups[2] - prewups[2],
513                      wakeups[3] - prewups[3],
514                      wakeups[4] - prewups[4] );
515         prewups[2] = wakeups[2];
516         prewups[3] = wakeups[3];
517         prewups[4] = wakeups[4];
518         
519         // move them on to waiting for a semaphore
520         intercom = SEM;
521         ercd = wup_tsk( 2 );
522         CYG_TEST_CHECK( E_OK == ercd, "wup_tsk(2) bad ercd" );
523         ercd = wup_tsk( 3 );
524         CYG_TEST_CHECK( E_OK == ercd, "wup_tsk(3) bad ercd" );
525         ercd = wup_tsk( 4 );
526         CYG_TEST_CHECK( E_OK == ercd, "wup_tsk(4) bad ercd" );
527         
528         CYG_TEST_CHECK(              0 == wakeups[0], "wup_tsk: Wakeups[0] hit" );
529         CYG_TEST_CHECK(              0 == wakeups[1], "wup_tsk: Wakeups[1] hit" );
530         CYG_TEST_CHECK( prewups[2] + 1 == wakeups[2], "wup_tsk: Wakeups[2] not hit" );
531         CYG_TEST_CHECK( prewups[3] + 1 == wakeups[3], "wup_tsk: Wakeups[3] not hit" );
532         CYG_TEST_CHECK( prewups[4] + 1 == wakeups[4], "wup_tsk: Wakeups[4] not hit" );
533         prewups[2] = wakeups[2];
534         prewups[3] = wakeups[3];
535         prewups[4] = wakeups[4];
536         
537         // -------- TIMERS AND TIMESLICING DISABLED ---------
538         // install an isr that will wake them all up in turn
539         attach_isr( isr_sig_sem );
540         DELAY();
541         detach_isr( isr_sig_sem );
542         // -------- timers and timeslicing ENABLED ---------
543         
544         CYG_TEST_CHECK(         0 == wakeups[0], "isig_sem: Wakeups[0] hit" );
545         CYG_TEST_CHECK(         0 == wakeups[1], "isig_sem: Wakeups[1] hit" );
546         CYG_TEST_CHECK( prewups[2] < wakeups[2], "isig_sem: Wakeups[2] not hit" );
547         CYG_TEST_CHECK( prewups[3] < wakeups[3], "isig_sem: Wakeups[3] not hit" );
548         CYG_TEST_CHECK( prewups[4] < wakeups[4], "isig_sem: Wakeups[4] not hit" );
549         diag_printf( "INFO:<(fg loops %10d) semaphore waits: %2d %2d %2d >\n", count,
550                      wakeups[2] - prewups[2],
551                      wakeups[3] - prewups[3],
552                      wakeups[4] - prewups[4] );
553         prewups[2] = wakeups[2];
554         prewups[3] = wakeups[3];
555         prewups[4] = wakeups[4];
556
557         // move them on to waiting for a flag
558         intercom = FLG;
559         ercd = sig_sem( 1 );
560         CYG_TEST_CHECK( E_OK == ercd, "sig_sem(1) bad ercd" );
561         ercd = sig_sem( 2 );
562         CYG_TEST_CHECK( E_OK == ercd, "sig_sem(2) bad ercd" );
563         ercd = sig_sem( 3 );
564         CYG_TEST_CHECK( E_OK == ercd, "sig_sem(3) bad ercd" );
565
566         CYG_TEST_CHECK(              0 == wakeups[0], "sig_sem: Wakeups[0] hit" );
567         CYG_TEST_CHECK(              0 == wakeups[1], "sig_sem: Wakeups[1] hit" );
568         CYG_TEST_CHECK( prewups[2] + 1 == wakeups[2], "sig_sem: Wakeups[2] not hit" );
569         CYG_TEST_CHECK( prewups[3] + 1 == wakeups[3], "sig_sem: Wakeups[3] not hit" );
570         CYG_TEST_CHECK( prewups[4] + 1 == wakeups[4], "sig_sem: Wakeups[4] not hit" );
571         prewups[2] = wakeups[2];
572         prewups[3] = wakeups[3];
573         prewups[4] = wakeups[4];
574         
575         // -------- TIMERS AND TIMESLICING DISABLED ---------
576         // install an isr that will wake them all up in turn
577         attach_isr( isr_set_flg );
578         DELAY();
579         detach_isr( isr_set_flg );
580         // -------- timers and timeslicing ENABLED ---------
581         
582         CYG_TEST_CHECK(         0 == wakeups[0], "iset_flg: Wakeups[0] hit" );
583         CYG_TEST_CHECK(         0 == wakeups[1], "iset_flg: Wakeups[1] hit" );
584         CYG_TEST_CHECK( prewups[2] < wakeups[2], "iset_flg: Wakeups[2] not hit" );
585         CYG_TEST_CHECK( prewups[3] < wakeups[3], "iset_flg: Wakeups[3] not hit" );
586         CYG_TEST_CHECK( prewups[4] < wakeups[4], "iset_flg: Wakeups[4] not hit" );
587         diag_printf( "INFO:<(fg loops %10d) flag waits/sets: %2d %2d %2d >\n", count,
588                      wakeups[2] - prewups[2],
589                      wakeups[3] - prewups[3],
590                      wakeups[4] - prewups[4] );
591         prewups[2] = wakeups[2];
592         prewups[3] = wakeups[3];
593         prewups[4] = wakeups[4];
594
595         // move them on to waiting for a message box
596         intercom = MBX;
597         ercd = set_flg( 2, 0xfff );
598         CYG_TEST_CHECK( E_OK == ercd, "set_flg(2) bad ercd" );
599         ercd = set_flg( 3, 0xfff );
600         CYG_TEST_CHECK( E_OK == ercd, "set_flg(3) bad ercd" );
601         ercd = set_flg( 4, 0xfff );
602         CYG_TEST_CHECK( E_OK == ercd, "set_flg(4) bad ercd" );
603         
604         CYG_TEST_CHECK(              0 == wakeups[0], "set_flg: Wakeups[0] hit" );
605         CYG_TEST_CHECK(              0 == wakeups[1], "set_flg: Wakeups[1] hit" );
606         CYG_TEST_CHECK( prewups[2] + 1 == wakeups[2], "set_flg: Wakeups[2] not hit" );
607         CYG_TEST_CHECK( prewups[3] + 1 == wakeups[3], "set_flg: Wakeups[3] not hit" );
608         CYG_TEST_CHECK( prewups[4] + 1 == wakeups[4], "set_flg: Wakeups[4] not hit" );
609         prewups[2] = wakeups[2];
610         prewups[3] = wakeups[3];
611         prewups[4] = wakeups[4];
612         
613         // -------- TIMERS AND TIMESLICING DISABLED ---------
614         // install an isr that will wake them all up in turn
615         attach_isr( isr_snd_msg );
616         DELAY();
617         detach_isr( isr_snd_msg );
618         // -------- timers and timeslicing ENABLED ---------
619
620         CYG_TEST_CHECK(         0 == wakeups[0], "isnd_msg: Wakeups[0] hit" );
621         CYG_TEST_CHECK(         0 == wakeups[1], "isnd_msg: Wakeups[1] hit" );
622         CYG_TEST_CHECK( prewups[2] < wakeups[2], "isnd_msg: Wakeups[2] not hit" );
623         CYG_TEST_CHECK( prewups[3] < wakeups[3], "isnd_msg: Wakeups[3] not hit" );
624         CYG_TEST_CHECK( prewups[4] < wakeups[4], "isnd_msg: Wakeups[4] not hit" );
625         diag_printf( "INFO:<(fg loops %10d) message rec'pts: %2d %2d %2d >\n", count,
626                      wakeups[2] - prewups[2],
627                      wakeups[3] - prewups[3],
628                      wakeups[4] - prewups[4] );
629         prewups[2] = wakeups[2];
630         prewups[3] = wakeups[3];
631         prewups[4] = wakeups[4];
632
633         // move them on to exiting, all done
634         if ( 1 == loops )
635             // then we are about to exit
636             intercom = EXIT;
637         else
638             intercom = SLP;
639         ercd = snd_msg( 2, (T_MSG *)&intercom );
640         CYG_TEST_CHECK( E_OK == ercd, "snd_msg(2) bad ercd" );
641         ercd = snd_msg( 3, (T_MSG *)&intercom );
642         CYG_TEST_CHECK( E_OK == ercd, "snd_msg(3) bad ercd" );
643         ercd = snd_msg( 4, (T_MSG *)&intercom );
644         CYG_TEST_CHECK( E_OK == ercd, "snd_msg(4) bad ercd" );
645
646         CYG_TEST_CHECK(              0 == wakeups[0], "snd_msg: Wakeups[0] hit" );
647         CYG_TEST_CHECK(              0 == wakeups[1], "snd_msg: Wakeups[1] hit" );
648         CYG_TEST_CHECK( prewups[2] + 1 == wakeups[2], "snd_msg: Wakeups[2] not hit" );
649         CYG_TEST_CHECK( prewups[3] + 1 == wakeups[3], "snd_msg: Wakeups[3] not hit" );
650         CYG_TEST_CHECK( prewups[4] + 1 == wakeups[4], "snd_msg: Wakeups[4] not hit" );
651         prewups[2] = wakeups[2];
652         prewups[3] = wakeups[3];
653         prewups[4] = wakeups[4];
654
655         CYG_TEST_PASS( "Tested ISR invoked uITRON functions" );
656
657     } while ( 0 < --loops );
658
659     CYG_TEST_EXIT( "All done" );
660     ext_tsk();
661 }
662
663
664 void body( int n )
665 {
666     unsigned int z;
667     ER ercd;
668     T_MSG *pk_msg;
669
670     do {
671         switch ( intercom ) {
672         case NOTHING:
673             ercd = slp_tsk();
674             CYG_TEST_CHECK( E_OK == ercd, "slp_tsk (doing nothing)" );
675             continue;
676         case SLP:
677             ercd = slp_tsk();
678             CYG_TEST_CHECK( E_OK == ercd, "slp_tsk bad ercd" );
679             wakeups[ n ]++;
680             break;
681         case SEM:
682             ercd = wai_sem( n-1 ); // 1..3 for semas
683             CYG_TEST_CHECK( E_OK == ercd, "wai_sem bad ercd" );
684             wakeups[ n ]++;
685             break;
686         case FLG:
687             ercd = wai_flg( &z, n, (1<<n), TWF_CLR | TWF_ANDW );
688             CYG_TEST_CHECK( E_OK == ercd, "wai_flg bad ercd" );
689             CYG_TEST_CHECK( z & (1<<n), "Flag bit not set" );
690             wakeups[ n ]++;
691             break;
692         case MBX:
693             ercd = rcv_msg( &pk_msg, n );
694             CYG_TEST_CHECK( E_OK == ercd, "rcv_msg bad ercd" );
695             CYG_TEST_CHECK( pk_msg, "rcv_msg NULL msg" );
696             wakeups[ n ]++;
697             break;
698         case EXIT:
699             return;
700         }
701     } while ( 1 );
702 }
703
704 void task2( unsigned int arg )
705 {
706     ER ercd;
707     CYG_TEST_INFO( "Task 2 running" );
708     ercd = get_tid( &scratch );
709     CYG_TEST_CHECK( E_OK == ercd, "get_tid bad ercd" );
710     CYG_TEST_CHECK( 2 == scratch, "tid not 2" );
711     if ( 222 != arg )
712         CYG_TEST_FAIL( "Task 2 arg not 222" );
713     body(2);
714     CYG_TEST_INFO( "Task 2 exiting" );
715     ext_tsk();
716     CYG_TEST_FAIL( "Task 2 failed to exit" );
717 }
718
719 void task3( unsigned int arg )
720 {
721     ER ercd;
722     CYG_TEST_INFO("Task 3 running");
723     ercd = get_tid( &scratch );
724     CYG_TEST_CHECK( E_OK == ercd, "get_tid bad ercd" );
725     CYG_TEST_CHECK( 3 == scratch, "tid not 3" );
726     if ( 333 != arg )
727         CYG_TEST_FAIL( "Task 3 arg not 333" );
728     body(3);
729     CYG_TEST_INFO( "Task 3 exiting" );
730     ext_tsk();
731     CYG_TEST_FAIL( "Task 3 failed to exit" );
732 }
733
734 void task4( unsigned int arg )
735 {
736     ER ercd;
737     CYG_TEST_INFO("Task 4 running");
738     ercd = get_tid( &scratch );
739     CYG_TEST_CHECK( E_OK == ercd, "get_tid bad ercd" );
740     CYG_TEST_CHECK( 4 == scratch, "tid not 4" );
741     if ( 444 != arg )
742         CYG_TEST_FAIL( "Task 4 arg not 444" );
743     body(4);
744     CYG_TEST_INFO( "Task 4 exiting" );
745     ext_tsk();
746     CYG_TEST_FAIL( "Task 4 failed to exit" );
747 }
748
749 // ------------------------------------------------------------------------
750 // Start of C++ aware portion, so to speak.
751 //
752
753 #include <cyg/hal/hal_intr.h>
754 #include <cyg/kernel/intr.hxx>
755 #include <cyg/kernel/clock.hxx>
756 #include <cyg/kernel/sched.hxx>
757 #include <cyg/kernel/sched.inl>
758
759 void set_interrupt_number( void )
760 {
761     clock_interrupt = CYGNUM_HAL_INTERRUPT_RTC;
762 }
763
764 // This snippet stolen from kernel/.../clock.cxx to be able to detach
765 // the RTC from its interrupt source.
766 class Cyg_RealTimeClock
767     : public Cyg_Clock
768 {
769 public:
770     Cyg_Interrupt       interrupt;
771
772     static cyg_uint32 isr(cyg_vector vector, CYG_ADDRWORD data);
773
774     static void dsr(cyg_vector vector, cyg_ucount32 count, CYG_ADDRWORD data);
775
776     Cyg_RealTimeClock();
777 };
778
779
780 static Cyg_Interrupt uit_intr(
781         (unsigned)CYGNUM_HAL_INTERRUPT_RTC, // Vector to attach to
782         0,                              // Queue priority
783         (unsigned)0,                    // Data pointer
784         &isr_wup_tsk,                   // Interrupt Service Routine
785         &cyg_uitron_dsr                 // Deferred Service Routine
786 );
787
788 void
789 attach_isr( unsigned int (*isr)(unsigned int, unsigned int) )
790 {
791     int inuse;
792     int old_ints;
793     Cyg_RealTimeClock *prtc = (Cyg_RealTimeClock *)Cyg_Clock::real_time_clock;
794     HAL_DISABLE_INTERRUPTS(old_ints);
795     HAL_INTERRUPT_MASK( CYGNUM_HAL_INTERRUPT_RTC );
796     prtc->interrupt.detach();
797 #ifndef CYGIMP_KERNEL_INTERRUPTS_CHAIN
798     // Only check that the vector was cleared when there's a specific
799     // vector for the RTC.  In chain mode, other interrupt handlers
800     // may prevent the shared vector from being cleared when detaching
801     // the RTC ISR, and this assertion fails.
802     HAL_INTERRUPT_IN_USE( CYGNUM_HAL_INTERRUPT_RTC, inuse );
803     CYG_TEST_CHECK( !inuse, "Failed to detach clock ISR" );
804 #endif
805     uit_intr = Cyg_Interrupt( 
806         CYGNUM_HAL_INTERRUPT_RTC,       // Vector to attach to
807         1,                              // Queue priority
808         0,                              // Data pointer
809         isr,                            // Interrupt Service Routine
810         cyg_uitron_dsr                  // Deferred Service Routine
811         );    
812     uit_intr.attach();
813     HAL_INTERRUPT_IN_USE( CYGNUM_HAL_INTERRUPT_RTC, inuse );
814     CYG_TEST_CHECK( inuse, "Failed to attach new ISR" );
815     ACK_CLOCK();
816     HAL_INTERRUPT_UNMASK( CYGNUM_HAL_INTERRUPT_RTC );
817     HAL_RESTORE_INTERRUPTS(old_ints);
818 }
819
820 void
821 detach_isr( unsigned int (*isr)(unsigned int, unsigned int) )
822 {
823     int inuse;
824     int old_ints;
825     Cyg_RealTimeClock *prtc = (Cyg_RealTimeClock *)Cyg_Clock::real_time_clock;
826     HAL_DISABLE_INTERRUPTS(old_ints);
827     HAL_INTERRUPT_MASK( CYGNUM_HAL_INTERRUPT_RTC );
828     uit_intr.detach();
829 #ifndef CYGIMP_KERNEL_INTERRUPTS_CHAIN
830     // See comment above in attach_isr.
831     HAL_INTERRUPT_IN_USE( CYGNUM_HAL_INTERRUPT_RTC, inuse );
832     CYG_TEST_CHECK( !inuse, "Failed to detach my ISR" );
833 #endif
834     prtc->interrupt.attach();
835     HAL_INTERRUPT_IN_USE( CYGNUM_HAL_INTERRUPT_RTC, inuse );
836     CYG_TEST_CHECK( inuse, "Failed to attach clock ISR" );
837     ACK_CLOCK();
838     HAL_INTERRUPT_UNMASK( CYGNUM_HAL_INTERRUPT_RTC );
839     HAL_RESTORE_INTERRUPTS(old_ints);
840 }
841
842
843 void
844 lock_sched( void )
845 {
846     cyg_uint32 l;
847     Cyg_Scheduler::lock();
848     l = Cyg_Scheduler::get_sched_lock();
849     CYG_TEST_CHECK( 0 < l, "lock: Sched not locked" );
850     CYG_TEST_CHECK( 2 > l, "lock: Sched already locked" );
851 }
852
853 void
854 unlock_sched( void )
855 {
856     cyg_uint32 l;
857     l = Cyg_Scheduler::get_sched_lock();
858     CYG_TEST_CHECK( 0 < l, "unlock: Sched not locked" );
859     CYG_TEST_CHECK( 2 > l, "unlock: Sched already locked" );
860     Cyg_Scheduler::unlock();
861 }
862
863
864 #else // not enough (or too many) uITRON objects configured in
865 #define N_A_MSG "not enough uITRON objects to run test"
866 #endif // not enough (or too many) uITRON objects configured in
867 #else  // not C++ and some C++ specific options enabled
868 #define N_A_MSG "C++ specific options selected but this is C"
869 #endif  // not C++ and some C++ specific options enabled
870 #else // ! CYGVAR_KERNEL_COUNTERS_CLOCK   - can't test without it
871 #define N_A_MSG "no CYGVAR_KERNEL_COUNTERS_CLOCK"
872 #endif // ! CYGVAR_KERNEL_COUNTERS_CLOCK  - can't test without it
873 #else  // ! CYGFUN_KERNEL_THREADS_TIMER   - can't test without it
874 #define N_A_MSG "no CYGFUN_KERNEL_THREADS_TIMER"
875 #endif // ! CYGFUN_KERNEL_THREADS_TIMER   - can't test without it
876 #else  // ! CYGIMP_THREAD_PRIORITY        - can't test without it
877 #define N_A_MSG "no CYGSEM_KERNEL_SCHED_MLQUEUE"
878 #endif // ! CYGSEM_KERNEL_SCHED_MLQUEUE   - can't test without it
879 #else  // ! CYGPKG_UITRON
880 #define N_A_MSG "uITRON Compatibility layer disabled"
881 #endif // CYGPKG_UITRON
882
883 #ifdef N_A_MSG
884 externC void
885 cyg_start( void )
886 {
887     CYG_TEST_INIT();
888     CYG_TEST_NA( N_A_MSG );
889 }
890 #endif // N_A_MSG defined ie. we are N/A.
891
892 // EOF testintr.c