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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [compat/] [posix/] [current/] [src/] [mqueue.cxx] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
/*========================================================================
2
//
3
//      mqueue.cxx
4
//
5
//      Message queues tests
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 Free Software Foundation, 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
16
// version.
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT
19
// ANY 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
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
26
//
27
// As a special exception, if other files instantiate templates or use
28
// macros or inline functions from this file, or you compile this file
29
// and link it with other works to produce a work based on this file,
30
// this file does not by itself cause the resulting work to be covered by
31
// the GNU General Public License. However the source code for this file
32
// must still be made available in accordance with section (3) of the GNU
33
// General Public License v2.
34
//
35
// This exception does not invalidate any other reasons why a work based
36
// on this file might be covered by the GNU General Public License.
37
// -------------------------------------------
38
// ####ECOSGPLCOPYRIGHTEND####
39
//========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):     jlarmour
43
// Contributors:
44
// Date:          2000-05-14
45
// Purpose:       This file provides the implementation for POSIX message
46
//                queues
47
// Description:   It uses eCos kernel mqueues as the underlying
48
//                implementation
49
// Usage:
50
//
51
//####DESCRIPTIONEND####
52
//
53
//======================================================================
54
*/
55
 
56
/* CONFIGURATION */
57
 
58
#include <pkgconf/posix.h>
59
 
60
#include <pkgconf/kernel.h>
61
 
62
/* INCLUDES */
63
 
64
#include <cyg/infra/cyg_type.h>      // common types etc.
65
#include <cyg/infra/cyg_ass.h>       // Assertion support
66
#include <cyg/infra/cyg_trac.h>      // Tracing support
67
#include <cyg/kernel/mqueue.hxx>     // eCos Mqueue Header
68
#include <cyg/kernel/sched.hxx>      // Cyg_Scheduler::lock()
69
#include <cyg/kernel/sched.inl>      // inlines for above
70
#include <mqueue.h>                  // Standard POSIX mqueue header
71
#include <sys/types.h>               // mode_t, ssize_t
72
#include <limits.h>                  // PATH_MAX
73
#include <stdlib.h>                  // malloc, etc.
74
#include <errno.h>                   // errno
75
#include <fcntl.h>                   // O_*
76
#include <stdarg.h>                  // varargs
77
#include <pthread.h>                 // mutexes
78
#include <string.h>                  // strncpy
79
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
80
# include <signal.h>
81
# include "pprivate.h"               // cyg_sigqueue()
82
#endif
83
#ifdef CYGFUN_KERNEL_THREADS_TIMER
84
# include <time.h>
85
# include "pprivate.h"               // cyg_timespec_to_ticks()
86
#endif
87
 
88
/* CONSTANTS */
89
 
90
#define MQ_VALID_MAGIC  0x6db256c1
91
 
92
/* TYPE DEFINITIONS */
93
 
94
struct mqtabent;
95
 
96
// this is a queue user - each one of these corresponds to a mqd_t
97
struct mquser {
98
    int flags;               // O_RDONLY, O_WRONLY, O_RDWR, O_NONBLOCK
99
    struct mqtabent *tabent; // back pointer to table entry
100
    struct mquser *next;
101
    bool notifieruser;       // POSIX sucks so bad. It requires a mq_close
102
                             // to only deregister the notification if it
103
                             // was done via this descriptor. So we have to
104
                             // know if it was this one
105
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
106
    cyg_uint32 magic;        // magic number: MQ_VALID_MAGIC if valid
107
#endif    
108
};
109
 
110
struct mqtabent {
111
    char name[ PATH_MAX ]; // ascii name - set to "" when unused
112
    Cyg_Mqueue *mq;        // the underlying queue object
113
    long maxmsg;           // as set on creation
114
    long msgsize;          // as set on creation
115
    bool unlinkme;         // unlink when final user closes?
116
    struct mquser *users;  // each user
117
 
118
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
119
    const struct sigevent *sigev; // notification event
120
#endif
121
};
122
 
123
/* GLOBALS */
124
 
125
static struct mqtabent mqtab[ CYGNUM_POSIX_MQUEUE_OPEN_MAX ];
126
static pthread_mutex_t mqtab_mut = PTHREAD_MUTEX_INITIALIZER;
127
 
128
/* LOCAL FUNCTIONS */
129
 
130
//------------------------------------------------------------------------
131
 
132
// placement new definition
133
inline void *operator new(size_t size, void *ptr)
134
{
135
    CYG_CHECK_DATA_PTR( ptr, "Bad pointer" );
136
    return ptr;
137
}
138
 
139
// Deallocation callback from Cyg_Mqueue
140
static void
141
my_free( void *ptr, size_t )
142
{
143
    free( ptr );
144
}
145
 
146
//------------------------------------------------------------------------
147
 
