Subversion Repositories shark

Rev

Rev 29 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
/*
2
 * Project: S.Ha.R.K.
3
 *
4
 * Coordinators:
5
 *   Giorgio Buttazzo    <giorgio@sssup.it>
6
 *   Paolo Gai           <pj@gandalf.sssup.it>
7
 *
8
 * Authors     :
9
 *   Paolo Gai           <pj@gandalf.sssup.it>
10
 *   (see the web pages for full authors list)
11
 *
12
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
13
 *
14
 * http://www.sssup.it
15
 * http://retis.sssup.it
16
 * http://shark.sssup.it
17
 */
18
 
19
/**
20
 ------------
38 pj 21
 CVS :        $Id: mqueue.c,v 1.3 2003-01-07 17:07:49 pj Exp $
2 pj 22
 
23
 File:        $File$
38 pj 24
 Revision:    $Revision: 1.3 $
25
 Last update: $Date: 2003-01-07 17:07:49 $
2 pj 26
 ------------
27
 
28
 POSIX message queues
29
 
30
**/
31
 
32
/*
33
 * Copyright (C) 2000 Paolo Gai
34
 *
35
 * This program is free software; you can redistribute it and/or modify
36
 * it under the terms of the GNU General Public License as published by
37
 * the Free Software Foundation; either version 2 of the License, or
38
 * (at your option) any later version.
39
 *
40
 * This program is distributed in the hope that it will be useful,
41
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43
 * GNU General Public License for more details.
44
 *
45
 * You should have received a copy of the GNU General Public License
46
 * along with this program; if not, write to the Free Software
47
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
48
 *
49
 */
50
 
51
#include <mqueue.h>
52
#include <ll/string.h>
53
#include <kernel/types.h>
54
#include <kernel/var.h>
55
#include <kernel/func.h>
56
#include <errno.h>
57
#include <stdarg.h>
58
#include <pthread.h>
59
#include <sys/types.h>
60
 
61
/* some flags... */
62
#define MQ_USED                 1
63
#define MQ_NONBLOCK             2
64
#define MQ_NOTIFICATION_PRESENT 4
65
 
66
static int mq_once = 1;
67
 
68
struct mq_elem {
69
  unsigned int mq_prio;   /* the priority of a message */
70
  ssize_t msglen;         /* the length of a message   */
71
  int next;               /* the priority queue        */
72
};
73
 
74
/* Semaphores descriptor tables */
75
static struct mq_des {
76
    char *name;              /* a name */
77
    int  flags;              /* flags... */
78
 
79
    long maxmsg;             /* maximum number of messages */
80
    long msgsize;            /* Maximum message size */
81
 
82
    long count;              /* Number of messages currently queued */
83
    long start;              /* first not-empty message */
84
 
85
    BYTE *mq_data;           /* the data... */
86
    struct mq_elem *mq_info; /* the priorities */
87
    int mq_first;            /* the first empty message */
88
 
89
    struct sigevent notification; /* the notification, valid only if the
90
                                     correct bit is set */
91
 
92
    /* the blocked processes queues */
29 pj 93
    IQUEUE blocked_send;
94
    IQUEUE blocked_rcv;
2 pj 95
 
96
    int next;            /* the mq queue */
97
} mq_table[MQ_OPEN_MAX];
98
 
99
 
100
/* this -IS- an extension to the proc_table!!! */
101
static struct {
102
    int intsig;   /* Normally it is =0, -1 only when a task is woken up
103
                     by a signal */
104
    int mqdes;    /* message queue on which a task is blocked (meaningless
105
                     if the task is not blocked...) */
106
} mqproc_table[MAX_PROC];
107
 
29 pj 108
static int free_mq;         /* Queue of free sem                    */
2 pj 109
 
