错误码_芯片运行在极限的边缘,怪异问题集(一)创建消息队列,错误码24

现象描述:板子中原本运行有A、B、C三个进程。其中A进程优先级比较高。现在将A的优先级恢复到普通优先级后,再添加D进程。发现B、C会随机启动不起来。将A优先级提高或删掉D后,又全部可以正常运行。

进一步分析log,返现B、C起不来是因为mq_open失败,返回24,即EMFILE。

解决方案:步骤1:按照常规解决问题的方法,先查EMFILE的原因,大概意思是进程打开文件数量超过系统限制(我的开发板是1024个),但是我的进程压根没有打开多少文件。所以,这应该是不可能的。增大文件数量的限制,果然没有效果。

步骤2:分析mq_open系统调用源码:sys_mq_open调用do_create,do_create调用vfs_create,vfs_create调用inode_operations的create,即mqueue_create

static const struct inode_operations mqueue_dir_inode_operations = {.lookup = simple_lookup,.create = mqueue_create,.unlink = mqueue_unlink,};

mqueue_create调用了我们的主角mqueue_get_inode,重点分析该函数:

static struct inode *mqueue_get_inode(struct super_block *sb,struct ipc_namespace *ipc_ns, umode_t mode,struct mq_attr *attr){struct user_struct *u = current_user();//获取当前用户struct inode *inode;int ret = -ENOMEM;inode = new_inode(sb);//为queue创建一个文件节点if (!inode)goto err;inode->i_ino = get_next_ino();inode->i_mode = mode;inode->i_uid = current_fsuid();inode->i_gid = current_fsgid();inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME;if (S_ISREG(mode)) {struct mqueue_inode_info *info;unsigned long mq_bytes, mq_treesize;inode->i_fop = &mqueue_file_operations;inode->i_size = FILENT_SIZE;/* mqueue specific info */info = MQUEUE_I(inode);spin_lock_init(&info->lock);init_waitqueue_head(&info->wait_q);INIT_LIST_HEAD(&info->e_wait_q[0].list);INIT_LIST_HEAD(&info->e_wait_q[1].list);info->notify_owner = NULL;info->notify_user_ns = NULL;info->qsize = 0;info->user = NULL;/* set when all is ok */info->msg_tree = RB_ROOT;info->node_cache = NULL;memset(&info->attr, 0, sizeof(info->attr));info->attr.mq_maxmsg = min(ipc_ns->mq_msg_max, ipc_ns->mq_msg_default);info->attr.mq_msgsize = min(ipc_ns->mq_msgsize_max, ipc_ns->mq_msgsize_default);if (attr) {info->attr.mq_maxmsg = attr->mq_maxmsg;info->attr.mq_msgsize = attr->mq_msgsize;}mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *sizeof(struct posix_msg_tree_node);mq_bytes = mq_treesize + (info->attr.mq_maxmsg * info->attr.mq_msgsize);spin_lock(&mq_lock); //下面这个坑爹的判断,同一个用户创建的所有queue的需要的内存大小如果超过了当前进程的最大queue的大小限制的话,就会失败。错误码24!!!!!!!!!!!! if (u->mq_bytes + mq_bytes < u->mq_bytes ||  u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) { spin_unlock(&mq_lock); /* mqueue_evict_inode() releases info->messages */ ret = -EMFILE;//错误码24!!!!!!!!!!!!! goto out_inode; } u->mq_bytes += mq_bytes; spin_unlock(&mq_lock); /* all is ok */ info->user = get_uid(u); } else if (S_ISDIR(mode)) { inc_nlink(inode); /* Some things misbehave if size == 0 on a directory */ inode->i_size = 2 * DIRENT_SIZE; inode->i_op = &mqueue_dir_inode_operations; inode->i_fop = &simple_dir_operations;}return inode;out_inode:iput(inode);err:return ERR_PTR(ret);}

到这里,原因已经找到了。因此,将所有进程的RLIMIT_MSGQUEUE搞大就可以解决问题。这些进程都是由同一个父进程启动的,因此只要在父进程中修改RLIMIT_MSGQUEUE。

但是这里还有最后一个问题,为什么去掉A进程的优先级后,也会影响queue size的限制呢?

查看A进程的代码返现,它中间调用了如下代码改变了自己创建的queue的所有者,去掉实时调度优先级后,下面的代码来不及执行,加大了出现问题的概率,(A进程有实时调度也会出现该问题,只是概率很小),坑爹的外包啊。

if (chown(inputChannel.c_str(), 0, userInfo->pw_gid) == -1) {MM_LOG_ERROR(ATB3_CONTEXT_INBOUND, MM_MSG("Failed to change group id on '" << inputChannel << "' (" << strerror(errno) << ")."));throw std::runtime_error("Failed to change group id");}
5d5dff955035d99067ef09ae268d4966.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值