ipc/mqueue.c

Source file repositories/reference/linux-study-clean/ipc/mqueue.c

File Facts

System
Linux kernel
Corpus path
ipc/mqueue.c
Extension
.c
Size
43791 bytes
Lines
1681
Domain
Core OS
Bucket
IPC
Inferred role
Core OS: syscall or user/kernel boundary
Status
core implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
		struct mq_attr __user *, u_attr)
{
	struct mq_attr attr;
	if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
		return -EFAULT;

	return do_mq_open(u_name, oflag, mode, u_attr ? &attr : NULL);
}

SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
{
	int err;
	struct dentry *dentry;
	struct inode *inode;
	struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
	struct vfsmount *mnt = ipc_ns->mq_mnt;
	CLASS(filename, name)(u_name);

	if (IS_ERR(name))
		return PTR_ERR(name);

	audit_inode_parent_hidden(name, mnt->mnt_root);
	err = mnt_want_write(mnt);
	if (err)
		return err;
	dentry = start_removing_noperm(mnt->mnt_root, &QSTR(name->name));
	if (IS_ERR(dentry)) {
		err = PTR_ERR(dentry);
		goto out_drop_write;
	}

	inode = d_inode(dentry);
	ihold(inode);
	err = vfs_unlink(&nop_mnt_idmap, d_inode(mnt->mnt_root),
			 dentry, NULL);
	end_removing(dentry);
	iput(inode);

out_drop_write:
	mnt_drop_write(mnt);
	return err;
}

/* Pipelined send and receive functions.
 *
 * If a receiver finds no waiting message, then it registers itself in the
 * list of waiting receivers. A sender checks that list before adding the new
 * message into the message array. If there is a waiting receiver, then it
 * bypasses the message array and directly hands the message over to the
 * receiver. The receiver accepts the message and returns without grabbing the
 * queue spinlock:
 *
 * - Set pointer to message.
 * - Queue the receiver task for later wakeup (without the info->lock).
 * - Update its state to STATE_READY. Now the receiver can continue.
 * - Wake up the process after the lock is dropped. Should the process wake up
 *   before this wakeup (due to a timeout or a signal) it will either see
 *   STATE_READY and continue or acquire the lock to check the state again.
 *
 * The same algorithm is used for senders.
 */

static inline void __pipelined_op(struct wake_q_head *wake_q,
				  struct mqueue_inode_info *info,
				  struct ext_wait_queue *this)
{
	struct task_struct *task;

	list_del(&this->list);
	task = get_task_struct(this->task);

	/* see MQ_BARRIER for purpose/pairing */
	smp_store_release(&this->state, STATE_READY);
	wake_q_add_safe(wake_q, task);
}

/* pipelined_send() - send a message directly to the task waiting in
 * sys_mq_timedreceive() (without inserting message into a queue).
 */
static inline void pipelined_send(struct wake_q_head *wake_q,
				  struct mqueue_inode_info *info,
				  struct msg_msg *message,
				  struct ext_wait_queue *receiver)
{
	receiver->msg = message;
	__pipelined_op(wake_q, info, receiver);
}

/* pipelined_receive() - if there is task waiting in sys_mq_timedsend()

Annotation

Implementation Notes