110
mqd_t mq_open(const char *name, int oflag, ...)
111
{
112
    int     i;
113
    int     found = 0;
114
    mode_t  m;
115
    mqd_t   mq;
116
    struct mq_attr *attr;
117
 
118
    kern_cli();
119
 
120
    for (i = 0; i < MQ_OPEN_MAX; i++)
121
      if (mq_table[i].flags & MQ_USED) {
122
        if (strcmp((char*)name, mq_table[i].name) == 0) {
123
          found = 1;
124
          break;
125
        }
126
      }
127
    if (found) {
128
      if (oflag == (O_CREAT | O_EXCL)) {
129
          errno = EEXIST;
130
          kern_sti();
131
          return -1;
132
      } else {
133
          kern_sti();
134
          return i;
135
      }
136
    } else {
137
      if (!(oflag & O_CREAT)) {
138
          errno = ENOENT;
139
          kern_sti();
140
          return -1;
141
      } else if (!(oflag & O_RDWR)) {
142
          errno = EACCES;
143
          kern_sti();
144
          return -1;
145
      } else {
146
          va_list l;
147
 
148
          va_start(l, oflag);
149
            m = va_arg(l,mode_t);
150
            attr = va_arg(l, struct mq_attr *);
151
          va_end(l);
152
 
153
          mq = free_mq;
154
          if (mq != -1) {
155
            mq_table[mq].name = kern_alloc(strlen((char *)name)+1);
156
            if (!mq_table[mq].name) {
157
              errno = ENOSPC;
158
              kern_sti();
159
              return -1;
160
            }
161
            strcpy(mq_table[mq].name, (char *)name);
162
 
163
            if (attr) {
164
              mq_table[mq].maxmsg  = attr->mq_maxmsg;
165
              mq_table[mq].msgsize = attr->mq_msgsize;
166
            }
167
            else {
168
              mq_table[mq].maxmsg  = MQ_DEFAULT_MAXMSG;
169
              mq_table[mq].msgsize = MQ_DEFAULT_MSGSIZE;
170
            }
29 pj 171
            iq_init(&mq_table[mq].blocked_send, &freedesc, 0);
172
            iq_init(&mq_table[mq].blocked_rcv, &freedesc, 0);
2 pj 173
 
174
            mq_table[mq].count = 0;
175
            mq_table[mq].start = -1;
176
 
177
            mq_table[mq].mq_first = 0;
178
 
179
            if (oflag & O_NONBLOCK)
180
              mq_table[mq].flags = MQ_USED | MQ_NONBLOCK;
181
            else
182
              mq_table[mq].flags = MQ_USED;
183
 
184
            mq_table[mq].mq_data = (BYTE *)
185
              kern_alloc(mq_table[mq].maxmsg * mq_table[mq].msgsize);
186
            if (!mq_table[mq].mq_data) {
187
              kern_free(mq_table[mq].name,strlen((char *)name)+1);
188
 
189
              errno = ENOSPC;
190
              kern_sti();
191
              return -1;
192
            }
193
 
194
            mq_table[mq].mq_info = (struct mq_elem *)
195
              kern_alloc(mq_table[mq].maxmsg * sizeof(struct mq_elem));
196
            if (!mq_table[mq].mq_info) {
197
              kern_free(mq_table[mq].name,strlen((char *)name)+1);
198
              kern_free(mq_table[mq].mq_data,
199
                        mq_table[mq].maxmsg * mq_table[mq].msgsize);
200
 
201
              errno = ENOSPC;
202
              kern_sti();
203
              return -1;
204
            }
205
 
206
            /* set up the element queue */
207
            for (i=0; i<mq_table[mq].maxmsg-1; i++)
208
              mq_table[mq].mq_info[i].next = i+1;
209
            mq_table[mq].mq_info[mq_table[mq].maxmsg-1].next = -1;
210
            mq_table[mq].mq_first = 0;
211
 
212
            free_mq = mq_table[mq].next;
213
            kern_sti();
214
            return mq;
215
          }
216
          else {
217
            errno = ENOSPC;
218
            kern_sti();
219
            return -1;
220
          }
221
      }
222
    }
223
}
224
 
