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

Subversion Repositories or1k

[/] [or1k/] [tags/] [LINUX_2_4_26_OR32/] [linux/] [linux-2.4/] [ipc/] [msg.c] - Blame information for rev 1780

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

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/ipc/msg.c
3
 * Copyright (C) 1992 Krishna Balasubramanian
4
 *
5
 * Removed all the remaining kerneld mess
6
 * Catch the -EFAULT stuff properly
7
 * Use GFP_KERNEL for messages as in 1.2
8
 * Fixed up the unchecked user space derefs
9
 * Copyright (C) 1998 Alan Cox & Andi Kleen
10
 *
11
 * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
12
 *
13
 * mostly rewritten, threaded and wake-one semantics added
14
 * MSGMAX limit removed, sysctl's added
15
 * (c) 1999 Manfred Spraul <manfreds@colorfullife.com>
16
 */
17
 
18
#include <linux/config.h>
19
#include <linux/slab.h>
20
#include <linux/msg.h>
21
#include <linux/spinlock.h>
22
#include <linux/init.h>
23
#include <linux/proc_fs.h>
24
#include <linux/list.h>
25
#include <asm/uaccess.h>
26
#include "util.h"
27
 
28
/* sysctl: */
29
int msg_ctlmax = MSGMAX;
30
int msg_ctlmnb = MSGMNB;
31
int msg_ctlmni = MSGMNI;
32
 
33
/* one msg_receiver structure for each sleeping receiver */
34
struct msg_receiver {
35
        struct list_head r_list;
36
        struct task_struct* r_tsk;
37
 
38
        int r_mode;
39
        long r_msgtype;
40
        long r_maxsize;
41
 
42
        struct msg_msg* volatile r_msg;
43
};
44
 
45
/* one msg_sender for each sleeping sender */
46
struct msg_sender {
47
        struct list_head list;
48
        struct task_struct* tsk;
49
};
50
 
51
struct msg_msgseg {
52
        struct msg_msgseg* next;
53
        /* the next part of the message follows immediately */
54
};
55
/* one msg_msg structure for each message */
56
struct msg_msg {
57
        struct list_head m_list;
58
        long  m_type;
59
        int m_ts;           /* message text size */
60
        struct msg_msgseg* next;
61
        /* the actual message follows immediately */
62
};
63
 
64
#define DATALEN_MSG     (PAGE_SIZE-sizeof(struct msg_msg))
65
#define DATALEN_SEG     (PAGE_SIZE-sizeof(struct msg_msgseg))
66
 
67
/* one msq_queue structure for each present queue on the system */
68
struct msg_queue {
69
        struct kern_ipc_perm q_perm;
70
        time_t q_stime;                 /* last msgsnd time */
71
        time_t q_rtime;                 /* last msgrcv time */
72
        time_t q_ctime;                 /* last change time */
73
        unsigned long q_cbytes;         /* current number of bytes on queue */
74
        unsigned long q_qnum;           /* number of messages in queue */
75
        unsigned long q_qbytes;         /* max number of bytes on queue */
76
        pid_t q_lspid;                  /* pid of last msgsnd */
77
        pid_t q_lrpid;                  /* last receive pid */
78
 
79
        struct list_head q_messages;
80
        struct list_head q_receivers;
81
        struct list_head q_senders;
82
};
83
 
84
#define SEARCH_ANY              1
85
#define SEARCH_EQUAL            2
86
#define SEARCH_NOTEQUAL         3
87
#define SEARCH_LESSEQUAL        4
88
 
89
static atomic_t msg_bytes = ATOMIC_INIT(0);
90
static atomic_t msg_hdrs = ATOMIC_INIT(0);
91
 
92
static struct ipc_ids msg_ids;
93
 
94
#define msg_lock(id)    ((struct msg_queue*)ipc_lock(&msg_ids,id))
95
#define msg_unlock(id)  ipc_unlock(&msg_ids,id)
96
#define msg_rmid(id)    ((struct msg_queue*)ipc_rmid(&msg_ids,id))
97
#define msg_checkid(msq, msgid) \
98
        ipc_checkid(&msg_ids,&msq->q_perm,msgid)