148
// Do the actual "unlink" of a queue, i.e. mark it invalid in the table.
149
// The table mutex is assumed to be locked
150
static void
151
do_mq_unlink( struct mqtabent *tabent )
152
{
153
    CYG_REPORT_FUNCTION();
154
    CYG_CHECK_DATA_PTRC( tabent );
155
 
156
    tabent->name[0] = '\0'; // won't match anything the user sends now
157
    tabent->mq->~Cyg_Mqueue();
158
    free( tabent->mq );
159
    tabent->mq=NULL;
160
 
161
    CYG_REPORT_RETURN();
162
}
163
 
164
//------------------------------------------------------------------------
165
 
166
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
167
 
168
static void
169
notifyme( Cyg_Mqueue &q, CYG_ADDRWORD data )
170
{
171
    CYG_REPORT_FUNCTION();
172
    struct mquser *user = (struct mquser *)data;
173
    CYG_CHECK_DATA_PTRC( user );
174
    struct mqtabent *tabent = user->tabent;
175
    CYG_CHECK_DATA_PTRC( tabent );
176
 
177
    Cyg_Scheduler::lock();
178
    // we may have been pre-empted before this, so check there's still a
179
    // notification to do
180
 
181
    if ( NULL == tabent->sigev ) {
182
        Cyg_Scheduler::unlock();
183
        CYG_REPORT_RETURN();
184
        return;
185
    } // if
186
 
187
    const struct sigevent *ev = tabent->sigev;
188
 
189
    // first deregister
190
    q.setnotify( NULL, 0 );
191
    tabent->sigev = NULL;
192
    user->notifieruser = false; // not any more
193
 
194
    // now the rest of the world can go
195
    Cyg_Scheduler::unlock();
196
 
197
    // queue event. If it fails... nothing we can do :-( so ignore return code
198
    cyg_sigqueue( ev, SI_MESGQ );
199
 
200
    cyg_deliver_signals();
201
 
202
    CYG_REPORT_RETURN();
203
}
204
 
205
#endif // ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
206
 
207
//------------------------------------------------------------------------
208
 
209
/* EXPORTED FUNCTIONS */
210
 
211
externC mqd_t
212
mq_open( const char *name, int oflag, ... )
213
{
214
    CYG_REPORT_FUNCTYPE( "returning %08x" );
215
    CYG_REPORT_FUNCARG2( "name=%08x, oflag=%d", name, oflag );
216
    CYG_CHECK_DATA_PTRC( name );
217
 
218
    if ( ((oflag & O_RDONLY) != O_RDONLY) &&
219
         ((oflag & O_WRONLY) != O_WRONLY) &&
220
         ((oflag & O_RDWR) != O_RDWR)) {
221
        // user didn't specify mode
222
        errno = EINVAL;
223
        CYG_REPORT_RETVAL( -1 );
224
        return (mqd_t)-1;
225
    } // if
226
 
227
    mqd_t retval;
228
    cyg_ucount32 i;
229
    struct mqtabent *qtabent=NULL;
230
    int interr CYGBLD_ATTRIB_UNUSED;
231
 
232
    interr = pthread_mutex_lock( &mqtab_mut );
233
    // should never fail
234
    CYG_ASSERT( interr == 0, "internal lock failed!" );
235
 
236
    // find if a matching entry exists first
237
    // FIXME: Should check for length and return ENAMETOOLONG
238
    for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
239
        if ( 0 == strncmp(name, mqtab[i].name, PATH_MAX) ) {
240
            qtabent = &mqtab[i];
241
            break;
242
        } // if
243
    } // for
244
 
245
    if ( (NULL != qtabent) && (O_EXCL == (oflag & O_EXCL)) ) {
246
        errno = EEXIST;
247
        retval = (mqd_t)-1;
248
        goto exit_unlock;
249
    }
250
 
251
    if ( (NULL == qtabent) && (O_CREAT != (oflag & O_CREAT)) ) {
252
        errno = ENOENT;
253
        retval = (mqd_t)-1;
254
        goto exit_unlock;
255
    }
256
 
257
    // so if we didn't find something, we must be being asked to create it
258
    if (NULL == qtabent) {
259
        mode_t mode CYGBLD_ATTRIB_UNUSED; // FIXME: mode ignored for now
260
        const struct mq_attr *attr;
261
        const struct mq_attr default_attr = { 0, MQ_OPEN_MAX, 128 };
262
        va_list args;
263
 
264
        va_start( args, oflag );
265
        mode = va_arg( args, mode_t );
266
        attr = va_arg( args, struct mq_attr * );
267
        va_end( args );
268
 
269
        // find an empty table entry
270
        for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
271
            if ( NULL == mqtab[i].mq )
272
                break;
273
        }
274
 
