OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [net/] [common/] [current/] [tests/] [multi_lo_select.c] - Blame information for rev 856

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      tests/multi_lo_test.c
4
// 
5
//      Multiple selects-at-one-time test, using lo for portability.
6
//
7
//==========================================================================
8
// ####BSDALTCOPYRIGHTBEGIN####                                             
9
// -------------------------------------------                              
10
// Portions of this software may have been derived from FreeBSD, OpenBSD,   
11
// or other sources, and if so are covered by the appropriate copyright     
12
// and license included herein.                                             
13
// -------------------------------------------                              
14
// ####BSDALTCOPYRIGHTEND####                                               
15
//==========================================================================
16
//#####DESCRIPTIONBEGIN####
17
//
18
// Author(s):    sorin@netappi.com, hmt
19
// Contributors: gthomas,sorin@netappi.com
20
// Date:         2000-05-24
21
// Description:
22
//
23
//      This test is to test that the internal producer operation to select
24
//      truly has broadcast semantics; there was a bug in there whereby it
25
//      doesn't, so events get lost and/or the wrong thread is awakened.
26
//
27
//      We need to create N threads selecting on different sockets
28
//      (different ports) (including one or two selecting on several
29
//      sockets) and have a further thread or threads which send data to
30
//      the those sockets in an order "random" with respect to the order in
31
//      which the N selectors entered the wait, and their thread
32
//      priorities.
33
//
34
//      If this all works, then we know that select always wakes the right
35
//      thread in the right order.  I think...
36
//
37
//      I think 10 threads 0-9 where #2,#3,#6,#7 wait for multiple threads
38
//      will do it.  #0-4 will be prio HI, #5-9 will be prio LO.  Sender
39
//      thread A at prio MID will send to sockets 1,3,5,7,9.  Sender thread
40
//      B at prio LOWEST will send to sockets 0,2,4,6,8.
41
//
42
//      Each sender thread will wait for a different semaphore signal
43
//      before doing their next send, thus confirming correct ordering.
44
//      Two common semaphores will also be signalled, one when a send
45
//      occurs, the other when a recv happens.
46
//
47
//      The master thread will start off VERYHIGHPRI, then drop after
48
//      starting all the others, to VERYLOW... when it next runs, those
49
//      common semaphores should both have value 10 == NLISTENERS.
50
//
51
//
52
//#####DESCRIPTIONEND#####
53
//
54
//==========================================================================
55
 
56
#include <network.h>
57
 
58
#include <cyg/infra/testcase.h>
59
 
60
#ifndef CYGPKG_LIBC_STDIO
61
#define perror(s) diag_printf(#s ": %s\n", strerror(errno))
62
#endif
63
 
64
#define SOURCE_PORT1 9900
65
#define SOURCE_PORT2 9800 // for those who listen to multiple ports
66
#define SOURCE_PORT3 9700 // for the dummy consumers of events
67
 
68
#define PRIO_DUMMY 4 // Really high, so they're always right back there
69
 
70
#define PRIO_LISTENER_HI 10
71
#define PRIO_LISTENER_LO 15
72
 
73
#define PRIO_SENDER_MID  12
74
#define PRIO_SENDER_LOW  17
75
 
76
#define PRIO_MASTERHIGH   3
77
#define PRIO_MASTERLOW   25
78
 
79
#ifndef CYGPKG_IO_FILEIO
80
#if CYGPKG_IO_NFILE > 30
81
#define NLISTENERS 10
82
#else
83
// fewer threads if not many sockets available
84
#define NLISTENERS (CYGPKG_IO_NFILE/3)
85
#endif
86
#else
87
#include <pkgconf/io_fileio.h>
88
#if CYGNUM_FILEIO_NFD > 30
89
#define NLISTENERS 10
90
#else
91
// fewer threads if not many sockets available
92
#define NLISTENERS (CYGNUM_FILEIO_NFD/3)
93
#endif
94
#endif
95
 
96
#define NDUMMIES   10
97
 
98
#define NSENDERS 2
99
 
100
#define NUM_BUF  NLISTENERS
101
#define MAX_BUF 100
102
 
103
// buffers for receiving into:
104
static unsigned char data_buf1[NUM_BUF][MAX_BUF];
105
 
106
static unsigned char data_buf_write1[]="Client is alive";
107
 
108
#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL)
109
#define MASTER_STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
110
 
111
static char stack_master[MASTER_STACK_SIZE];
112
static cyg_thread master_thread_data;
113
static cyg_handle_t master_thread_handle;
114
 
