720 likes | 942 Views
IPC- InterProcess Communication. 939607 張佑竹 9662637 林其翰 9662658 馮秉森 9664522 李立偉. System V IPC. IPC (Interprocess Communication) commonly refers to a set of mechanisms that allow a User Mode process to do the following: Send messages to other processes or receive messages from them.
E N D
IPC-InterProcess Communication 939607 張佑竹 9662637 林其翰 9662658 馮秉森 9664522 李立偉
System V IPC • IPC (Interprocess Communication) commonly refers to a set of mechanisms that allow a User Mode process to do the following: • Send messages to other processes or receive messages from them. • Synchronize itself with other processes by means of semaphores. • Share a memory area with other processes.
Data Structure • msg_ids • msg_queue • msg_msg • msg_msgseg • msg_receiver • msg_sender
Data Structure • IPC message queue data structures
msg_ids static struct ipc_ids msg_ids; // ipc/msg.c line 69 struct ipc_ids { // ipc/util.h line 33 int in_use; unsigned short seq; unsigned short seq_max; struct rw_semaphorerw_mutex; struct idripcs_idr; };
msg_queue // include/linux/msg.hline 78 structmsg_queue{ structkern_ipc_permq_perm; time_tq_stime; // Time of last msgsnd( ) time_tq_rtime; // Time of last msgrcv( ) time_tq_ctime; // Last change time unsigned long q_cbytes; // Current bytes in queue unsigned long q_qnum; // Number of messages in queue unsigned long q_qbytes; // Max number of byte in queue pid_tq_lspid; // PID of last msgsnd( ) pid_tq_lrpid; // PID of last msgrcv( ) structlist_headq_messages;//List of messages in queue structlist_headq_receivers; // List of processes receiving messages structlist_headq_senders; // List of processes sending messages };
msg_msg // include/linux/msg.h 68 struct msg_msg{ structlist_headm_list;// Pointers for message list longm_type;// Message type intm_ts;/* message text size */ structmsg_msgseg*next; //Next portion of the message void*security; //Pointer to a security data structure (used by SELinux) //The actual message follows immediately };
msg_msgseg // ipc/msgutil.c line 20 structmsg_msgseg { structmsg_msgseg* next; /* the next part of the message follows immediately*/ };
msg_receiver // ipc/msg.c line 47 structmsg_receiver { structlist_head r_list; // A link list for all msg_receiver struct task_struct* r_tsk; int r_mode; long r_msgtype; long r_maxsize; structmsg_msg *volatile r_msg; };
msg_sender // ipc/msg.c line 59 structmsg_sender { struct list_head list; // A link list for all msg_sender structtask_struct *tsk; // Pointer to process structure which is waiting for receiving messages };
Functions • sys_msgget() • newque() • sys_msgctl() • sys_msgsnd() & do_msgsnd() • load_msg() • pipelined_send() • sys_msgrcv() &do_msgrcv()
sys_msgget() // ipc/msg.c line 313 • Allocate a new message queue, or access to an existing message queue again. • Flags • IPC_CREAT:A new queue will be created if it is not yet created → newque() • IPC_EXCL:If IPC_CREAT is set and such a queue exists, the function will return with the error EEXIST.
sys_msgget() no OK T key=IPC_PRIVATE? msg_ids is full? (newqueue) yes ERROR F T no key is exist? msgflg & IPC_CREAT yes F ENOENT msgflg & IPC_CREAT && msgflg & IPC_EXCL ? T EEXIST ERROR msq=msg_lock() ipcperm(msgflg) EACCES msg_buildid OK
newque() // ipc/msg.c line 181 failure ipc_rcu_alloc (struct msg_queue) ENOMEM OK id==-1 id=ipc_addid() ipc_rcu_free id!=-1 set initial value ENOSPC msg_buildid (IPCMNI*seq + id) OK
sys_msgctl() // ipc/msg.c line 424 • IPC_INFO:Copy some message queue information to user space from kernel space. • IPC_STAT:Copy some message queue states to user space from kernel space. • IPC_SET:Modify values of message queue objects. • IPC_RMID:Remove all associated message queue structure.
sys_msgsnd() & do_msgsnd() // ipc/msg.c line 752 longsys_msgsnd(….){ long mtype; if (get_user(mtype, &msgp->mtype)) return -EFAULT; returndo_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg); }
sys_msgsnd() & do_msgsnd() T // ipc/msg.c line 661 msgsz > ns->msg_ctlmax || msgsz < 0 || msqid < 0 ERROR F F msg = load_msg() PTR_ERR(msg) F msq = msg_lock() EINVAL F msg_checkid, ipcperm ERROR EINTER EAGAIN msgsz + q_cbytes > q_qbytes || q_qnum +1 > q_qbyte T F T T F msgflg & IPC_NOWAIT Update q_lspid ,q_stime Check signal_pending F OK Add to q_senders pipelined_send() Remove from q_senders No one is waiting OK msq=msg_lock() call schedule() Add to q_messages F EIDRM END
load_msg() ……….
load_msg() // ipc/msgutil.c line 28 while (len > 0) { struct msg_msgseg *seg; alen = len; if (alen > DATALEN_SEG) alen = DATALEN_SEG; seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL); if (seg == NULL) { err = -ENOMEM; goto out_err; } *pseg = seg; seg->next = NULL; if (copy_from_user(seg + 1, src, alen)) { err = -EFAULT; goto out_err; } pseg = &seg->next; len -= alen; src = ((char __user *)src) + alen; }
pipelined_send() msr=msg_receiver.r_list testmsg(r_msgtype, r_mode) OK F Delete msr r_maxsize < msg->m_ts T F r_msg=E2BIG r_msg=msg wakeup r_tsk wakeup r_tsk T FOUND next msg_receiver F END
sys_msgrcv() &do_msgrcv() F msqid<0 || msqsz<0 msg=msg_lock() T F OK EINVAL F ERROR ipcperms OK T msq->q_messages.next != &msq->q_messages testmsg() F F T found_msg F T add to q_receivers msgflg & IPC_NOWAIT msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR ENOMSG schedule() F Check has_messages Remove found_msg rcu_read_lock() F T wakeup q_senders Check signal_pending F T END put msg to user space EINTR OK F EFAULT
Data Structure • init_sem_ids • sem • sem_array • sem_queue • sem_undo
Data Structure • init_sem_ids • sem • sem_array • sem_queue • sem_undo
init_sem_ids static struct ipc_ids init_sem_ids; //ipc/sem.c line 95 structipc_ids { //ipc/util.h line 31 int in_use; unsigned short seq; unsigned short seq_max; structrw_semaphore rw_mutex; structidr ipcs_idr; };
Data Structure • init_sem_ids • sem • sem_array • sem_queue • sem_undo
sem structsem { //include/linux/sem.h line 85 int semval; //current value int sempid; //pid of last operation };
Data Structure • init_sem_ids • sem • sem_array • sem_queue • sem_undo
sem_array structsem_array { //include/linux/sem.h line 91 structkern_ipc_perm sem_perm; //permissions time_t sem_otime; //last semop time time_t sem_ctime; //last change time structsem *sem_base; //ptr to first semaphore in array struct sem_queue *sem_pending; //pending operations to be processed structsem_queue **sem_pending_last; //last pending operation structsem_undo *undo; //undo requests on this array unsigned long sem_nsems; //no. of semaphores in array };
Data Structure • init_sem_ids • sem • sem_array • sem_queue • sem_undo
sem_queue structsem_queue { //include/linux/sem.h line 103 structsem_queue *next; //next entry in the queue structsem_queue **prev; //previous entry in the queue, *(q->prev) == q structtask_struct *sleeper; //this process structsem_undo *undo; //undo structure int pid; //process id of requesting process int status; //completion status of operation structsem_array *sma; //semaphore array for operations int id; //internal sem id struct sembuf *sops; //array of pending operations int nsops; //number of operations int alter; //does the operation alter the array? };
Data Structure • init_sem_ids • sem • sem_array • sem_queue • sem_undo
sem_undo struct sem_undo { //include/linux/sem.h line 120 structsem_undo *proc_next; //next entry on this process structsem_undo *id_next; //next entry on this semaphore set int semid; //semaphore set identifier short *semadj; //array of adjustments, one per semaphore };
Functions • sys_semget() • newary() • sys_semctl() • semctl_nolock() • semctl_main() • semctl_down() • sys_semop() • sys_semtimedop() • update_to_queue()
sys_semget() // ipc/sem.c line 335 • Allocate a new semaphore, or access to an existing semaphore again. • Flags • IPC_CREAT:A new semaphore will be created if it is not yet created → newary() • IPC_EXCL:If IPC_CREAT is set and such a semaphore exists, the function will return with the error EEXIST.
sys_semget() no OK T key=IPC_PRIVATE Init_sem_ids is full? (newary) yes ERROR F T no key is exist? semflg & IPC_CREATE yes F ENOENT semflg & IPC_CREATE && semflg & IPC_EXCL ? T EEXIST T ERROR sma=sem_lock() T ipcperm(semflg) EACCES sem_buildid OK
newary() // ipc/sem.c line 255 failure ipc_rcu_alloc (struct aem_array) ENOMEM OK id==-1 id=ipc_addid() ipc_rcu_free id!=-1 set initial value ENOSPC sem_buildid (IPCMNI*seq + id) OK
sys_semget() asmlinkagelong sys_semget (key_t key, int nsems, int semflg) { // ipc/sem.c line 335 if (nsems < 0 || nsems > ns->sc_semmsl) return -EINVAL; if (key == IPC_PRIVATE) { newary(); }else if ((id = ipc_findkey(&sem_ids(ns), key)) == -1) { if (!(semflg & IPC_CREAT)) err = -ENOENT; else newary(); }else if (semflg & IPC_CREAT && semflg & IPC_EXCL) { err = -EEXIST; }else //other code }
Functions • sys_semget() • newary() • sys_semctl() • semctl_nolock() • semctl_main() • semctl_down() • sys_semop() • sys_semtimedop() • update_to_queue()
sys_semctl() // ipc/sem.c line 967 true cmd = IPC_INFO ? cmd = SEM_INFO ? cmd = SEM_STAT ? failure semctl_nolock cmd = GETALL ? cmd = GETVAL ? cmd = GETPID ? cmd = GETNCNT ? cmd = GETZCNT ? cmd = IPC_STAT ? cmd = SETVAL ? cmd = SETALL ? true semctl_main semctl_main failure true cmd = IPC_RMID ? cmd = IPC_SET ? failure EINVAL
semctl_nolock() staticint semctl_nolock(structipc_namespace *ns, int semid, int semnum, int cmd, int version, union semun arg) { // ipc/sem.c line 610 switch(cmd) { case IPC_INFO: case SEM_INFO: …… return (max_id < 0) ? 0: max_id; case SEM_STAT: …… return id; default: return -EINVAL; } }
semctl_main() if(semnum < 0 || semnum >= nsems) goto out_unlock; case GETVAL: // sem_base[semnum].semval case GETPID: // sem_base[semnum].sempid case GETNCNT: // count_semncnt() case GETZCNT: // count_semzcnt() case SETVAL: // set sem_case[semnum] default: err = -EINVAL; } sem_unlock(sma); } staticint semctl_main(structipc_namespace *ns, int semid, int semnum,int cmd, int version, union semun arg) { // ipc/sem.c line 689 sma = sem_lock_check(ns, semid); switch (cmd) { case GETALL: // get sem_base[] value case SETALL: // set sem_base[] value case IPC_STAT: // get semid64_ds
semctl_down() staticint semctl_down(structipc_namespace *ns, int semid, int semnum, int cmd, int version, union semun arg) { // ipc/sem.c line 904 if(cmd == IPC_SET) if(copy_semid_from_user (&setbuf, arg.buf, version)) return -EFAULT; sma = sem_lock_check_down(ns, semid); switch(cmd){ case IPC_RMID: freeary(ns, sma); case IPC_SET: //update uid, gid, mode default: err = -EINVAL; } sem_unlock(sma); }
Functions • sys_semget() • newary() • sys_semctl() • semctl_nolock() • semctl_main() • semctl_down() • sys_semop() • sys_semtimedop() • update_to_queue()
sys_semop() asmlinkagelong sys_semop (int semid, structsembuf __user *tsops, unsigned nsops) { // ipc/sem.c line 1288 return sys_semtimedop(semid, tsops, nsops, NULL); }
sys_semtimedop() return = 0 < 0 Do checks return update_queue() > 0 try_atomic_semop() return error return append_to_queue()
sys_semtimedop() asmlinkagelong sys_semtimedop(int semid, struct sembuf __user *tsops, unsigned nsops, const structtimespec __user *timeout) {// ipc/sem.c line 1122 sma = sem_lock_check(ns, semid); // do checks error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current)); if (error == 0) update_queue (sma); else if (error > 0) append_to_queue(sma ,&queue); // do checks sem_unlock(sma); return error; }