275
        // if not found, table is full
276
        if ( i == CYGNUM_POSIX_MQUEUE_OPEN_MAX ) {
277
            errno = ENFILE;
278
            retval = (mqd_t)-1;
279
            goto exit_unlock;
280
        }
281
 
282
        Cyg_Mqueue::qerr_t qerr;
283
 
284
        // user can specify NULL attr, which means arbitrary message queue
285
        // size! Duh.
286
        if ( NULL == attr )
287
            attr = &default_attr;
288
        else {
289
            // if they do supply one, POSIX says we're meant to check it
290
            if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) {
291
                errno = EINVAL;
292
                retval = (mqd_t)-1;
293
                goto exit_unlock;
294
            }
295
        } // else
296
 
297
        // allocate the underlying queue
298
        Cyg_Mqueue *mqholder = (Cyg_Mqueue *)malloc( sizeof(Cyg_Mqueue) );
299
        if ( NULL == mqholder ) {
300
            errno = ENOSPC;
301
            retval = (mqd_t)-1;
302
            goto exit_unlock;
303
        }
304
 
305
        // construct it with placement new
306
        mqtab[i].mq = new (mqholder) Cyg_Mqueue( attr->mq_maxmsg,
307
                                                 attr->mq_msgsize,
308
                                                 &malloc, &my_free, &qerr );
309
 
310
        switch (qerr) {
311
        case Cyg_Mqueue::OK:
312
            break;
313
        case Cyg_Mqueue::NOMEM:
314
            free( mqholder );
315
            errno = ENOSPC;
316
            retval = (mqd_t)-1;
317
            goto exit_unlock;
318
        default:
319
            CYG_FAIL("Unhandled Cyg_Mqueue constructor return error");
320
            break;
321
        } // switch
322
 
323
        mqtab[i].users = (struct mquser *) malloc( sizeof(struct mquser) );
324
        if ( NULL == mqtab[i].users ) {
325
            mqtab[i].mq->~Cyg_Mqueue();
326
            free( mqholder );
327
            errno = ENOSPC;
328
            retval = (mqd_t)-1;
329
            goto exit_unlock;
330
        }
331
 
332
        // initialize mqtab[i]
333
        mqtab[i].maxmsg  = attr->mq_maxmsg;
334
        mqtab[i].msgsize = attr->mq_msgsize;
335
        mqtab[i].unlinkme = false;
336
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
337
        mqtab[i].sigev = NULL;
338
#endif
339
        strncpy( mqtab[i].name, name, PATH_MAX );
340
 
341
        // initialize first mqtab[i].users
342
        mqtab[i].users->next = NULL;
343
        // set the mode for later, but also note that O_NONBLOCK can
344
        // be set in oflags *or* the attr the user passed
345
        mqtab[i].users->flags = oflag | (attr->mq_flags & O_NONBLOCK);
346
 
347
        // set back pointer so that message queue handle can find actual queue
348
        mqtab[i].users->tabent = &mqtab[i];
349
 
350
        mqtab[i].users->notifieruser = false;
351
 
352
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
353
        mqtab[i].users->magic = MQ_VALID_MAGIC; // now valid
354
#endif
355
 
356
        retval=(mqd_t)mqtab[i].users;
357
 
358
        goto exit_unlock;
359
    } // if (NULL == qtabent)
360
 
361
    // so we're not creating, and we have a valid qtabent
362
 
363
    // But this qtabent may be being unlinked. If so, we are permitted
364
    // to return an error, so we will. (see under mq_unlink() in POSIX)
365
    // Which error though? EINVAL seems best, but POSIX doesn't say :-/
366
 
367
    if (true == qtabent->unlinkme) {
368
        errno = EINVAL;
369
        retval = (mqd_t)-1;
370
        goto exit_unlock;
371
    }
372
 
373
    // now we have a usable qtabent
374
 
375
    struct mquser *user;
376
    user = (struct mquser *) malloc( sizeof(struct mquser) );
377
    if ( NULL == user ) {
378
            errno = ENOSPC;
379
            retval = (mqd_t)-1;
380
            goto exit_unlock;
381
    }
382
 
383
    // prepend to qtab user list
384
    user->next = qtabent->users;
385
    qtabent->users = user;
386
 
387
    // set back pointer so that message queue handle can find actual queue
388
    user->tabent = qtabent;
389
 
390
    user->flags = oflag;
391
 
392
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
393
    user->magic = MQ_VALID_MAGIC; // now valid
394
#endif
395
 
396
    retval=(mqd_t)user;
397
 
398
 exit_unlock:
399
    interr = pthread_mutex_unlock( &mqtab_mut );
400
    // should never fail
401
    CYG_ASSERT( interr == 0, "internal lock failed!" );
402
    CYG_REPORT_RETVAL( retval );