115
static char stack_dummy[NDUMMIES][STACK_SIZE];
116
static cyg_thread dummy_thread_data[NDUMMIES];
117
static cyg_handle_t dummy_thread_handle[NDUMMIES];
118
 
119
static char stack_listener[NLISTENERS][STACK_SIZE];
120
static cyg_thread listener_thread_data[NLISTENERS];
121
static cyg_handle_t listener_thread_handle[NLISTENERS];
122
 
123
static char stack_sender[NSENDERS][STACK_SIZE];
124
static cyg_thread sender_thread_data[NSENDERS];
125
static cyg_handle_t sender_thread_handle[NSENDERS];
126
 
127
static cyg_sem_t listen_sema[NLISTENERS];
128
 
129
static cyg_sem_t send_sema;
130
static cyg_sem_t recv_sema;
131
 
132
static cyg_thread_entry_t master;
133
static cyg_thread_entry_t listener;
134
static cyg_thread_entry_t sender;
135
 
136
// ------------------------------------------------------------------------
137
 
138
void
139
pexit(char *s)
140
{
141
    CYG_TEST_FAIL_FINISH( s );
142
}
143
 
144
 
145
#ifndef max
146
#define max(a,b) (((a) > (b)) ? (a) : (b))
147
#endif
148
 
149
// ------------------------------------------------------------------------
150
 
151
void dummy( cyg_addrword_t which )
152
{
153
    // Share the same socket... we appear to run out otherwise.
154
    static int s_s1 = -1;
155
    static struct sockaddr_in local;
156
 
157
    // locals...
158
    fd_set in_fds;
159
    int num;
160
 
161
    CYG_TEST_CHECK( 0 <= which, "which under" );
162
    CYG_TEST_CHECK( NDUMMIES > which, "which over" );
163
 
164
    diag_printf( "Dummy %d alive\n", which );
165
 
166
    if ( s_s1 < 0 ) {
167
        s_s1 = socket(AF_INET, SOCK_STREAM, 0);
168
        if (s_s1 < 0) {
169
            pexit("stream socket 1");
170
        }
171
        memset(&local, 0, sizeof(local));
172
        local.sin_family = AF_INET;
173
        local.sin_len = sizeof(local);
174
        local.sin_port = ntohs(SOURCE_PORT3 + which);
175
        local.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
176
        if(bind(s_s1, (struct sockaddr *) &local, sizeof(local)) < 0) {
177
            pexit("dummy bind /source_1/ error");
178
        }
179
        listen(s_s1, SOMAXCONN);
180
    }
181
 
182
    while (true) {
183
        FD_ZERO(&in_fds);
184
        FD_SET(s_s1, &in_fds);
185
        num = select( s_s1+1, &in_fds,0,0,0);
186
 
187
        if (FD_ISSET(s_s1,&in_fds)) {
188
            CYG_TEST_FAIL( "Activity on dummy port!" );
189
        }
190
    }   /* while (true) */
191
}
192
 
193
// ------------------------------------------------------------------------
194
 