225
int mq_close(mqd_t mqdes)
226
{
227
    kern_cli();
228
 
229
    if (mqdes < 0 ||
230
        mqdes >= MQ_OPEN_MAX ||
231
        !(mq_table[mqdes].flags & MQ_USED) ) {
232
      errno = EBADF;
233
      kern_sti();
234
      return -1;
235
    }
236
 
237
    kern_free(mq_table[mqdes].name, strlen(mq_table[mqdes].name)+1);
238
    kern_free(mq_table[mqdes].mq_data,
239
              mq_table[mqdes].maxmsg * mq_table[mqdes].msgsize);
240
    kern_free(mq_table[mqdes].mq_info,
241
              mq_table[mqdes].maxmsg * sizeof(struct mq_elem));
242
 
243
    mq_table[mqdes].flags = 0;
244
    mq_table[mqdes].next = free_mq;
245
    free_mq = mqdes;
246
 
247
    kern_sti();
248
    return 0;
249
}
250
 
251
int mq_unlink(const char *name)
252
{
253
    int i;
254
    int found = 0;
255
 
256
    kern_cli();
257
 
258
    for (i = 0; i < MQ_OPEN_MAX; i++)
259
      if (mq_table[i].flags & MQ_USED) {
260
        if (strcmp((char*)name, mq_table[i].name) == 0) {
261
          found = 1;
262
        }
263
      }
264
 
265
    if (found) {
266
      kern_free(mq_table[i].name, strlen((char *)name)+1);
267
      kern_free(mq_table[i].mq_data,
268
                mq_table[i].maxmsg * mq_table[i].msgsize);
269
      kern_free(mq_table[i].mq_info,
270
                mq_table[i].maxmsg * sizeof(struct mq_elem));
271
 
272
      mq_table[i].flags = 0;
273
      mq_table[i].next = free_mq;
274
      free_mq = i;
275
      kern_sti();
276
      return 0;
277
    } else {
278
      errno = ENOENT;
279
      kern_sti();
280
      return -1;
281
    }
282
}
283
 
284
/* this function inserts a message in amessage queue mantaining the
285
   priority order */
286
static void insert_mq_entry(mqd_t mqdes, int newmsg)
287
{
288
    int prio; /* the priority of the message to insert */
289
    int p,q;  /* the messages... */
290
 
291
    p = NIL;
292
    q = mq_table[mqdes].start;
293
    prio = mq_table[mqdes].mq_info[ newmsg ].mq_prio;
294
 
295
    while ((q != NIL) && (prio <= mq_table[mqdes].mq_info[ q ].mq_prio)) {
296
        p = q;
297
        q = mq_table[mqdes].mq_info[ q ].next;
298
    }
299
 
300
    if (p != NIL)
301
      mq_table[mqdes].mq_info[ p ].next = newmsg;
302
    else
303
      mq_table[mqdes].start = newmsg;
304
 
305
    mq_table[mqdes].mq_info[ newmsg ].next = q;
306
}
307
 
308
 
309
 
310
 
311
 
312
 
313
/* this is the test that is done when a task is being killed
314
   and it is waiting on a sigwait */
315
static int mq_cancellation_point(PID i, void *arg)
316
{
317
    LEVEL l;
318
 
319
    if (proc_table[i].status == WAIT_MQSEND) {
320
      /* the task that have to be killed is waiting on a mq_send */
321
 
322
      /* we have to extract the task from the blocked queue... */
29 pj 323
      iq_extract(i,&mq_table[mqproc_table[i].mqdes].blocked_send);
2 pj 324
 
325
      /* and the task have to be reinserted into the ready queues, so it
326
         will fall into task_testcancel */
327
      l = proc_table[i].task_level;
38 pj 328
      level_table[l]->public_unblock(l,i);
2 pj 329
 
330
      return 1;
331
    }
332
 
333
    if (proc_table[i].status == WAIT_MQRECEIVE) {
334
      /* the task that have to be killed is waiting on a mq_send */
335
 
336
      /* we have to extract the task from the blocked queue... */
29 pj 337
      iq_extract(i, &mq_table[mqproc_table[i].mqdes].blocked_rcv);
2 pj 338
 
339
      /* and the task have to be reinserted into the ready queues, so it
340
         will fall into task_testcancel */
341
      l = proc_table[i].task_level;
38 pj 342
      level_table[l]->public_unblock(l,i);
2 pj 343
 
344
      return 1;
345
    }
346
 
347
    return 0;
348
}
349
 