403
    return retval;
404
} // mq_open()
405
 
406
//------------------------------------------------------------------------
407
 
408
// NOTE: It is the *user*'s responsibility to ensure that nothing is
409
// blocked in mq_send() or mq_receive() when closing the queue with
410
// that descriptor. The standard does not specify the behaviour, so that's
411
// what I am assuming
412
 
413
externC int
414
mq_close( mqd_t mqdes )
415
{
416
    CYG_REPORT_FUNCTYPE( "returning %d" );
417
    CYG_REPORT_FUNCARG1XV( mqdes );
418
 
419
    struct mquser *user = (struct mquser *)mqdes;
420
 
421
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
422
    if ( user->magic != MQ_VALID_MAGIC ) {
423
        errno  = EBADF;
424
        CYG_REPORT_RETVAL( -1 );
425
        return -1;
426
    }
427
#endif
428
 
429
    int interr CYGBLD_ATTRIB_UNUSED;
430
 
431
    interr = pthread_mutex_lock( &mqtab_mut );
432
    // should never fail
433
    CYG_ASSERT( interr == 0, "internal lock failed!" );
434
 
435
    struct mqtabent *tabent = user->tabent;
436
    struct mquser *usertmp;
437
 
438
    // perhaps should return EBADF instead of assert?
439
    CYG_ASSERT( tabent->users != NULL, "Null message queue user list" );
440
 
441
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
442
    // deregister notification iff this was the message queue descriptor
443
    // that was used to register it (POSIX says)
444
    if ( true == user->notifieruser ) {
445
        tabent->mq->setnotify( NULL, 0 );
446
        tabent->sigev = NULL;
447
        // not worth clearing notifieruser
448
    }
449
#endif
450
 
451
    // find in the list for this queue and remove - sucks a bit, but seems
452
    // best over all - the list shouldn't be too long
453
    if ( tabent->users == user ) {
454
        tabent->users = user->next;  // remove
455
    } else {
456
        for ( usertmp=tabent->users;
457
              NULL != usertmp->next;
458
              usertmp = usertmp->next ) {
459
            if ( usertmp->next == user )
460
                break;
461
        } // for
462
 
463
        // perhaps should return EBADF instead of assert?
464
        CYG_ASSERT( usertmp->next != NULL, "Couldn't find message queue user" );
465
 
466
        usertmp->next = user->next; // remove
467
    } // else
468
 
469
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
470
    user->magic = 0; // invalidate
471
#endif
472
 
473
    // free it up
474
    free( user );
475
 
476
    if ( (true == tabent->unlinkme) && (NULL == tabent->users) ) {
477
        do_mq_unlink( tabent );
478
    } // if
479
 
480
    interr = pthread_mutex_unlock( &mqtab_mut );
481
    // should never fail
482
    CYG_ASSERT( interr == 0, "internal lock failed!" );
483
    CYG_REPORT_RETVAL( 0 );
484
    return 0;
485
} // mq_close()
486
 
487
 
488
//------------------------------------------------------------------------
489
 
490
externC int
491
mq_unlink( const char *name )
492
{
493
    CYG_REPORT_FUNCTYPE( "returning %d" );
494
    CYG_REPORT_FUNCARG1( "name=%s", name );
495
 
496
    int retval;
497
    int interr CYGBLD_ATTRIB_UNUSED;
498
    cyg_ucount32 i;
499
    struct mqtabent *qtabent=NULL;
500
 
501
    interr = pthread_mutex_lock( &mqtab_mut );
502
    // should never fail
503
    CYG_ASSERT( interr == 0, "internal lock failed!" );
504
 
505
    // find the entry first
506
    // FIXME: Should check for length and return ENAMETOOLONG
507
    for ( i=0; i < CYGNUM_POSIX_MQUEUE_OPEN_MAX; i++ ) {
508
        if ( 0 == strncmp(name, mqtab[i].name, PATH_MAX) ) {
509
            qtabent = &mqtab[i];
510
            break;
511
        } // if
512
    } // for
513
 
514
    if ( NULL == qtabent ) { // not found
515
        errno = ENOENT;
516
        retval = -1;
517
        goto exit_unlock;
518
    }
519
 
520
    if ( NULL != qtabent->users ) {   // still in use
521
        qtabent->unlinkme = true;     // so mark it as pending deletion
522
    } else {
523
        do_mq_unlink( qtabent );
524
    } // else
525
 
526
    retval = 0;
527
 
528
 exit_unlock:
529
    interr = pthread_mutex_unlock( &mqtab_mut );
530
    // should never fail
531
    CYG_ASSERT( interr == 0, "internal lock failed!" );
532
    CYG_REPORT_RETVAL( retval );
533
    return retval;
534
} // mq_unlink()
535
 
