]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/io/fileio/v2_0/tests/pselect.c
Initial revision
[karo-tx-redboot.git] / packages / io / fileio / v2_0 / tests / pselect.c
1 //==========================================================================
2 //
3 //      pselect.c
4 //
5 //      Test pselect implementation
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 // Copyright (C) 2002 Nick Garnett
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):           nickg
45 // Contributors:        nickg
46 // Date:                2002-11-08
47 // Purpose:             Test pselect implementation
48 // Description:         
49 //                      
50 //                      
51 //                      
52 //
53 //####DESCRIPTIONEND####
54 //
55 //==========================================================================
56
57 #include <pkgconf/system.h>
58 #include <pkgconf/isoinfra.h>
59 #ifdef CYGPKG_POSIX
60 #include <pkgconf/posix.h>
61 #endif
62
63 #ifndef CYGINT_ISO_PTHREAD_IMPL
64 # define NA_MSG "POSIX threads needed to run test"
65 #elif !defined(CYGPKG_NET)
66 # define NA_MSG "NET package needed to run test"
67 #elif !defined(CYGPKG_POSIX_SIGNALS)
68 # define NA_MSG "POSIX signals package needed to run test"
69 #endif
70
71 #include <cyg/infra/testcase.h>
72
73 #ifndef NA_MSG
74
75 #include <pkgconf/hal.h>
76 #include <pkgconf/kernel.h>
77 #include <pkgconf/io_fileio.h>
78
79 #define __ECOS 1                        // dont like this at all
80
81 #include <cyg/kernel/ktypes.h>         // base kernel types
82 #include <cyg/infra/cyg_trac.h>        // tracing macros
83 #include <cyg/infra/cyg_ass.h>         // assertion macros
84
85 #include <unistd.h>
86 #include <fcntl.h>
87 #include <sys/stat.h>
88 #include <errno.h>
89 #include <string.h>
90
91 #include <network.h>
92 #include <arpa/inet.h>
93
94 #include <pthread.h>
95 #include <signal.h>
96
97 #include <sys/select.h>
98
99
100 #include <cyg/infra/diag.h>            // HAL polled output
101
102 #define NUM_TEST_SIGNALS 1500          // So test completes in ~30 seconds
103
104 //--------------------------------------------------------------------------
105
106 #define SHOW_RESULT( _fn, _res ) \
107 diag_printf("INFO: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");
108
109 //--------------------------------------------------------------------------
110 // Thread stacks
111
112 char thread1_stack[PTHREAD_STACK_MIN*2];
113 char thread2_stack[PTHREAD_STACK_MIN*2];
114
115 //--------------------------------------------------------------------------
116 // Local variables
117
118 // Thread IDs
119 pthread_t thread1;
120 pthread_t thread2;
121
122 struct sockaddr_in sa;
123
124 volatile int sigusr1_calls = 0;
125 volatile int sigusr1_sent = 0;
126 volatile int pselect_wakeups = 0;
127 volatile int pselect_eintr = 0;
128
129 volatile cyg_bool running = true;
130
131 //--------------------------------------------------------------------------
132
133 void show_fdsets( char *s, int nfd, fd_set *rd, fd_set *wr, fd_set *ex )
134 {
135     int i;
136     diag_printf("INFO:<%s nfd %d ",s,nfd);
137
138     if( rd )
139     {
140         diag_printf("rd: [");
141         for( i = 0; i < nfd ; i++ )
142             if( FD_ISSET( i, rd ) ) diag_printf("%d ",i);
143         diag_printf("] ");        
144     }    
145     if( wr )
146     {
147         diag_printf("wr: [");                
148         for( i = 0; i < nfd ; i++ )
149             if( FD_ISSET( i, wr ) ) diag_printf("%d ",i);
150         diag_printf("] ");        
151     }
152     if( ex )
153     {
154         diag_printf("ex: [");                
155         for( i = 0; i < nfd ; i++ )
156             if( FD_ISSET( i, ex ) ) diag_printf("%d ",i);
157         diag_printf("] ");                
158     }
159
160     diag_printf(">\n");
161 }
162
163 //--------------------------------------------------------------------------
164
165 void sigusr1( int sig, siginfo_t *info, void *context )
166 {
167     CYG_TEST_CHECK( pthread_self() == thread1, "Sigusr1: not called by thread 1\n");
168     
169     sigusr1_calls++;
170 }
171
172 //--------------------------------------------------------------------------
173 // Selecting thread
174
175 // This thread just opens up a socket ready to accept a connection and
176 // then calls pselect() to wait for it. The timeout is set to 0 so we
177 // actually just poll.
178
179 void *pthread_entry1( void *arg)
180 {
181     int fd = 0;
182     int err;
183     fd_set rd, wr;
184     sigset_t mask, oldmask;
185     struct sigaction sigact;
186     struct timespec ts;
187     
188     CYG_TEST_INFO( "Thread 1 running" );
189
190     FD_ZERO( &rd );
191     FD_ZERO( &wr );
192
193     sigfillset( &mask );
194     pthread_sigmask( SIG_SETMASK, &mask, &oldmask );
195     
196     sigdelset( &mask, SIGUSR1 );
197
198     sigact.sa_mask = mask;
199     sigact.sa_flags = SA_SIGINFO;
200     sigact.sa_sigaction = sigusr1;
201
202     err = sigaction( SIGUSR1, &sigact, NULL );
203     if( err < 0 ) SHOW_RESULT( sigact, err );
204
205     CYG_TEST_INFO( "Thread1: calling socket()");        
206     fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
207     if( fd < 0 ) SHOW_RESULT( socket, fd );
208     CYG_TEST_CHECK( fd >= 0, "socket() returned error");
209
210     CYG_TEST_INFO( "Thread1: calling bind()");
211     err = bind( fd, (struct sockaddr *)&sa, sizeof(sa));
212     if( err < 0 ) SHOW_RESULT( bind, err );    
213     CYG_TEST_CHECK( err == 0, "bind() returned error");
214
215     CYG_TEST_INFO( "Thread1: calling listen()");
216     err = listen( fd, 3);
217     if( err < 0 ) SHOW_RESULT( listen, err );    
218     CYG_TEST_CHECK( err == 0, "listen() returned error");
219
220     FD_SET( fd, &rd );
221
222     ts.tv_sec = 0;
223     ts.tv_nsec = 0;
224         
225     
226     while( running )
227     {
228         fd_set rd_res = rd;
229         fd_set wr_res = wr;
230
231 //        ts.tv_nsec = 1000000 * (pselect_wakeups % 10);
232         
233         err = pselect( 8, &rd_res, &wr_res, NULL, &ts, &mask );
234         if( err < 0 )
235         {
236             if( errno == EINTR ) pselect_eintr++;
237             else SHOW_RESULT( pselect, err );
238         }
239         if( err > 0 ) show_fdsets( "Thread1 result: ", 8, &rd_res, &wr_res, NULL );
240         pselect_wakeups++;
241         
242     }
243
244     // If we were interrupted at just the wrong point above we may still
245     // have a SIGUSR1 signal pending that we didn't handle, and so won't
246     // have accounted for. So let's look...
247     CYG_TEST_CHECK( 0 == sigpending( &mask ), "sigpending() returned error");
248     if (1 == sigismember(&mask, SIGUSR1) )
249         pselect_eintr++;
250
251     pthread_sigmask( SIG_SETMASK, &oldmask, NULL );
252
253     pthread_exit(arg);
254 }
255
256 //--------------------------------------------------------------------------
257
258 void *pthread_entry2( void *arg)
259 {
260     struct timespec zzz;
261     int err;
262     
263     zzz.tv_sec = 0;
264     zzz.tv_nsec = 10*1000000;
265     
266     CYG_TEST_INFO( "Thread 2: running" );
267
268     CYG_TEST_INFO( "Thread 2: sleeping" );
269     nanosleep( &zzz, NULL );
270     nanosleep( &zzz, NULL );
271     nanosleep( &zzz, NULL );
272     
273     while( sigusr1_sent < NUM_TEST_SIGNALS )
274     {
275         nanosleep( &zzz, NULL );
276
277         err = pthread_kill( thread1, SIGUSR1 );
278         if( err < 0 ) SHOW_RESULT( pthread_kill, err );
279
280         sigusr1_sent++;
281
282         if( (sigusr1_sent % 500) == 0 )
283             diag_printf("INFO: <Thread 2: %d signals sent>\n",sigusr1_sent);
284     }
285
286     running = false;
287         
288     CYG_TEST_INFO( "Thread 2: exit" );
289     pthread_exit( arg );
290 }
291
292 //==========================================================================
293 // main
294
295 int main( int argc, char **argv )
296 {
297     void *retval;
298     pthread_attr_t attr;
299     struct sched_param schedparam;
300
301     CYG_TEST_INIT();
302
303     sa.sin_family = AF_INET;
304     sa.sin_len = sizeof(sa);
305     inet_aton("127.0.0.1", &sa.sin_addr);
306     sa.sin_port = htons(1234);
307     init_all_network_interfaces();
308     
309     // Create test threads
310
311     {
312         pthread_attr_init( &attr );
313
314         schedparam.sched_priority = 5;
315         pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
316         pthread_attr_setschedpolicy( &attr, SCHED_RR );
317         pthread_attr_setschedparam( &attr, &schedparam );
318         pthread_attr_setstackaddr( &attr, (void *)&thread1_stack[sizeof(thread1_stack)] );
319         pthread_attr_setstacksize( &attr, sizeof(thread1_stack) );
320
321         pthread_create( &thread1,
322                         &attr,
323                         pthread_entry1,
324                         (void *)0x12345671);
325     }
326
327     {
328         pthread_attr_init( &attr );
329
330         schedparam.sched_priority = 10;
331         pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
332         pthread_attr_setschedpolicy( &attr, SCHED_RR );
333         pthread_attr_setschedparam( &attr, &schedparam );
334         pthread_attr_setstackaddr( &attr, (void *)&thread2_stack[sizeof(thread2_stack)] );
335         pthread_attr_setstacksize( &attr, sizeof(thread2_stack) );
336
337         pthread_create( &thread2,
338                         &attr,
339                         pthread_entry2,
340                         (void *)0x12345672);
341     }
342     
343     // Now join with thread1
344     CYG_TEST_INFO( "Main: calling pthread_join(thread1)");
345     pthread_join( thread1, &retval );
346
347     // And thread 2
348     CYG_TEST_INFO( "Main: calling pthread_join(thread2)");
349     pthread_join( thread2, &retval );
350
351     diag_printf("INFO: pselect returns: %d\n", pselect_wakeups );
352     diag_printf("INFO: pselect EINTR returns: %d\n", pselect_eintr );
353     diag_printf("INFO: SIGUSR1 sent: %d\n", sigusr1_sent );
354     diag_printf("INFO: SIGUSR1 delivered: %d\n", sigusr1_calls );
355     
356     CYG_TEST_CHECK( sigusr1_sent == sigusr1_calls, "SIGUSR1 calls != delivered");
357     CYG_TEST_CHECK( sigusr1_sent == pselect_eintr, "SIGUSR1 calls != pselect EINTR wakeups");
358     
359     CYG_TEST_PASS_FINISH("pselect");
360 }
361
362 #else
363
364 //==========================================================================
365 // main
366
367 void cyg_start(void)
368 {
369     CYG_TEST_INIT();
370
371     CYG_TEST_NA(NA_MSG);
372 }
373
374 #endif
375