350
int mq_interrupted_by_signal(PID i, void *arg)
351
{
352
    LEVEL l;
353
 
354
    if (proc_table[i].status == WAIT_MQSEND) {
355
      /* the task is waiting on a nanosleep and it is still receiving a
356
         signal... */
357
      mqproc_table[exec_shadow].intsig = 1;
358
 
359
      /* we have to extract the task from the blocked queue... */
29 pj 360
      iq_extract(i, &mq_table[mqproc_table[i].mqdes].blocked_send);
2 pj 361
 
362
      /* and the task have to be reinserted into the ready queues, so it
363
         will fall into task_testcancel */
364
      l = proc_table[i].task_level;
38 pj 365
      level_table[l]->public_unblock(l,i);
2 pj 366
 
367
      return 1;
368
    }
369
 
370
    if (proc_table[i].status == WAIT_MQRECEIVE) {
371
      /* the task is waiting on a nanosleep and it is still receiving a
372
         signal... */
373
      mqproc_table[exec_shadow].intsig = 1;
374
 
375
      /* we have to extract the task from the blocked queue... */
29 pj 376
      iq_extract(i, &mq_table[mqproc_table[i].mqdes].blocked_rcv);
2 pj 377
 
378
      /* and the task have to be reinserted into the ready queues, so it
379
         will fall into task_testcancel */
380
      l = proc_table[i].task_level;
38 pj 381
      level_table[l]->public_unblock(l,i);
2 pj 382
 
383
      return 1;
384
    }
385
 
386
    return 0;
387
}
388
 
389
 
390
 
391
 
392
 
393
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len,
394
            unsigned int msg_prio)