536
//------------------------------------------------------------------------
537
 
538
externC int
539
mq_send( mqd_t mqdes, const char *msg_ptr, size_t msg_len,
540
         unsigned int msg_prio )
541
{
542
    CYG_REPORT_FUNCTYPE( "returning %d" );
543
    CYG_REPORT_FUNCARG4( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%u",
544
                         mqdes, msg_ptr, msg_len, msg_prio );
545
    CYG_CHECK_DATA_PTRC( msg_ptr );
546
 
547
    struct mquser *user = (struct mquser *)mqdes;
548
    struct mqtabent *tabent = user->tabent;
549
 
550
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
551
    if ( user->magic != MQ_VALID_MAGIC ) {
552
        errno  = EBADF;
553
        CYG_REPORT_RETVAL( -1 );
554
        return -1;
555
    }
556
#endif
557
 
558
    if ( msg_len > (size_t)tabent->msgsize ) {
559
        errno = EMSGSIZE;
560
        CYG_REPORT_RETVAL( -1 );
561
        return -1;
562
    }
563
 
564
    if ( msg_prio > MQ_PRIO_MAX ) {
565
        errno = EINVAL;
566
        CYG_REPORT_RETVAL( -1 );
567
        return -1;
568
    }
569
 
570
    if ( (O_WRONLY != (user->flags & O_WRONLY)) &&
571
         (O_RDWR != (user->flags & O_RDWR)) ) {
572
        errno = EBADF;
573
        CYG_REPORT_RETVAL( -1 );
574
        return -1;
575
    }
576
 
577
    // go for it
578
    Cyg_Mqueue::qerr_t err;
579
    err = tabent->mq->put( msg_ptr, msg_len, msg_prio,
580
                           ((user->flags & O_NONBLOCK) != O_NONBLOCK) );
581
    switch (err) {
582
 
583
    case Cyg_Mqueue::INTR:
584
        errno = EINTR;
585
        CYG_REPORT_RETVAL( -1 );
586
        return -1;
587
 
588
    case Cyg_Mqueue::WOULDBLOCK:
589
        CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
590
                    "Message queue assumed non-blocking when blocking requested"
591
            );
592
        errno = EAGAIN;
593
        CYG_REPORT_RETVAL( -1 );
594
        return -1;
595
 
596
    case Cyg_Mqueue::OK:
597
        CYG_REPORT_RETVAL( 0 );
598
        return 0;
599
 
600
    default:
601
        CYG_FAIL( "unhandled message queue return code" );
602
        return -1; // keep compiler happy
603
    } // switch
604
} // mq_send()
605
 
606
//------------------------------------------------------------------------
607
 
608
 
609
externC ssize_t
610
mq_receive( mqd_t mqdes, char *msg_ptr, size_t msg_len,
611
            unsigned int *msg_prio )
612
{
613
    CYG_REPORT_FUNCTYPE( "returning %ld" );
614
    CYG_REPORT_FUNCARG4( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%08x",
615
                         mqdes, msg_ptr, msg_len, msg_prio );
616
    CYG_CHECK_DATA_PTRC( msg_ptr );
617
    CYG_CHECK_DATA_PTRC( msg_ptr+msg_len-1 );
618
    if ( NULL != msg_prio )
619
        CYG_CHECK_DATA_PTRC( msg_prio );
620
 
621
 
622
    struct mquser *user = (struct mquser *)mqdes;
623
    struct mqtabent *tabent = user->tabent;
624
 
625
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
626
    if ( user->magic != MQ_VALID_MAGIC ) {
627
        errno  = EBADF;
628
        CYG_REPORT_RETVAL( -1 );
629
        return (ssize_t)-1;
630
    }
631
#endif
632
 
633
    if ( (O_RDONLY != (user->flags & O_RDONLY)) &&
634
         (O_RDWR != (user->flags & O_RDWR)) ) {
635
        errno = EBADF;
636
        CYG_REPORT_RETVAL( -1 );
637
        return (ssize_t)-1;
638
    }
639
 
640
    if ( msg_len < (size_t)tabent->msgsize ) {
641
        errno = EMSGSIZE;
642
        CYG_REPORT_RETVAL( -1 );
643
        return (ssize_t)-1;
644
    }
645
 
646
    // go for it
647
    Cyg_Mqueue::qerr_t err;
648
    err = tabent->mq->get( msg_ptr, &msg_len, msg_prio,
649
                           ((user->flags & O_NONBLOCK) != O_NONBLOCK) );
650
    switch (err) {
651
 
652
    case Cyg_Mqueue::INTR:
653
        errno = EINTR;
654
        CYG_REPORT_RETVAL( -1 );
655
        return (ssize_t)-1;
656
 
657
    case Cyg_Mqueue::WOULDBLOCK:
658
        CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
659
                    "Message queue assumed non-blocking when blocking requested"
660
            );
661
        errno = EAGAIN;
662
        CYG_REPORT_RETVAL( -1 );
663
        return (ssize_t)-1;
664
 
665
    case Cyg_Mqueue::OK:
666
        CYG_ASSERT( msg_len <= (size_t)tabent->msgsize,
667
                    "returned message too long" );
668
        if ( NULL != msg_prio )
669
            CYG_ASSERT( *msg_prio <= MQ_PRIO_MAX,
670
                        "returned message has invalid priority" );
671
        CYG_REPORT_RETVAL( msg_len );
672
        return (ssize_t)msg_len;
673
 
674
    default:
675
        CYG_FAIL( "unhandled message queue return code" );
676
        return (ssize_t)-1; // keep compiler happy
677
    } // switch