195
void listener( cyg_addrword_t which )
196
{
197
    int s_s1 = -1, e_s1 = 0, s_s2 = -1, e_s2 = 0;
198
    struct sockaddr_in e_s1_addr,e_s2_addr,local;
199
    fd_set in_fds;
200
    socklen_t len;
201
    int num;
202
 
203
    // do we select on multiple sources?
204
    int dual = (3 == (which & 3)) || (2 == (which & 3));
205
    // then which is 2,3,6,7 so set up a 2nd listener
206
 
207
    CYG_TEST_CHECK( 0 <= which, "which under" );
208
    CYG_TEST_CHECK( NLISTENERS > which, "which over" );
209
 
210
    diag_printf( "Listener %d alive [%s]\n", which, dual ? "dual" : "single" );
211
 
212
    s_s1 = socket(AF_INET, SOCK_STREAM, 0);
213
    if (s_s1 < 0) {
214
        pexit("stream socket 1");
215
    }
216
    memset(&local, 0, sizeof(local));
217
    local.sin_family = AF_INET;
218
    local.sin_len = sizeof(local);
219
    local.sin_port = ntohs(SOURCE_PORT1 + which);
220
    local.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
221
    if(bind(s_s1, (struct sockaddr *) &local, sizeof(local)) < 0) {
222
        pexit("bind /source_1/ error");
223
    }
224
    listen(s_s1, SOMAXCONN);
225
 
226
    if ( dual ) {
227
        s_s2 = socket(AF_INET, SOCK_STREAM, 0);
228
        if (s_s2 < 0) {
229
            pexit("stream socket 2");
230
        }
231
        memset(&local, 0, sizeof(local));
232
        local.sin_family = AF_INET;
233
        local.sin_len = sizeof(local);
234
        local.sin_port = ntohs(SOURCE_PORT2 + which);
235
        local.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
236
        if(bind(s_s2, (struct sockaddr *) &local, sizeof(local)) < 0) {
237
            pexit("bind /source_2/ error");
238
        }
239
        listen(s_s2, SOMAXCONN);
240
    }
241
 
242
    while (true) {
243
        FD_ZERO(&in_fds);
244
        FD_SET(s_s1, &in_fds);
245
        if ( dual )
246
            FD_SET(s_s2, &in_fds);
247
        num = select ( max(s_s1,s_s2)+1, &in_fds,0,0,0);
248
 
249
        if (FD_ISSET(s_s1,&in_fds)) {
250
            len = sizeof(e_s1_addr);
251
            if ((e_s1 = accept(s_s1,(struct sockaddr *)&e_s1_addr,&len))<0) {
252
                pexit("accept /source_1/");
253
            }
254
            diag_printf("TCP SERVER connection from %s: %d\n",
255
                        inet_ntoa(e_s1_addr.sin_addr),ntohs(e_s1_addr.sin_port));
256
        }
257
 
258
        if ( dual ) {
259
            if (FD_ISSET(s_s2,&in_fds)) {
260
                len = sizeof(e_s2_addr);
261
                if ((e_s2 = accept(s_s2,(struct sockaddr *)&e_s2_addr,&len))<0) {
262
                    pexit("accept /source_2/");
263
                }
264
                diag_printf("TCP SERVER connection from %s: %d\n",
265
                            inet_ntoa(e_s2_addr.sin_addr), ntohs(e_s2_addr.sin_port));
266
            }
267
        }
268
        if ((e_s1 != 0) || ( e_s2 != 0)) {
269
            break;
270
        }
271
    }   /* while (true) */
272
 
273
    CYG_TEST_CHECK( 0 != e_s1, "No connection made on s1!" );
274
 
275
    if ((len = read(e_s1, data_buf1[which], MAX_BUF)) < 0  ) {
276
        perror("I/O error s1");
277
        CYG_TEST_FAIL( "Read s1 failed" );
278
    }
279
    diag_printf("Listener %d: %s\n", which, data_buf1[which]);
280
 
281
    close( s_s1 );
282
    if ( dual )
283
        close( s_s2 );
284
    if ( 0 != e_s1 )
285
        close ( e_s1 );
286
    if ( 0 != e_s2 )
287
        close ( e_s2 );
288
 
289
    cyg_semaphore_post( &listen_sema[which] ); // Verify that I was here
290
    cyg_semaphore_post( &recv_sema );          // Count receptions
291
 
292
    cyg_thread_exit(); // explicitly
293
}
294
 
295
// ------------------------------------------------------------------------
296
static void sender( cyg_addrword_t which ) // which means which set (odd/even) here...
297
{
298
    int s_source;
299
    struct sockaddr_in local;
300
    int len;
301
 
302
    diag_printf("client %d [%s] :started\n", which, (which & 1) ? "odd" : "even" );
303
 
304
    for ( /* which as is */; which < NLISTENERS; which += 2 ) {
305
 
306
        s_source = socket(AF_INET, SOCK_STREAM, 0);
307
        if (s_source < 0) {
308
            pexit("stream socket");
309
        }
310
        memset(&local, 0, sizeof(local));
311
        local.sin_family = AF_INET;
312
        local.sin_len = sizeof(local);
313
        local.sin_port = htons( SOURCE_PORT1 + which );
314
        local.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
315
 
316
        if (connect(s_source, (struct sockaddr *)&local, sizeof(local)) < 0) {
317
            pexit("Can't connect to target");
318
        }
319
 
320
        if ((len = write(s_source,data_buf_write1,sizeof(data_buf_write1) )) < 0) {
321
            CYG_TEST_FAIL_FINISH("Error writing buffer");
322
        }
323
        cyg_semaphore_wait( &listen_sema[which] ); // wait for the appropriate semaphore "reply"
324
        cyg_semaphore_post( &send_sema ); // count up successful sends
325
 
326
        close ( s_source );
327
    }
328
    cyg_thread_exit(); // explicitly
329
}
330
 
331
 