99
#define msg_buildid(id, seq) \
100
        ipc_buildid(&msg_ids, id, seq)
101
 
102
static void freeque (int id);
103
static int newque (key_t key, int msgflg);
104
#ifdef CONFIG_PROC_FS
105
static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
106
#endif
107
 
108
void __init msg_init (void)
109
{
110
        ipc_init_ids(&msg_ids,msg_ctlmni);
111
 
112
#ifdef CONFIG_PROC_FS
113
        create_proc_read_entry("sysvipc/msg", 0, 0, sysvipc_msg_read_proc, NULL);
114
#endif
115
}
116
 
117
static int newque (key_t key, int msgflg)
118
{
119
        int id;
120
        struct msg_queue *msq;
121
 
122
        msq  = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL);
123
        if (!msq)
124
                return -ENOMEM;
125
        id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);
126
        if(id == -1) {
127
                kfree(msq);
128
                return -ENOSPC;
129
        }
130
        msq->q_perm.mode = (msgflg & S_IRWXUGO);
131
        msq->q_perm.key = key;
132
 
133
        msq->q_stime = msq->q_rtime = 0;
134
        msq->q_ctime = CURRENT_TIME;
135
        msq->q_cbytes = msq->q_qnum = 0;
136
        msq->q_qbytes = msg_ctlmnb;
137
        msq->q_lspid = msq->q_lrpid = 0;
138
        INIT_LIST_HEAD(&msq->q_messages);
139
        INIT_LIST_HEAD(&msq->q_receivers);
140
        INIT_LIST_HEAD(&msq->q_senders);
141
        msg_unlock(id);
142
 
143
        return msg_buildid(id,msq->q_perm.seq);
144
}
145
 
146
static void free_msg(struct msg_msg* msg)
147
{
148
        struct msg_msgseg* seg;
149
        seg = msg->next;
150
        kfree(msg);
151
        while(seg != NULL) {
152
                struct msg_msgseg* tmp = seg->next;
153
                kfree(seg);
154
                seg = tmp;
155
        }
156
}
157
 
158
static struct msg_msg* load_msg(void* src, int len)
159
{
160
        struct msg_msg* msg;
161
        struct msg_msgseg** pseg;
162
        int err;
163
        int alen;
164
 
165
        alen = len;
166
        if(alen > DATALEN_MSG)
167
                alen = DATALEN_MSG;
168
 
169
        msg = (struct msg_msg *) kmalloc (sizeof(*msg) + alen, GFP_KERNEL);
170
        if(msg==NULL)
171
                return ERR_PTR(-ENOMEM);
172
 
173
        msg->next = NULL;
174
 
175
        if (copy_from_user(msg+1, src, alen)) {
176
                err = -EFAULT;
177
                goto out_err;
178
        }
179
 
180
        len -= alen;
181
        src = ((char*)src)+alen;
182
        pseg = &msg->next;
183
        while(len > 0) {
184
                struct msg_msgseg* seg;
185
                alen = len;
186
                if(alen > DATALEN_SEG)
187
                        alen = DATALEN_SEG;
188
                seg = (struct msg_msgseg *) kmalloc (sizeof(*seg) + alen, GFP_KERNEL);
189
                if(seg==NULL) {
190
                        err=-ENOMEM;
191
                        goto out_err;
192
                }
193
                *pseg = seg;
194
                seg->next = NULL;
195
                if(copy_from_user (seg+1, src, alen)) {
196
                        err = -EFAULT;
197
                        goto out_err;
198
                }
199
                pseg = &seg->next;
200
                len -= alen;
201
                src = ((char*)src)+alen;
202
        }
203
        return msg;
204
 
205
out_err:
206
        free_msg(msg);
207
        return ERR_PTR(err);
208
}
209
 
