1 / 97

I P C u920938 顏嘉佑

I P C u920938 顏嘉佑. Chapter 1: System V. System V IPC. Semaphore: syncronization Message Queue: one to one share data Share Memory: like bulletin board . System Call. Chapter 2: Semaphore. What is semaphore ?. 2.1: introduction.

Download Presentation

I P C u920938 顏嘉佑

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. I P Cu920938 顏嘉佑

  2. Chapter 1: System V

  3. System V IPC • Semaphore: syncronization • Message Queue: one to one share data • Share Memory: like bulletin board System Call

  4. Chapter 2: Semaphore

  5. What is semaphore ?

  6. 2.1: introduction Critical Section: 受保護的資源,被多個process所共享,但同一時間,只能有一個process使用之。 section 1a section 2a Wait(S) Wait(S) Share Data Critical Section Crtical Section Signal(s) Signal(S) section 1b section 2b

  7. not efficiency!!! Singal(S) { S++; } Wait(S) { while(S<=0) ; S--; } How to improve???

  8. System V Semaphore VSKernel Syncronization • 每個IPC semaphore資源提供多組計數器 (semaphore primitive),可對多個資源進行保護動作。 • 提供UNDO機制,使當process意外終止時,所掌控的semaphore得以復原,避免dead lock的產生。

  9. 2.2: Data Structure • ipc_ids • sem_array • sem_queue • sem • sembuf • sem_undo

  10. structipc_ids{ • int in_use; • int max_id; • unsignedshort seq; • unsignedshort seq_max; • structmutex mutex; • structipc_id_ary nullentry; • structipc_id_ary* entries;}; staticstructipc_idssem_ids;

  11. struct sem_array{ • struct kern_ipc_perm sem_perm; • int sem_id; • time_t sem_otime; • time_t sem_ctime; • struct sem *sem_base; • struct sem_queue *sem_pending; • structsem_queue **sem_pending_last; • struct sem_undo *undo; • unsigned long sem_nsems; };

  12. structsem_queue{ • structsem_queue * next; • structsem_queue ** prev; • structtask_struct* sleeper; • structsem_undo * undo; • int pid; • int status; • structsem_array * sma; • intid; • structsembuf * sops; • int nsops; • int alter; }

  13. structsem{ • int semval; • int sempid; };

  14. structsembuf{ • unsigned short sem_num; • short sem_op; • short sem_flg; };

  15. structsem_undo{ • structsem_undo * proc_next; • structsem_undo * id_next; • int semid; • short * semadj; };

  16. sem_ids的結構圖 O'Reilly-Understanding_The_Linux Kernel_3rd

  17. 2.3 重要的函式 • sys_semget • newary、sem_buildid • sys_semctl • semctl_nolock、semctl_main、semctl_down • sys_semop • try_atomic_semop、update_queue • sem_exit

  18. sys_semget • FLAG : 依使用者需求做調整 • IPC_CREAT • IPC_EXCL • CHECK參數是否有誤? • 根據FLAG判斷是否是建立新的IPC物件還是 回傳已存在的identifier,甚至回傳錯誤訊息。

  19. sys_semget: flow chart true false

  20. asmlinkage long sys_semget (key_t key, int nsems, int semflg) { int id, err = -EINVAL; struct sem_array *sma; struct ipc_namespace *ns; ns = current->nsproxy->ipc_ns; if (nsems < 0 || nsems > ns->sc_semmsl) return -EINVAL; mutex_lock(&sem_ids(ns).mutex); // kernel syncronization if (key == IPC_PRIVATE) { err = newary(ns, key, nsems, semflg); } else if ((id = ipc_findkey(&sem_ids(ns), key)) == -1) { check range create a new IPC key exist in the system ?

  21. If not found the key and not set the ENOENT flag if (!(semflg & IPC_CREAT)) err = -ENOENT; else err = newary(ns, key, nsems, semflg); } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) { err = -EEXIST; } else { sma = sem_lock(ns, id); BUG_ON(sma==NULL); if (nsems > sma->sem_nsems) err = -EINVAL; else if (ipcperms(&sma->sem_perm, semflg)) err = -EACCES; else { int semid = sem_buildid(ns, id, sma->sem_perm.seq); err = security_sem_associate(sma, semflg); if (!err) err = semid; IPC_EXCL IPC_CREAT are both set so return EEXIST S*IPCMNI+id

  22. } sem_unlock(sma); } sem_unlock(sma); } mutex_unlock(&sem_ids(ns).mutex); return err; }

  23. newary: flow chart failure size=sizeof (*sma) + nsems * sizeof (struct sem); ipc_rcu_alloc(size); ENOMEM id = ipc_addid(&sem_ids(ns), &sma-> sem_perm, ns->sc_semmni); Ipc_rcu_putref(sma); return -ENOSPC; Id == -1 Id !=-1 set initial value sem_buildid : s+IPCMNI+id DONE

  24. staticintnewary (struct ipc_namespace *ns, key_t key, int nsems, int semflg) ………. if (!nsems) return -EINVAL; if (ns->used_sems + nsems > ns->sc_semmns) return -ENOSPC; size = sizeof (*sma) + nsems * sizeof (struct sem); sma = ipc_rcu_alloc(size); if (!sma) { return -ENOMEM; } memset (sma, 0, size); sma->sem_perm.mode = (semflg & S_IRWXUGO); sma->sem_perm.key = key; sma->sem_perm.security = NULL; retval = security_sem_alloc(sma); if (retval) { ipc_rcu_putref(sma); return retval; }

  25. id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); if(id == -1) { security_sem_free(sma); ipc_rcu_putref(sma); return -ENOSPC; } ns->used_sems += nsems; sma->sem_id = sem_buildid(ns, id, sma->sem_perm.seq); sma->sem_base = (struct sem *) &sma[1]; /* sma->sem_pending = NULL; */ sma->sem_pending_last = &sma->sem_pending; /* sma->undo = NULL; */ sma->sem_nsems = nsems; sma->sem_ctime = get_seconds(); sem_unlock(sma); return sma->sem_id; } for (id = 0; id < size; id++) { if(ids->entries->p[id] == NULL) goto found; } …………….. ids->entries->p[id] = new; return id;

  26. sys_semctl (int semid, int semnum, int cmd, union semun arg) • 判斷傳入的cmd類型。 • 若為IPC_INFO ,SEM_INFO,SEM_STAT這三類的話,執行semctl_nolock函式。 • 若為GETVAL,GETALL,GETPID,GETNCNT,GETZCNT,IPC_STAT,SETVAL,SETALL。執行semctl_main函式。 • 若為IPC_RMID,IPC_SET則執行semctl_down函式。

  27. sys_semctl: flow chart true cmd = IPC_INFO? cmd = SEM_INFO? cmd = SEM_STAT? semct_nolock false Cmd = GETALL? Cmd = GETVAL? Cmd = GETPID? Cmd = GETNCNT? Cmd = GETZVNT? Cmd = IPC_STAT? Cmd = SETVAL? Cmd = SETALL? true semctl_main false true cmd = IPC_RMID? cmd = IPC_SET? Semctl_down false EINVAL

  28. switch(cmd) { case IPC_INFO: case SEM_INFO: case SEM_STAT: err = semctl_nolock(ns,semid,semnum,cmd,version,arg); return err; case GETALL: case GETVAL: case GETPID: case GETNCNT: case GETZCNT: case IPC_STAT: case SETVAL: case SETALL: err = semctl_main(ns,semid,semnum,cmd,version,arg); return err; case IPC_RMID: case IPC_SET: mutex_lock(&sem_ids(ns).mutex); err = semctl_down(ns,semid,semnum,cmd,version,arg); mutex_unlock(&sem_ids(ns).mutex); return err; default: return -EINVAL; }

  29. semctl_nolock: flow chart true fill seminfo items cmd= IPC_INFO or SEM_INFO? false EINVAL Cmd=SEM_STAT? copy_to_user true DONE Get semid64_ds info copy_semid_to_user DONE

  30. struct seminfo seminfo; ………. memset(&seminfo,0,sizeof(seminfo)); seminfo.semmni = ns->sc_semmni; seminfo.semmns = ns->sc_semmns; seminfo.semmsl = ns->sc_semmsl; seminfo.semopm = ns->sc_semopm; seminfo.semvmx = SEMVMX; seminfo.semmnu = SEMMNU; seminfo.semmap = SEMMAP; seminfo.semume = SEMUME; mutex_lock(&sem_ids(ns).mutex); if (cmd == SEM_INFO) { seminfo.semusz = sem_ids(ns).in_use; seminfo.semaem = ns->used_sems; } else { seminfo.semusz = SEMUSZ; seminfo.semaem = SEMAEM; } max_id = sem_ids(ns).max_id;

  31. struct semid64_ds tbuf; int id; if(semid >= sem_ids(ns).entries->size) return -EINVAL; memset(&tbuf,0,sizeof(tbuf)); sma = sem_lock(ns, semid); if(sma == NULL) return -EINVAL; err = -EACCES; if (ipcperms (&sma->sem_perm, S_IRUGO)) goto out_unlock; err = security_sem_semctl(sma, cmd); if (err) goto out_unlock; id = sem_buildid(ns, semid, sma->sem_perm.seq); kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); tbuf.sem_otime = sma->sem_otime; tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; sem_unlock(sma); if (copy_semid_to_user (arg.buf, &tbuf, version)) return -EFAULT; return id; 35768*seq + id

  32. EINVAL semctl_main: flow chart false cmd = SETVAL? failure sma = sem_lock() false EINVAL failure cmd = GETZCNT? OK count_semzcnt() EIDRM sem_checkid false OK failure count_semncnt() cmd = GETTNCNT? ipcperms EACCESS false OK true cmd = GRTPID? cmd = GETALL? get sem_base false false true cmd = SETALL? cmd = GETVAL set sem_base false false cmd = IPC_STAT? semnum < 0 || semnum >= nsems true true Get semid64_ds EINVAL

  33. …………………… sma = sem_lock(ns, semid); if(sma==NULL) return -EINVAL; nsems = sma->sem_nsems; err=-EIDRM; if (sem_checkid(ns,sma,semid)) goto out_unlock; err = -EACCES; if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO\ :S_IRUGO)) goto out_unlock; err = security_sem_semctl(sma, cmd); if (err) goto out_unlock;

  34. GETALL: ushort* sem_io = fast_sem_io; ……………….. for (i = 0; i < sma->sem_nsems; i++) sem_io[i] = sma->sem_base[i].semval; sem_unlock(sma); err = 0; if(copy_to_user(array, sem_io, nsems*sizeof(ushort))) err = -EFAULT; goto out_free;

  35. SETALL: if (copy_from_user (sem_io, arg.array,\ nsems*sizeof(ushort))) { ipc_lock_by_ptr(&sma->sem_perm); ipc_rcu_putref(sma); sem_unlock(sma); err = -EFAULT; goto out_free; } for (i = 0; i < nsems; i++) { if (sem_io[i] > SEMVMX) { …… sem_unlock(sma); err = -ERANGE; goto out_free; } } for (i = 0; i < nsems; i++) sma->sem_base[i].semval = sem_io[i]; for (un = sma->undo; un; un = un->id_next) for (i = 0; i < nsems; i++) un->semadj[i] = 0; sma->sem_ctime = get_seconds(); update_queue(sma); err = 0; goto out_unlock;

  36. IPC_STAT GETVAL GETPID case IPC_STAT:{ struct semid64_ds tbuf; memset(&tbuf,0,sizeof(tbuf)); kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); tbuf.sem_otime = sma->sem_otime; tbuf.sem_ctime = sma->sem_ctime; tbuf.sem_nsems = sma->sem_nsems; sem_unlock(sma); if (copy_semid_to_user (arg.buf, &tbuf, version)) return -EFAULT; return0; } -------------------------------------------------------------------------------------- case GETVAL: err = curr->semval; goto out_unlock; case GETPID: err = curr->sempid; goto out_unlock; return err;

  37. count_semzcnt staticint count_semzcnt (struct sem_array * sma, ushort semnum) { int semzcnt; struct sem_queue * q; semzcnt = 0; for (q = sma->sem_pending; q; q = q->next) { struct sembuf * sops = q->sops; int nsops = q->nsops; int i; for (i = 0; i < nsops; i++) if (sops[i].sem_num == semnum && (sops[i].sem_op == 0) && !(sops[i].sem_flg & IPC_NOWAIT)) semzcnt++; } return semzcnt; }

  38. count_semncnt staticint count_semncnt (struct sem_array * sma, ushort semnum) { int semncnt; struct sem_queue * q; semncnt = 0; for (q = sma->sem_pending; q; q = q->next) { struct sembuf * sops = q->sops; int nsops = q->nsops; int i; for (i = 0; i < nsops; i++) if (sops[i].sem_num == semnum && (sops[i].sem_op < 0) && !(sops[i].sem_flg & IPC_NOWAIT)) semncnt++; } return semncnt; }

  39. semctl_down: flow chart failure true cmd = IPC_SET? copy_semid_from_user EFAULT false OK failure sma = sem_lock() EINVAL OK failure OK failure EPERM EIDRM check cuid uid ? sem_checkid OK true END cmd = IPC_RMID? cmd = IPC_SET? false true cmd = IPC_SET? cmd = IPC_SET? END false EINVAL

  40. if(cmd == IPC_SET) { if(copy_semid_from_user (&setbuf, arg.buf, version)) return -EFAULT; } sma = sem_lock(ns, semid); if(sma==NULL) return -EINVAL; if (sem_checkid(ns,sma,semid)) { err=-EIDRM; goto out_unlock; } …………………………………. case IPC_RMID: freeary(ns, sma, semid); err = 0; break; case IPC_SET: ipcp->uid = setbuf.uid; ipcp->gid = setbuf.gid; ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | (setbuf.mode & S_IRWXUGO); sma->sem_ctime = get_seconds(); sem_unlock(sma); err = 0; break;

  41. freeary for (un = sma->undo; un; un = un->id_next) un->semid = -1; /* Wake up all pending processes and let them fail with EIDRM. */ q = sma->sem_pending; while(q) { struct sem_queue *n; /* lazy remove_from_queue: we are killing the whole queue */ q->prev = NULL; n = q->next; q->status = IN_WAKEUP; wake_up_process(q->sleeper); /* doesn't sleep */ smp_wmb(); q->status = -EIDRM; /* hands-off q */ q = n; } /* Remove the semaphore set from the ID array*/ sma = sem_rmid(ns, id); sem_unlock(sma); ids->in_use--; if (lid == ids->max_id) { do { lid--; if(lid == -1) break; } while (ids->entries->p[lid] == NULL); ids->max_id = lid; }

  42. sys_semop if (nsops < 1 || semid < 0) return -EINVAL; if (nsops > ns->sc_semopm) return -E2BIG; if(nsops > SEMOPM_FAST) { sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL); if(sops==NULL) return -ENOMEM; } if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) { error=-EFAULT; goto out_free; } ………… max = 0;

  43. for (sop = sops; sop < sops + nsops; sop++) { if (sop->sem_num >= max) max = sop->sem_num; if (sop->sem_flg & SEM_UNDO) undos = 1; if (sop->sem_op != 0) alter = 1; } error = try_atomic_semop (sma, sops, nsops, un, current->tgid); if (error <= 0) { if (alter && error == 0) update_queue (sma); goto out_unlock_free; } queue.sma = sma; queue.sops = sops; queue.nsops = nsops; queue.undo = un; queue.pid = current->tgid; queue.id = semid; queue.alter = alter;

  44. if (alter) append_to_queue(sma ,&queue); else prepend_to_queue(sma ,&queue); queue.status = -EINTR; queue.sleeper = current; current->state = TASK_INTERRUPTIBLE; sem_unlock(sma); …………… schedule();

  45. staticvoid update_queue (struct sem_array * sma) { int error; struct sem_queue * q; q = sma->sem_pending; while(q) { error = try_atomic_semop(sma, q->sops, q->nsops, q->undo, q->pid); /* Does q->sleeper still need to sleep? */ if (error <= 0) { struct sem_queue *n; remove_from_queue(sma,q); q->status = IN_WAKEUP; if (q->alter) n = sma->sem_pending; else n = q->next; wake_up_process(q->sleeper); smp_wmb(); q->status = error; q = n; } else { q = q->next; } } } update queue

  46. for (sop = sops; sop < sops + nsops; sop++) { curr = sma->sem_base + sop->sem_num; sem_op = sop->sem_op; result = curr->semval; if (!sem_op && result) goto would_block; result += sem_op; if (result < 0) goto would_block; if (result > SEMVMX) goto out_of_range; if (sop->sem_flg & SEM_UNDO) { int undo = un->semadj[sop->sem_num] - sem_op; /* * Exceeding the undo range is an error. */ if (undo < (-SEMAEM - 1) || undo > SEMAEM) goto out_of_range; } curr->semval = result; } try_atomic_semop

  47. sop--; while (sop >= sops) { sma->sem_base[sop->sem_num].sempid = pid; if (sop->sem_flg & SEM_UNDO) un->semadj[sop->sem_num] -= sop->sem_op; sop--; } sma->sem_otime = get_seconds(); return0;

  48. out_of_range: result = -ERANGE; goto undo; would_block: if (sop->sem_flg & IPC_NOWAIT) result = -EAGAIN; else result = 1; undo: sop--; while (sop >= sops) { sma->sem_base[sop->sem_num].semval -= sop->sem_op; sop--; } return result;

  49. for (up = &undo_list->proc_list; (u = *up); *up = u->proc_next, kfree(u)) { struct sem_array *sma; int nsems, i; struct sem_undo *un, **unp; int semid; semid = u->semid; if(semid == -1) continue; sma = sem_lock(ns, semid); if (sma == NULL) continue; if (u->semid == -1) goto next_entry; BUG_ON(sem_checkid(ns,sma,u->semid)); for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { if (u == un) goto found; } printk ("exit_sem undo list error id=%d\n", u->semid); goto next_entry; sem_exit

More Related