今天有一同事问我,如果msgsnd函数的最后一个flag如果直接置0,调用该函数会是什么结果!
我不太清楚是怎样的,还是直接看代码:
msgsnd是一个系统调用,所以它在glibc中只是一个桩函数:
glibcglibc-2.4.srcsysvipcmsgsnd.c
int
msgsnd (msqid, msgp, msgsz, msgflg)
int msqid;
const void *msgp;
size_t msgsz;
int msgflg;
{
__set_errno (ENOSYS);
return -1;
}
stub_warning (msgsnd)
而在内核中的实现函数:
~kernellinux-2.6.21.1.srcipcmsg.c
Code
1
asmlinkage long
2
sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg)
3

{
4
long mtype;
5
6
if (get_user(mtype, &msgp->mtype))
7
return -EFAULT;
8
return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
9
}
10
11
12
13
14
long do_msgsnd(int msqid, long mtype, void __user *mtext,
15
size_t msgsz, int msgflg)
16

{
17
struct msg_queue *msq;
18
struct msg_msg *msg;
19
int err;
20
struct ipc_namespace *ns;
21
22
ns = current->nsproxy->ipc_ns;
23
24
if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
25
return -EINVAL;
26
if (mtype < 1)
27
return -EINVAL;
28
29
msg = load_msg(mtext, msgsz);
30
if (IS_ERR(msg))
31
return PTR_ERR(msg);
32
33
msg->m_type = mtype;
34
msg->m_ts = msgsz;
35
36
msq = msg_lock(ns, msqid);
37
err = -EINVAL;
38
if (msq == NULL)
39
goto out_free;
40
41
err= -EIDRM;
42
if (msg_checkid(ns, msq, msqid))
43
goto out_unlock_free;
44
45
for (;;)
{
46
struct msg_sender s;
47
48
err = -EACCES;
49
if (ipcperms(&msq->q_perm, S_IWUGO))
50
goto out_unlock_free;
51
52
err = security_msg_queue_msgsnd(msq, msg, msgflg);
53
if (err)
54
goto out_unlock_free;
55
56
if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
57
1 + msq->q_qnum <= msq->q_qbytes)
{
58
break;
59
}
60
61
/**//* queue full, wait: */
62
if (msgflg & IPC_NOWAIT)
{
63
err = -EAGAIN;
64
goto out_unlock_free;
65
}
66
ss_add(msq, &s);
67
ipc_rcu_getref(msq);
68
msg_unlock(msq);
69
schedule();
70
71
ipc_lock_by_ptr(&msq->q_perm);
72
ipc_rcu_putref(msq);
73
if (msq->q_perm.deleted)
{
74
err = -EIDRM;
75
goto out_unlock_free;
76
}
77
ss_del(&s);
78
79
if (signal_pending(current))
{
80
err = -ERESTARTNOHAND;
81
goto out_unlock_free;
82
}
83
}
84
85
msq->q_lspid = current->tgid;
86
msq->q_stime = get_seconds();
87
88
if (!pipelined_send(msq, msg))
{
89
/**//* noone is waiting for this message, enqueue it */
90
list_add_tail(&msg->m_list, &msq->q_messages);
91
msq->q_cbytes += msgsz;
92
msq->q_qnum++;
93
atomic_add(msgsz, &msg_bytes);
94
atomic_inc(&msg_hdrs);
95
}
96
97
err = 0;
98
msg = NULL;
99
100
out_unlock_free:
101
msg_unlock(msq);
102
out_free:
103
if (msg != NULL)
104
free_msg(msg);
105
return err;
106
}
107
108
Code
1
asmlinkage long
2
sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg)
3

{
4
long mtype;
5
6
if (get_user(mtype, &msgp->mtype))
7
return -EFAULT;
8
return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
9
}
10
11
12
13
14
long do_msgsnd(int msqid, long mtype, void __user *mtext,
15
size_t msgsz, int msgflg)
16

{
17
struct msg_queue *msq;
18
struct msg_msg *msg;
19
int err;
20
struct ipc_namespace *ns;
21
22
ns = current->nsproxy->ipc_ns;
23
24
if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
25
return -EINVAL;
26
if (mtype < 1)
27
return -EINVAL;
28
29
msg = load_msg(mtext, msgsz);
30
if (IS_ERR(msg))
31
return PTR_ERR(msg);
32
33
msg->m_type = mtype;
34
msg->m_ts = msgsz;
35
36
msq = msg_lock(ns, msqid);
37
err = -EINVAL;
38
if (msq == NULL)
39
goto out_free;
40
41
err= -EIDRM;
42
if (msg_checkid(ns, msq, msqid))
43
goto out_unlock_free;
44
45
for (;;)
{
46
struct msg_sender s;
47
48
err = -EACCES;
49
if (ipcperms(&msq->q_perm, S_IWUGO))
50
goto out_unlock_free;
51
52
err = security_msg_queue_msgsnd(msq, msg, msgflg);
53
if (err)
54
goto out_unlock_free;
55
56
if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
57
1 + msq->q_qnum <= msq->q_qbytes)
{
58
break;
59
}
60
61
/**//* queue full, wait: */
62
if (msgflg & IPC_NOWAIT)
{
63
err = -EAGAIN;
64
goto out_unlock_free;
65
}
66
ss_add(msq, &s);
67
ipc_rcu_getref(msq);
68
msg_unlock(msq);
69
schedule();
70
71
ipc_lock_by_ptr(&msq->q_perm);
72
ipc_rcu_putref(msq);
73
if (msq->q_perm.deleted)
{
74
err = -EIDRM;
75
goto out_unlock_free;
76
}
77
ss_del(&s);
78
79
if (signal_pending(current))
{
80
err = -ERESTARTNOHAND;
81
goto out_unlock_free;
82
}
83
}
84
85
msq->q_lspid = current->tgid;
86
msq->q_stime = get_seconds();
87
88
if (!pipelined_send(msq, msg))
{
89
/**//* noone is waiting for this message, enqueue it */
90
list_add_tail(&msg->m_list, &msq->q_messages);
91
msq->q_cbytes += msgsz;
92
msq->q_qnum++;
93
atomic_add(msgsz, &msg_bytes);
94
atomic_inc(&msg_hdrs);
95
}
96
97
err = 0;
98
msg = NULL;
99
100
out_unlock_free:
101
msg_unlock(msq);
102
out_free:
103
if (msg != NULL)
104
free_msg(msg);
105
return err;
106
}
107
108
security_msg_queue_msgsnd函数是调用一个钩子函数,之后没有对flag进行处理。所以,flag只在这个函数中有效:
即,只有在队列满,且标志位与IPC_NOWAIT或时不为0,则返回错误,否则没有什么影响。如果为0时,与IPC_NOWAIT取或运算显然为不0,所以会阻塞在这里,直到队列可用!
发表评论 取消回复