210
static int store_msg(void* dest, struct msg_msg* msg, int len)
211
{
212
        int alen;
213
        struct msg_msgseg *seg;
214
 
215
        alen = len;
216
        if(alen > DATALEN_MSG)
217
                alen = DATALEN_MSG;
218
        if(copy_to_user (dest, msg+1, alen))
219
                return -1;
220
 
221
        len -= alen;
222
        dest = ((char*)dest)+alen;
223
        seg = msg->next;
224
        while(len > 0) {
225
                alen = len;
226
                if(alen > DATALEN_SEG)
227
                        alen = DATALEN_SEG;
228
                if(copy_to_user (dest, seg+1, alen))
229
                        return -1;
230
                len -= alen;
231
                dest = ((char*)dest)+alen;
232
                seg=seg->next;
233
        }
234
        return 0;
235
}
236
 
237
static inline void ss_add(struct msg_queue* msq, struct msg_sender* mss)
238
{
239
        mss->tsk=current;
240
        current->state=TASK_INTERRUPTIBLE;
241
        list_add_tail(&mss->list,&msq->q_senders);
242
}
243
 
244
static inline void ss_del(struct msg_sender* mss)
245
{
246
        if(mss->list.next != NULL)
247
                list_del(&mss->list);
248
}
249
 
250
static void ss_wakeup(struct list_head* h, int kill)
251
{
252
        struct list_head *tmp;
253
 
254
        tmp = h->next;
255
        while (tmp != h) {
256
                struct msg_sender* mss;
257
 
258
                mss = list_entry(tmp,struct msg_sender,list);
259
                tmp = tmp->next;
260
                if(kill)
261
                        mss->list.next=NULL;
262
                wake_up_process(mss->tsk);
263
        }
264
}
265
 
266
static void expunge_all(struct msg_queue* msq, int res)
267
{
268
        struct list_head *tmp;
269
 
270
        tmp = msq->q_receivers.next;
271
        while (tmp != &msq->q_receivers) {
272
                struct msg_receiver* msr;
273
 
274
                msr = list_entry(tmp,struct msg_receiver,r_list);
275
                tmp = tmp->next;
276
                msr->r_msg = ERR_PTR(res);
277
                wake_up_process(msr->r_tsk);
278
        }
279
}
280
 
281
static void freeque (int id)
282
{
283
        struct msg_queue *msq;
284
        struct list_head *tmp;
285
 
286
        msq = msg_rmid(id);
287
 
288
        expunge_all(msq,-EIDRM);
289
        ss_wakeup(&msq->q_senders,1);
290
        msg_unlock(id);
291
 
292
        tmp = msq->q_messages.next;
293
        while(tmp != &msq->q_messages) {
294
                struct msg_msg* msg = list_entry(tmp,struct msg_msg,m_list);
295
                tmp = tmp->next;
296
                atomic_dec(&msg_hdrs);
297
                free_msg(msg);
298
        }
299
        atomic_sub(msq->q_cbytes, &msg_bytes);
300
        kfree(msq);
301
}
302
 
303
asmlinkage long sys_msgget (key_t key, int msgflg)
304
{
305
        int id, ret = -EPERM;
306
        struct msg_queue *msq;
307
 
308
        down(&msg_ids.sem);
309
        if (key == IPC_PRIVATE)
310
                ret = newque(key, msgflg);
311
        else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */
312
                if (!(msgflg & IPC_CREAT))
313
                        ret = -ENOENT;
314
                else
315
                        ret = newque(key, msgflg);
316
        } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
317
                ret = -EEXIST;
318
        } else {
319
                msq = msg_lock(id);
320
                if(msq==NULL)
321
                        BUG();
322
                if (ipcperms(&msq->q_perm, msgflg))
323
                        ret = -EACCES;
324
                else
325
                        ret = msg_buildid(id, msq->q_perm.seq);
326
                msg_unlock(id);
327
        }
328
        up(&msg_ids.sem);
329
        return ret;
330
}
331
 