395
{
396
  int newmsg;
397
 
398
  task_testcancel();
399
 
400
  kern_cli();
401
 
402
  /* first, if it is the first time that mq_receive or mq_send is called,
403
     register the cancellation point */
404
  if (mq_once) {
405
    mq_once = 0;
406
    register_cancellation_point(mq_cancellation_point, NULL);
407
    register_interruptable_point(mq_interrupted_by_signal, NULL);
408
  }
409
 
410
  if (mqdes < 0 ||
411
      mqdes >= MQ_OPEN_MAX ||
412
      !(mq_table[mqdes].flags & MQ_USED) ) {
413
    errno = EBADF;
414
    kern_sti();
415
    return -1;
416
  }
417
 
418
  if (msg_len > mq_table[mqdes].msgsize) {
419
    errno = EMSGSIZE;
420
    kern_sti();
421
    return -1;
422
  }
423
 
424
  if (msg_prio > MQ_PRIO_MAX) {
425
    errno = EINVAL;
426
    kern_sti();
427
    return -1;
428
  }
429
 
430
  /* block the task if necessary */
431
  if (mq_table[mqdes].mq_first == -1) {
432
    /* the message queue is full!!! */
433
    if (mq_table[mqdes].flags & O_NONBLOCK) {
434
      errno = EAGAIN;
435
      kern_sti();
436
      return -1;
437
    }
438
    else {
439
      LEVEL l;
440
 
441
      /* we block the task until:
442
         - a message is received, or
443
         - a signal is sent to the task, or
444
         - the task is killed               */
445
 
446
      mqproc_table[exec_shadow].intsig = 0;
447
 
38 pj 448
      kern_epilogue_macro();
2 pj 449
 
450
      l = proc_table[exec_shadow].task_level;
38 pj 451
      level_table[l]->public_block(l,exec_shadow);
2 pj 452
 
453
      /* we insert the task in the message queue */
454
      proc_table[exec_shadow].status = WAIT_MQSEND;
29 pj 455
      iq_priority_insert(exec_shadow,&mq_table[mqdes].blocked_send);
2 pj 456
 
457
      /* and finally we reschedule */
458
      exec = exec_shadow = -1;
459
      scheduler();
460
      ll_context_to(proc_table[exec_shadow].context);
461
      kern_deliver_pending_signals();
462
 
463
      /* mq_send is a cancellation point... */
464
      task_testcancel();
465
 
466
      if (mqproc_table[exec_shadow].intsig) {
467
        errno = EINTR;
468
        kern_sti();
469
        return -1;
470
      }
471
    }
472
  }
473
 
474
  /* Now there is space to insert a new message */
475
  /* alloc a descriptor */
476
  newmsg = mq_table[mqdes].mq_first;
477
  mq_table[mqdes].mq_first = mq_table[mqdes].mq_info[newmsg].next;
478
  mq_table[mqdes].count++;
479
 
480
  /* fill the data */
481
  memcpy(mq_table[mqdes].mq_data + newmsg * mq_table[mqdes].msgsize,
482
         msg_ptr, msg_len);
483
  mq_table[mqdes].mq_info[ newmsg ].mq_prio = msg_prio;
484
  mq_table[mqdes].mq_info[ newmsg ].msglen  = msg_len;
485
 
486
  /* insert the data in an ordered way */
487
  insert_mq_entry(mqdes, newmsg);
488
 
489
//  kern_printf("Ûmq_des=%d, newmsg=%d, count=%dÛ",
490
//              mqdes, newmsg, mq_table[mqdes].count);
491
 
492
  if (mq_table[mqdes].count == 1) {
493
    /* the mq was empty */
494
    PID p;
495
 
29 pj 496
    p = iq_getfirst(&mq_table[mqdes].blocked_rcv);
2 pj 497
 
498
    if ( p != NIL) {
499
      /* The first blocked task has to be woken up */
500
      LEVEL l;
501
 
502
      proc_table[exec_shadow].context = ll_context_from();
503
 
504
      l = proc_table[p].task_level;
38 pj 505
      level_table[l]->public_unblock(l,p);
2 pj 506
 
507
      /* Preempt if necessary */
508
      scheduler();
509
      kern_context_load(proc_table[exec_shadow].context);
510
      return 0;
511
    }
512
    else if (mq_table[mqdes].flags & MQ_NOTIFICATION_PRESENT) {
513
      mq_table[mqdes].flags &= ~MQ_NOTIFICATION_PRESENT;
514
 
515
      // manage the notification...
516
      if (mq_table[mqdes].notification.sigev_notify == SIGEV_SIGNAL) {
517
          // there is no signal pending... post the signal!!!
518
          sigqueue_internal(0,
519
                            mq_table[mqdes].notification.sigev_signo,
520
                            mq_table[mqdes].notification.sigev_value,
521
                            SI_MESGQ);
522
      } else if (mq_table[mqdes].notification.sigev_notify == SIGEV_THREAD) {
523
        /* a new thread must be created; note that the pthread_create
524
           calls task_createn and task_activate; if task_activate is called
525
           into signal handlers and calls event_need_reschedule */
526
        pthread_t new_thread;
527
 
528
        if (mq_table[mqdes].notification.sigev_notify_attributes)
529
          pthread_create(&new_thread,
530
                         mq_table[mqdes].notification.sigev_notify_attributes,
531
                         (void *(*)(void *))mq_table[mqdes].notification.sigev_notify_function,
532
                         mq_table[mqdes].notification.sigev_value.sival_ptr);
533
        else {
534
          pthread_attr_t new_attr;
535
          // the task must be created detached
536
          pthread_attr_init(&new_attr);
537
          pthread_attr_setdetachstate(&new_attr, PTHREAD_CREATE_DETACHED);
538
 
539
          pthread_create(&new_thread,
540
                         &new_attr,
541
                         (void *(*)(void *))mq_table[mqdes].notification.sigev_notify_function,
542
                         &mq_table[mqdes].notification.sigev_value);
543
        }
544
      }
545
    }
546
  }
547
 
548
  kern_sti();
549
  return 0;
550
}
551
 