332
static void
333
master(cyg_addrword_t param)
334
{
335
    int i;
336
    cyg_handle_t self = cyg_thread_self();
337
 
338
    cyg_semaphore_init( &send_sema, 0 );
339
    cyg_semaphore_init( &recv_sema, 0 );
340
 
341
    for ( i = 0 ; i < NLISTENERS; i++ )
342
        cyg_semaphore_init( &listen_sema[i], 0 );
343
 
344
    init_all_network_interfaces();
345
    CYG_TEST_INFO("Start multiple loopback select test");
346
#if NLOOP > 0
347
    // We are currently running at high prio, so we can just go and make
348
    // loads of threads:
349
 
350
    // Some at higher prio
351
    for ( i = 0; i < NLISTENERS/2; i++ )
352
        cyg_thread_create(PRIO_LISTENER_HI,       // Priority
353
                          listener,               // entry
354
                          i,                      // entry parameter
355
                          "listener",             // Name
356
                          &stack_listener[i][0],  // Stack
357
                          STACK_SIZE,             // Size
358
                          &listener_thread_handle[i], // Handle
359
                          &listener_thread_data[i] // Thread data structure
360
            );
361
    // the rest at lower prio
362
    for (      ; i < NLISTENERS  ; i++ )
363
        cyg_thread_create(PRIO_LISTENER_LO,       // Priority
364
                          listener,               // entry
365
                          i,                      // entry parameter
366
                          "listener",             // Name
367
                          &stack_listener[i][0],  // Stack
368
                          STACK_SIZE,             // Size
369
                          &listener_thread_handle[i], // Handle
370
                          &listener_thread_data[i] // Thread data structure
371
            );
372
 
373
    // make the dummy event-grabber threads
374
    for ( i = 0; i < NDUMMIES; i++ )
375
        cyg_thread_create(PRIO_DUMMY,             // Priority
376
                          dummy,                  // entry
377
                          i,                      // entry parameter
378
                          "dummy",                // Name
379
                          &stack_dummy[i][0],     // Stack
380
                          STACK_SIZE,             // Size
381
                          &dummy_thread_handle[i], // Handle
382
                          &dummy_thread_data[i]   // Thread data structure
383
            );
384
 
385
    // Start those threads
386
    for ( i = 0; i < NLISTENERS; i++ )
387
        cyg_thread_resume(listener_thread_handle[i]);
388
    for ( i = 0; i < NDUMMIES; i++ )
389
        cyg_thread_resume(   dummy_thread_handle[i]);
390
 
391
    // and let them start up and start listening...
392
    cyg_thread_set_priority( self, PRIO_MASTERLOW );
393
    CYG_TEST_INFO("All listeners should be go now");
394
    cyg_thread_set_priority( self, PRIO_MASTERHIGH );
395
 
396
    for ( i = 0; i < NSENDERS; i++ ) {
397
        cyg_thread_create( (0 == i)
398
                           ?PRIO_SENDER_MID
399
                           : PRIO_SENDER_LOW,     // Priority
400
                           sender,                // entry
401
                           i,                     // entry parameter
402
                           "sender",              // Name
403
                           &stack_sender[i][0],   // Stack
404
                           STACK_SIZE,            // Size
405
                           &sender_thread_handle[i], // Handle
406
                           &sender_thread_data[i] // Thread data structure
407
            );
408
        cyg_thread_resume(sender_thread_handle[i]);
409
    }
410
 
411
    // Now we are still higher priority; so go low and let everyone else
412
    // have their head.  When we next run after this, it should all be
413
    // over.
414
    cyg_thread_set_priority( self, PRIO_MASTERLOW );
415
 
416
    cyg_semaphore_peek( &recv_sema, &i );
417
    CYG_TEST_CHECK( NLISTENERS == i, "Not enough recvs occurred!" );
418
 
419
    cyg_semaphore_peek( &send_sema, &i );
420
    CYG_TEST_CHECK( NLISTENERS == i, "Not enough sends occurred!" );
421
 
422
    CYG_TEST_PASS_FINISH("Master returned OK");
423
#endif
424
    CYG_TEST_NA( "No loopback devs" );
425
}
426
 
427
void
428
cyg_user_start(void)
429
{
430
    CYG_TEST_INIT();
431
 
432
    cyg_thread_create(PRIO_MASTERHIGH,            // Priority
433
                      master,                     // entry
434
                      0,                          // entry parameter
435
                      "master",                   // Name
436
                      &stack_master[0],           // Stack
437
                      MASTER_STACK_SIZE,          // Size
438
                      &master_thread_handle,      // Handle
439
                      &master_thread_data         // Thread data structure
440
            );
441
    cyg_thread_resume(master_thread_handle);      // Start it
442
}
443
 
444
// EOF multi_lo_select.c

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.