332
static inline unsigned long copy_msqid_to_user(void *buf, struct msqid64_ds *in, int version)
333
{
334
        switch(version) {
335
        case IPC_64:
336
                return copy_to_user (buf, in, sizeof(*in));
337
        case IPC_OLD:
338
            {
339
                struct msqid_ds out;
340
 
341
                memset(&out,0,sizeof(out));
342
 
343
                ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm);
344
 
345
                out.msg_stime           = in->msg_stime;
346
                out.msg_rtime           = in->msg_rtime;
347
                out.msg_ctime           = in->msg_ctime;
348
 
349
                if(in->msg_cbytes > USHRT_MAX)
350
                        out.msg_cbytes  = USHRT_MAX;
351
                else
352
                        out.msg_cbytes  = in->msg_cbytes;
353
                out.msg_lcbytes         = in->msg_cbytes;
354
 
355
                if(in->msg_qnum > USHRT_MAX)
356
                        out.msg_qnum    = USHRT_MAX;
357
                else
358
                        out.msg_qnum    = in->msg_qnum;
359
 
360
                if(in->msg_qbytes > USHRT_MAX)
361
                        out.msg_qbytes  = USHRT_MAX;
362
                else
363
                        out.msg_qbytes  = in->msg_qbytes;
364
                out.msg_lqbytes         = in->msg_qbytes;
365
 
366
                out.msg_lspid           = in->msg_lspid;
367
                out.msg_lrpid           = in->msg_lrpid;
368
 
369
                return copy_to_user (buf, &out, sizeof(out));
370
            }
371
        default:
372
                return -EINVAL;
373
        }
374
}
375
 
376
struct msq_setbuf {
377
        unsigned long   qbytes;
378
        uid_t           uid;
379
        gid_t           gid;
380
        mode_t          mode;
381
};
382
 
383
static inline unsigned long copy_msqid_from_user(struct msq_setbuf *out, void *buf, int version)
384
{
385
        switch(version) {
386
        case IPC_64:
387
            {
388
                struct msqid64_ds tbuf;
389
 
390
                if (copy_from_user (&tbuf, buf, sizeof (tbuf)))
391
                        return -EFAULT;
392
 
393
                out->qbytes             = tbuf.msg_qbytes;
394
                out->uid                = tbuf.msg_perm.uid;
395
                out->gid                = tbuf.msg_perm.gid;
396
                out->mode               = tbuf.msg_perm.mode;
397
 
398
                return 0;
399
            }
400
        case IPC_OLD:
401
            {
402
                struct msqid_ds tbuf_old;
403
 
404
                if (copy_from_user (&tbuf_old, buf, sizeof (tbuf_old)))
405
                        return -EFAULT;
406
 
407
                out->uid                = tbuf_old.msg_perm.uid;
408
                out->gid                = tbuf_old.msg_perm.gid;
409
                out->mode               = tbuf_old.msg_perm.mode;
410
 
411
                if(tbuf_old.msg_qbytes == 0)
412
                        out->qbytes     = tbuf_old.msg_lqbytes;
413
                else
414
                        out->qbytes     = tbuf_old.msg_qbytes;
415
 
416
                return 0;
417
            }
418
        default:
419
                return -EINVAL;
420
        }
421
}
422
 