552
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len,
553
                   unsigned int *msg_prio)
554
{
555
  int msg;
556
  PID p;
557
  ssize_t returnvalue;
558
 
559
  task_testcancel();
560
 
561
  kern_cli();
562
 
563
  /* first, if it is the first time that mq_receive or mq_send is called,
564
     register the cancellation point */
565
  if (mq_once) {
566
    mq_once = 0;
567
    register_cancellation_point(mq_cancellation_point, NULL);
568
    register_interruptable_point(mq_interrupted_by_signal, NULL);
569
  }
570
 
571
  if (mqdes < 0 ||
572
      mqdes >= MQ_OPEN_MAX ||
573
      !(mq_table[mqdes].flags & MQ_USED) ) {
574
    errno = EBADF;
575
    kern_sti();
576
    return -1;
577
  }
578
 
579
  if (msg_len > mq_table[mqdes].msgsize) {
580
    errno = EMSGSIZE;
581
    kern_sti();
582
    return -1;
583
  }
584
 
585
  /* block the task if necessary */
586
  if (mq_table[mqdes].start == -1) {
587
    /* the message queue is empty!!! */
588
    if (mq_table[mqdes].flags & O_NONBLOCK) {
589
      errno = EAGAIN;
590
      kern_sti();
591
      return -1;
592
    }
593
    else {
594
      LEVEL l;
595
 
596
      /* we block the task until:
597
         - a message arrives, or
598
         - a signal is sent to the task, or
599
         - the task is killed               */
600
 
601
      mqproc_table[exec_shadow].intsig = 0;
602
 
38 pj 603
      kern_epilogue_macro();
2 pj 604
 
605
      l = proc_table[exec_shadow].task_level;
38 pj 606
      level_table[l]->public_block(l,exec_shadow);
2 pj 607
 
608
      /* we insert the task into the message queue */
609
      proc_table[exec_shadow].status = WAIT_MQRECEIVE;
29 pj 610
      iq_priority_insert(exec_shadow,&mq_table[mqdes].blocked_rcv);
2 pj 611
 
612
      /* and finally we reschedule */
613
      exec = exec_shadow = -1;
614
      scheduler();
615
      ll_context_to(proc_table[exec_shadow].context);
616
      kern_deliver_pending_signals();
617
 
618
      /* mq_receive is a cancellation point... */
619
      task_testcancel();
620
 
621
      if (mqproc_table[exec_shadow].intsig) {
622
        errno = EINTR;
623
        kern_sti();
624
        return -1;
625
      }
626
    }
627
  }
628
 
629
  /* Now there is at least one message...
630
     copy it to the destination, ... */
631
  msg = mq_table[mqdes].start;
632
  memcpy(msg_ptr,
633
         mq_table[mqdes].mq_data + msg * mq_table[mqdes].msgsize,
634
         mq_table[mqdes].msgsize);
635
 
636
  /* ...update the first messagee and the counters, ... */
637
  mq_table[mqdes].count++;
638
  mq_table[mqdes].start = mq_table[mqdes].mq_info[ msg ].next;
639
  /* and finally the free message queue */
640
  mq_table[mqdes].mq_info[ msg ].next = mq_table[mqdes].mq_first;
641
  mq_table[mqdes].mq_first = msg;
642
 
643
  /* return the priority if required */
644
  if (msg_prio) {
645
    *msg_prio = mq_table[mqdes].mq_info[ msg ].mq_prio;
646
  }
647
 
648
  /* set the returnvalue */
649
  returnvalue = mq_table[mqdes].mq_info[ msg ].msglen;
650
 
651
  /* if the mq was full, there may be a task into blocked-send queue */
29 pj 652
  p = iq_getfirst(&mq_table[mqdes].blocked_send);
2 pj 653
 
654
  if ( p != NIL) {
655
    /* The first blocked task on send has to be woken up */
656
    LEVEL l;
657
 
658
    proc_table[exec_shadow].context = ll_context_from();
659
 
660
    l = proc_table[p].task_level;
38 pj 661
    level_table[l]->public_unblock(l,p);
2 pj 662
 
663
    /* Preempt if necessary */
664
    scheduler();
665
    kern_context_load(proc_table[exec_shadow].context);
666
    return returnvalue;
667
  }
668
 
669
  kern_sti();
670
  return returnvalue;
671
}
672
 