678
 
679
} // mq_receive()
680
 
681
 
682
//------------------------------------------------------------------------
683
#ifdef CYGFUN_KERNEL_THREADS_TIMER
684
externC int
685
mq_timedsend( mqd_t mqdes, const char *msg_ptr, size_t msg_len,
686
              unsigned int msg_prio, const struct timespec *abs_timeout)
687
{
688
    CYG_REPORT_FUNCTYPE( "returning %d" );
689
    CYG_REPORT_FUNCARG6( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%u, "
690
                         "abs_timeout = %lu, %ld",
691
                         mqdes, msg_ptr, msg_len, msg_prio,
692
                         abs_timeout->tv_sec, abs_timeout->tv_nsec);
693
    CYG_CHECK_DATA_PTRC( msg_ptr );
694
 
695
    struct mquser *user = (struct mquser *)mqdes;
696
    struct mqtabent *tabent = user->tabent;
697
 
698
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
699
    if ( user->magic != MQ_VALID_MAGIC ) {
700
        errno  = EBADF;
701
        CYG_REPORT_RETVAL( -1 );
702
        return -1;
703
    }
704
#endif
705
 
706
    if ( msg_len > (size_t)tabent->msgsize ) {
707
        errno = EMSGSIZE;
708
        CYG_REPORT_RETVAL( -1 );
709
        return -1;
710
    }
711
 
712
    if ( msg_prio > MQ_PRIO_MAX ) {
713
        errno = EINVAL;
714
        CYG_REPORT_RETVAL( -1 );
715
        return -1;
716
    }
717
 
718
    if ( (O_WRONLY != (user->flags & O_WRONLY)) &&
719
         (O_RDWR != (user->flags & O_RDWR)) ) {
720
        errno = EBADF;
721
        CYG_REPORT_RETVAL( -1 );
722
        return -1;
723
    }
724
 
725
    // go for it
726
    Cyg_Mqueue::qerr_t err;
727
    bool nonblocking = ((user->flags & O_NONBLOCK) == O_NONBLOCK);
728
    bool badtimespec = (abs_timeout->tv_nsec < 0) ||
729
        (abs_timeout->tv_nsec > 999999999l);
730
    cyg_tick_count abs_ticks = cyg_timespec_to_ticks(abs_timeout);
731
 
732
    // We should never time out if there is room in the queue.  Simplest
733
    // way to ensure this is to try the non-blocking put() first.
734
    err = tabent->mq->put( msg_ptr, msg_len, msg_prio, false, abs_ticks );
735
 
736
    // If the blocking variant would have blocked and that is what's wanted
737
    if ( Cyg_Mqueue::WOULDBLOCK == err && !nonblocking && !badtimespec ) {
738
        err = tabent->mq->put( msg_ptr, msg_len, msg_prio, true,
739
                               abs_ticks );
740
    }
741
 
742
    switch (err) {
743
 
744
    case Cyg_Mqueue::INTR:
745
        errno = EINTR;
746
        CYG_REPORT_RETVAL( -1 );
747
        return -1;
748
 
749
    case Cyg_Mqueue::WOULDBLOCK:
750
        if (badtimespec) {
751
            errno = EINVAL;
752
            CYG_REPORT_RETVAL( -1 );
753
            return -1;
754
        }
755
        CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
756
                    "Message queue assumed non-blocking when blocking requested"
757
            );
758
        errno = EAGAIN;
759
        CYG_REPORT_RETVAL( -1 );
760
        return -1;
761
 
762
    case Cyg_Mqueue::TIMEOUT:
763
        errno = ETIMEDOUT;
764
        CYG_REPORT_RETVAL( -1 );
765
        return -1;
766
 
767
    case Cyg_Mqueue::OK:
768
        CYG_REPORT_RETVAL( 0 );
769
        return 0;
770
 
771
    default:
772
        CYG_FAIL( "unhandled message queue return code" );
773
        return -1; // keep compiler happy
774
    } // switch