423
asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
424
{
425
        int err, version;
426
        struct msg_queue *msq;
427
        struct msq_setbuf setbuf;
428
        struct kern_ipc_perm *ipcp;
429
 
430
        if (msqid < 0 || cmd < 0)
431
                return -EINVAL;
432
 
433
        version = ipc_parse_version(&cmd);
434
 
435
        switch (cmd) {
436
        case IPC_INFO:
437
        case MSG_INFO:
438
        {
439
                struct msginfo msginfo;
440
                int max_id;
441
                if (!buf)
442
                        return -EFAULT;
443
                /* We must not return kernel stack data.
444
                 * due to padding, it's not enough
445
                 * to set all member fields.
446
                 */
447
                memset(&msginfo,0,sizeof(msginfo));
448
                msginfo.msgmni = msg_ctlmni;
449
                msginfo.msgmax = msg_ctlmax;
450
                msginfo.msgmnb = msg_ctlmnb;
451
                msginfo.msgssz = MSGSSZ;
452
                msginfo.msgseg = MSGSEG;
453
                down(&msg_ids.sem);
454
                if (cmd == MSG_INFO) {
455
                        msginfo.msgpool = msg_ids.in_use;
456
                        msginfo.msgmap = atomic_read(&msg_hdrs);
457
                        msginfo.msgtql = atomic_read(&msg_bytes);
458
                } else {
459
                        msginfo.msgmap = MSGMAP;
460
                        msginfo.msgpool = MSGPOOL;
461
                        msginfo.msgtql = MSGTQL;
462
                }
463
                max_id = msg_ids.max_id;
464
                up(&msg_ids.sem);
465
                if (copy_to_user (buf, &msginfo, sizeof(struct msginfo)))
466
                        return -EFAULT;
467
                return (max_id < 0) ? 0: max_id;
468
        }
469
        case MSG_STAT:
470
        case IPC_STAT:
471
        {
472
                struct msqid64_ds tbuf;
473
                int success_return;
474
                if (!buf)
475
                        return -EFAULT;
476
                if(cmd == MSG_STAT && msqid >= msg_ids.size)
477
                        return -EINVAL;
478
 
479
                memset(&tbuf,0,sizeof(tbuf));
480
 
481
                msq = msg_lock(msqid);
482
                if (msq == NULL)
483
                        return -EINVAL;
484
 
485
                if(cmd == MSG_STAT) {
486
                        success_return = msg_buildid(msqid, msq->q_perm.seq);
487
                } else {
488
                        err = -EIDRM;
489
                        if (msg_checkid(msq,msqid))
490
                                goto out_unlock;
491
                        success_return = 0;
492
                }
493
                err = -EACCES;
494
                if (ipcperms (&msq->q_perm, S_IRUGO))
495
                        goto out_unlock;
496
 
497
                kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
498
                tbuf.msg_stime  = msq->q_stime;
499
                tbuf.msg_rtime  = msq->q_rtime;
500
                tbuf.msg_ctime  = msq->q_ctime;
501
                tbuf.msg_cbytes = msq->q_cbytes;
502
                tbuf.msg_qnum   = msq->q_qnum;
503
                tbuf.msg_qbytes = msq->q_qbytes;
504
                tbuf.msg_lspid  = msq->q_lspid;
505
                tbuf.msg_lrpid  = msq->q_lrpid;
506
                msg_unlock(msqid);
507
                if (copy_msqid_to_user(buf, &tbuf, version))
508
                        return -EFAULT;
509
                return success_return;
510
        }
511
        case IPC_SET:
512
                if (!buf)
513
                        return -EFAULT;
514
                if (copy_msqid_from_user (&setbuf, buf, version))
515
                        return -EFAULT;
516
                break;
517
        case IPC_RMID:
518
                break;
519
        default:
520
                return  -EINVAL;
521
        }
522
 
523
        down(&msg_ids.sem);
524
        msq = msg_lock(msqid);
525
        err=-EINVAL;
526
        if (msq == NULL)
527
                goto out_up;
528
 
529
        err = -EIDRM;
530
        if (msg_checkid(msq,msqid))
531
                goto out_unlock_up;
532
        ipcp = &msq->q_perm;
533
        err = -EPERM;
534
        if (current->euid != ipcp->cuid &&
535
            current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
536
            /* We _could_ check for CAP_CHOWN above, but we don't */
537
                goto out_unlock_up;
538
 
539
        switch (cmd) {
540
        case IPC_SET:
541
        {
542
                if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
543
                        goto out_unlock_up;
544
                msq->q_qbytes = setbuf.qbytes;
545
 
546
                ipcp->uid = setbuf.uid;
547
                ipcp->gid = setbuf.gid;
548
                ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
549
                        (S_IRWXUGO & setbuf.mode);
550
                msq->q_ctime = CURRENT_TIME;
551
                /* sleeping receivers might be excluded by
552
                 * stricter permissions.
553
                 */
554
                expunge_all(msq,-EAGAIN);
555
                /* sleeping senders might be able to send
556
                 * due to a larger queue size.
557
                 */
558
                ss_wakeup(&msq->q_senders,0);
559
                msg_unlock(msqid);
560
                break;
561
        }
562
        case IPC_RMID:
563
                freeque (msqid);
564
                break;
565
        }
566
        err = 0;
567
out_up:
568
        up(&msg_ids.sem);
569
        return err;
570
out_unlock_up:
571
        msg_unlock(msqid);
572
        goto out_up;
573
out_unlock:
574
        msg_unlock(msqid);
575
        return err;
576
}
577
 
578
static int testmsg(struct msg_msg* msg,long type,int mode)
579
{
580
        switch(mode)
581
        {
582
                case SEARCH_ANY:
583
                        return 1;
584
                case SEARCH_LESSEQUAL:
585
                        if(msg->m_type <=type)
586
                                return 1;
587
                        break;
588
                case SEARCH_EQUAL:
589
                        if(msg->m_type == type)
590
                                return 1;
591
                        break;
592
                case SEARCH_NOTEQUAL:
593
                        if(msg->m_type != type)
594
                                return 1;
595
                        break;
596
        }
597
        return 0;
598
}
599
 
600
static int inline pipelined_send(struct msg_queue* msq, struct msg_msg* msg)
601
{
602
        struct list_head* tmp;
603
 
604
        tmp = msq->q_receivers.next;
605
        while (tmp != &msq->q_receivers) {
606
                struct msg_receiver* msr;
607
                msr = list_entry(tmp,struct msg_receiver,r_list);
608
                tmp = tmp->next;
609
                if(testmsg(msg,msr->r_msgtype,msr->r_mode)) {
610
                        list_del(&msr->r_list);
611
                        if(msr->r_maxsize < msg->m_ts) {
612
                                msr->r_msg = ERR_PTR(-E2BIG);
613
                                wake_up_process(msr->r_tsk);
614
                        } else {
615
                                msr->r_msg = msg;
616
                                msq->q_lrpid = msr->r_tsk->pid;
617
                                msq->q_rtime = CURRENT_TIME;
618
                                wake_up_process(msr->r_tsk);
619
                                return 1;
620
                        }
621
                }
622
        }
623
        return 0;
624
}
625
 
626
asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg)
627
{
628
        struct msg_queue *msq;
629
        struct msg_msg *msg;
630
        long mtype;
631
        int err;
632
 
633
        if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0)
