Chinaunix首页 | 论坛 | 博客
  • 博客访问: 21152
  • 博文数量: 6
  • 博客积分: 477
  • 博客等级: 下士
  • 技术积分: 70
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-28 17:10
文章存档

2010年(1)

2009年(5)

我的朋友
最近访客

分类: LINUX

2010-01-08 10:39:32

最近一个在mmo游戏的服务器,上面用到了消息队列。
 
觉得unix/linux下面的消息队列还是挺好的,可以支持多进程对一个同一个队列同时读写,因为对于消息队列
内核层已经为我们解决了同步问题,在用户层不需要额外的同步代码,直接使用就可以了。
 
下面贴一段代码是关于发送消息的msgsnd是实现:
关于代码的帖子:

// 先看msgsnd()函数,它通过系统调用接口界面,进入内核执行,代码如下:

SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
        int, msgflg)
{
    long mtype;

    if (get_user(mtype, &msgp->mtype))
        return -EFAULT;
    return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
}
// 接下来看do_msgsnd()部分的代码,如下:

long do_msgsnd(int msqid, long mtype, void __user *mtext,
        size_t msgsz, int msgflg)
{
    struct msg_queue *msq;
    struct msg_msg *msg;
    int err;
    struct ipc_namespace *ns;

    ns = current->nsproxy->ipc_ns;

    if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
        return -EINVAL;
    if (mtype < 1)
        return -EINVAL;

    msg = load_msg(mtext, msgsz);
    if (IS_ERR(msg))
        return PTR_ERR(msg);

    msg->m_type = mtype;
    msg->m_ts = msgsz;

    msq = msg_lock_check(ns, msqid);
    if (IS_ERR(msq)) {
        err = PTR_ERR(msq);
        goto out_free;
    }

    for (;;) {
        struct msg_sender s;

        err = -EACCES;
        if (ipcperms(&msq->q_perm, S_IWUGO))
            goto out_unlock_free;

        err = security_msg_queue_msgsnd(msq, msg, msgflg);
        if (err)
            goto out_unlock_free;

        if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
                1 + msq->q_qnum <= msq->q_qbytes) {
            break;
        }

        /* queue full, wait: */
        if (msgflg & IPC_NOWAIT) {
            err = -EAGAIN;
            goto out_unlock_free;
        }
        ss_add(msq, &s);
        ipc_rcu_getref(msq);
        msg_unlock(msq);
        schedule();

        ipc_lock_by_ptr(&msq->q_perm);
        ipc_rcu_putref(msq);
        if (msq->q_perm.deleted) {
            err = -EIDRM;
            goto out_unlock_free;
        }
        ss_del(&s);

        if (signal_pending(current)) {
            err = -ERESTARTNOHAND;
            goto out_unlock_free;
        }
    }

    msq->q_lspid = task_tgid_vnr(current);
    msq->q_stime = get_seconds();

    if (!pipelined_send(msq, msg)) {
        /* noone is waiting for this message, enqueue it */
        list_add_tail(&msg->m_list, &msq->q_messages);
        msq->q_cbytes += msgsz;
        msq->q_qnum++;
        atomic_add(msgsz, &ns->msg_bytes);
        atomic_inc(&ns->msg_hdrs);
    }

    err = 0;
    msg = NULL;

out_unlock_free:
    msg_unlock(msq);
out_free:
    if (msg != NULL)
        free_msg(msg);
    return err;
}
// 在这段代码中,请注意临近入口位置的这个函数msg_lock_check(),我们跟进,看一下这个lock是如何check

// 的,代码如下:

static inline struct msg_queue *msg_lock_check(struct ipc_namespace *ns,
                        int id)
{
    struct kern_ipc_perm *ipcp = ipc_lock_check(&msg_ids(ns), id);

    if (IS_ERR(ipcp))
        return (struct msg_queue *)ipcp;

    return container_of(ipcp, struct msg_queue, q_perm);
}
// ipc_lock_check()是一个能够check所有IPC object同步信息的函数,它的定义如下:

struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id)
{
    struct kern_ipc_perm *out;

    out = ipc_lock(ids, id);
    if (IS_ERR(out))
        return out;

    if (ipc_checkid(out, id)) {
        ipc_unlock(out);
        return ERR_PTR(-EIDRM);
    }

    return out;
}
// 这里的ipc_lock()是至关重要的地方!通过这个函数的注释,也能明白它的作用了:

/**
 * ipc_lock - Lock an ipc structure without rw_mutex held
 * @ids: IPC identifier set
 * @id: ipc id to look for
 *
 * Look for an id in the ipc ids idr and lock the associated ipc object.
 *
 * The ipc object is locked on exit.
 */


struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
{
    struct kern_ipc_perm *out;
    int lid = ipcid_to_idx(id);

    rcu_read_lock();
    out = idr_find(&ids->ipcs_idr, lid);
    if (out == NULL) {
        rcu_read_unlock();
        return ERR_PTR(-EINVAL);
    }

    spin_lock(&out->lock);
    
    /* ipc_rmid() may have already freed the ID while ipc_lock
     * was spinning: here verify that the structure is still valid
     */

    if (out->deleted) {
        spin_unlock(&out->lock);
        rcu_read_unlock();
        return ERR_PTR(-EINVAL);
    }

    return out;
}


对于msgrcv同理可得,都是在内核层已经加锁了。。。。。。。
阅读(1047) | 评论(0) | 转发(0) |
0

上一篇:select,epoll关于阻塞和非阻塞的分析

下一篇:没有了

给主人留下些什么吧!~~