673
int mq_notify(mqd_t mqdes, const struct sigevent *notification)
674
{
675
  kern_cli();
676
 
677
  if (mqdes < 0 ||
678
      mqdes >= MQ_OPEN_MAX ||
679
      !(mq_table[mqdes].flags & MQ_USED) ) {
680
    errno = EBADF;
681
    kern_sti();
682
    return -1;
683
  }
684
 
685
  if (mq_table[mqdes].flags & MQ_NOTIFICATION_PRESENT) {
686
    if (!notification) {
687
      mq_table[mqdes].flags &= ~MQ_NOTIFICATION_PRESENT;
688
      kern_sti();
689
      return 0;
690
    }
691
    else {
692
      errno = EBUSY;
693
      kern_sti();
694
      return -1;
695
    }
696
  }
697
 
698
  mq_table[mqdes].flags |= MQ_NOTIFICATION_PRESENT;
699
 
700
  memcpy(&mq_table[mqdes].notification, notification,sizeof(struct sigevent));
701
 
702
  kern_sti();
703
  return 0;
704
}
705
 
706
int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat,
707
               struct mq_attr *omqstat)
708
{
709
  kern_cli();
710
 
711
  if (mqdes < 0 ||
712
      mqdes >= MQ_OPEN_MAX ||
713
      !(mq_table[mqdes].flags & MQ_USED) ) {
714
    errno = EBADF;
715
    kern_sti();
716
    return -1;
717
  }
718
 
719
  if (omqstat) {
720
    omqstat->mq_flags   = mq_table[mqdes].flags & O_NONBLOCK;
721
    omqstat->mq_maxmsg  = mq_table[mqdes].maxmsg;
722
    omqstat->mq_msgsize = mq_table[mqdes].msgsize;
723
    omqstat->mq_curmsgs = mq_table[mqdes].count;
724
  }
725
 
726
  mq_table[mqdes].flags = (mq_table[mqdes].flags & ~O_NONBLOCK) |
727
                          (mqstat->mq_flags & O_NONBLOCK);
728
  kern_sti();
729
  return 0;
730
}
731
 
732
int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat)
733
{
734
  kern_cli();
735
 
736
  if (mqdes < 0 ||
737
      mqdes >= MQ_OPEN_MAX ||
738
      !(mq_table[mqdes].flags & MQ_USED) ) {
739
    errno = EBADF;
740
    kern_sti();
741
    return -1;
742
  }
743
 
744
  mqstat->mq_flags   = mq_table[mqdes].flags & O_NONBLOCK;
745
  mqstat->mq_maxmsg  = mq_table[mqdes].maxmsg;
746
  mqstat->mq_msgsize = mq_table[mqdes].msgsize;
747
  mqstat->mq_curmsgs = mq_table[mqdes].count;
748
 
749
  kern_sti();
750
  return 0;
751
}