634
                return -EINVAL;
635
        if (get_user(mtype, &msgp->mtype))
636
                return -EFAULT;
637
        if (mtype < 1)
638
                return -EINVAL;
639
 
640
        msg = load_msg(msgp->mtext, msgsz);
641
        if(IS_ERR(msg))
642
                return PTR_ERR(msg);
643
 
644
        msg->m_type = mtype;
645
        msg->m_ts = msgsz;
646
 
647
        msq = msg_lock(msqid);
648
        err=-EINVAL;
649
        if(msq==NULL)
650
                goto out_free;
651
retry:
652
        err= -EIDRM;
653
        if (msg_checkid(msq,msqid))
654
                goto out_unlock_free;
655
 
656
        err=-EACCES;
657
        if (ipcperms(&msq->q_perm, S_IWUGO))
658
                goto out_unlock_free;
659
 
660
        if(msgsz + msq->q_cbytes > msq->q_qbytes ||
661
                1 + msq->q_qnum > msq->q_qbytes) {
662
                struct msg_sender s;
663
 
664
                if(msgflg&IPC_NOWAIT) {
665
                        err=-EAGAIN;
666
                        goto out_unlock_free;
667
                }
668
                ss_add(msq, &s);
669
                msg_unlock(msqid);
670
                schedule();
671
                current->state= TASK_RUNNING;
672
 
673
                msq = msg_lock(msqid);
674
                err = -EIDRM;
675
                if(msq==NULL)
676
                        goto out_free;
677
                ss_del(&s);
678
 
679
                if (signal_pending(current)) {
680
                        err=-EINTR;
681
                        goto out_unlock_free;
682
                }
683
                goto retry;
684
        }
