The kernel does this lock for you.
Look at the implementation in ipc / mqueue.c:
SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr, size_t, msg_len, unsigned int __user *, u_msg_prio, const struct timespec __user *, u_abs_timeout) { ... struct mqueue_inode_info *info; ... filp = fget(mqdes); if (unlikely(!filp)) { ret = -EBADF; goto out; } inode = filp->f_path.dentry->d_inode; ... spin_lock(&info->lock); if (info->attr.mq_curmsgs == 0) { if (filp->f_flags & O_NONBLOCK) { spin_unlock(&info->lock); ... } else { msg_ptr = msg_get(info); inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; pipelined_receive(info); spin_unlock(&info->lock); ret = 0; }
Each mqueue has a spin lock, which is obtained before checking for new messages.
In the latter case (pipelined_receive) there is an error message. This is protected by the info-> lock, so neither of the two threads can receive the same message.
source share