775
} // mq_timedsend()
776
 
777
//------------------------------------------------------------------------
778
 
779
 
780
externC ssize_t
781
mq_timedreceive( mqd_t mqdes, char *msg_ptr, size_t msg_len,
782
            unsigned int *msg_prio, const struct timespec *abs_timeout)
783
{
784
    CYG_REPORT_FUNCTYPE( "returning %ld" );
785
    CYG_REPORT_FUNCARG6( "mqdes=%08x, msg_ptr=%08x, msg_len=%u, msg_prio=%08x, "
786
                         "abs_timeout = %lu, %ld",
787
                         mqdes, msg_ptr, msg_len, msg_prio,
788
                         abs_timeout->tv_sec, abs_timeout->tv_nsec );
789
    CYG_CHECK_DATA_PTRC( msg_ptr );
790
    CYG_CHECK_DATA_PTRC( msg_ptr+msg_len-1 );
791
    if ( NULL != msg_prio )
792
        CYG_CHECK_DATA_PTRC( msg_prio );
793
 
794
 
795
    struct mquser *user = (struct mquser *)mqdes;
796
    struct mqtabent *tabent = user->tabent;
797
 
798
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
799
    if ( user->magic != MQ_VALID_MAGIC ) {
800
        errno  = EBADF;
801
        CYG_REPORT_RETVAL( -1 );
802
        return (ssize_t)-1;
803
    }
804
#endif
805
 
806
    if ( (O_RDONLY != (user->flags & O_RDONLY)) &&
807
         (O_RDWR != (user->flags & O_RDWR)) ) {
808
        errno = EBADF;
809
        CYG_REPORT_RETVAL( -1 );
810
        return (ssize_t)-1;
811
    }
812
 
813
    if ( msg_len < (size_t)tabent->msgsize ) {
814
        errno = EMSGSIZE;
815
        CYG_REPORT_RETVAL( -1 );
816
        return (ssize_t)-1;
817
    }
818
 
819
    // go for it
820
    Cyg_Mqueue::qerr_t err;
821
    bool nonblocking = ((user->flags & O_NONBLOCK) == O_NONBLOCK);
822
    bool badtimespec = (abs_timeout->tv_nsec < 0) ||
823
        (abs_timeout->tv_nsec > 999999999l);
824
    cyg_tick_count abs_ticks = cyg_timespec_to_ticks(abs_timeout);
825
 
826
    // We should never time out if there is something to read.  Simplest
827
    // way to ensure this is to try the non-blocking get() first.
828
    err = tabent->mq->get( msg_ptr, &msg_len, msg_prio, false, abs_ticks );
829
 
830
    // If the blocking variant would have blocked and that is what's wanted
831
    if ( Cyg_Mqueue::WOULDBLOCK == err && !nonblocking && !badtimespec ) {
832
        err = tabent->mq->get( msg_ptr, &msg_len, msg_prio, true, abs_ticks );
833
    }
834
 
835
    switch (err) {
836
 
837
    case Cyg_Mqueue::INTR:
838
        errno = EINTR;
839
        CYG_REPORT_RETVAL( -1 );
840
        return (ssize_t)-1;
841
 
842
    case Cyg_Mqueue::WOULDBLOCK:
843
        if (badtimespec) {
844
            errno = EINVAL;
845
            CYG_REPORT_RETVAL( -1 );
846
            return -1;
847
        }
848
        CYG_ASSERT( (user->flags & O_NONBLOCK) == O_NONBLOCK,
849
                    "Message queue assumed non-blocking when blocking requested"
850
            );
851
        errno = EAGAIN;
852
        CYG_REPORT_RETVAL( -1 );
853
        return (ssize_t)-1;
854
 
855
    case Cyg_Mqueue::TIMEOUT:
856
        errno = ETIMEDOUT;
857
        CYG_REPORT_RETVAL( -1 );
858
        return -1;
859
 
860
    case Cyg_Mqueue::OK:
861
        CYG_ASSERT( msg_len <= (size_t)tabent->msgsize,
862
                    "returned message too long" );
863
        if ( NULL != msg_prio )
864
            CYG_ASSERT( *msg_prio <= MQ_PRIO_MAX,
865
                        "returned message has invalid priority" );
866
        CYG_REPORT_RETVAL( msg_len );
867
        return (ssize_t)msg_len;
868
 
869
    default:
870
        CYG_FAIL( "unhandled message queue return code" );
871
        return (ssize_t)-1; // keep compiler happy
872
    } // switch
873
 
874
} // mq_timedreceive()
875
 
876
//------------------------------------------------------------------------
877
#endif
878
 
879
#ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
880
 