685
 
686
        msq->q_lspid = current->pid;
687
        msq->q_stime = CURRENT_TIME;
688
 
689
        if(!pipelined_send(msq,msg)) {
690
                /* noone is waiting for this message, enqueue it */
691
                list_add_tail(&msg->m_list,&msq->q_messages);
692
                msq->q_cbytes += msgsz;
693
                msq->q_qnum++;
694
                atomic_add(msgsz,&msg_bytes);
695
                atomic_inc(&msg_hdrs);
696
        }
697
 
698
        err = 0;
699
        msg = NULL;
700
 
701
out_unlock_free:
702
        msg_unlock(msqid);
703
out_free:
704
        if(msg!=NULL)
705
                free_msg(msg);
706
        return err;
707
}
708
 
709
static int inline convert_mode(long* msgtyp, int msgflg)
710
{
711
        /*
712
         *  find message of correct type.
713
         *  msgtyp = 0 => get first.
714
         *  msgtyp > 0 => get first message of matching type.
715
         *  msgtyp < 0 => get message with least type must be < abs(msgtype).
716
         */
717
        if(*msgtyp==0)
718
                return SEARCH_ANY;
719
        if(*msgtyp<0) {
720
                *msgtyp=-(*msgtyp);
721
                return SEARCH_LESSEQUAL;
722
        }
723
        if(msgflg & MSG_EXCEPT)
724
                return SEARCH_NOTEQUAL;
725
        return SEARCH_EQUAL;
726
}
727
 
728
asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz,
729
                            long msgtyp, int msgflg)
730
{
731
        struct msg_queue *msq;
732
        struct msg_receiver msr_d;
733
        struct list_head* tmp;
734
        struct msg_msg* msg, *found_msg;
735
        int err;
736
        int mode;
737
 
738
        if (msqid < 0 || (long) msgsz < 0)
739
                return -EINVAL;
740
        mode = convert_mode(&msgtyp,msgflg);
741
 
742
        msq = msg_lock(msqid);
743
        if(msq==NULL)
744
                return -EINVAL;
745
retry:
746
        err = -EIDRM;
747
        if (msg_checkid(msq,msqid))
748
                goto out_unlock;
749
 
750
        err=-EACCES;
751
        if (ipcperms (&msq->q_perm, S_IRUGO))
752
                goto out_unlock;
753
 
754
        tmp = msq->q_messages.next;
755
        found_msg=NULL;
756
        while (tmp != &msq->q_messages) {
757
                msg = list_entry(tmp,struct msg_msg,m_list);
758
                if(testmsg(msg,msgtyp,mode)) {
759
                        found_msg = msg;
760
                        if(mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
761
                                found_msg=msg;
762
                                msgtyp=msg->m_type-1;
763
                        } else {
764
                                found_msg=msg;
765
                                break;
766
                        }
767
                }
768
                tmp = tmp->next;
769
        }
770
        if(found_msg) {
771
                msg=found_msg;
772
                if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
773
                        err=-E2BIG;
774
                        goto out_unlock;
775
                }
776
                list_del(&msg->m_list);
777
                msq->q_qnum--;
778
                msq->q_rtime = CURRENT_TIME;
779
                msq->q_lrpid = current->pid;
780
                msq->q_cbytes -= msg->m_ts;
781
                atomic_sub(msg->m_ts,&msg_bytes);
782
                atomic_dec(&msg_hdrs);
783
                ss_wakeup(&msq->q_senders,0);
784
                msg_unlock(msqid);
785
out_success:
786
                msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz;
787
                if (put_user (msg->m_type, &msgp->mtype) ||
788
                    store_msg(msgp->mtext, msg, msgsz)) {
789
                            msgsz = -EFAULT;
790
                }
791
                free_msg(msg);
792
                return msgsz;
793
        } else
