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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [compat/] [posix/] [v2_0/] [src/] [mqueue.cxx] - Blame information for rev 248

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

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

powered by: WebSVN 2.1.0

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