881
externC int
882
mq_notify( mqd_t mqdes, const struct sigevent *notification )
883
{
884
    CYG_REPORT_FUNCTYPE( "returning %d" );
885
    CYG_REPORT_FUNCARG2( "mqdes=%08x, notification=%08x", mqdes, notification );
886
    if ( NULL != notification )
887
        CYG_CHECK_DATA_PTRC( notification );
888
 
889
    struct mquser *user = (struct mquser *)mqdes;
890
    struct mqtabent *tabent = user->tabent;
891
 
892
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
893
    if ( user->magic != MQ_VALID_MAGIC ) {
894
        errno  = EBADF;
895
        CYG_REPORT_RETVAL( -1 );
896
        return -1;
897
    }
898
#endif
899
 
900
    // lock scheduler since we test and set non-atomically
901
    Cyg_Scheduler::lock();
902
 
903
    // we are being told to clear the notification function
904
    if ( NULL == notification ) {
905
        tabent->mq->setnotify( NULL, 0 );
906
        tabent->sigev = NULL;
907
        Cyg_Scheduler::unlock();
908
        CYG_REPORT_RETVAL( 0 );
909
        return 0;
910
    } // if
911
 
912
    if ( NULL != tabent->sigev ) {  // already registered
913
        Cyg_Scheduler::unlock();
914
        errno = EBUSY;
915
        CYG_REPORT_RETVAL( -1 );
916
        return -1;
917
    } // if
918
 
919
    tabent->sigev = notification;
920
    user->notifieruser = true; // Used for deciding about whether to
921
                               // deregister in mq_close()
922
    tabent->mq->setnotify( &notifyme, (CYG_ADDRWORD) user );
923
    Cyg_Scheduler::unlock();
924
 
925
    CYG_REPORT_RETVAL( 0 );
926
    return 0;
927
} // mq_notify()
928
 
929
#endif // ifdef CYGFUN_POSIX_MQUEUE_NOTIFY
930
 
931
//------------------------------------------------------------------------
932
 
933
externC int
934
mq_setattr( mqd_t mqdes, const struct mq_attr *mqstat,
935
            struct mq_attr *omqstat )
936
{
937
    CYG_REPORT_FUNCTYPE( "returning %d" );
938
    CYG_REPORT_FUNCARG3( "mqdes=%08x, mqstat=%08x, omqstat=%08x",
939
                         mqdes, mqstat, omqstat );
940
    CYG_CHECK_DATA_PTRC( mqstat );
941
 
942
    struct mquser *user = (struct mquser *)mqdes;
943
 
944
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
945
    if ( user->magic != MQ_VALID_MAGIC ) {
946
        errno  = EBADF;
947
        CYG_REPORT_RETVAL( -1 );
948
        return -1;
949
    }
950
#endif
951
 
952
    if ( NULL != omqstat ) {
953
        CYG_CHECK_DATA_PTRC( omqstat );
954
        mq_getattr( mqdes, omqstat );
955
    } // if
956
 
957
    // Two-stage update, so lock sched since it's quick
958
    Cyg_Scheduler::lock();
959
    user->flags &= ~O_NONBLOCK;  // clear
960
    if ( (mqstat->mq_flags & O_NONBLOCK) == O_NONBLOCK ) {
961
        user->flags |= O_NONBLOCK;
962
    } // if
963
    Cyg_Scheduler::unlock();
964
 
965
    CYG_REPORT_RETVAL( 0 );
966
    return 0;
967
} // mq_setattr()
968
 
969
//------------------------------------------------------------------------
970
 
971
externC int
972
mq_getattr( mqd_t mqdes, struct mq_attr *mqstat )
973
{
974
    CYG_REPORT_FUNCTYPE( "returning %d" );
975
    CYG_REPORT_FUNCARG2( "mqdes=%08x, mqstat=%08x", mqdes, mqstat );
976
    CYG_CHECK_DATA_PTRC( mqstat );
977
 
978
    struct mquser *user = (struct mquser *)mqdes;
979
    struct mqtabent *tabent = user->tabent;
980
 
981
#ifdef CYGIMP_POSIX_MQUEUE_VALIDATE_DESCRIPTOR
982
    if ( user->magic != MQ_VALID_MAGIC ) {
983
        errno  = EBADF;
984
        CYG_REPORT_RETVAL( -1 );
985
        return -1;
986
    }
987
#endif
988
 
989
    mqstat->mq_flags   = user->flags;
990
    mqstat->mq_maxmsg  = tabent->maxmsg;
991
    mqstat->mq_msgsize = tabent->msgsize;
992
    mqstat->mq_curmsgs = tabent->mq->count();
993
 
994
    CYG_REPORT_RETVAL( 0 );
995
    return 0;
996
} // mq_getattr()
997
 
998
 
999
//------------------------------------------------------------------------
1000
 
1001
/* EOF mqueue.cxx */

powered by: WebSVN 2.1.0

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