794
        {
795
                struct msg_queue *t;
796
                /* no message waiting. Prepare for pipelined
797
                 * receive.
798
                 */
799
                if (msgflg & IPC_NOWAIT) {
800
                        err=-ENOMSG;
801
                        goto out_unlock;
802
                }
803
                list_add_tail(&msr_d.r_list,&msq->q_receivers);
804
                msr_d.r_tsk = current;
805
                msr_d.r_msgtype = msgtyp;
806
                msr_d.r_mode = mode;
807
                if(msgflg & MSG_NOERROR)
808
                        msr_d.r_maxsize = INT_MAX;
809
                 else
810
                        msr_d.r_maxsize = msgsz;
811
                msr_d.r_msg = ERR_PTR(-EAGAIN);
812
                current->state = TASK_INTERRUPTIBLE;
813
                msg_unlock(msqid);
814
 
815
                schedule();
816
                current->state = TASK_RUNNING;
817
 
818
                /* This introduces a race so we must always take
819
                   the slow path
820
                msg = (struct msg_msg*) msr_d.r_msg;
821
                if(!IS_ERR(msg))
822
                        goto out_success;
823
                */
824
                t = msg_lock(msqid);
825
                if(t==NULL)
826
                        msqid=-1;
827
                msg = (struct msg_msg*)msr_d.r_msg;
828
                if(!IS_ERR(msg)) {
829
                        /* our message arived while we waited for
830
                         * the spinlock. Process it.
831
                         */
832
                        if(msqid!=-1)
833
                                msg_unlock(msqid);
834
                        goto out_success;
835
                }
836
                err = PTR_ERR(msg);
837
                if(err == -EAGAIN) {
838
                        if(msqid==-1)
839
                                BUG();
840
                        list_del(&msr_d.r_list);
841
                        if (signal_pending(current))
842
                                err=-EINTR;
843
                         else
844
                                goto retry;
845
                }
846
        }
847
out_unlock:
848
        if(msqid!=-1)
849
                msg_unlock(msqid);
850
        return err;
851
}
852
 
853
#ifdef CONFIG_PROC_FS
854
static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
855
{
856
        off_t pos = 0;
857
        off_t begin = 0;
858
        int i, len = 0;
859
 
860
        down(&msg_ids.sem);
861
        len += sprintf(buffer, "       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n");
862
 
863
        for(i = 0; i <= msg_ids.max_id; i++) {
864
                struct msg_queue * msq;
865
                msq = msg_lock(i);
866
                if(msq != NULL) {
867
                        len += sprintf(buffer + len, "%10d %10d  %4o  %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
868
                                msq->q_perm.key,
869
                                msg_buildid(i,msq->q_perm.seq),
870
                                msq->q_perm.mode,
871
                                msq->q_cbytes,
872
                                msq->q_qnum,
873
                                msq->q_lspid,
874
                                msq->q_lrpid,
875
                                msq->q_perm.uid,
876
                                msq->q_perm.gid,
877
                                msq->q_perm.cuid,
878
                                msq->q_perm.cgid,
879
                                msq->q_stime,
880
                                msq->q_rtime,
881
                                msq->q_ctime);
882
                        msg_unlock(i);
883
 
884
                        pos += len;
885
                        if(pos < offset) {
886
                                len = 0;
887
                                begin = pos;
888
                        }
889
                        if(pos > offset + length)
890
                                goto done;
891
                }
892
 
893
        }
894
        *eof = 1;
895
done:
896
        up(&msg_ids.sem);
897
        *start = buffer + (offset - begin);
898
        len -= (offset - begin);
899
        if(len > length)
900
                len = length;
901
        if(len < 0)
902
                len = 0;
903
        return len;
904
}
905
#endif

powered by: WebSVN 2.1.0

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